2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
145 # if HAVE_LIBREADLINE /* add gnu-readline support */
146 #include <readline/readline.h>
147 #include <readline/history.h>
150 #include <X11/Intrinsic.h>
151 #include <X11/StringDefs.h>
152 #include <X11/Shell.h>
153 #include <X11/cursorfont.h>
154 #include <X11/Xatom.h>
155 #include <X11/Xmu/Atoms.h>
157 #include <X11/Xaw3d/Dialog.h>
158 #include <X11/Xaw3d/Form.h>
159 #include <X11/Xaw3d/List.h>
160 #include <X11/Xaw3d/Label.h>
161 #include <X11/Xaw3d/SimpleMenu.h>
162 #include <X11/Xaw3d/SmeBSB.h>
163 #include <X11/Xaw3d/SmeLine.h>
164 #include <X11/Xaw3d/Box.h>
165 #include <X11/Xaw3d/MenuButton.h>
166 #include <X11/Xaw3d/Text.h>
167 #include <X11/Xaw3d/AsciiText.h>
169 #include <X11/Xaw/Dialog.h>
170 #include <X11/Xaw/Form.h>
171 #include <X11/Xaw/List.h>
172 #include <X11/Xaw/Label.h>
173 #include <X11/Xaw/SimpleMenu.h>
174 #include <X11/Xaw/SmeBSB.h>
175 #include <X11/Xaw/SmeLine.h>
176 #include <X11/Xaw/Box.h>
177 #include <X11/Xaw/MenuButton.h>
178 #include <X11/Xaw/Text.h>
179 #include <X11/Xaw/AsciiText.h>
182 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
187 #include "pixmaps/pixmaps.h"
188 #define IMAGE_EXT "xpm"
190 #define IMAGE_EXT "xim"
191 #include "bitmaps/bitmaps.h"
194 #include "bitmaps/icon_white.bm"
195 #include "bitmaps/icon_black.bm"
196 #include "bitmaps/checkmark.bm"
198 #include "frontend.h"
200 #include "backendz.h"
204 #include "xgamelist.h"
205 #include "xhistory.h"
206 #include "xedittags.h"
209 // must be moved to xengineoutput.h
211 void EngineOutputProc P((Widget w, XEvent *event,
212 String *prms, Cardinal *nprms));
213 void EvalGraphProc P((Widget w, XEvent *event,
214 String *prms, Cardinal *nprms));
221 #define usleep(t) _sleep2(((t)+500)/1000)
225 # define _(s) gettext (s)
226 # define N_(s) gettext_noop (s)
242 int main P((int argc, char **argv));
243 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
244 char *init_path, char *mode, int (*show_entry)(), char **name_return));
245 RETSIGTYPE CmailSigHandler P((int sig));
246 RETSIGTYPE IntSigHandler P((int sig));
247 RETSIGTYPE TermSizeSigHandler P((int sig));
248 void CreateGCs P((void));
249 void CreateXIMPieces P((void));
250 void CreateXPMPieces P((void));
251 void CreateXPMBoard P((char *s, int n));
252 void CreatePieces P((void));
253 void CreatePieceMenus P((void));
254 Widget CreateMenuBar P((Menu *mb));
255 Widget CreateButtonBar P ((MenuItem *mi));
256 char *FindFont P((char *pattern, int targetPxlSize));
257 void PieceMenuPopup P((Widget w, XEvent *event,
258 String *params, Cardinal *num_params));
259 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
260 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
261 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
262 u_int wreq, u_int hreq));
263 void CreateGrid P((void));
264 int EventToSquare P((int x, int limit));
265 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
266 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
267 void HandleUserMove P((Widget w, XEvent *event,
268 String *prms, Cardinal *nprms));
269 void AnimateUserMove P((Widget w, XEvent * event,
270 String * params, Cardinal * nParams));
271 void HandlePV P((Widget w, XEvent * event,
272 String * params, Cardinal * nParams));
273 void SelectPV P((Widget w, XEvent * event,
274 String * params, Cardinal * nParams));
275 void StopPV P((Widget w, XEvent * event,
276 String * params, Cardinal * nParams));
277 void WhiteClock P((Widget w, XEvent *event,
278 String *prms, Cardinal *nprms));
279 void BlackClock P((Widget w, XEvent *event,
280 String *prms, Cardinal *nprms));
281 void DrawPositionProc P((Widget w, XEvent *event,
282 String *prms, Cardinal *nprms));
283 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
285 void CommentClick P((Widget w, XEvent * event,
286 String * params, Cardinal * nParams));
287 void CommentPopUp P((char *title, char *label));
288 void CommentPopDown P((void));
289 void CommentCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void ICSInputBoxPopUp P((void));
292 void ICSInputBoxPopDown P((void));
293 void FileNamePopUp P((char *label, char *def,
294 FileProc proc, char *openMode));
295 void FileNamePopDown P((void));
296 void FileNameCallback P((Widget w, XtPointer client_data,
297 XtPointer call_data));
298 void FileNameAction P((Widget w, XEvent *event,
299 String *prms, Cardinal *nprms));
300 void AskQuestionReplyAction P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void AskQuestionProc P((Widget w, XEvent *event,
303 String *prms, Cardinal *nprms));
304 void AskQuestionPopDown P((void));
305 void PromotionPopDown P((void));
306 void PromotionCallback P((Widget w, XtPointer client_data,
307 XtPointer call_data));
308 void EditCommentPopDown P((void));
309 void EditCommentCallback P((Widget w, XtPointer client_data,
310 XtPointer call_data));
311 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
312 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
316 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
318 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
320 void LoadPositionProc P((Widget w, XEvent *event,
321 String *prms, Cardinal *nprms));
322 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
324 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
326 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
328 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
330 void PastePositionProc P((Widget w, XEvent *event, String *prms,
332 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void SavePositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
340 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
344 void MachineWhiteProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void AnalyzeModeProc P((Widget w, XEvent *event,
347 String *prms, Cardinal *nprms));
348 void AnalyzeFileProc P((Widget w, XEvent *event,
349 String *prms, Cardinal *nprms));
350 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
352 void IcsClientProc P((Widget w, XEvent *event, String *prms,
354 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void EditPositionProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void EditCommentProc P((Widget w, XEvent *event,
359 String *prms, Cardinal *nprms));
360 void IcsInputBoxProc P((Widget w, XEvent *event,
361 String *prms, Cardinal *nprms));
362 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void StopObservingProc P((Widget w, XEvent *event, String *prms,
378 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
380 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
389 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
391 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
394 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
396 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
398 void AutocommProc P((Widget w, XEvent *event, String *prms,
400 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void AutobsProc P((Widget w, XEvent *event, String *prms,
404 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
409 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
412 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
414 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
416 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
420 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
422 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
424 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
426 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
428 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
432 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
434 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
436 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
438 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void DisplayMove P((int moveNumber));
450 void DisplayTitle P((char *title));
451 void ICSInitScript P((void));
452 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
453 void ErrorPopUp P((char *title, char *text, int modal));
454 void ErrorPopDown P((void));
455 static char *ExpandPathName P((char *path));
456 static void CreateAnimVars P((void));
457 static void DragPieceMove P((int x, int y));
458 static void DrawDragPiece P((void));
459 char *ModeToWidgetName P((GameMode mode));
460 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
468 void GameListOptionsPopDown P(());
469 void ShufflePopDown P(());
470 void EnginePopDown P(());
471 void UciPopDown P(());
472 void TimeControlPopDown P(());
473 void NewVariantPopDown P(());
474 void SettingsPopDown P(());
475 void update_ics_width P(());
476 int get_term_width P(());
477 int CopyMemoProc P(());
479 # if HAVE_LIBREADLINE /* add gnu-readline support */
480 static void ReadlineCompleteHandler P((char *));
484 * XBoard depends on Xt R4 or higher
486 int xtVersion = XtSpecificationRelease;
491 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
492 jailSquareColor, highlightSquareColor, premoveHighlightColor;
493 Pixel lowTimeWarningColor;
494 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
495 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
496 wjPieceGC, bjPieceGC, prelineGC, countGC;
497 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
498 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
499 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
500 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
501 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
502 ICSInputShell, fileNameShell, askQuestionShell;
503 Widget historyShell, evalGraphShell, gameListShell;
504 int hOffset; // [HGM] dual
505 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
506 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
507 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
508 Font clockFontID, coordFontID, countFontID;
509 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
510 XtAppContext appContext;
512 char *oldICSInteractionTitle;
516 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
518 # if HAVE_LIBREADLINE /* gnu readline support */
519 static char* readline_buffer;
520 static int readline_complete=0;
521 extern int sending_ICS_login;
522 extern int sending_ICS_password;
525 Position commentX = -1, commentY = -1;
526 Dimension commentW, commentH;
527 typedef unsigned int BoardSize;
529 Boolean chessProgram;
531 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
532 int squareSize, smallLayout = 0, tinyLayout = 0,
533 marginW, marginH, // [HGM] for run-time resizing
534 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
535 ICSInputBoxUp = False, askQuestionUp = False,
536 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
537 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
538 Pixel timerForegroundPixel, timerBackgroundPixel;
539 Pixel buttonForegroundPixel, buttonBackgroundPixel;
540 char *chessDir, *programName, *programVersion,
541 *gameCopyFilename, *gamePasteFilename;
542 Boolean alwaysOnTop = False;
543 Boolean saveSettingsOnExit;
544 char *settingsFileName;
545 char *icsTextMenuString;
547 char *firstChessProgramNames;
548 char *secondChessProgramNames;
550 WindowPlacement wpMain;
551 WindowPlacement wpConsole;
552 WindowPlacement wpComment;
553 WindowPlacement wpMoveHistory;
554 WindowPlacement wpEvalGraph;
555 WindowPlacement wpEngineOutput;
556 WindowPlacement wpGameList;
557 WindowPlacement wpTags;
561 Pixmap pieceBitmap[2][(int)BlackPawn];
562 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
563 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
564 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
565 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
566 Pixmap xpmBoardBitmap[2];
567 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
568 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
569 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
570 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
571 XImage *ximLightSquare, *ximDarkSquare;
574 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
575 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
577 #define White(piece) ((int)(piece) < (int)BlackPawn)
579 /* Variables for doing smooth animation. This whole thing
580 would be much easier if the board was double-buffered,
581 but that would require a fairly major rewrite. */
586 GC blitGC, pieceGC, outlineGC;
587 XPoint startSquare, prevFrame, mouseDelta;
591 int startBoardX, startBoardY;
594 /* There can be two pieces being animated at once: a player
595 can begin dragging a piece before the remote opponent has moved. */
597 static AnimState game, player;
599 /* Bitmaps for use as masks when drawing XPM pieces.
600 Need one for each black and white piece. */
601 static Pixmap xpmMask[BlackKing + 1];
603 /* This magic number is the number of intermediate frames used
604 in each half of the animation. For short moves it's reduced
605 by 1. The total number of frames will be factor * 2 + 1. */
608 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
610 MenuItem fileMenu[] = {
611 {N_("New Game"), ResetProc},
612 {N_("New Shuffle Game ..."), ShuffleMenuProc},
613 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
614 {"----", NothingProc},
615 {N_("Load Game"), LoadGameProc},
616 {N_("Load Next Game"), LoadNextGameProc},
617 {N_("Load Previous Game"), LoadPrevGameProc},
618 {N_("Reload Same Game"), ReloadGameProc},
619 {N_("Save Game"), SaveGameProc},
620 {"----", NothingProc},
621 {N_("Copy Game"), CopyGameProc},
622 {N_("Paste Game"), PasteGameProc},
623 {"----", NothingProc},
624 {N_("Load Position"), LoadPositionProc},
625 {N_("Load Next Position"), LoadNextPositionProc},
626 {N_("Load Previous Position"), LoadPrevPositionProc},
627 {N_("Reload Same Position"), ReloadPositionProc},
628 {N_("Save Position"), SavePositionProc},
629 {"----", NothingProc},
630 {N_("Copy Position"), CopyPositionProc},
631 {N_("Paste Position"), PastePositionProc},
632 {"----", NothingProc},
633 {N_("Mail Move"), MailMoveProc},
634 {N_("Reload CMail Message"), ReloadCmailMsgProc},
635 {"----", NothingProc},
636 {N_("Exit"), QuitProc},
640 MenuItem modeMenu[] = {
641 {N_("Machine White"), MachineWhiteProc},
642 {N_("Machine Black"), MachineBlackProc},
643 {N_("Two Machines"), TwoMachinesProc},
644 {N_("Analysis Mode"), AnalyzeModeProc},
645 {N_("Analyze File"), AnalyzeFileProc },
646 {N_("ICS Client"), IcsClientProc},
647 {N_("Edit Game"), EditGameProc},
648 {N_("Edit Position"), EditPositionProc},
649 {N_("Training"), TrainingProc},
650 {"----", NothingProc},
651 {N_("Show Engine Output"), EngineOutputProc},
652 {N_("Show Evaluation Graph"), EvalGraphProc},
653 {N_("Show Game List"), ShowGameListProc},
654 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
655 {"----", NothingProc},
656 {N_("Edit Tags"), EditTagsProc},
657 {N_("Edit Comment"), EditCommentProc},
658 {N_("ICS Input Box"), IcsInputBoxProc},
659 {N_("Pause"), PauseProc},
663 MenuItem actionMenu[] = {
664 {N_("Accept"), AcceptProc},
665 {N_("Decline"), DeclineProc},
666 {N_("Rematch"), RematchProc},
667 {"----", NothingProc},
668 {N_("Call Flag"), CallFlagProc},
669 {N_("Draw"), DrawProc},
670 {N_("Adjourn"), AdjournProc},
671 {N_("Abort"), AbortProc},
672 {N_("Resign"), ResignProc},
673 {"----", NothingProc},
674 {N_("Stop Observing"), StopObservingProc},
675 {N_("Stop Examining"), StopExaminingProc},
676 {N_("Upload to Examine"), UploadProc},
677 {"----", NothingProc},
678 {N_("Adjudicate to White"), AdjuWhiteProc},
679 {N_("Adjudicate to Black"), AdjuBlackProc},
680 {N_("Adjudicate Draw"), AdjuDrawProc},
684 MenuItem stepMenu[] = {
685 {N_("Backward"), BackwardProc},
686 {N_("Forward"), ForwardProc},
687 {N_("Back to Start"), ToStartProc},
688 {N_("Forward to End"), ToEndProc},
689 {N_("Revert"), RevertProc},
690 {N_("Annotate"), AnnotateProc},
691 {N_("Truncate Game"), TruncateGameProc},
692 {"----", NothingProc},
693 {N_("Move Now"), MoveNowProc},
694 {N_("Retract Move"), RetractMoveProc},
698 MenuItem optionsMenu[] = {
699 {N_("Flip View"), FlipViewProc},
700 {"----", NothingProc},
701 {N_("Adjudications ..."), EngineMenuProc},
702 {N_("General Settings ..."), UciMenuProc},
703 {N_("Engine #1 Settings ..."), FirstSettingsProc},
704 {N_("Engine #2 Settings ..."), SecondSettingsProc},
705 {N_("Time Control ..."), TimeControlProc},
706 {N_("Game List ..."), GameListOptionsPopUp},
707 {"----", NothingProc},
708 {N_("Always Queen"), AlwaysQueenProc},
709 {N_("Animate Dragging"), AnimateDraggingProc},
710 {N_("Animate Moving"), AnimateMovingProc},
711 {N_("Auto Comment"), AutocommProc},
712 {N_("Auto Flag"), AutoflagProc},
713 {N_("Auto Flip View"), AutoflipProc},
714 {N_("Auto Observe"), AutobsProc},
715 {N_("Auto Raise Board"), AutoraiseProc},
716 {N_("Auto Save"), AutosaveProc},
717 {N_("Blindfold"), BlindfoldProc},
718 {N_("Flash Moves"), FlashMovesProc},
719 {N_("Get Move List"), GetMoveListProc},
721 {N_("Highlight Dragging"), HighlightDraggingProc},
723 {N_("Highlight Last Move"), HighlightLastMoveProc},
724 {N_("Move Sound"), MoveSoundProc},
725 {N_("ICS Alarm"), IcsAlarmProc},
726 {N_("Old Save Style"), OldSaveStyleProc},
727 {N_("Periodic Updates"), PeriodicUpdatesProc},
728 {N_("Ponder Next Move"), PonderNextMoveProc},
729 {N_("Popup Exit Message"), PopupExitMessageProc},
730 {N_("Popup Move Errors"), PopupMoveErrorsProc},
731 {N_("Premove"), PremoveProc},
732 {N_("Quiet Play"), QuietPlayProc},
733 {N_("Show Coords"), ShowCoordsProc},
734 {N_("Hide Thinking"), HideThinkingProc},
735 {N_("Test Legality"), TestLegalityProc},
736 {"----", NothingProc},
737 {N_("Save Settings Now"), SaveSettingsProc},
738 {N_("Save Settings on Exit"), SaveOnExitProc},
742 MenuItem helpMenu[] = {
743 {N_("Info XBoard"), InfoProc},
744 {N_("Man XBoard"), ManProc},
745 {"----", NothingProc},
746 {N_("Hint"), HintProc},
747 {N_("Book"), BookProc},
748 {"----", NothingProc},
749 {N_("About XBoard"), AboutProc},
754 {N_("File"), fileMenu},
755 {N_("Mode"), modeMenu},
756 {N_("Action"), actionMenu},
757 {N_("Step"), stepMenu},
758 {N_("Options"), optionsMenu},
759 {N_("Help"), helpMenu},
763 #define PAUSE_BUTTON N_("P")
764 MenuItem buttonBar[] = {
767 {PAUSE_BUTTON, PauseProc},
773 #define PIECE_MENU_SIZE 18
774 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
775 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
776 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
777 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
778 N_("Empty square"), N_("Clear board") },
779 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
780 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
781 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
782 N_("Empty square"), N_("Clear board") }
784 /* must be in same order as PieceMenuStrings! */
785 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
786 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
787 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
788 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
789 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
790 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
791 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
792 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
793 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
796 #define DROP_MENU_SIZE 6
797 String dropMenuStrings[DROP_MENU_SIZE] = {
798 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
800 /* must be in same order as PieceMenuStrings! */
801 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
802 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
803 WhiteRook, WhiteQueen
811 DropMenuEnables dmEnables[] = {
829 { XtNborderWidth, 0 },
830 { XtNdefaultDistance, 0 },
834 { XtNborderWidth, 0 },
835 { XtNresizable, (XtArgVal) True },
839 { XtNborderWidth, 0 },
845 { XtNjustify, (XtArgVal) XtJustifyRight },
846 { XtNlabel, (XtArgVal) "..." },
847 { XtNresizable, (XtArgVal) True },
848 { XtNresize, (XtArgVal) False }
851 Arg messageArgs[] = {
852 { XtNjustify, (XtArgVal) XtJustifyLeft },
853 { XtNlabel, (XtArgVal) "..." },
854 { XtNresizable, (XtArgVal) True },
855 { XtNresize, (XtArgVal) False }
859 { XtNborderWidth, 0 },
860 { XtNjustify, (XtArgVal) XtJustifyLeft }
863 XtResource clientResources[] = {
864 { "flashCount", "flashCount", XtRInt, sizeof(int),
865 XtOffset(AppDataPtr, flashCount), XtRImmediate,
866 (XtPointer) FLASH_COUNT },
869 XrmOptionDescRec shellOptions[] = {
870 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
871 { "-flash", "flashCount", XrmoptionNoArg, "3" },
872 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
875 XtActionsRec boardActions[] = {
876 { "DrawPosition", DrawPositionProc },
877 { "HandleUserMove", HandleUserMove },
878 { "AnimateUserMove", AnimateUserMove },
879 { "HandlePV", HandlePV },
880 { "SelectPV", SelectPV },
881 { "StopPV", StopPV },
882 { "FileNameAction", FileNameAction },
883 { "AskQuestionProc", AskQuestionProc },
884 { "AskQuestionReplyAction", AskQuestionReplyAction },
885 { "PieceMenuPopup", PieceMenuPopup },
886 { "WhiteClock", WhiteClock },
887 { "BlackClock", BlackClock },
888 { "Iconify", Iconify },
889 { "ResetProc", ResetProc },
890 { "NewVariantProc", NewVariantProc },
891 { "LoadGameProc", LoadGameProc },
892 { "LoadNextGameProc", LoadNextGameProc },
893 { "LoadPrevGameProc", LoadPrevGameProc },
894 { "LoadSelectedProc", LoadSelectedProc },
895 { "SetFilterProc", SetFilterProc },
896 { "ReloadGameProc", ReloadGameProc },
897 { "LoadPositionProc", LoadPositionProc },
898 { "LoadNextPositionProc", LoadNextPositionProc },
899 { "LoadPrevPositionProc", LoadPrevPositionProc },
900 { "ReloadPositionProc", ReloadPositionProc },
901 { "CopyPositionProc", CopyPositionProc },
902 { "PastePositionProc", PastePositionProc },
903 { "CopyGameProc", CopyGameProc },
904 { "PasteGameProc", PasteGameProc },
905 { "SaveGameProc", SaveGameProc },
906 { "SavePositionProc", SavePositionProc },
907 { "MailMoveProc", MailMoveProc },
908 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
909 { "QuitProc", QuitProc },
910 { "MachineWhiteProc", MachineWhiteProc },
911 { "MachineBlackProc", MachineBlackProc },
912 { "AnalysisModeProc", AnalyzeModeProc },
913 { "AnalyzeFileProc", AnalyzeFileProc },
914 { "TwoMachinesProc", TwoMachinesProc },
915 { "IcsClientProc", IcsClientProc },
916 { "EditGameProc", EditGameProc },
917 { "EditPositionProc", EditPositionProc },
918 { "TrainingProc", EditPositionProc },
919 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
920 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
921 { "ShowGameListProc", ShowGameListProc },
922 { "ShowMoveListProc", HistoryShowProc},
923 { "EditTagsProc", EditCommentProc },
924 { "EditCommentProc", EditCommentProc },
925 { "IcsAlarmProc", IcsAlarmProc },
926 { "IcsInputBoxProc", IcsInputBoxProc },
927 { "PauseProc", PauseProc },
928 { "AcceptProc", AcceptProc },
929 { "DeclineProc", DeclineProc },
930 { "RematchProc", RematchProc },
931 { "CallFlagProc", CallFlagProc },
932 { "DrawProc", DrawProc },
933 { "AdjournProc", AdjournProc },
934 { "AbortProc", AbortProc },
935 { "ResignProc", ResignProc },
936 { "AdjuWhiteProc", AdjuWhiteProc },
937 { "AdjuBlackProc", AdjuBlackProc },
938 { "AdjuDrawProc", AdjuDrawProc },
939 { "EnterKeyProc", EnterKeyProc },
940 { "UpKeyProc", UpKeyProc },
941 { "DownKeyProc", DownKeyProc },
942 { "StopObservingProc", StopObservingProc },
943 { "StopExaminingProc", StopExaminingProc },
944 { "UploadProc", UploadProc },
945 { "BackwardProc", BackwardProc },
946 { "ForwardProc", ForwardProc },
947 { "ToStartProc", ToStartProc },
948 { "ToEndProc", ToEndProc },
949 { "RevertProc", RevertProc },
950 { "AnnotateProc", AnnotateProc },
951 { "TruncateGameProc", TruncateGameProc },
952 { "MoveNowProc", MoveNowProc },
953 { "RetractMoveProc", RetractMoveProc },
954 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
955 { "UciMenuProc", (XtActionProc) UciMenuProc },
956 { "TimeControlProc", (XtActionProc) TimeControlProc },
957 { "AlwaysQueenProc", AlwaysQueenProc },
958 { "AnimateDraggingProc", AnimateDraggingProc },
959 { "AnimateMovingProc", AnimateMovingProc },
960 { "AutoflagProc", AutoflagProc },
961 { "AutoflipProc", AutoflipProc },
962 { "AutobsProc", AutobsProc },
963 { "AutoraiseProc", AutoraiseProc },
964 { "AutosaveProc", AutosaveProc },
965 { "BlindfoldProc", BlindfoldProc },
966 { "FlashMovesProc", FlashMovesProc },
967 { "FlipViewProc", FlipViewProc },
968 { "GetMoveListProc", GetMoveListProc },
970 { "HighlightDraggingProc", HighlightDraggingProc },
972 { "HighlightLastMoveProc", HighlightLastMoveProc },
973 { "IcsAlarmProc", IcsAlarmProc },
974 { "MoveSoundProc", MoveSoundProc },
975 { "OldSaveStyleProc", OldSaveStyleProc },
976 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
977 { "PonderNextMoveProc", PonderNextMoveProc },
978 { "PopupExitMessageProc", PopupExitMessageProc },
979 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
980 { "PremoveProc", PremoveProc },
981 { "QuietPlayProc", QuietPlayProc },
982 { "ShowCoordsProc", ShowCoordsProc },
983 { "ShowThinkingProc", ShowThinkingProc },
984 { "HideThinkingProc", HideThinkingProc },
985 { "TestLegalityProc", TestLegalityProc },
986 { "SaveSettingsProc", SaveSettingsProc },
987 { "SaveOnExitProc", SaveOnExitProc },
988 { "InfoProc", InfoProc },
989 { "ManProc", ManProc },
990 { "HintProc", HintProc },
991 { "BookProc", BookProc },
992 { "AboutGameProc", AboutGameProc },
993 { "AboutProc", AboutProc },
994 { "DebugProc", DebugProc },
995 { "NothingProc", NothingProc },
996 { "CommentClick", (XtActionProc) CommentClick },
997 { "CommentPopDown", (XtActionProc) CommentPopDown },
998 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
999 { "TagsPopDown", (XtActionProc) TagsPopDown },
1000 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1001 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1002 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1003 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1004 { "GameListPopDown", (XtActionProc) GameListPopDown },
1005 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1006 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1007 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1008 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1009 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1010 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1011 { "EnginePopDown", (XtActionProc) EnginePopDown },
1012 { "UciPopDown", (XtActionProc) UciPopDown },
1013 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1014 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1015 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1016 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1019 char globalTranslations[] =
1020 ":<Key>F9: ResignProc() \n \
1021 :Ctrl<Key>n: ResetProc() \n \
1022 :Meta<Key>V: NewVariantProc() \n \
1023 :Ctrl<Key>o: LoadGameProc() \n \
1024 :Meta<Key>Next: LoadNextGameProc() \n \
1025 :Meta<Key>Prior: LoadPrevGameProc() \n \
1026 :Ctrl<Key>s: SaveGameProc() \n \
1027 :Ctrl<Key>c: CopyGameProc() \n \
1028 :Ctrl<Key>v: PasteGameProc() \n \
1029 :Ctrl<Key>O: LoadPositionProc() \n \
1030 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1031 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1032 :Ctrl<Key>S: SavePositionProc() \n \
1033 :Ctrl<Key>C: CopyPositionProc() \n \
1034 :Ctrl<Key>V: PastePositionProc() \n \
1035 :Ctrl<Key>q: QuitProc() \n \
1036 :Ctrl<Key>w: MachineWhiteProc() \n \
1037 :Ctrl<Key>b: MachineBlackProc() \n \
1038 :Ctrl<Key>t: TwoMachinesProc() \n \
1039 :Ctrl<Key>a: AnalysisModeProc() \n \
1040 :Ctrl<Key>f: AnalyzeFileProc() \n \
1041 :Ctrl<Key>e: EditGameProc() \n \
1042 :Ctrl<Key>E: EditPositionProc() \n \
1043 :Meta<Key>O: EngineOutputProc() \n \
1044 :Meta<Key>E: EvalGraphProc() \n \
1045 :Meta<Key>G: ShowGameListProc() \n \
1046 :Meta<Key>H: ShowMoveListProc() \n \
1047 :<Key>Pause: PauseProc() \n \
1048 :<Key>F3: AcceptProc() \n \
1049 :<Key>F4: DeclineProc() \n \
1050 :<Key>F12: RematchProc() \n \
1051 :<Key>F5: CallFlagProc() \n \
1052 :<Key>F6: DrawProc() \n \
1053 :<Key>F7: AdjournProc() \n \
1054 :<Key>F8: AbortProc() \n \
1055 :<Key>F10: StopObservingProc() \n \
1056 :<Key>F11: StopExaminingProc() \n \
1057 :Meta Ctrl<Key>F12: DebugProc() \n \
1058 :Meta<Key>End: ToEndProc() \n \
1059 :Meta<Key>Right: ForwardProc() \n \
1060 :Meta<Key>Home: ToStartProc() \n \
1061 :Meta<Key>Left: BackwardProc() \n \
1062 :Ctrl<Key>m: MoveNowProc() \n \
1063 :Ctrl<Key>x: RetractMoveProc() \n \
1064 :Meta<Key>J: EngineMenuProc() \n \
1065 :Meta<Key>U: UciMenuProc() \n \
1066 :Meta<Key>T: TimeControlProc() \n \
1067 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1068 :Ctrl<Key>F: AutoflagProc() \n \
1069 :Ctrl<Key>A: AnimateMovingProc() \n \
1070 :Ctrl<Key>P: PonderNextMoveProc() \n \
1071 :Ctrl<Key>L: TestLegalityProc() \n \
1072 :Ctrl<Key>H: HideThinkingProc() \n \
1073 :<Key>-: Iconify() \n \
1074 :<Key>F1: ManProc() \n \
1075 :<Key>F2: FlipViewProc() \n \
1076 <KeyDown>.: BackwardProc() \n \
1077 <KeyUp>.: ForwardProc() \n \
1078 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1079 \"Send to chess program:\",,1) \n \
1080 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1081 \"Send to second chess program:\",,2) \n";
1083 char boardTranslations[] =
1084 "<Btn1Down>: HandleUserMove(0) \n \
1085 Shift<Btn1Up>: HandleUserMove(1) \n \
1086 <Btn1Up>: HandleUserMove(0) \n \
1087 <Btn1Motion>: AnimateUserMove() \n \
1088 <Btn3Motion>: HandlePV() \n \
1089 <Btn3Up>: PieceMenuPopup(menuB) \n \
1090 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1091 PieceMenuPopup(menuB) \n \
1092 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1093 PieceMenuPopup(menuW) \n \
1094 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1095 PieceMenuPopup(menuW) \n \
1096 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1097 PieceMenuPopup(menuB) \n";
1099 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1100 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1102 char ICSInputTranslations[] =
1103 "<Key>Up: UpKeyProc() \n "
1104 "<Key>Down: DownKeyProc() \n "
1105 "<Key>Return: EnterKeyProc() \n";
1107 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1108 // as the widget is destroyed before the up-click can call extend-end
1109 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1111 String xboardResources[] = {
1112 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1113 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1114 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1119 /* Max possible square size */
1120 #define MAXSQSIZE 256
1122 static int xpm_avail[MAXSQSIZE];
1124 #ifdef HAVE_DIR_STRUCT
1126 /* Extract piece size from filename */
1128 xpm_getsize(name, len, ext)
1139 if ((p=strchr(name, '.')) == NULL ||
1140 StrCaseCmp(p+1, ext) != 0)
1146 while (*p && isdigit(*p))
1153 /* Setup xpm_avail */
1155 xpm_getavail(dirname, ext)
1163 for (i=0; i<MAXSQSIZE; ++i)
1166 if (appData.debugMode)
1167 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1169 dir = opendir(dirname);
1172 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1173 programName, dirname);
1177 while ((ent=readdir(dir)) != NULL) {
1178 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1179 if (i > 0 && i < MAXSQSIZE)
1189 xpm_print_avail(fp, ext)
1195 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1196 for (i=1; i<MAXSQSIZE; ++i) {
1202 /* Return XPM piecesize closest to size */
1204 xpm_closest_to(dirname, size, ext)
1210 int sm_diff = MAXSQSIZE;
1214 xpm_getavail(dirname, ext);
1216 if (appData.debugMode)
1217 xpm_print_avail(stderr, ext);
1219 for (i=1; i<MAXSQSIZE; ++i) {
1222 diff = (diff<0) ? -diff : diff;
1223 if (diff < sm_diff) {
1231 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1237 #else /* !HAVE_DIR_STRUCT */
1238 /* If we are on a system without a DIR struct, we can't
1239 read the directory, so we can't collect a list of
1240 filenames, etc., so we can't do any size-fitting. */
1242 xpm_closest_to(dirname, size, ext)
1247 fprintf(stderr, _("\
1248 Warning: No DIR structure found on this system --\n\
1249 Unable to autosize for XPM/XIM pieces.\n\
1250 Please report this error to frankm@hiwaay.net.\n\
1251 Include system type & operating system in message.\n"));
1254 #endif /* HAVE_DIR_STRUCT */
1256 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1257 "magenta", "cyan", "white" };
1261 TextColors textColors[(int)NColorClasses];
1263 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1265 parse_color(str, which)
1269 char *p, buf[100], *d;
1272 if (strlen(str) > 99) /* watch bounds on buf */
1277 for (i=0; i<which; ++i) {
1284 /* Could be looking at something like:
1286 .. in which case we want to stop on a comma also */
1287 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1291 return -1; /* Use default for empty field */
1294 if (which == 2 || isdigit(*p))
1297 while (*p && isalpha(*p))
1302 for (i=0; i<8; ++i) {
1303 if (!StrCaseCmp(buf, cnames[i]))
1304 return which? (i+40) : (i+30);
1306 if (!StrCaseCmp(buf, "default")) return -1;
1308 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1313 parse_cpair(cc, str)
1317 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1318 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1323 /* bg and attr are optional */
1324 textColors[(int)cc].bg = parse_color(str, 1);
1325 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1326 textColors[(int)cc].attr = 0;
1332 /* Arrange to catch delete-window events */
1333 Atom wm_delete_window;
1335 CatchDeleteWindow(Widget w, String procname)
1338 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1339 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1340 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1347 XtSetArg(args[0], XtNiconic, False);
1348 XtSetValues(shellWidget, args, 1);
1350 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1353 //---------------------------------------------------------------------------------------------------------
1354 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1357 #define CW_USEDEFAULT (1<<31)
1358 #define ICS_TEXT_MENU_SIZE 90
1359 #define DEBUG_FILE "xboard.debug"
1360 #define SetCurrentDirectory chdir
1361 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1365 // these two must some day move to frontend.h, when they are implemented
1366 Boolean GameListIsUp();
1368 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1371 // front-end part of option handling
1373 // [HGM] This platform-dependent table provides the location for storing the color info
1374 extern char *crWhite, * crBlack;
1378 &appData.whitePieceColor,
1379 &appData.blackPieceColor,
1380 &appData.lightSquareColor,
1381 &appData.darkSquareColor,
1382 &appData.highlightSquareColor,
1383 &appData.premoveHighlightColor,
1384 &appData.lowTimeWarningColor,
1395 // [HGM] font: keep a font for each square size, even non-stndard ones
1396 #define NUM_SIZES 18
1397 #define MAX_SIZE 130
1398 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1399 char *fontTable[NUM_FONTS][MAX_SIZE];
1402 ParseFont(char *name, int number)
1403 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1405 if(sscanf(name, "size%d:", &size)) {
1406 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1407 // defer processing it until we know if it matches our board size
1408 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1409 fontTable[number][size] = strdup(strchr(name, ':')+1);
1410 fontValid[number][size] = True;
1415 case 0: // CLOCK_FONT
1416 appData.clockFont = strdup(name);
1418 case 1: // MESSAGE_FONT
1419 appData.font = strdup(name);
1421 case 2: // COORD_FONT
1422 appData.coordFont = strdup(name);
1427 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1432 { // only 2 fonts currently
1433 appData.clockFont = CLOCK_FONT_NAME;
1434 appData.coordFont = COORD_FONT_NAME;
1435 appData.font = DEFAULT_FONT_NAME;
1440 { // no-op, until we identify the code for this already in XBoard and move it here
1444 ParseColor(int n, char *name)
1445 { // in XBoard, just copy the color-name string
1446 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1450 ParseTextAttribs(ColorClass cc, char *s)
1452 (&appData.colorShout)[cc] = strdup(s);
1456 ParseBoardSize(void *addr, char *name)
1458 appData.boardSize = strdup(name);
1463 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1467 SetCommPortDefaults()
1468 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1471 // [HGM] args: these three cases taken out to stay in front-end
1473 SaveFontArg(FILE *f, ArgDescriptor *ad)
1476 int i, n = (int)ad->argLoc;
1478 case 0: // CLOCK_FONT
1479 name = appData.clockFont;
1481 case 1: // MESSAGE_FONT
1482 name = appData.font;
1484 case 2: // COORD_FONT
1485 name = appData.coordFont;
1490 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1491 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1492 fontTable[n][squareSize] = strdup(name);
1493 fontValid[n][squareSize] = True;
1496 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1497 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1502 { // nothing to do, as the sounds are at all times represented by their text-string names already
1506 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1507 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1508 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1512 SaveColor(FILE *f, ArgDescriptor *ad)
1513 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1514 if(colorVariable[(int)ad->argLoc])
1515 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1519 SaveBoardSize(FILE *f, char *name, void *addr)
1520 { // wrapper to shield back-end from BoardSize & sizeInfo
1521 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1525 ParseCommPortSettings(char *s)
1526 { // no such option in XBoard (yet)
1529 extern Widget engineOutputShell;
1530 extern Widget tagsShell, editTagsShell;
1532 GetActualPlacement(Widget wg, WindowPlacement *wp)
1542 XtSetArg(args[i], XtNx, &x); i++;
1543 XtSetArg(args[i], XtNy, &y); i++;
1544 XtSetArg(args[i], XtNwidth, &w); i++;
1545 XtSetArg(args[i], XtNheight, &h); i++;
1546 XtGetValues(wg, args, i);
1555 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1556 // In XBoard this will have to wait until awareness of window parameters is implemented
1557 GetActualPlacement(shellWidget, &wpMain);
1558 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1559 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1560 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1561 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1562 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1563 else GetActualPlacement(editShell, &wpComment);
1564 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1565 else GetActualPlacement(editTagsShell, &wpTags);
1569 PrintCommPortSettings(FILE *f, char *name)
1570 { // This option does not exist in XBoard
1574 MySearchPath(char *installDir, char *name, char *fullname)
1575 { // just append installDir and name. Perhaps ExpandPath should be used here?
1576 name = ExpandPathName(name);
1577 if(name && name[0] == '/')
1578 safeStrCpy(fullname, name, MSG_SIZ );
1580 sprintf(fullname, "%s%c%s", installDir, '/', name);
1586 MyGetFullPathName(char *name, char *fullname)
1587 { // should use ExpandPath?
1588 name = ExpandPathName(name);
1589 safeStrCpy(fullname, name, MSG_SIZ );
1594 EnsureOnScreen(int *x, int *y, int minX, int minY)
1601 { // [HGM] args: allows testing if main window is realized from back-end
1602 return xBoardWindow != 0;
1606 PopUpStartupDialog()
1607 { // start menu not implemented in XBoard
1611 ConvertToLine(int argc, char **argv)
1613 static char line[128*1024], buf[1024];
1617 for(i=1; i<argc; i++)
1619 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1620 && argv[i][0] != '{' )
1621 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1623 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1624 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1627 line[strlen(line)-1] = NULLCHAR;
1631 //--------------------------------------------------------------------------------------------
1633 extern Boolean twoBoards, partnerUp;
1636 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1638 #define BoardSize int
1639 void InitDrawingSizes(BoardSize boardSize, int flags)
1640 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1641 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1643 XtGeometryResult gres;
1646 if(!formWidget) return;
1649 * Enable shell resizing.
1651 shellArgs[0].value = (XtArgVal) &w;
1652 shellArgs[1].value = (XtArgVal) &h;
1653 XtGetValues(shellWidget, shellArgs, 2);
1655 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1656 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1657 XtSetValues(shellWidget, &shellArgs[2], 4);
1659 XtSetArg(args[0], XtNdefaultDistance, &sep);
1660 XtGetValues(formWidget, args, 1);
1662 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1663 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1665 hOffset = boardWidth + 10;
1666 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1667 secondSegments[i] = gridSegments[i];
1668 secondSegments[i].x1 += hOffset;
1669 secondSegments[i].x2 += hOffset;
1672 XtSetArg(args[0], XtNwidth, boardWidth);
1673 XtSetArg(args[1], XtNheight, boardHeight);
1674 XtSetValues(boardWidget, args, 2);
1676 timerWidth = (boardWidth - sep) / 2;
1677 XtSetArg(args[0], XtNwidth, timerWidth);
1678 XtSetValues(whiteTimerWidget, args, 1);
1679 XtSetValues(blackTimerWidget, args, 1);
1681 XawFormDoLayout(formWidget, False);
1683 if (appData.titleInWindow) {
1685 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1686 XtSetArg(args[i], XtNheight, &h); i++;
1687 XtGetValues(titleWidget, args, i);
1689 w = boardWidth - 2*bor;
1691 XtSetArg(args[0], XtNwidth, &w);
1692 XtGetValues(menuBarWidget, args, 1);
1693 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1696 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1697 if (gres != XtGeometryYes && appData.debugMode) {
1699 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1700 programName, gres, w, h, wr, hr);
1704 XawFormDoLayout(formWidget, True);
1707 * Inhibit shell resizing.
1709 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1710 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1711 shellArgs[4].value = shellArgs[2].value = w;
1712 shellArgs[5].value = shellArgs[3].value = h;
1713 XtSetValues(shellWidget, &shellArgs[0], 6);
1715 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1718 for(i=0; i<4; i++) {
1720 for(p=0; p<=(int)WhiteKing; p++)
1721 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1722 if(gameInfo.variant == VariantShogi) {
1723 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1724 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1725 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1726 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1727 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1730 if(gameInfo.variant == VariantGothic) {
1731 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1735 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1736 for(p=0; p<=(int)WhiteKing; p++)
1737 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1738 if(gameInfo.variant == VariantShogi) {
1739 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1740 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1741 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1742 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1743 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1746 if(gameInfo.variant == VariantGothic) {
1747 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1753 for(i=0; i<2; i++) {
1755 for(p=0; p<=(int)WhiteKing; p++)
1756 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1757 if(gameInfo.variant == VariantShogi) {
1758 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1759 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1760 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1761 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1762 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1765 if(gameInfo.variant == VariantGothic) {
1766 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1782 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1783 XSetWindowAttributes window_attributes;
1785 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1786 XrmValue vFrom, vTo;
1787 XtGeometryResult gres;
1790 int forceMono = False;
1792 srandom(time(0)); // [HGM] book: make random truly random
1794 setbuf(stdout, NULL);
1795 setbuf(stderr, NULL);
1798 # if HAVE_LIBREADLINE
1799 /* install gnu-readline handler */
1800 rl_callback_handler_install("> ", ReadlineCompleteHandler);
1801 rl_readline_name="XBoard";
1804 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1805 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1809 programName = strrchr(argv[0], '/');
1810 if (programName == NULL)
1811 programName = argv[0];
1816 XtSetLanguageProc(NULL, NULL, NULL);
1817 bindtextdomain(PACKAGE, LOCALEDIR);
1818 textdomain(PACKAGE);
1822 XtAppInitialize(&appContext, "XBoard", shellOptions,
1823 XtNumber(shellOptions),
1824 &argc, argv, xboardResources, NULL, 0);
1825 appData.boardSize = "";
1826 InitAppData(ConvertToLine(argc, argv));
1828 if (p == NULL) p = "/tmp";
1829 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1830 gameCopyFilename = (char*) malloc(i);
1831 gamePasteFilename = (char*) malloc(i);
1832 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1833 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1835 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1836 clientResources, XtNumber(clientResources),
1839 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1840 static char buf[MSG_SIZ];
1841 EscapeExpand(buf, appData.initString);
1842 appData.initString = strdup(buf);
1843 EscapeExpand(buf, appData.secondInitString);
1844 appData.secondInitString = strdup(buf);
1845 EscapeExpand(buf, appData.firstComputerString);
1846 appData.firstComputerString = strdup(buf);
1847 EscapeExpand(buf, appData.secondComputerString);
1848 appData.secondComputerString = strdup(buf);
1851 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1854 if (chdir(chessDir) != 0) {
1855 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1861 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1862 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1863 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1864 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1867 setbuf(debugFP, NULL);
1870 /* [HGM,HR] make sure board size is acceptable */
1871 if(appData.NrFiles > BOARD_FILES ||
1872 appData.NrRanks > BOARD_RANKS )
1873 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1876 /* This feature does not work; animation needs a rewrite */
1877 appData.highlightDragging = FALSE;
1881 xDisplay = XtDisplay(shellWidget);
1882 xScreen = DefaultScreen(xDisplay);
1883 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1885 gameInfo.variant = StringToVariant(appData.variant);
1886 InitPosition(FALSE);
1889 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1891 if (isdigit(appData.boardSize[0])) {
1892 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1893 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1894 &fontPxlSize, &smallLayout, &tinyLayout);
1896 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1897 programName, appData.boardSize);
1901 /* Find some defaults; use the nearest known size */
1902 SizeDefaults *szd, *nearest;
1903 int distance = 99999;
1904 nearest = szd = sizeDefaults;
1905 while (szd->name != NULL) {
1906 if (abs(szd->squareSize - squareSize) < distance) {
1908 distance = abs(szd->squareSize - squareSize);
1909 if (distance == 0) break;
1913 if (i < 2) lineGap = nearest->lineGap;
1914 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1915 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1916 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1917 if (i < 6) smallLayout = nearest->smallLayout;
1918 if (i < 7) tinyLayout = nearest->tinyLayout;
1921 SizeDefaults *szd = sizeDefaults;
1922 if (*appData.boardSize == NULLCHAR) {
1923 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1924 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1927 if (szd->name == NULL) szd--;
1928 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1930 while (szd->name != NULL &&
1931 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1932 if (szd->name == NULL) {
1933 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1934 programName, appData.boardSize);
1938 squareSize = szd->squareSize;
1939 lineGap = szd->lineGap;
1940 clockFontPxlSize = szd->clockFontPxlSize;
1941 coordFontPxlSize = szd->coordFontPxlSize;
1942 fontPxlSize = szd->fontPxlSize;
1943 smallLayout = szd->smallLayout;
1944 tinyLayout = szd->tinyLayout;
1945 // [HGM] font: use defaults from settings file if available and not overruled
1947 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1948 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1949 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1950 appData.font = fontTable[MESSAGE_FONT][squareSize];
1951 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1952 appData.coordFont = fontTable[COORD_FONT][squareSize];
1954 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1955 if (strlen(appData.pixmapDirectory) > 0) {
1956 p = ExpandPathName(appData.pixmapDirectory);
1958 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1959 appData.pixmapDirectory);
1962 if (appData.debugMode) {
1963 fprintf(stderr, _("\
1964 XBoard square size (hint): %d\n\
1965 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1967 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1968 if (appData.debugMode) {
1969 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1973 /* [HR] height treated separately (hacked) */
1974 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1975 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1976 if (appData.showJail == 1) {
1977 /* Jail on top and bottom */
1978 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1979 XtSetArg(boardArgs[2], XtNheight,
1980 boardHeight + 2*(lineGap + squareSize));
1981 } else if (appData.showJail == 2) {
1983 XtSetArg(boardArgs[1], XtNwidth,
1984 boardWidth + 2*(lineGap + squareSize));
1985 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1988 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1989 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1993 * Determine what fonts to use.
1995 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1996 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1997 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1998 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1999 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2000 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2001 appData.font = FindFont(appData.font, fontPxlSize);
2002 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2003 countFontStruct = XQueryFont(xDisplay, countFontID);
2004 // appData.font = FindFont(appData.font, fontPxlSize);
2006 xdb = XtDatabase(xDisplay);
2007 XrmPutStringResource(&xdb, "*font", appData.font);
2010 * Detect if there are not enough colors available and adapt.
2012 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2013 appData.monoMode = True;
2016 if (!appData.monoMode) {
2017 vFrom.addr = (caddr_t) appData.lightSquareColor;
2018 vFrom.size = strlen(appData.lightSquareColor);
2019 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2020 if (vTo.addr == NULL) {
2021 appData.monoMode = True;
2024 lightSquareColor = *(Pixel *) vTo.addr;
2027 if (!appData.monoMode) {
2028 vFrom.addr = (caddr_t) appData.darkSquareColor;
2029 vFrom.size = strlen(appData.darkSquareColor);
2030 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2031 if (vTo.addr == NULL) {
2032 appData.monoMode = True;
2035 darkSquareColor = *(Pixel *) vTo.addr;
2038 if (!appData.monoMode) {
2039 vFrom.addr = (caddr_t) appData.whitePieceColor;
2040 vFrom.size = strlen(appData.whitePieceColor);
2041 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2042 if (vTo.addr == NULL) {
2043 appData.monoMode = True;
2046 whitePieceColor = *(Pixel *) vTo.addr;
2049 if (!appData.monoMode) {
2050 vFrom.addr = (caddr_t) appData.blackPieceColor;
2051 vFrom.size = strlen(appData.blackPieceColor);
2052 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2053 if (vTo.addr == NULL) {
2054 appData.monoMode = True;
2057 blackPieceColor = *(Pixel *) vTo.addr;
2061 if (!appData.monoMode) {
2062 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2063 vFrom.size = strlen(appData.highlightSquareColor);
2064 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2065 if (vTo.addr == NULL) {
2066 appData.monoMode = True;
2069 highlightSquareColor = *(Pixel *) vTo.addr;
2073 if (!appData.monoMode) {
2074 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2075 vFrom.size = strlen(appData.premoveHighlightColor);
2076 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2077 if (vTo.addr == NULL) {
2078 appData.monoMode = True;
2081 premoveHighlightColor = *(Pixel *) vTo.addr;
2086 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2089 if (appData.bitmapDirectory == NULL ||
2090 appData.bitmapDirectory[0] == NULLCHAR)
2091 appData.bitmapDirectory = DEF_BITMAP_DIR;
2094 if (appData.lowTimeWarning && !appData.monoMode) {
2095 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2096 vFrom.size = strlen(appData.lowTimeWarningColor);
2097 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2098 if (vTo.addr == NULL)
2099 appData.monoMode = True;
2101 lowTimeWarningColor = *(Pixel *) vTo.addr;
2104 if (appData.monoMode && appData.debugMode) {
2105 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2106 (unsigned long) XWhitePixel(xDisplay, xScreen),
2107 (unsigned long) XBlackPixel(xDisplay, xScreen));
2110 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2111 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2112 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2113 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2114 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2115 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2116 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2117 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2118 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2119 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2121 if (appData.colorize) {
2123 _("%s: can't parse color names; disabling colorization\n"),
2126 appData.colorize = FALSE;
2128 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2129 textColors[ColorNone].attr = 0;
2131 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2137 layoutName = "tinyLayout";
2138 } else if (smallLayout) {
2139 layoutName = "smallLayout";
2141 layoutName = "normalLayout";
2143 /* Outer layoutWidget is there only to provide a name for use in
2144 resources that depend on the layout style */
2146 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2147 layoutArgs, XtNumber(layoutArgs));
2149 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2150 formArgs, XtNumber(formArgs));
2151 XtSetArg(args[0], XtNdefaultDistance, &sep);
2152 XtGetValues(formWidget, args, 1);
2155 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2156 XtSetArg(args[0], XtNtop, XtChainTop);
2157 XtSetArg(args[1], XtNbottom, XtChainTop);
2158 XtSetArg(args[2], XtNright, XtChainLeft);
2159 XtSetValues(menuBarWidget, args, 3);
2161 widgetList[j++] = whiteTimerWidget =
2162 XtCreateWidget("whiteTime", labelWidgetClass,
2163 formWidget, timerArgs, XtNumber(timerArgs));
2164 XtSetArg(args[0], XtNfont, clockFontStruct);
2165 XtSetArg(args[1], XtNtop, XtChainTop);
2166 XtSetArg(args[2], XtNbottom, XtChainTop);
2167 XtSetValues(whiteTimerWidget, args, 3);
2169 widgetList[j++] = blackTimerWidget =
2170 XtCreateWidget("blackTime", labelWidgetClass,
2171 formWidget, timerArgs, XtNumber(timerArgs));
2172 XtSetArg(args[0], XtNfont, clockFontStruct);
2173 XtSetArg(args[1], XtNtop, XtChainTop);
2174 XtSetArg(args[2], XtNbottom, XtChainTop);
2175 XtSetValues(blackTimerWidget, args, 3);
2177 if (appData.titleInWindow) {
2178 widgetList[j++] = titleWidget =
2179 XtCreateWidget("title", labelWidgetClass, formWidget,
2180 titleArgs, XtNumber(titleArgs));
2181 XtSetArg(args[0], XtNtop, XtChainTop);
2182 XtSetArg(args[1], XtNbottom, XtChainTop);
2183 XtSetValues(titleWidget, args, 2);
2186 if (appData.showButtonBar) {
2187 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2188 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2189 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2190 XtSetArg(args[2], XtNtop, XtChainTop);
2191 XtSetArg(args[3], XtNbottom, XtChainTop);
2192 XtSetValues(buttonBarWidget, args, 4);
2195 widgetList[j++] = messageWidget =
2196 XtCreateWidget("message", labelWidgetClass, formWidget,
2197 messageArgs, XtNumber(messageArgs));
2198 XtSetArg(args[0], XtNtop, XtChainTop);
2199 XtSetArg(args[1], XtNbottom, XtChainTop);
2200 XtSetValues(messageWidget, args, 2);
2202 widgetList[j++] = boardWidget =
2203 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2204 XtNumber(boardArgs));
2206 XtManageChildren(widgetList, j);
2208 timerWidth = (boardWidth - sep) / 2;
2209 XtSetArg(args[0], XtNwidth, timerWidth);
2210 XtSetValues(whiteTimerWidget, args, 1);
2211 XtSetValues(blackTimerWidget, args, 1);
2213 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2214 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2215 XtGetValues(whiteTimerWidget, args, 2);
2217 if (appData.showButtonBar) {
2218 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2219 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2220 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2224 * formWidget uses these constraints but they are stored
2228 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2229 XtSetValues(menuBarWidget, args, i);
2230 if (appData.titleInWindow) {
2233 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2234 XtSetValues(whiteTimerWidget, args, i);
2236 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2237 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2238 XtSetValues(blackTimerWidget, args, i);
2240 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2241 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2242 XtSetValues(titleWidget, args, i);
2244 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2245 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2246 XtSetValues(messageWidget, args, i);
2247 if (appData.showButtonBar) {
2249 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2250 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2251 XtSetValues(buttonBarWidget, args, i);
2255 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2256 XtSetValues(whiteTimerWidget, args, i);
2258 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2259 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2260 XtSetValues(blackTimerWidget, args, i);
2262 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2263 XtSetValues(titleWidget, args, i);
2265 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2266 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2267 XtSetValues(messageWidget, args, i);
2268 if (appData.showButtonBar) {
2270 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2271 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2272 XtSetValues(buttonBarWidget, args, i);
2277 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2278 XtSetValues(whiteTimerWidget, args, i);
2280 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2281 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2282 XtSetValues(blackTimerWidget, args, i);
2284 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2285 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2286 XtSetValues(messageWidget, args, i);
2287 if (appData.showButtonBar) {
2289 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2290 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2291 XtSetValues(buttonBarWidget, args, i);
2295 XtSetArg(args[0], XtNfromVert, messageWidget);
2296 XtSetArg(args[1], XtNtop, XtChainTop);
2297 XtSetArg(args[2], XtNbottom, XtChainBottom);
2298 XtSetArg(args[3], XtNleft, XtChainLeft);
2299 XtSetArg(args[4], XtNright, XtChainRight);
2300 XtSetValues(boardWidget, args, 5);
2302 XtRealizeWidget(shellWidget);
2305 XtSetArg(args[0], XtNx, wpMain.x);
2306 XtSetArg(args[1], XtNy, wpMain.y);
2307 XtSetValues(shellWidget, args, 2);
2311 * Correct the width of the message and title widgets.
2312 * It is not known why some systems need the extra fudge term.
2313 * The value "2" is probably larger than needed.
2315 XawFormDoLayout(formWidget, False);
2317 #define WIDTH_FUDGE 2
2319 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2320 XtSetArg(args[i], XtNheight, &h); i++;
2321 XtGetValues(messageWidget, args, i);
2322 if (appData.showButtonBar) {
2324 XtSetArg(args[i], XtNwidth, &w); i++;
2325 XtGetValues(buttonBarWidget, args, i);
2326 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2328 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2331 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2332 if (gres != XtGeometryYes && appData.debugMode) {
2333 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2334 programName, gres, w, h, wr, hr);
2337 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2338 /* The size used for the child widget in layout lags one resize behind
2339 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2341 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2342 if (gres != XtGeometryYes && appData.debugMode) {
2343 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2344 programName, gres, w, h, wr, hr);
2347 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2348 XtSetArg(args[1], XtNright, XtChainRight);
2349 XtSetValues(messageWidget, args, 2);
2351 if (appData.titleInWindow) {
2353 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2354 XtSetArg(args[i], XtNheight, &h); i++;
2355 XtGetValues(titleWidget, args, i);
2357 w = boardWidth - 2*bor;
2359 XtSetArg(args[0], XtNwidth, &w);
2360 XtGetValues(menuBarWidget, args, 1);
2361 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2364 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2365 if (gres != XtGeometryYes && appData.debugMode) {
2367 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2368 programName, gres, w, h, wr, hr);
2371 XawFormDoLayout(formWidget, True);
2373 xBoardWindow = XtWindow(boardWidget);
2375 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2376 // not need to go into InitDrawingSizes().
2380 * Create X checkmark bitmap and initialize option menu checks.
2382 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2383 checkmark_bits, checkmark_width, checkmark_height);
2384 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2385 if (appData.alwaysPromoteToQueen) {
2386 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2389 if (appData.animateDragging) {
2390 XtSetValues(XtNameToWidget(menuBarWidget,
2391 "menuOptions.Animate Dragging"),
2394 if (appData.animate) {
2395 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2398 if (appData.autoComment) {
2399 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2402 if (appData.autoCallFlag) {
2403 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2406 if (appData.autoFlipView) {
2407 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2410 if (appData.autoObserve) {
2411 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2414 if (appData.autoRaiseBoard) {
2415 XtSetValues(XtNameToWidget(menuBarWidget,
2416 "menuOptions.Auto Raise Board"), args, 1);
2418 if (appData.autoSaveGames) {
2419 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2422 if (appData.saveGameFile[0] != NULLCHAR) {
2423 /* Can't turn this off from menu */
2424 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2426 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2430 if (appData.blindfold) {
2431 XtSetValues(XtNameToWidget(menuBarWidget,
2432 "menuOptions.Blindfold"), args, 1);
2434 if (appData.flashCount > 0) {
2435 XtSetValues(XtNameToWidget(menuBarWidget,
2436 "menuOptions.Flash Moves"),
2439 if (appData.getMoveList) {
2440 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2444 if (appData.highlightDragging) {
2445 XtSetValues(XtNameToWidget(menuBarWidget,
2446 "menuOptions.Highlight Dragging"),
2450 if (appData.highlightLastMove) {
2451 XtSetValues(XtNameToWidget(menuBarWidget,
2452 "menuOptions.Highlight Last Move"),
2455 if (appData.icsAlarm) {
2456 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2459 if (appData.ringBellAfterMoves) {
2460 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2463 if (appData.oldSaveStyle) {
2464 XtSetValues(XtNameToWidget(menuBarWidget,
2465 "menuOptions.Old Save Style"), args, 1);
2467 if (appData.periodicUpdates) {
2468 XtSetValues(XtNameToWidget(menuBarWidget,
2469 "menuOptions.Periodic Updates"), args, 1);
2471 if (appData.ponderNextMove) {
2472 XtSetValues(XtNameToWidget(menuBarWidget,
2473 "menuOptions.Ponder Next Move"), args, 1);
2475 if (appData.popupExitMessage) {
2476 XtSetValues(XtNameToWidget(menuBarWidget,
2477 "menuOptions.Popup Exit Message"), args, 1);
2479 if (appData.popupMoveErrors) {
2480 XtSetValues(XtNameToWidget(menuBarWidget,
2481 "menuOptions.Popup Move Errors"), args, 1);
2483 if (appData.premove) {
2484 XtSetValues(XtNameToWidget(menuBarWidget,
2485 "menuOptions.Premove"), args, 1);
2487 if (appData.quietPlay) {
2488 XtSetValues(XtNameToWidget(menuBarWidget,
2489 "menuOptions.Quiet Play"), args, 1);
2491 if (appData.showCoords) {
2492 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2495 if (appData.hideThinkingFromHuman) {
2496 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2499 if (appData.testLegality) {
2500 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2503 if (saveSettingsOnExit) {
2504 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2511 ReadBitmap(&wIconPixmap, "icon_white.bm",
2512 icon_white_bits, icon_white_width, icon_white_height);
2513 ReadBitmap(&bIconPixmap, "icon_black.bm",
2514 icon_black_bits, icon_black_width, icon_black_height);
2515 iconPixmap = wIconPixmap;
2517 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2518 XtSetValues(shellWidget, args, i);
2521 * Create a cursor for the board widget.
2523 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2524 XChangeWindowAttributes(xDisplay, xBoardWindow,
2525 CWCursor, &window_attributes);
2528 * Inhibit shell resizing.
2530 shellArgs[0].value = (XtArgVal) &w;
2531 shellArgs[1].value = (XtArgVal) &h;
2532 XtGetValues(shellWidget, shellArgs, 2);
2533 shellArgs[4].value = shellArgs[2].value = w;
2534 shellArgs[5].value = shellArgs[3].value = h;
2535 XtSetValues(shellWidget, &shellArgs[2], 4);
2536 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2537 marginH = h - boardHeight;
2539 CatchDeleteWindow(shellWidget, "QuitProc");
2544 if (appData.bitmapDirectory[0] != NULLCHAR) {
2548 CreateXPMBoard(appData.liteBackTextureFile, 1);
2549 CreateXPMBoard(appData.darkBackTextureFile, 0);
2553 /* Create regular pieces */
2554 if (!useImages) CreatePieces();
2559 if (appData.animate || appData.animateDragging)
2562 XtAugmentTranslations(formWidget,
2563 XtParseTranslationTable(globalTranslations));
2564 XtAugmentTranslations(boardWidget,
2565 XtParseTranslationTable(boardTranslations));
2566 XtAugmentTranslations(whiteTimerWidget,
2567 XtParseTranslationTable(whiteTranslations));
2568 XtAugmentTranslations(blackTimerWidget,
2569 XtParseTranslationTable(blackTranslations));
2571 /* Why is the following needed on some versions of X instead
2572 * of a translation? */
2573 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2574 (XtEventHandler) EventProc, NULL);
2577 /* [AS] Restore layout */
2578 if( wpMoveHistory.visible ) {
2582 if( wpEvalGraph.visible )
2587 if( wpEngineOutput.visible ) {
2588 EngineOutputPopUp();
2593 if (errorExitStatus == -1) {
2594 if (appData.icsActive) {
2595 /* We now wait until we see "login:" from the ICS before
2596 sending the logon script (problems with timestamp otherwise) */
2597 /*ICSInitScript();*/
2598 if (appData.icsInputBox) ICSInputBoxPopUp();
2602 signal(SIGWINCH, TermSizeSigHandler);
2604 signal(SIGINT, IntSigHandler);
2605 signal(SIGTERM, IntSigHandler);
2606 if (*appData.cmailGameName != NULLCHAR) {
2607 signal(SIGUSR1, CmailSigHandler);
2610 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2612 XtSetKeyboardFocus(shellWidget, formWidget);
2614 XtAppMainLoop(appContext);
2615 if (appData.debugMode) fclose(debugFP); // [DM] debug
2622 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2623 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2625 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2626 unlink(gameCopyFilename);
2627 unlink(gamePasteFilename);
2629 # if HAVE_LIBREADLINE
2630 /* remove gnu-readline handler. */
2631 rl_callback_handler_remove();
2637 RETSIGTYPE TermSizeSigHandler(int sig)
2650 CmailSigHandler(sig)
2656 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2658 /* Activate call-back function CmailSigHandlerCallBack() */
2659 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2661 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2665 CmailSigHandlerCallBack(isr, closure, message, count, error)
2673 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2675 /**** end signal code ****/
2681 /* try to open the icsLogon script, either in the location given
2682 * or in the users HOME directory
2689 f = fopen(appData.icsLogon, "r");
2692 homedir = getenv("HOME");
2693 if (homedir != NULL)
2695 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2696 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2697 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2698 f = fopen(buf, "r");
2703 ProcessICSInitScript(f);
2705 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2714 EditCommentPopDown();
2729 if (!menuBarWidget) return;
2730 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2732 DisplayError("menuStep.Revert", 0);
2734 XtSetSensitive(w, !grey);
2736 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2738 DisplayError("menuStep.Annotate", 0);
2740 XtSetSensitive(w, !grey);
2745 SetMenuEnables(enab)
2749 if (!menuBarWidget) return;
2750 while (enab->name != NULL) {
2751 w = XtNameToWidget(menuBarWidget, enab->name);
2753 DisplayError(enab->name, 0);
2755 XtSetSensitive(w, enab->value);
2761 Enables icsEnables[] = {
2762 { "menuFile.Mail Move", False },
2763 { "menuFile.Reload CMail Message", False },
2764 { "menuMode.Machine Black", False },
2765 { "menuMode.Machine White", False },
2766 { "menuMode.Analysis Mode", False },
2767 { "menuMode.Analyze File", False },
2768 { "menuMode.Two Machines", False },
2770 { "menuHelp.Hint", False },
2771 { "menuHelp.Book", False },
2772 { "menuStep.Move Now", False },
2773 { "menuOptions.Periodic Updates", False },
2774 { "menuOptions.Hide Thinking", False },
2775 { "menuOptions.Ponder Next Move", False },
2777 { "menuStep.Annotate", False },
2781 Enables ncpEnables[] = {
2782 { "menuFile.Mail Move", False },
2783 { "menuFile.Reload CMail Message", False },
2784 { "menuMode.Machine White", False },
2785 { "menuMode.Machine Black", False },
2786 { "menuMode.Analysis Mode", False },
2787 { "menuMode.Analyze File", False },
2788 { "menuMode.Two Machines", False },
2789 { "menuMode.ICS Client", False },
2790 { "menuMode.ICS Input Box", False },
2791 { "Action", False },
2792 { "menuStep.Revert", False },
2793 { "menuStep.Annotate", False },
2794 { "menuStep.Move Now", False },
2795 { "menuStep.Retract Move", False },
2796 { "menuOptions.Auto Comment", False },
2797 { "menuOptions.Auto Flag", False },
2798 { "menuOptions.Auto Flip View", False },
2799 { "menuOptions.Auto Observe", False },
2800 { "menuOptions.Auto Raise Board", False },
2801 { "menuOptions.Get Move List", False },
2802 { "menuOptions.ICS Alarm", False },
2803 { "menuOptions.Move Sound", False },
2804 { "menuOptions.Quiet Play", False },
2805 { "menuOptions.Hide Thinking", False },
2806 { "menuOptions.Periodic Updates", False },
2807 { "menuOptions.Ponder Next Move", False },
2808 { "menuHelp.Hint", False },
2809 { "menuHelp.Book", False },
2813 Enables gnuEnables[] = {
2814 { "menuMode.ICS Client", False },
2815 { "menuMode.ICS Input Box", False },
2816 { "menuAction.Accept", False },
2817 { "menuAction.Decline", False },
2818 { "menuAction.Rematch", False },
2819 { "menuAction.Adjourn", False },
2820 { "menuAction.Stop Examining", False },
2821 { "menuAction.Stop Observing", False },
2822 { "menuAction.Upload to Examine", False },
2823 { "menuStep.Revert", False },
2824 { "menuStep.Annotate", False },
2825 { "menuOptions.Auto Comment", False },
2826 { "menuOptions.Auto Observe", False },
2827 { "menuOptions.Auto Raise Board", False },
2828 { "menuOptions.Get Move List", False },
2829 { "menuOptions.Premove", False },
2830 { "menuOptions.Quiet Play", False },
2832 /* The next two options rely on SetCmailMode being called *after* */
2833 /* SetGNUMode so that when GNU is being used to give hints these */
2834 /* menu options are still available */
2836 { "menuFile.Mail Move", False },
2837 { "menuFile.Reload CMail Message", False },
2841 Enables cmailEnables[] = {
2843 { "menuAction.Call Flag", False },
2844 { "menuAction.Draw", True },
2845 { "menuAction.Adjourn", False },
2846 { "menuAction.Abort", False },
2847 { "menuAction.Stop Observing", False },
2848 { "menuAction.Stop Examining", False },
2849 { "menuFile.Mail Move", True },
2850 { "menuFile.Reload CMail Message", True },
2854 Enables trainingOnEnables[] = {
2855 { "menuMode.Edit Comment", False },
2856 { "menuMode.Pause", False },
2857 { "menuStep.Forward", False },
2858 { "menuStep.Backward", False },
2859 { "menuStep.Forward to End", False },
2860 { "menuStep.Back to Start", False },
2861 { "menuStep.Move Now", False },
2862 { "menuStep.Truncate Game", False },
2866 Enables trainingOffEnables[] = {
2867 { "menuMode.Edit Comment", True },
2868 { "menuMode.Pause", True },
2869 { "menuStep.Forward", True },
2870 { "menuStep.Backward", True },
2871 { "menuStep.Forward to End", True },
2872 { "menuStep.Back to Start", True },
2873 { "menuStep.Move Now", True },
2874 { "menuStep.Truncate Game", True },
2878 Enables machineThinkingEnables[] = {
2879 { "menuFile.Load Game", False },
2880 { "menuFile.Load Next Game", False },
2881 { "menuFile.Load Previous Game", False },
2882 { "menuFile.Reload Same Game", False },
2883 { "menuFile.Paste Game", False },
2884 { "menuFile.Load Position", False },
2885 { "menuFile.Load Next Position", False },
2886 { "menuFile.Load Previous Position", False },
2887 { "menuFile.Reload Same Position", False },
2888 { "menuFile.Paste Position", False },
2889 { "menuMode.Machine White", False },
2890 { "menuMode.Machine Black", False },
2891 { "menuMode.Two Machines", False },
2892 { "menuStep.Retract Move", False },
2896 Enables userThinkingEnables[] = {
2897 { "menuFile.Load Game", True },
2898 { "menuFile.Load Next Game", True },
2899 { "menuFile.Load Previous Game", True },
2900 { "menuFile.Reload Same Game", True },
2901 { "menuFile.Paste Game", True },
2902 { "menuFile.Load Position", True },
2903 { "menuFile.Load Next Position", True },
2904 { "menuFile.Load Previous Position", True },
2905 { "menuFile.Reload Same Position", True },
2906 { "menuFile.Paste Position", True },
2907 { "menuMode.Machine White", True },
2908 { "menuMode.Machine Black", True },
2909 { "menuMode.Two Machines", True },
2910 { "menuStep.Retract Move", True },
2916 SetMenuEnables(icsEnables);
2919 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2920 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2927 SetMenuEnables(ncpEnables);
2933 SetMenuEnables(gnuEnables);
2939 SetMenuEnables(cmailEnables);
2945 SetMenuEnables(trainingOnEnables);
2946 if (appData.showButtonBar) {
2947 XtSetSensitive(buttonBarWidget, False);
2953 SetTrainingModeOff()
2955 SetMenuEnables(trainingOffEnables);
2956 if (appData.showButtonBar) {
2957 XtSetSensitive(buttonBarWidget, True);
2962 SetUserThinkingEnables()
2964 if (appData.noChessProgram) return;
2965 SetMenuEnables(userThinkingEnables);
2969 SetMachineThinkingEnables()
2971 if (appData.noChessProgram) return;
2972 SetMenuEnables(machineThinkingEnables);
2974 case MachinePlaysBlack:
2975 case MachinePlaysWhite:
2976 case TwoMachinesPlay:
2977 XtSetSensitive(XtNameToWidget(menuBarWidget,
2978 ModeToWidgetName(gameMode)), True);
2985 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2986 #define HISTORY_SIZE 64
\r
2987 static char *history[HISTORY_SIZE];
\r
2988 int histIn = 0, histP = 0;
\r
2991 SaveInHistory(char *cmd)
\r
2993 if (history[histIn] != NULL) {
\r
2994 free(history[histIn]);
\r
2995 history[histIn] = NULL;
\r
2997 if (*cmd == NULLCHAR) return;
\r
2998 history[histIn] = StrSave(cmd);
\r
2999 histIn = (histIn + 1) % HISTORY_SIZE;
\r
3000 if (history[histIn] != NULL) {
\r
3001 free(history[histIn]);
\r
3002 history[histIn] = NULL;
\r
3008 PrevInHistory(char *cmd)
\r
3011 if (histP == histIn) {
\r
3012 if (history[histIn] != NULL) free(history[histIn]);
\r
3013 history[histIn] = StrSave(cmd);
\r
3015 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
3016 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3018 return history[histP];
\r
3024 if (histP == histIn) return NULL;
\r
3025 histP = (histP + 1) % HISTORY_SIZE;
\r
3026 return history[histP];
\r
3028 // end of borrowed code
\r
3030 #define Abs(n) ((n)<0 ? -(n) : (n))
3033 * Find a font that matches "pattern" that is as close as
3034 * possible to the targetPxlSize. Prefer fonts that are k
3035 * pixels smaller to fonts that are k pixels larger. The
3036 * pattern must be in the X Consortium standard format,
3037 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3038 * The return value should be freed with XtFree when no
3042 FindFont(pattern, targetPxlSize)
3046 char **fonts, *p, *best, *scalable, *scalableTail;
3047 int i, j, nfonts, minerr, err, pxlSize;
3050 char **missing_list;
3052 char *def_string, *base_fnt_lst, strInt[3];
3054 XFontStruct **fnt_list;
3056 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3057 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3058 p = strstr(pattern, "--");
3059 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3060 strcat(base_fnt_lst, strInt);
3061 strcat(base_fnt_lst, strchr(p + 2, '-'));
3063 if ((fntSet = XCreateFontSet(xDisplay,
3067 &def_string)) == NULL) {
3069 fprintf(stderr, _("Unable to create font set.\n"));
3073 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3075 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3077 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3078 programName, pattern);
3086 for (i=0; i<nfonts; i++) {
3089 if (*p != '-') continue;
3091 if (*p == NULLCHAR) break;
3092 if (*p++ == '-') j++;
3094 if (j < 7) continue;
3097 scalable = fonts[i];
3100 err = pxlSize - targetPxlSize;
3101 if (Abs(err) < Abs(minerr) ||
3102 (minerr > 0 && err < 0 && -err == minerr)) {
3108 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3109 /* If the error is too big and there is a scalable font,
3110 use the scalable font. */
3111 int headlen = scalableTail - scalable;
3112 p = (char *) XtMalloc(strlen(scalable) + 10);
3113 while (isdigit(*scalableTail)) scalableTail++;
3114 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3116 p = (char *) XtMalloc(strlen(best) + 2);
3117 safeStrCpy(p, best, strlen(best)+1 );
3119 if (appData.debugMode) {
3120 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3121 pattern, targetPxlSize, p);
3124 if (missing_count > 0)
3125 XFreeStringList(missing_list);
3126 XFreeFontSet(xDisplay, fntSet);
3128 XFreeFontNames(fonts);
3135 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3136 | GCBackground | GCFunction | GCPlaneMask;
3137 XGCValues gc_values;
3140 gc_values.plane_mask = AllPlanes;
3141 gc_values.line_width = lineGap;
3142 gc_values.line_style = LineSolid;
3143 gc_values.function = GXcopy;
3145 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3146 gc_values.background = XBlackPixel(xDisplay, xScreen);
3147 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3149 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3150 gc_values.background = XWhitePixel(xDisplay, xScreen);
3151 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3152 XSetFont(xDisplay, coordGC, coordFontID);
3154 // [HGM] make font for holdings counts (white on black0
3155 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3156 gc_values.background = XBlackPixel(xDisplay, xScreen);
3157 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3158 XSetFont(xDisplay, countGC, countFontID);
3160 if (appData.monoMode) {
3161 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3162 gc_values.background = XWhitePixel(xDisplay, xScreen);
3163 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3165 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3166 gc_values.background = XBlackPixel(xDisplay, xScreen);
3167 lightSquareGC = wbPieceGC
3168 = XtGetGC(shellWidget, value_mask, &gc_values);
3170 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3171 gc_values.background = XWhitePixel(xDisplay, xScreen);
3172 darkSquareGC = bwPieceGC
3173 = XtGetGC(shellWidget, value_mask, &gc_values);
3175 if (DefaultDepth(xDisplay, xScreen) == 1) {
3176 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3177 gc_values.function = GXcopyInverted;
3178 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3179 gc_values.function = GXcopy;
3180 if (XBlackPixel(xDisplay, xScreen) == 1) {
3181 bwPieceGC = darkSquareGC;
3182 wbPieceGC = copyInvertedGC;
3184 bwPieceGC = copyInvertedGC;
3185 wbPieceGC = lightSquareGC;
3189 gc_values.foreground = highlightSquareColor;
3190 gc_values.background = highlightSquareColor;
3191 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3193 gc_values.foreground = premoveHighlightColor;
3194 gc_values.background = premoveHighlightColor;
3195 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3197 gc_values.foreground = lightSquareColor;
3198 gc_values.background = darkSquareColor;
3199 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3201 gc_values.foreground = darkSquareColor;
3202 gc_values.background = lightSquareColor;
3203 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3205 gc_values.foreground = jailSquareColor;
3206 gc_values.background = jailSquareColor;
3207 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3209 gc_values.foreground = whitePieceColor;
3210 gc_values.background = darkSquareColor;
3211 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3213 gc_values.foreground = whitePieceColor;
3214 gc_values.background = lightSquareColor;
3215 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3217 gc_values.foreground = whitePieceColor;
3218 gc_values.background = jailSquareColor;
3219 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3221 gc_values.foreground = blackPieceColor;
3222 gc_values.background = darkSquareColor;
3223 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3225 gc_values.foreground = blackPieceColor;
3226 gc_values.background = lightSquareColor;
3227 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3229 gc_values.foreground = blackPieceColor;
3230 gc_values.background = jailSquareColor;
3231 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3235 void loadXIM(xim, xmask, filename, dest, mask)
3248 fp = fopen(filename, "rb");
3250 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3257 for (y=0; y<h; ++y) {
3258 for (x=0; x<h; ++x) {
3263 XPutPixel(xim, x, y, blackPieceColor);
3265 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3268 XPutPixel(xim, x, y, darkSquareColor);
3270 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3273 XPutPixel(xim, x, y, whitePieceColor);
3275 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3278 XPutPixel(xim, x, y, lightSquareColor);
3280 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3286 /* create Pixmap of piece */
3287 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3289 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3292 /* create Pixmap of clipmask
3293 Note: We assume the white/black pieces have the same
3294 outline, so we make only 6 masks. This is okay
3295 since the XPM clipmask routines do the same. */
3297 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3299 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3302 /* now create the 1-bit version */
3303 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3306 values.foreground = 1;
3307 values.background = 0;
3309 /* Don't use XtGetGC, not read only */
3310 maskGC = XCreateGC(xDisplay, *mask,
3311 GCForeground | GCBackground, &values);
3312 XCopyPlane(xDisplay, temp, *mask, maskGC,
3313 0, 0, squareSize, squareSize, 0, 0, 1);
3314 XFreePixmap(xDisplay, temp);
3319 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3321 void CreateXIMPieces()
3326 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3331 /* The XSynchronize calls were copied from CreatePieces.
3332 Not sure if needed, but can't hurt */
3333 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3336 /* temp needed by loadXIM() */
3337 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3338 0, 0, ss, ss, AllPlanes, XYPixmap);
3340 if (strlen(appData.pixmapDirectory) == 0) {
3344 if (appData.monoMode) {
3345 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3349 fprintf(stderr, _("\nLoading XIMs...\n"));
3351 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3352 fprintf(stderr, "%d", piece+1);
3353 for (kind=0; kind<4; kind++) {
3354 fprintf(stderr, ".");
3355 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3356 ExpandPathName(appData.pixmapDirectory),
3357 piece <= (int) WhiteKing ? "" : "w",
3358 pieceBitmapNames[piece],
3360 ximPieceBitmap[kind][piece] =
3361 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3362 0, 0, ss, ss, AllPlanes, XYPixmap);
3363 if (appData.debugMode)
3364 fprintf(stderr, _("(File:%s:) "), buf);
3365 loadXIM(ximPieceBitmap[kind][piece],
3367 &(xpmPieceBitmap2[kind][piece]),
3368 &(ximMaskPm2[piece]));
3369 if(piece <= (int)WhiteKing)
3370 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3372 fprintf(stderr," ");
3374 /* Load light and dark squares */
3375 /* If the LSQ and DSQ pieces don't exist, we will
3376 draw them with solid squares. */
3377 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3378 if (access(buf, 0) != 0) {
3382 fprintf(stderr, _("light square "));
3384 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3385 0, 0, ss, ss, AllPlanes, XYPixmap);
3386 if (appData.debugMode)
3387 fprintf(stderr, _("(File:%s:) "), buf);
3389 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3390 fprintf(stderr, _("dark square "));
3391 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3392 ExpandPathName(appData.pixmapDirectory), ss);
3393 if (appData.debugMode)
3394 fprintf(stderr, _("(File:%s:) "), buf);
3396 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3397 0, 0, ss, ss, AllPlanes, XYPixmap);
3398 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3399 xpmJailSquare = xpmLightSquare;
3401 fprintf(stderr, _("Done.\n"));
3403 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3407 void CreateXPMBoard(char *s, int kind)
3411 if(s == NULL || *s == 0 || *s == '*') return;
3412 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3413 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3417 void CreateXPMPieces()
3421 u_int ss = squareSize;
3423 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3424 XpmColorSymbol symbols[4];
3426 /* The XSynchronize calls were copied from CreatePieces.
3427 Not sure if needed, but can't hurt */
3428 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3430 /* Setup translations so piece colors match square colors */
3431 symbols[0].name = "light_piece";
3432 symbols[0].value = appData.whitePieceColor;
3433 symbols[1].name = "dark_piece";
3434 symbols[1].value = appData.blackPieceColor;
3435 symbols[2].name = "light_square";
3436 symbols[2].value = appData.lightSquareColor;
3437 symbols[3].name = "dark_square";
3438 symbols[3].value = appData.darkSquareColor;
3440 attr.valuemask = XpmColorSymbols;
3441 attr.colorsymbols = symbols;
3442 attr.numsymbols = 4;
3444 if (appData.monoMode) {
3445 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3449 if (strlen(appData.pixmapDirectory) == 0) {
3450 XpmPieces* pieces = builtInXpms;
3453 while (pieces->size != squareSize && pieces->size) pieces++;
3454 if (!pieces->size) {
3455 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3458 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3459 for (kind=0; kind<4; kind++) {
3461 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3462 pieces->xpm[piece][kind],
3463 &(xpmPieceBitmap2[kind][piece]),
3464 NULL, &attr)) != 0) {
3465 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3469 if(piece <= (int) WhiteKing)
3470 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3474 xpmJailSquare = xpmLightSquare;
3478 fprintf(stderr, _("\nLoading XPMs...\n"));
3481 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3482 fprintf(stderr, "%d ", piece+1);
3483 for (kind=0; kind<4; kind++) {
3484 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3485 ExpandPathName(appData.pixmapDirectory),
3486 piece > (int) WhiteKing ? "w" : "",
3487 pieceBitmapNames[piece],
3489 if (appData.debugMode) {
3490 fprintf(stderr, _("(File:%s:) "), buf);
3492 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3493 &(xpmPieceBitmap2[kind][piece]),
3494 NULL, &attr)) != 0) {
3495 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3496 // [HGM] missing: read of unorthodox piece failed; substitute King.
3497 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3498 ExpandPathName(appData.pixmapDirectory),
3500 if (appData.debugMode) {
3501 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3503 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3504 &(xpmPieceBitmap2[kind][piece]),
3508 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3513 if(piece <= (int) WhiteKing)
3514 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3517 /* Load light and dark squares */
3518 /* If the LSQ and DSQ pieces don't exist, we will
3519 draw them with solid squares. */
3520 fprintf(stderr, _("light square "));
3521 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3522 if (access(buf, 0) != 0) {
3526 if (appData.debugMode)
3527 fprintf(stderr, _("(File:%s:) "), buf);
3529 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3530 &xpmLightSquare, NULL, &attr)) != 0) {
3531 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3534 fprintf(stderr, _("dark square "));
3535 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3536 ExpandPathName(appData.pixmapDirectory), ss);
3537 if (appData.debugMode) {
3538 fprintf(stderr, _("(File:%s:) "), buf);
3540 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3541 &xpmDarkSquare, NULL, &attr)) != 0) {
3542 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3546 xpmJailSquare = xpmLightSquare;
3547 fprintf(stderr, _("Done.\n"));
3549 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3552 #endif /* HAVE_LIBXPM */
3555 /* No built-in bitmaps */
3560 u_int ss = squareSize;
3562 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3565 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3566 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3567 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3568 pieceBitmapNames[piece],
3569 ss, kind == SOLID ? 's' : 'o');
3570 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3571 if(piece <= (int)WhiteKing)
3572 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3576 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3580 /* With built-in bitmaps */
3583 BuiltInBits* bib = builtInBits;
3586 u_int ss = squareSize;
3588 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3591 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3593 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3594 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3595 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3596 pieceBitmapNames[piece],
3597 ss, kind == SOLID ? 's' : 'o');
3598 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3599 bib->bits[kind][piece], ss, ss);
3600 if(piece <= (int)WhiteKing)
3601 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3605 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3610 void ReadBitmap(pm, name, bits, wreq, hreq)
3613 unsigned char bits[];
3619 char msg[MSG_SIZ], fullname[MSG_SIZ];
3621 if (*appData.bitmapDirectory != NULLCHAR) {
3622 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3623 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3624 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3625 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3626 &w, &h, pm, &x_hot, &y_hot);
3627 fprintf(stderr, "load %s\n", name);
3628 if (errcode != BitmapSuccess) {
3630 case BitmapOpenFailed:
3631 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3633 case BitmapFileInvalid:
3634 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3636 case BitmapNoMemory:
3637 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3641 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3645 fprintf(stderr, _("%s: %s...using built-in\n"),
3647 } else if (w != wreq || h != hreq) {
3649 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3650 programName, fullname, w, h, wreq, hreq);
3656 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3665 if (lineGap == 0) return;
3667 /* [HR] Split this into 2 loops for non-square boards. */
3669 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3670 gridSegments[i].x1 = 0;
3671 gridSegments[i].x2 =
3672 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3673 gridSegments[i].y1 = gridSegments[i].y2
3674 = lineGap / 2 + (i * (squareSize + lineGap));
3677 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3678 gridSegments[j + i].y1 = 0;
3679 gridSegments[j + i].y2 =
3680 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3681 gridSegments[j + i].x1 = gridSegments[j + i].x2
3682 = lineGap / 2 + (j * (squareSize + lineGap));
3686 static void MenuBarSelect(w, addr, index)
3691 XtActionProc proc = (XtActionProc) addr;
3693 (proc)(NULL, NULL, NULL, NULL);
3696 void CreateMenuBarPopup(parent, name, mb)
3706 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3709 XtSetArg(args[j], XtNleftMargin, 20); j++;
3710 XtSetArg(args[j], XtNrightMargin, 20); j++;
3712 while (mi->string != NULL) {
3713 if (strcmp(mi->string, "----") == 0) {
3714 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3717 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3718 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3720 XtAddCallback(entry, XtNcallback,
3721 (XtCallbackProc) MenuBarSelect,
3722 (caddr_t) mi->proc);
3728 Widget CreateMenuBar(mb)
3732 Widget anchor, menuBar;
3734 char menuName[MSG_SIZ];
3737 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3738 XtSetArg(args[j], XtNvSpace, 0); j++;
3739 XtSetArg(args[j], XtNborderWidth, 0); j++;
3740 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3741 formWidget, args, j);
3743 while (mb->name != NULL) {
3744 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3745 strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
3747 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3750 shortName[0] = _(mb->name)[0];
3751 shortName[1] = NULLCHAR;
3752 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3755 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3758 XtSetArg(args[j], XtNborderWidth, 0); j++;
3759 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3761 CreateMenuBarPopup(menuBar, menuName, mb);
3767 Widget CreateButtonBar(mi)
3771 Widget button, buttonBar;
3775 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3777 XtSetArg(args[j], XtNhSpace, 0); j++;
3779 XtSetArg(args[j], XtNborderWidth, 0); j++;
3780 XtSetArg(args[j], XtNvSpace, 0); j++;
3781 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3782 formWidget, args, j);
3784 while (mi->string != NULL) {
3787 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3788 XtSetArg(args[j], XtNborderWidth, 0); j++;
3790 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3791 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3792 buttonBar, args, j);
3793 XtAddCallback(button, XtNcallback,
3794 (XtCallbackProc) MenuBarSelect,
3795 (caddr_t) mi->proc);
3802 CreatePieceMenu(name, color)
3809 ChessSquare selection;
3811 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3812 boardWidget, args, 0);
3814 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3815 String item = pieceMenuStrings[color][i];
3817 if (strcmp(item, "----") == 0) {
3818 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3821 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3822 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3824 selection = pieceMenuTranslation[color][i];
3825 XtAddCallback(entry, XtNcallback,
3826 (XtCallbackProc) PieceMenuSelect,
3827 (caddr_t) selection);
3828 if (selection == WhitePawn || selection == BlackPawn) {
3829 XtSetArg(args[0], XtNpopupOnEntry, entry);
3830 XtSetValues(menu, args, 1);
3843 ChessSquare selection;
3845 whitePieceMenu = CreatePieceMenu("menuW", 0);
3846 blackPieceMenu = CreatePieceMenu("menuB", 1);
3848 XtRegisterGrabAction(PieceMenuPopup, True,
3849 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3850 GrabModeAsync, GrabModeAsync);
3852 XtSetArg(args[0], XtNlabel, _("Drop"));
3853 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3854 boardWidget, args, 1);
3855 for (i = 0; i < DROP_MENU_SIZE; i++) {
3856 String item = dropMenuStrings[i];
3858 if (strcmp(item, "----") == 0) {
3859 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3862 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3863 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3865 selection = dropMenuTranslation[i];
3866 XtAddCallback(entry, XtNcallback,
3867 (XtCallbackProc) DropMenuSelect,
3868 (caddr_t) selection);
3873 void SetupDropMenu()
3881 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3882 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3883 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3884 dmEnables[i].piece);
3885 XtSetSensitive(entry, p != NULL || !appData.testLegality
3886 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3887 && !appData.icsActive));
3889 while (p && *p++ == dmEnables[i].piece) count++;
3890 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3892 XtSetArg(args[j], XtNlabel, label); j++;
3893 XtSetValues(entry, args, j);
3897 void PieceMenuPopup(w, event, params, num_params)
3901 Cardinal *num_params;
3903 String whichMenu; int menuNr;
3904 if (event->type == ButtonRelease)
3905 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3906 else if (event->type == ButtonPress)
3907 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3909 case 0: whichMenu = params[0]; break;
3910 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3912 case -1: if (errorUp) ErrorPopDown();
3915 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3918 static void PieceMenuSelect(w, piece, junk)
3923 if (pmFromX < 0 || pmFromY < 0) return;
3924 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3927 static void DropMenuSelect(w, piece, junk)
3932 if (pmFromX < 0 || pmFromY < 0) return;
3933 DropMenuEvent(piece, pmFromX, pmFromY);
3936 void WhiteClock(w, event, prms, nprms)
3942 if (gameMode == EditPosition || gameMode == IcsExamining) {
3943 SetWhiteToPlayEvent();
3944 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3949 void BlackClock(w, event, prms, nprms)
3955 if (gameMode == EditPosition || gameMode == IcsExamining) {
3956 SetBlackToPlayEvent();
3957 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3964 * If the user selects on a border boundary, return -1; if off the board,
3965 * return -2. Otherwise map the event coordinate to the square.
3967 int EventToSquare(x, limit)
3975 if ((x % (squareSize + lineGap)) >= squareSize)
3977 x /= (squareSize + lineGap);
3983 static void do_flash_delay(msec)
3989 static void drawHighlight(file, rank, gc)
3995 if (lineGap == 0 || appData.blindfold) return;
3998 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3999 (squareSize + lineGap);
4000 y = lineGap/2 + rank * (squareSize + lineGap);
4002 x = lineGap/2 + file * (squareSize + lineGap);
4003 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4004 (squareSize + lineGap);
4007 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4008 squareSize+lineGap, squareSize+lineGap);
4011 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4012 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4015 SetHighlights(fromX, fromY, toX, toY)
4016 int fromX, fromY, toX, toY;
4018 if (hi1X != fromX || hi1Y != fromY) {
4019 if (hi1X >= 0 && hi1Y >= 0) {
4020 drawHighlight(hi1X, hi1Y, lineGC);
4022 } // [HGM] first erase both, then draw new!
4023 if (hi2X != toX || hi2Y != toY) {
4024 if (hi2X >= 0 && hi2Y >= 0) {
4025 drawHighlight(hi2X, hi2Y, lineGC);
4028 if (hi1X != fromX || hi1Y != fromY) {
4029 if (fromX >= 0 && fromY >= 0) {
4030 drawHighlight(fromX, fromY, highlineGC);
4033 if (hi2X != toX || hi2Y != toY) {
4034 if (toX >= 0 && toY >= 0) {
4035 drawHighlight(toX, toY, highlineGC);
4047 SetHighlights(-1, -1, -1, -1);
4052 SetPremoveHighlights(fromX, fromY, toX, toY)
4053 int fromX, fromY, toX, toY;
4055 if (pm1X != fromX || pm1Y != fromY) {
4056 if (pm1X >= 0 && pm1Y >= 0) {
4057 drawHighlight(pm1X, pm1Y, lineGC);
4059 if (fromX >= 0 && fromY >= 0) {
4060 drawHighlight(fromX, fromY, prelineGC);
4063 if (pm2X != toX || pm2Y != toY) {
4064 if (pm2X >= 0 && pm2Y >= 0) {
4065 drawHighlight(pm2X, pm2Y, lineGC);
4067 if (toX >= 0 && toY >= 0) {
4068 drawHighlight(toX, toY, prelineGC);
4078 ClearPremoveHighlights()
4080 SetPremoveHighlights(-1, -1, -1, -1);
4083 static int CutOutSquare(x, y, x0, y0, kind)
4084 int x, y, *x0, *y0, kind;
4086 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4087 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4089 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4090 if(textureW[kind] < W*squareSize)
4091 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4093 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4094 if(textureH[kind] < H*squareSize)
4095 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4097 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4101 static void BlankSquare(x, y, color, piece, dest, fac)
4102 int x, y, color, fac;
4105 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4107 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4108 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4109 squareSize, squareSize, x*fac, y*fac);
4111 if (useImages && useImageSqs) {
4115 pm = xpmLightSquare;
4120 case 2: /* neutral */
4125 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4126 squareSize, squareSize, x*fac, y*fac);
4136 case 2: /* neutral */
4141 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4146 I split out the routines to draw a piece so that I could
4147 make a generic flash routine.
4149 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4151 int square_color, x, y;
4154 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4155 switch (square_color) {
4157 case 2: /* neutral */
4159 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4160 ? *pieceToOutline(piece)
4161 : *pieceToSolid(piece),
4162 dest, bwPieceGC, 0, 0,
4163 squareSize, squareSize, x, y);
4166 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4167 ? *pieceToSolid(piece)
4168 : *pieceToOutline(piece),
4169 dest, wbPieceGC, 0, 0,
4170 squareSize, squareSize, x, y);
4175 static void monoDrawPiece(piece, square_color, x, y, dest)
4177 int square_color, x, y;
4180 switch (square_color) {
4182 case 2: /* neutral */
4184 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4185 ? *pieceToOutline(piece)
4186 : *pieceToSolid(piece),
4187 dest, bwPieceGC, 0, 0,
4188 squareSize, squareSize, x, y, 1);
4191 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4192 ? *pieceToSolid(piece)
4193 : *pieceToOutline(piece),
4194 dest, wbPieceGC, 0, 0,
4195 squareSize, squareSize, x, y, 1);
4200 static void colorDrawPiece(piece, square_color, x, y, dest)
4202 int square_color, x, y;
4205 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4206 switch (square_color) {
4208 XCopyPlane(xDisplay, *pieceToSolid(piece),
4209 dest, (int) piece < (int) BlackPawn
4210 ? wlPieceGC : blPieceGC, 0, 0,
4211 squareSize, squareSize, x, y, 1);
4214 XCopyPlane(xDisplay, *pieceToSolid(piece),
4215 dest, (int) piece < (int) BlackPawn
4216 ? wdPieceGC : bdPieceGC, 0, 0,
4217 squareSize, squareSize, x, y, 1);
4219 case 2: /* neutral */
4221 XCopyPlane(xDisplay, *pieceToSolid(piece),
4222 dest, (int) piece < (int) BlackPawn
4223 ? wjPieceGC : bjPieceGC, 0, 0,
4224 squareSize, squareSize, x, y, 1);
4229 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4231 int square_color, x, y;
4234 int kind, p = piece;
4236 switch (square_color) {
4238 case 2: /* neutral */
4240 if ((int)piece < (int) BlackPawn) {
4248 if ((int)piece < (int) BlackPawn) {
4256 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4257 if(useTexture & square_color+1) {
4258 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4259 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4260 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4261 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4262 XSetClipMask(xDisplay, wlPieceGC, None);
4263 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4265 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4266 dest, wlPieceGC, 0, 0,
4267 squareSize, squareSize, x, y);
4270 typedef void (*DrawFunc)();
4272 DrawFunc ChooseDrawFunc()
4274 if (appData.monoMode) {
4275 if (DefaultDepth(xDisplay, xScreen) == 1) {
4276 return monoDrawPiece_1bit;
4278 return monoDrawPiece;
4282 return colorDrawPieceImage;
4284 return colorDrawPiece;
4288 /* [HR] determine square color depending on chess variant. */
4289 static int SquareColor(row, column)
4294 if (gameInfo.variant == VariantXiangqi) {
4295 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4297 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4299 } else if (row <= 4) {
4305 square_color = ((column + row) % 2) == 1;
4308 /* [hgm] holdings: next line makes all holdings squares light */
4309 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4311 return square_color;
4314 void DrawSquare(row, column, piece, do_flash)
4315 int row, column, do_flash;
4318 int square_color, x, y, direction, font_ascent, font_descent;
4321 XCharStruct overall;
4325 /* Calculate delay in milliseconds (2-delays per complete flash) */
4326 flash_delay = 500 / appData.flashRate;
4329 x = lineGap + ((BOARD_WIDTH-1)-column) *
4330 (squareSize + lineGap);
4331 y = lineGap + row * (squareSize + lineGap);
4333 x = lineGap + column * (squareSize + lineGap);
4334 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4335 (squareSize + lineGap);
4338 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4340 square_color = SquareColor(row, column);
4342 if ( // [HGM] holdings: blank out area between board and holdings
4343 column == BOARD_LEFT-1 || column == BOARD_RGHT
4344 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4345 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4346 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4348 // [HGM] print piece counts next to holdings
4349 string[1] = NULLCHAR;
4350 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4351 string[0] = '0' + piece;
4352 XTextExtents(countFontStruct, string, 1, &direction,
4353 &font_ascent, &font_descent, &overall);
4354 if (appData.monoMode) {
4355 XDrawImageString(xDisplay, xBoardWindow, countGC,
4356 x + squareSize - overall.width - 2,
4357 y + font_ascent + 1, string, 1);
4359 XDrawString(xDisplay, xBoardWindow, countGC,
4360 x + squareSize - overall.width - 2,
4361 y + font_ascent + 1, string, 1);
4364 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4365 string[0] = '0' + piece;
4366 XTextExtents(countFontStruct, string, 1, &direction,
4367 &font_ascent, &font_descent, &overall);
4368 if (appData.monoMode) {
4369 XDrawImageString(xDisplay, xBoardWindow, countGC,
4370 x + 2, y + font_ascent + 1, string, 1);
4372 XDrawString(xDisplay, xBoardWindow, countGC,
4373 x + 2, y + font_ascent + 1, string, 1);
4377 if (piece == EmptySquare || appData.blindfold) {
4378 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4380 drawfunc = ChooseDrawFunc();
4381 if (do_flash && appData.flashCount > 0) {
4382 for (i=0; i<appData.flashCount; ++i) {
4384 drawfunc(piece, square_color, x, y, xBoardWindow);
4385 XSync(xDisplay, False);
4386 do_flash_delay(flash_delay);
4388 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4389 XSync(xDisplay, False);
4390 do_flash_delay(flash_delay);
4393 drawfunc(piece, square_color, x, y, xBoardWindow);
4397 string[1] = NULLCHAR;
4398 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4399 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4400 string[0] = 'a' + column - BOARD_LEFT;
4401 XTextExtents(coordFontStruct, string, 1, &direction,
4402 &font_ascent, &font_descent, &overall);
4403 if (appData.monoMode) {
4404 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4405 x + squareSize - overall.width - 2,
4406 y + squareSize - font_descent - 1, string, 1);
4408 XDrawString(xDisplay, xBoardWindow, coordGC,
4409 x + squareSize - overall.width - 2,
4410 y + squareSize - font_descent - 1, string, 1);
4413 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4414 string[0] = ONE + row;
4415 XTextExtents(coordFontStruct, string, 1, &direction,
4416 &font_ascent, &font_descent, &overall);
4417 if (appData.monoMode) {
4418 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4419 x + 2, y + font_ascent + 1, string, 1);
4421 XDrawString(xDisplay, xBoardWindow, coordGC,
4422 x + 2, y + font_ascent + 1, string, 1);
4425 if(!partnerUp && marker[row][column]) {
4426 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4427 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4432 /* Why is this needed on some versions of X? */
4433 void EventProc(widget, unused, event)
4438 if (!XtIsRealized(widget))
4441 switch (event->type) {
4443 if (event->xexpose.count > 0) return; /* no clipping is done */
4444 XDrawPosition(widget, True, NULL);
4445 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4446 flipView = !flipView; partnerUp = !partnerUp;
4447 XDrawPosition(widget, True, NULL);
4448 flipView = !flipView; partnerUp = !partnerUp;
4452 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4459 void DrawPosition(fullRedraw, board)
4460 /*Boolean*/int fullRedraw;
4463 XDrawPosition(boardWidget, fullRedraw, board);
4466 /* Returns 1 if there are "too many" differences between b1 and b2
4467 (i.e. more than 1 move was made) */
4468 static int too_many_diffs(b1, b2)
4474 for (i=0; i<BOARD_HEIGHT; ++i) {
4475 for (j=0; j<BOARD_WIDTH; ++j) {
4476 if (b1[i][j] != b2[i][j]) {
4477 if (++c > 4) /* Castling causes 4 diffs */
4486 /* Matrix describing castling maneuvers */
4487 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4488 static int castling_matrix[4][5] = {
4489 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4490 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4491 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4492 { 7, 7, 4, 5, 6 } /* 0-0, black */
4495 /* Checks whether castling occurred. If it did, *rrow and *rcol
4496 are set to the destination (row,col) of the rook that moved.
4498 Returns 1 if castling occurred, 0 if not.
4500 Note: Only handles a max of 1 castling move, so be sure
4501 to call too_many_diffs() first.
4503 static int check_castle_draw(newb, oldb, rrow, rcol)
4510 /* For each type of castling... */
4511 for (i=0; i<4; ++i) {
4512 r = castling_matrix[i];
4514 /* Check the 4 squares involved in the castling move */
4516 for (j=1; j<=4; ++j) {
4517 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4524 /* All 4 changed, so it must be a castling move */
4533 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4534 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4536 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4539 void DrawSeekBackground( int left, int top, int right, int bottom )
4541 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4544 void DrawSeekText(char *buf, int x, int y)
4546 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4549 void DrawSeekDot(int x, int y, int colorNr)
4551 int square = colorNr & 0x80;
4554 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4556 XFillRectangle(xDisplay, xBoardWindow, color,
4557 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4559 XFillArc(xDisplay, xBoardWindow, color,
4560 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4563 static int damage[2][BOARD_RANKS][BOARD_FILES];
4566 * event handler for redrawing the board
4568 void XDrawPosition(w, repaint, board)
4570 /*Boolean*/int repaint;
4574 static int lastFlipView = 0;
4575 static int lastBoardValid[2] = {0, 0};
4576 static Board lastBoard[2];
4579 int nr = twoBoards*partnerUp;
4581 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4583 if (board == NULL) {
4584 if (!lastBoardValid[nr]) return;
4585 board = lastBoard[nr];
4587 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4588 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4589 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4594 * It would be simpler to clear the window with XClearWindow()
4595 * but this causes a very distracting flicker.
4598 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4600 /* If too much changes (begin observing new game, etc.), don't
4602 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4604 /* Special check for castling so we don't flash both the king
4605 and the rook (just flash the king). */
4607 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4608 /* Draw rook with NO flashing. King will be drawn flashing later */
4609 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4610 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4614 /* First pass -- Draw (newly) empty squares and repair damage.
4615 This prevents you from having a piece show up twice while it
4616 is flashing on its new square */
4617 for (i = 0; i < BOARD_HEIGHT; i++)
4618 for (j = 0; j < BOARD_WIDTH; j++)
4619 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4620 || damage[nr][i][j]) {
4621 DrawSquare(i, j, board[i][j], 0);
4622 damage[nr][i][j] = False;
4625 /* Second pass -- Draw piece(s) in new position and flash them */
4626 for (i = 0; i < BOARD_HEIGHT; i++)
4627 for (j = 0; j < BOARD_WIDTH; j++)
4628 if (board[i][j] != lastBoard[nr][i][j]) {
4629 DrawSquare(i, j, board[i][j], do_flash);
4633 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4634 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4635 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4637 for (i = 0; i < BOARD_HEIGHT; i++)
4638 for (j = 0; j < BOARD_WIDTH; j++) {
4639 DrawSquare(i, j, board[i][j], 0);
4640 damage[nr][i][j] = False;
4644 CopyBoard(lastBoard[nr], board);
4645 lastBoardValid[nr] = 1;
4646 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4647 lastFlipView = flipView;
4649 /* Draw highlights */
4650 if (pm1X >= 0 && pm1Y >= 0) {
4651 drawHighlight(pm1X, pm1Y, prelineGC);
4653 if (pm2X >= 0 && pm2Y >= 0) {
4654 drawHighlight(pm2X, pm2Y, prelineGC);
4656 if (hi1X >= 0 && hi1Y >= 0) {
4657 drawHighlight(hi1X, hi1Y, highlineGC);
4659 if (hi2X >= 0 && hi2Y >= 0) {
4660 drawHighlight(hi2X, hi2Y, highlineGC);
4663 /* If piece being dragged around board, must redraw that too */
4666 XSync(xDisplay, False);
4671 * event handler for redrawing the board
4673 void DrawPositionProc(w, event, prms, nprms)
4679 XDrawPosition(w, True, NULL);
4684 * event handler for parsing user moves
4686 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4687 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4688 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4689 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4690 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4691 // and at the end FinishMove() to perform the move after optional promotion popups.
4692 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4693 void HandleUserMove(w, event, prms, nprms)
4699 if (w != boardWidget || errorExitStatus != -1) return;
4700 if(nprms) shiftKey = !strcmp(prms[0], "1");
4703 if (event->type == ButtonPress) {
4704 XtPopdown(promotionShell);
4705 XtDestroyWidget(promotionShell);
4706 promotionUp = False;
4714 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4715 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4716 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4719 void AnimateUserMove (Widget w, XEvent * event,
4720 String * params, Cardinal * nParams)
4722 DragPieceMove(event->xmotion.x, event->xmotion.y);
4725 void HandlePV (Widget w, XEvent * event,
4726 String * params, Cardinal * nParams)
4727 { // [HGM] pv: walk PV
4728 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4731 Widget CommentCreate(name, text, mutable, callback, lines)
4733 int /*Boolean*/ mutable;
4734 XtCallbackProc callback;
4738 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4743 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4744 XtGetValues(boardWidget, args, j);
4747 XtSetArg(args[j], XtNresizable, True); j++;
4750 XtCreatePopupShell(name, topLevelShellWidgetClass,
4751 shellWidget, args, j);
4754 XtCreatePopupShell(name, transientShellWidgetClass,
4755 shellWidget, args, j);
4758 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4759 layoutArgs, XtNumber(layoutArgs));
4761 XtCreateManagedWidget("form", formWidgetClass, layout,
4762 formArgs, XtNumber(formArgs));
4766 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4767 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4769 XtSetArg(args[j], XtNstring, text); j++;
4770 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4771 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4772 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4773 XtSetArg(args[j], XtNright, XtChainRight); j++;
4774 XtSetArg(args[j], XtNresizable, True); j++;
4775 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4776 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4777 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4778 XtSetArg(args[j], XtNautoFill, True); j++;
4779 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4781 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4782 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4786 XtSetArg(args[j], XtNfromVert, edit); j++;
4787 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4788 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4789 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4790 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4792 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4793 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4796 XtSetArg(args[j], XtNfromVert, edit); j++;
4797 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4798 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4799 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4800 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4801 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4803 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4804 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4807 XtSetArg(args[j], XtNfromVert, edit); j++;
4808 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4809 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4810 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4811 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4812 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4814 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4815 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4818 XtSetArg(args[j], XtNfromVert, edit); j++;
4819 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4820 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4821 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4822 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4824 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4825 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4828 XtSetArg(args[j], XtNfromVert, edit); j++;
4829 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4830 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4831 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4832 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4833 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4835 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4836 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4839 XtRealizeWidget(shell);
4841 if (commentX == -1) {
4844 Dimension pw_height;
4845 Dimension ew_height;
4848 XtSetArg(args[j], XtNheight, &ew_height); j++;
4849 XtGetValues(edit, args, j);
4852 XtSetArg(args[j], XtNheight, &pw_height); j++;
4853 XtGetValues(shell, args, j);
4854 commentH = pw_height + (lines - 1) * ew_height;
4855 commentW = bw_width - 16;
4857 XSync(xDisplay, False);
4859 /* This code seems to tickle an X bug if it is executed too soon
4860 after xboard starts up. The coordinates get transformed as if
4861 the main window was positioned at (0, 0).
4863 XtTranslateCoords(shellWidget,
4864 (bw_width - commentW) / 2, 0 - commentH / 2,
4865 &commentX, &commentY);
4867 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4868 RootWindowOfScreen(XtScreen(shellWidget)),
4869 (bw_width - commentW) / 2, 0 - commentH / 2,
4874 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4877 if(wpComment.width > 0) {
4878 commentX = wpComment.x;
4879 commentY = wpComment.y;
4880 commentW = wpComment.width;
4881 commentH = wpComment.height;
4885 XtSetArg(args[j], XtNheight, commentH); j++;
4886 XtSetArg(args[j], XtNwidth, commentW); j++;
4887 XtSetArg(args[j], XtNx, commentX); j++;
4888 XtSetArg(args[j], XtNy, commentY); j++;
4889 XtSetValues(shell, args, j);
4890 XtSetKeyboardFocus(shell, edit);
4895 /* Used for analysis window and ICS input window */
4896 Widget MiscCreate(name, text, mutable, callback, lines)
4898 int /*Boolean*/ mutable;
4899 XtCallbackProc callback;
4903 Widget shell, layout, form, edit;
4905 Dimension bw_width, pw_height, ew_height, w, h;
4911 XtSetArg(args[j], XtNresizable, True); j++;
4914 XtCreatePopupShell(name, topLevelShellWidgetClass,
4915 shellWidget, args, j);
4918 XtCreatePopupShell(name, transientShellWidgetClass,
4919 shellWidget, args, j);
4922 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4923 layoutArgs, XtNumber(layoutArgs));
4925 XtCreateManagedWidget("form", formWidgetClass, layout,
4926 formArgs, XtNumber(formArgs));
4930 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4931 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4933 XtSetArg(args[j], XtNstring, text); j++;
4934 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4935 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4936 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4937 XtSetArg(args[j], XtNright, XtChainRight); j++;
4938 XtSetArg(args[j], XtNresizable, True); j++;
4939 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4940 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4941 XtSetArg(args[j], XtNautoFill, True); j++;
4942 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4944 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4946 XtRealizeWidget(shell);
4949 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4950 XtGetValues(boardWidget, args, j);
4953 XtSetArg(args[j], XtNheight, &ew_height); j++;
4954 XtGetValues(edit, args, j);
4957 XtSetArg(args[j], XtNheight, &pw_height); j++;
4958 XtGetValues(shell, args, j);
4959 h = pw_height + (lines - 1) * ew_height;
4962 XSync(xDisplay, False);
4964 /* This code seems to tickle an X bug if it is executed too soon
4965 after xboard starts up. The coordinates get transformed as if
4966 the main window was positioned at (0, 0).
4968 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4970 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4971 RootWindowOfScreen(XtScreen(shellWidget)),
4972 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4976 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4979 XtSetArg(args[j], XtNheight, h); j++;
4980 XtSetArg(args[j], XtNwidth, w); j++;
4981 XtSetArg(args[j], XtNx, x); j++;
4982 XtSetArg(args[j], XtNy, y); j++;
4983 XtSetValues(shell, args, j);
4989 static int savedIndex; /* gross that this is global */
4991 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4994 XawTextPosition index, dummy;
4997 XawTextGetSelectionPos(w, &index, &dummy);
4998 XtSetArg(arg, XtNstring, &val);
4999 XtGetValues(w, &arg, 1);
5000 ReplaceComment(savedIndex, val);
5001 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5002 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5005 void EditCommentPopUp(index, title, text)
5014 if (text == NULL) text = "";
5016 if (editShell == NULL) {
5018 CommentCreate(title, text, True, EditCommentCallback, 4);
5019 XtRealizeWidget(editShell);
5020 CatchDeleteWindow(editShell, "EditCommentPopDown");
5022 edit = XtNameToWidget(editShell, "*form.text");
5024 XtSetArg(args[j], XtNstring, text); j++;
5025 XtSetValues(edit, args, j);
5027 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5028 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5029 XtSetValues(editShell, args, j);
5032 XtPopup(editShell, XtGrabNone);
5036 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5037 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5041 void EditCommentCallback(w, client_data, call_data)
5043 XtPointer client_data, call_data;
5051 XtSetArg(args[j], XtNlabel, &name); j++;
5052 XtGetValues(w, args, j);
5054 if (strcmp(name, _("ok")) == 0) {
5055 edit = XtNameToWidget(editShell, "*form.text");
5057 XtSetArg(args[j], XtNstring, &val); j++;
5058 XtGetValues(edit, args, j);
5059 ReplaceComment(savedIndex, val);
5060 EditCommentPopDown();
5061 } else if (strcmp(name, _("cancel")) == 0) {
5062 EditCommentPopDown();
5063 } else if (strcmp(name, _("clear")) == 0) {
5064 edit = XtNameToWidget(editShell, "*form.text");
5065 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5066 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5070 void EditCommentPopDown()
5075 if (!editUp) return;
5077 XtSetArg(args[j], XtNx, &commentX); j++;
5078 XtSetArg(args[j], XtNy, &commentY); j++;
5079 XtSetArg(args[j], XtNheight, &commentH); j++;
5080 XtSetArg(args[j], XtNwidth, &commentW); j++;
5081 XtGetValues(editShell, args, j);
5082 XtPopdown(editShell);
5085 XtSetArg(args[j], XtNleftBitmap, None); j++;
5086 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5090 void ICSInputBoxPopUp()
5095 char *title = _("ICS Input");
5098 if (ICSInputShell == NULL) {
5099 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5100 tr = XtParseTranslationTable(ICSInputTranslations);
5101 edit = XtNameToWidget(ICSInputShell, "*form.text");
5102 XtOverrideTranslations(edit, tr);
5103 XtRealizeWidget(ICSInputShell);
5104 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5107 edit = XtNameToWidget(ICSInputShell, "*form.text");
5109 XtSetArg(args[j], XtNstring, ""); j++;
5110 XtSetValues(edit, args, j);
5112 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5113 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5114 XtSetValues(ICSInputShell, args, j);
5117 XtPopup(ICSInputShell, XtGrabNone);
5118 XtSetKeyboardFocus(ICSInputShell, edit);
5120 ICSInputBoxUp = True;
5122 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5123 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5127 void ICSInputSendText()
5134 edit = XtNameToWidget(ICSInputShell, "*form.text");
5136 XtSetArg(args[j], XtNstring, &val); j++;
5137 XtGetValues(edit, args, j);
5139 SendMultiLineToICS(val);
5140 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5141 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5144 void ICSInputBoxPopDown()
5149 if (!ICSInputBoxUp) return;
5151 XtPopdown(ICSInputShell);
5152 ICSInputBoxUp = False;
5154 XtSetArg(args[j], XtNleftBitmap, None); j++;
5155 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5159 void CommentPopUp(title, text)
5166 savedIndex = currentMove; // [HGM] vari
5167 if (commentShell == NULL) {
5169 CommentCreate(title, text, False, CommentCallback, 4);
5170 XtRealizeWidget(commentShell);
5171 CatchDeleteWindow(commentShell, "CommentPopDown");
5173 edit = XtNameToWidget(commentShell, "*form.text");
5175 XtSetArg(args[j], XtNstring, text); j++;
5176 XtSetValues(edit, args, j);
5178 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5179 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5180 XtSetValues(commentShell, args, j);
5183 XtPopup(commentShell, XtGrabNone);
5184 XSync(xDisplay, False);
5189 void CommentCallback(w, client_data, call_data)
5191 XtPointer client_data, call_data;
5198 XtSetArg(args[j], XtNlabel, &name); j++;
5199 XtGetValues(w, args, j);
5201 if (strcmp(name, _("close")) == 0) {
5203 } else if (strcmp(name, _("edit")) == 0) {
5210 void CommentPopDown()
5215 if (!commentUp) return;
5217 XtSetArg(args[j], XtNx, &commentX); j++;
5218 XtSetArg(args[j], XtNy, &commentY); j++;
5219 XtSetArg(args[j], XtNwidth, &commentW); j++;
5220 XtSetArg(args[j], XtNheight, &commentH); j++;
5221 XtGetValues(commentShell, args, j);
5222 XtPopdown(commentShell);
5223 XSync(xDisplay, False);
5227 void FileNamePopUp(label, def, proc, openMode)
5233 fileProc = proc; /* I can't see a way not */
5234 fileOpenMode = openMode; /* to use globals here */
5235 { // [HGM] use file-selector dialog stolen from Ghostview
5237 int index; // this is not supported yet
5239 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5240 def, openMode, NULL, &name))
5241 (void) (*fileProc)(f, index=0, name);
5245 void FileNamePopDown()
5247 if (!filenameUp) return;
5248 XtPopdown(fileNameShell);
5249 XtDestroyWidget(fileNameShell);
5254 void FileNameCallback(w, client_data, call_data)
5256 XtPointer client_data, call_data;
5261 XtSetArg(args[0], XtNlabel, &name);
5262 XtGetValues(w, args, 1);
5264 if (strcmp(name, _("cancel")) == 0) {
5269 FileNameAction(w, NULL, NULL, NULL);
5272 void FileNameAction(w, event, prms, nprms)
5284 name = XawDialogGetValueString(w = XtParent(w));
5286 if ((name != NULL) && (*name != NULLCHAR)) {
5287 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5288 XtPopdown(w = XtParent(XtParent(w)));
5292 p = strrchr(buf, ' ');
5299 fullname = ExpandPathName(buf);
5301 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5304 f = fopen(fullname, fileOpenMode);
5306 DisplayError(_("Failed to open file"), errno);
5308 (void) (*fileProc)(f, index, buf);
5315 XtPopdown(w = XtParent(XtParent(w)));
5321 void PromotionPopUp()
5324 Widget dialog, layout;
5326 Dimension bw_width, pw_width;
5330 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5331 XtGetValues(boardWidget, args, j);
5334 XtSetArg(args[j], XtNresizable, True); j++;
5335 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5337 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5338 shellWidget, args, j);
5340 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5341 layoutArgs, XtNumber(layoutArgs));
5344 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5345 XtSetArg(args[j], XtNborderWidth, 0); j++;
5346 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5349 if(gameInfo.variant != VariantShogi) {
5350 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5351 (XtPointer) dialog);
5352 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5353 (XtPointer) dialog);
5354 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5355 (XtPointer) dialog);
5356 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5357 (XtPointer) dialog);
5358 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5359 gameInfo.variant == VariantGiveaway) {
5360 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5361 (XtPointer) dialog);
5363 if(gameInfo.variant == VariantCapablanca ||
5364 gameInfo.variant == VariantGothic ||
5365 gameInfo.variant == VariantCapaRandom) {
5366 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5367 (XtPointer) dialog);
5368 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5369 (XtPointer) dialog);
5371 } else // [HGM] shogi
5373 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5374 (XtPointer) dialog);
5375 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5376 (XtPointer) dialog);
5378 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5379 (XtPointer) dialog);
5381 XtRealizeWidget(promotionShell);
5382 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5385 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5386 XtGetValues(promotionShell, args, j);
5388 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5389 lineGap + squareSize/3 +
5390 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5391 0 : 6*(squareSize + lineGap)), &x, &y);
5394 XtSetArg(args[j], XtNx, x); j++;
5395 XtSetArg(args[j], XtNy, y); j++;
5396 XtSetValues(promotionShell, args, j);
5398 XtPopup(promotionShell, XtGrabNone);
5403 void PromotionPopDown()
5405 if (!promotionUp) return;
5406 XtPopdown(promotionShell);
5407 XtDestroyWidget(promotionShell);
5408 promotionUp = False;
5411 void PromotionCallback(w, client_data, call_data)
5413 XtPointer client_data, call_data;
5419 XtSetArg(args[0], XtNlabel, &name);
5420 XtGetValues(w, args, 1);
5424 if (fromX == -1) return;
5426 if (strcmp(name, _("cancel")) == 0) {
5430 } else if (strcmp(name, _("Knight")) == 0) {
5432 } else if (strcmp(name, _("Promote")) == 0) {
5434 } else if (strcmp(name, _("Defer")) == 0) {
5437 promoChar = ToLower(name[0]);
5440 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5442 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5443 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5448 void ErrorCallback(w, client_data, call_data)
5450 XtPointer client_data, call_data;
5453 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5455 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5461 if (!errorUp) return;
5463 XtPopdown(errorShell);
5464 XtDestroyWidget(errorShell);
5465 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5468 void ErrorPopUp(title, label, modal)
5469 char *title, *label;
5473 Widget dialog, layout;
5477 Dimension bw_width, pw_width;
5478 Dimension pw_height;
5482 XtSetArg(args[i], XtNresizable, True); i++;
5483 XtSetArg(args[i], XtNtitle, title); i++;
5485 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5486 shellWidget, args, i);
5488 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5489 layoutArgs, XtNumber(layoutArgs));
5492 XtSetArg(args[i], XtNlabel, label); i++;
5493 XtSetArg(args[i], XtNborderWidth, 0); i++;
5494 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5497 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5499 XtRealizeWidget(errorShell);
5500 CatchDeleteWindow(errorShell, "ErrorPopDown");
5503 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5504 XtGetValues(boardWidget, args, i);
5506 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5507 XtSetArg(args[i], XtNheight, &pw_height); i++;
5508 XtGetValues(errorShell, args, i);
5511 /* This code seems to tickle an X bug if it is executed too soon
5512 after xboard starts up. The coordinates get transformed as if
5513 the main window was positioned at (0, 0).
5515 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5516 0 - pw_height + squareSize / 3, &x, &y);
5518 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5519 RootWindowOfScreen(XtScreen(boardWidget)),
5520 (bw_width - pw_width) / 2,
5521 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5525 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5528 XtSetArg(args[i], XtNx, x); i++;
5529 XtSetArg(args[i], XtNy, y); i++;
5530 XtSetValues(errorShell, args, i);
5533 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5536 /* Disable all user input other than deleting the window */
5537 static int frozen = 0;
5541 /* Grab by a widget that doesn't accept input */
5542 XtAddGrab(messageWidget, TRUE, FALSE);
5546 /* Undo a FreezeUI */
5549 if (!frozen) return;
5550 XtRemoveGrab(messageWidget);
5554 char *ModeToWidgetName(mode)
5558 case BeginningOfGame:
5559 if (appData.icsActive)
5560 return "menuMode.ICS Client";
5561 else if (appData.noChessProgram ||
5562 *appData.cmailGameName != NULLCHAR)
5563 return "menuMode.Edit Game";
5565 return "menuMode.Machine Black";
5566 case MachinePlaysBlack:
5567 return "menuMode.Machine Black";
5568 case MachinePlaysWhite:
5569 return "menuMode.Machine White";
5571 return "menuMode.Analysis Mode";
5573 return "menuMode.Analyze File";
5574 case TwoMachinesPlay:
5575 return "menuMode.Two Machines";
5577 return "menuMode.Edit Game";
5578 case PlayFromGameFile:
5579 return "menuFile.Load Game";
5581 return "menuMode.Edit Position";
5583 return "menuMode.Training";
5584 case IcsPlayingWhite:
5585 case IcsPlayingBlack:
5589 return "menuMode.ICS Client";
5596 void ModeHighlight()
5599 static int oldPausing = FALSE;
5600 static GameMode oldmode = (GameMode) -1;
5603 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5605 if (pausing != oldPausing) {
5606 oldPausing = pausing;
5608 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5610 XtSetArg(args[0], XtNleftBitmap, None);
5612 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5615 if (appData.showButtonBar) {
5616 /* Always toggle, don't set. Previous code messes up when
5617 invoked while the button is pressed, as releasing it
5618 toggles the state again. */
5621 XtSetArg(args[0], XtNbackground, &oldbg);
5622 XtSetArg(args[1], XtNforeground, &oldfg);
5623 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5625 XtSetArg(args[0], XtNbackground, oldfg);
5626 XtSetArg(args[1], XtNforeground, oldbg);
5628 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5632 wname = ModeToWidgetName(oldmode);
5633 if (wname != NULL) {
5634 XtSetArg(args[0], XtNleftBitmap, None);
5635 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5637 wname = ModeToWidgetName(gameMode);
5638 if (wname != NULL) {
5639 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5640 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5644 /* Maybe all the enables should be handled here, not just this one */
5645 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5646 gameMode == Training || gameMode == PlayFromGameFile);
5651 * Button/menu procedures
5653 void ResetProc(w, event, prms, nprms)
5662 int LoadGamePopUp(f, gameNumber, title)
5667 cmailMsgLoaded = FALSE;
5668 if (gameNumber == 0) {
5669 int error = GameListBuild(f);
5671 DisplayError(_("Cannot build game list"), error);
5672 } else if (!ListEmpty(&gameList) &&
5673 ((ListGame *) gameList.tailPred)->number > 1) {
5674 GameListPopUp(f, title);
5680 return LoadGame(f, gameNumber, title, FALSE);
5683 void LoadGameProc(w, event, prms, nprms)
5689 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5692 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5695 void LoadNextGameProc(w, event, prms, nprms)
5704 void LoadPrevGameProc(w, event, prms, nprms)
5713 void ReloadGameProc(w, event, prms, nprms)
5722 void LoadNextPositionProc(w, event, prms, nprms)
5731 void LoadPrevPositionProc(w, event, prms, nprms)
5740 void ReloadPositionProc(w, event, prms, nprms)
5749 void LoadPositionProc(w, event, prms, nprms)
5755 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5758 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5761 void SaveGameProc(w, event, prms, nprms)
5767 FileNamePopUp(_("Save game file name?"),
5768 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5772 void SavePositionProc(w, event, prms, nprms)
5778 FileNamePopUp(_("Save position file name?"),
5779 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5783 void ReloadCmailMsgProc(w, event, prms, nprms)
5789 ReloadCmailMsgEvent(FALSE);
5792 void MailMoveProc(w, event, prms, nprms)
5801 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5802 char *selected_fen_position=NULL;
5805 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5806 Atom *type_return, XtPointer *value_return,
5807 unsigned long *length_return, int *format_return)
5809 char *selection_tmp;
5811 if (!selected_fen_position) return False; /* should never happen */
5812 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5813 /* note: since no XtSelectionDoneProc was registered, Xt will
5814 * automatically call XtFree on the value returned. So have to
5815 * make a copy of it allocated with XtMalloc */
5816 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5817 safeStrCpy(selection_tmp, selected_fen_position, sizeof(selection_tmp)/sizeof(selection_tmp[0]) );
5819 *value_return=selection_tmp;
5820 *length_return=strlen(selection_tmp);
5821 *type_return=*target;
5822 *format_return = 8; /* bits per byte */
5824 } else if (*target == XA_TARGETS(xDisplay)) {
5825 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5826 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5827 targets_tmp[1] = XA_STRING;
5828 *value_return = targets_tmp;
5829 *type_return = XA_ATOM;
5831 *format_return = 8 * sizeof(Atom);
5832 if (*format_return > 32) {
5833 *length_return *= *format_return / 32;
5834 *format_return = 32;
5842 /* note: when called from menu all parameters are NULL, so no clue what the
5843 * Widget which was clicked on was, or what the click event was
5845 void CopyPositionProc(w, event, prms, nprms)
5852 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5853 * have a notion of a position that is selected but not copied.
5854 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5856 if(gameMode == EditPosition) EditPositionDone(TRUE);
5857 if (selected_fen_position) free(selected_fen_position);
5858 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5859 if (!selected_fen_position) return;
5860 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5862 SendPositionSelection,
5863 NULL/* lose_ownership_proc */ ,
5864 NULL/* transfer_done_proc */);
5865 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5867 SendPositionSelection,
5868 NULL/* lose_ownership_proc */ ,
5869 NULL/* transfer_done_proc */);
5872 /* function called when the data to Paste is ready */
5874 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5875 Atom *type, XtPointer value, unsigned long *len, int *format)
5878 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5879 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5880 EditPositionPasteFEN(fenstr);
5884 /* called when Paste Position button is pressed,
5885 * all parameters will be NULL */
5886 void PastePositionProc(w, event, prms, nprms)
5892 XtGetSelectionValue(menuBarWidget,
5893 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5894 /* (XtSelectionCallbackProc) */ PastePositionCB,
5895 NULL, /* client_data passed to PastePositionCB */
5897 /* better to use the time field from the event that triggered the
5898 * call to this function, but that isn't trivial to get
5906 SendGameSelection(Widget w, Atom *selection, Atom *target,
5907 Atom *type_return, XtPointer *value_return,
5908 unsigned long *length_return, int *format_return)
5910 char *selection_tmp;
5912 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5913 FILE* f = fopen(gameCopyFilename, "r");
5916 if (f == NULL) return False;
5920 selection_tmp = XtMalloc(len + 1);
5921 count = fread(selection_tmp, 1, len, f);
5923 XtFree(selection_tmp);
5926 selection_tmp[len] = NULLCHAR;
5927 *value_return = selection_tmp;
5928 *length_return = len;
5929 *type_return = *target;
5930 *format_return = 8; /* bits per byte */
5932 } else if (*target == XA_TARGETS(xDisplay)) {
5933 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5934 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5935 targets_tmp[1] = XA_STRING;
5936 *value_return = targets_tmp;
5937 *type_return = XA_ATOM;
5939 *format_return = 8 * sizeof(Atom);
5940 if (*format_return > 32) {
5941 *length_return *= *format_return / 32;
5942 *format_return = 32;
5950 /* note: when called from menu all parameters are NULL, so no clue what the
5951 * Widget which was clicked on was, or what the click event was
5953 void CopyGameProc(w, event, prms, nprms)
5961 ret = SaveGameToFile(gameCopyFilename, FALSE);
5965 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5966 * have a notion of a game that is selected but not copied.
5967 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5969 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5972 NULL/* lose_ownership_proc */ ,
5973 NULL/* transfer_done_proc */);
5974 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5977 NULL/* lose_ownership_proc */ ,
5978 NULL/* transfer_done_proc */);
5981 /* function called when the data to Paste is ready */
5983 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5984 Atom *type, XtPointer value, unsigned long *len, int *format)
5987 if (value == NULL || *len == 0) {
5988 return; /* nothing had been selected to copy */
5990 f = fopen(gamePasteFilename, "w");
5992 DisplayError(_("Can't open temp file"), errno);
5995 fwrite(value, 1, *len, f);
5998 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
6001 /* called when Paste Game button is pressed,
6002 * all parameters will be NULL */
6003 void PasteGameProc(w, event, prms, nprms)
6009 XtGetSelectionValue(menuBarWidget,
6010 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
6011 /* (XtSelectionCallbackProc) */ PasteGameCB,
6012 NULL, /* client_data passed to PasteGameCB */
6014 /* better to use the time field from the event that triggered the
6015 * call to this function, but that isn't trivial to get
6025 SaveGameProc(NULL, NULL, NULL, NULL);
6029 void QuitProc(w, event, prms, nprms)
6038 void PauseProc(w, event, prms, nprms)
6048 void MachineBlackProc(w, event, prms, nprms)
6054 MachineBlackEvent();
6057 void MachineWhiteProc(w, event, prms, nprms)
6063 MachineWhiteEvent();
6066 void AnalyzeModeProc(w, event, prms, nprms)
6074 if (!first.analysisSupport) {
6075 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6076 DisplayError(buf, 0);
6079 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6080 if (appData.icsActive) {
6081 if (gameMode != IcsObserving) {
6082 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6083 DisplayError(buf, 0);
6085 if (appData.icsEngineAnalyze) {
6086 if (appData.debugMode)
6087 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6093 /* if enable, use want disable icsEngineAnalyze */
6094 if (appData.icsEngineAnalyze) {
6099 appData.icsEngineAnalyze = TRUE;
6100 if (appData.debugMode)
6101 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6103 if (!appData.showThinking)
6104 ShowThinkingProc(w,event,prms,nprms);
6109 void AnalyzeFileProc(w, event, prms, nprms)
6115 if (!first.analysisSupport) {
6117 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6118 DisplayError(buf, 0);
6123 if (!appData.showThinking)
6124 ShowThinkingProc(w,event,prms,nprms);
6127 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6128 AnalysisPeriodicEvent(1);
6131 void TwoMachinesProc(w, event, prms, nprms)
6140 void IcsClientProc(w, event, prms, nprms)
6149 void EditGameProc(w, event, prms, nprms)
6158 void EditPositionProc(w, event, prms, nprms)
6164 EditPositionEvent();
6167 void TrainingProc(w, event, prms, nprms)
6176 void EditCommentProc(w, event, prms, nprms)
6183 EditCommentPopDown();
6189 void IcsInputBoxProc(w, event, prms, nprms)
6195 if (ICSInputBoxUp) {
6196 ICSInputBoxPopDown();
6202 void AcceptProc(w, event, prms, nprms)
6211 void DeclineProc(w, event, prms, nprms)
6220 void RematchProc(w, event, prms, nprms)
6229 void CallFlagProc(w, event, prms, nprms)
6238 void DrawProc(w, event, prms, nprms)
6247 void AbortProc(w, event, prms, nprms)
6256 void AdjournProc(w, event, prms, nprms)
6265 void ResignProc(w, event, prms, nprms)
6274 void AdjuWhiteProc(w, event, prms, nprms)
6280 UserAdjudicationEvent(+1);
6283 void AdjuBlackProc(w, event, prms, nprms)
6289 UserAdjudicationEvent(-1);
6292 void AdjuDrawProc(w, event, prms, nprms)
6298 UserAdjudicationEvent(0);
6301 void EnterKeyProc(w, event, prms, nprms)
6307 if (ICSInputBoxUp == True)
6311 void UpKeyProc(w, event, prms, nprms)
6316 { // [HGM] input: let up-arrow recall previous line from history
6323 if (!ICSInputBoxUp) return;
6324 edit = XtNameToWidget(ICSInputShell, "*form.text");
6326 XtSetArg(args[j], XtNstring, &val); j++;
6327 XtGetValues(edit, args, j);
6328 val = PrevInHistory(val);
6329 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6330 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6332 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6333 XawTextReplace(edit, 0, 0, &t);
6334 XawTextSetInsertionPoint(edit, 9999);
6338 void DownKeyProc(w, event, prms, nprms)
6343 { // [HGM] input: let down-arrow recall next line from history
6348 if (!ICSInputBoxUp) return;
6349 edit = XtNameToWidget(ICSInputShell, "*form.text");
6350 val = NextInHistory();
6351 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6352 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6354 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6355 XawTextReplace(edit, 0, 0, &t);
6356 XawTextSetInsertionPoint(edit, 9999);
6360 void StopObservingProc(w, event, prms, nprms)
6366 StopObservingEvent();
6369 void StopExaminingProc(w, event, prms, nprms)
6375 StopExaminingEvent();
6378 void UploadProc(w, event, prms, nprms)
6388 void ForwardProc(w, event, prms, nprms)
6398 void BackwardProc(w, event, prms, nprms)
6407 void ToStartProc(w, event, prms, nprms)
6416 void ToEndProc(w, event, prms, nprms)
6425 void RevertProc(w, event, prms, nprms)
6434 void AnnotateProc(w, event, prms, nprms)
6443 void TruncateGameProc(w, event, prms, nprms)
6449 TruncateGameEvent();
6451 void RetractMoveProc(w, event, prms, nprms)
6460 void MoveNowProc(w, event, prms, nprms)
6470 void AlwaysQueenProc(w, event, prms, nprms)
6478 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6480 if (appData.alwaysPromoteToQueen) {
6481 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6483 XtSetArg(args[0], XtNleftBitmap, None);
6485 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6489 void AnimateDraggingProc(w, event, prms, nprms)
6497 appData.animateDragging = !appData.animateDragging;
6499 if (appData.animateDragging) {
6500 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6503 XtSetArg(args[0], XtNleftBitmap, None);
6505 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6509 void AnimateMovingProc(w, event, prms, nprms)
6517 appData.animate = !appData.animate;
6519 if (appData.animate) {
6520 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6523 XtSetArg(args[0], XtNleftBitmap, None);
6525 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6529 void AutocommProc(w, event, prms, nprms)
6537 appData.autoComment = !appData.autoComment;
6539 if (appData.autoComment) {
6540 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6542 XtSetArg(args[0], XtNleftBitmap, None);
6544 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6549 void AutoflagProc(w, event, prms, nprms)
6557 appData.autoCallFlag = !appData.autoCallFlag;
6559 if (appData.autoCallFlag) {
6560 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6562 XtSetArg(args[0], XtNleftBitmap, None);
6564 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6568 void AutoflipProc(w, event, prms, nprms)
6576 appData.autoFlipView = !appData.autoFlipView;
6578 if (appData.autoFlipView) {
6579 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6581 XtSetArg(args[0], XtNleftBitmap, None);
6583 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6587 void AutobsProc(w, event, prms, nprms)
6595 appData.autoObserve = !appData.autoObserve;
6597 if (appData.autoObserve) {
6598 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6600 XtSetArg(args[0], XtNleftBitmap, None);
6602 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6606 void AutoraiseProc(w, event, prms, nprms)
6614 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6616 if (appData.autoRaiseBoard) {
6617 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6619 XtSetArg(args[0], XtNleftBitmap, None);
6621 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6625 void AutosaveProc(w, event, prms, nprms)
6633 appData.autoSaveGames = !appData.autoSaveGames;
6635 if (appData.autoSaveGames) {
6636 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6638 XtSetArg(args[0], XtNleftBitmap, None);
6640 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6644 void BlindfoldProc(w, event, prms, nprms)
6652 appData.blindfold = !appData.blindfold;
6654 if (appData.blindfold) {
6655 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6657 XtSetArg(args[0], XtNleftBitmap, None);
6659 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6662 DrawPosition(True, NULL);
6665 void TestLegalityProc(w, event, prms, nprms)
6673 appData.testLegality = !appData.testLegality;
6675 if (appData.testLegality) {
6676 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6678 XtSetArg(args[0], XtNleftBitmap, None);
6680 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6685 void FlashMovesProc(w, event, prms, nprms)
6693 if (appData.flashCount == 0) {
6694 appData.flashCount = 3;
6696 appData.flashCount = -appData.flashCount;
6699 if (appData.flashCount > 0) {
6700 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6702 XtSetArg(args[0], XtNleftBitmap, None);
6704 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6708 void FlipViewProc(w, event, prms, nprms)
6714 flipView = !flipView;
6715 DrawPosition(True, NULL);
6718 void GetMoveListProc(w, event, prms, nprms)
6726 appData.getMoveList = !appData.getMoveList;
6728 if (appData.getMoveList) {
6729 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6732 XtSetArg(args[0], XtNleftBitmap, None);
6734 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6739 void HighlightDraggingProc(w, event, prms, nprms)
6747 appData.highlightDragging = !appData.highlightDragging;
6749 if (appData.highlightDragging) {
6750 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6752 XtSetArg(args[0], XtNleftBitmap, None);
6754 XtSetValues(XtNameToWidget(menuBarWidget,
6755 "menuOptions.Highlight Dragging"), args, 1);
6759 void HighlightLastMoveProc(w, event, prms, nprms)
6767 appData.highlightLastMove = !appData.highlightLastMove;
6769 if (appData.highlightLastMove) {
6770 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6772 XtSetArg(args[0], XtNleftBitmap, None);
6774 XtSetValues(XtNameToWidget(menuBarWidget,
6775 "menuOptions.Highlight Last Move"), args, 1);
6778 void IcsAlarmProc(w, event, prms, nprms)
6786 appData.icsAlarm = !appData.icsAlarm;
6788 if (appData.icsAlarm) {
6789 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6791 XtSetArg(args[0], XtNleftBitmap, None);
6793 XtSetValues(XtNameToWidget(menuBarWidget,
6794 "menuOptions.ICS Alarm"), args, 1);
6797 void MoveSoundProc(w, event, prms, nprms)
6805 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6807 if (appData.ringBellAfterMoves) {
6808 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6810 XtSetArg(args[0], XtNleftBitmap, None);
6812 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6817 void OldSaveStyleProc(w, event, prms, nprms)
6825 appData.oldSaveStyle = !appData.oldSaveStyle;
6827 if (appData.oldSaveStyle) {
6828 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6830 XtSetArg(args[0], XtNleftBitmap, None);
6832 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6836 void PeriodicUpdatesProc(w, event, prms, nprms)
6844 PeriodicUpdatesEvent(!appData.periodicUpdates);
6846 if (appData.periodicUpdates) {
6847 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6849 XtSetArg(args[0], XtNleftBitmap, None);
6851 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6855 void PonderNextMoveProc(w, event, prms, nprms)
6863 PonderNextMoveEvent(!appData.ponderNextMove);
6865 if (appData.ponderNextMove) {
6866 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6868 XtSetArg(args[0], XtNleftBitmap, None);
6870 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6874 void PopupExitMessageProc(w, event, prms, nprms)
6882 appData.popupExitMessage = !appData.popupExitMessage;
6884 if (appData.popupExitMessage) {
6885 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6887 XtSetArg(args[0], XtNleftBitmap, None);
6889 XtSetValues(XtNameToWidget(menuBarWidget,
6890 "menuOptions.Popup Exit Message"), args, 1);
6893 void PopupMoveErrorsProc(w, event, prms, nprms)
6901 appData.popupMoveErrors = !appData.popupMoveErrors;
6903 if (appData.popupMoveErrors) {
6904 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6906 XtSetArg(args[0], XtNleftBitmap, None);
6908 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6912 void PremoveProc(w, event, prms, nprms)
6920 appData.premove = !appData.premove;
6922 if (appData.premove) {
6923 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6925 XtSetArg(args[0], XtNleftBitmap, None);
6927 XtSetValues(XtNameToWidget(menuBarWidget,
6928 "menuOptions.Premove"), args, 1);
6931 void QuietPlayProc(w, event, prms, nprms)
6939 appData.quietPlay = !appData.quietPlay;
6941 if (appData.quietPlay) {
6942 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6944 XtSetArg(args[0], XtNleftBitmap, None);
6946 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6950 void ShowCoordsProc(w, event, prms, nprms)
6958 appData.showCoords = !appData.showCoords;
6960 if (appData.showCoords) {
6961 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6963 XtSetArg(args[0], XtNleftBitmap, None);
6965 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6968 DrawPosition(True, NULL);
6971 void ShowThinkingProc(w, event, prms, nprms)
6977 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6978 ShowThinkingEvent();
6981 void HideThinkingProc(w, event, prms, nprms)
6989 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6990 ShowThinkingEvent();
6992 if (appData.hideThinkingFromHuman) {
6993 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6995 XtSetArg(args[0], XtNleftBitmap, None);
6997 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
7001 void SaveOnExitProc(w, event, prms, nprms)
7009 saveSettingsOnExit = !saveSettingsOnExit;
7011 if (saveSettingsOnExit) {
7012 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
7014 XtSetArg(args[0], XtNleftBitmap, None);
7016 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
7020 void SaveSettingsProc(w, event, prms, nprms)
7026 SaveSettings(settingsFileName);
7029 void InfoProc(w, event, prms, nprms)
7036 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
7041 void ManProc(w, event, prms, nprms)
7049 if (nprms && *nprms > 0)
7053 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7057 void HintProc(w, event, prms, nprms)
7066 void BookProc(w, event, prms, nprms)
7075 void AboutProc(w, event, prms, nprms)
7083 char *zippy = " (with Zippy code)";
7087 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7088 programVersion, zippy,
7089 "Copyright 1991 Digital Equipment Corporation",
7090 "Enhancements Copyright 1992-2009 Free Software Foundation",
7091 "Enhancements Copyright 2005 Alessandro Scotti",
7092 PACKAGE, " is free software and carries NO WARRANTY;",
7093 "see the file COPYING for more information.");
7094 ErrorPopUp(_("About XBoard"), buf, FALSE);
7097 void DebugProc(w, event, prms, nprms)
7103 appData.debugMode = !appData.debugMode;
7106 void AboutGameProc(w, event, prms, nprms)
7115 void NothingProc(w, event, prms, nprms)
7124 void Iconify(w, event, prms, nprms)
7133 XtSetArg(args[0], XtNiconic, True);
7134 XtSetValues(shellWidget, args, 1);
7137 void DisplayMessage(message, extMessage)
7138 char *message, *extMessage;
7140 /* display a message in the message widget */
7149 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7154 message = extMessage;
7158 /* need to test if messageWidget already exists, since this function
7159 can also be called during the startup, if for example a Xresource
7160 is not set up correctly */
7163 XtSetArg(arg, XtNlabel, message);
7164 XtSetValues(messageWidget, &arg, 1);
7170 void DisplayTitle(text)
7175 char title[MSG_SIZ];
7178 if (text == NULL) text = "";
7180 if (appData.titleInWindow) {
7182 XtSetArg(args[i], XtNlabel, text); i++;
7183 XtSetValues(titleWidget, args, i);
7186 if (*text != NULLCHAR) {
7187 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7188 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7189 } else if (appData.icsActive) {
7190 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7191 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7192 } else if (appData.cmailGameName[0] != NULLCHAR) {
7193 snprintf(icon, sizeof(icon), "%s", "CMail");
7194 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7196 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7197 } else if (gameInfo.variant == VariantGothic) {
7198 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7199 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7202 } else if (gameInfo.variant == VariantFalcon) {
7203 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7204 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7206 } else if (appData.noChessProgram) {
7207 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7208 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7210 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7211 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7214 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7215 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7216 XtSetValues(shellWidget, args, i);
7221 DisplayError(message, error)
7228 if (appData.debugMode || appData.matchMode) {
7229 fprintf(stderr, "%s: %s\n", programName, message);
7232 if (appData.debugMode || appData.matchMode) {
7233 fprintf(stderr, "%s: %s: %s\n",
7234 programName, message, strerror(error));
7236 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7239 ErrorPopUp(_("Error"), message, FALSE);
7243 void DisplayMoveError(message)
7248 DrawPosition(FALSE, NULL);
7249 if (appData.debugMode || appData.matchMode) {
7250 fprintf(stderr, "%s: %s\n", programName, message);
7252 if (appData.popupMoveErrors) {
7253 ErrorPopUp(_("Error"), message, FALSE);
7255 DisplayMessage(message, "");
7260 void DisplayFatalError(message, error, status)
7266 errorExitStatus = status;
7268 fprintf(stderr, "%s: %s\n", programName, message);
7270 fprintf(stderr, "%s: %s: %s\n",
7271 programName, message, strerror(error));
7272 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7275 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7276 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7282 void DisplayInformation(message)
7286 ErrorPopUp(_("Information"), message, TRUE);
7289 void DisplayNote(message)
7293 ErrorPopUp(_("Note"), message, FALSE);
7297 NullXErrorCheck(dpy, error_event)
7299 XErrorEvent *error_event;
7304 void DisplayIcsInteractionTitle(message)
7307 if (oldICSInteractionTitle == NULL) {
7308 /* Magic to find the old window title, adapted from vim */
7309 char *wina = getenv("WINDOWID");
7311 Window win = (Window) atoi(wina);
7312 Window root, parent, *children;
7313 unsigned int nchildren;
7314 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7316 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7317 if (!XQueryTree(xDisplay, win, &root, &parent,
7318 &children, &nchildren)) break;
7319 if (children) XFree((void *)children);
7320 if (parent == root || parent == 0) break;
7323 XSetErrorHandler(oldHandler);
7325 if (oldICSInteractionTitle == NULL) {
7326 oldICSInteractionTitle = "xterm";
7329 printf("\033]0;%s\007", message);
7333 char pendingReplyPrefix[MSG_SIZ];
7334 ProcRef pendingReplyPR;
7336 void AskQuestionProc(w, event, prms, nprms)
7343 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7347 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7350 void AskQuestionPopDown()
7352 if (!askQuestionUp) return;
7353 XtPopdown(askQuestionShell);
7354 XtDestroyWidget(askQuestionShell);
7355 askQuestionUp = False;
7358 void AskQuestionReplyAction(w, event, prms, nprms)
7368 reply = XawDialogGetValueString(w = XtParent(w));
7369 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7370 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7371 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7372 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7373 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7374 AskQuestionPopDown();
7376 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7379 void AskQuestionCallback(w, client_data, call_data)
7381 XtPointer client_data, call_data;
7386 XtSetArg(args[0], XtNlabel, &name);
7387 XtGetValues(w, args, 1);
7389 if (strcmp(name, _("cancel")) == 0) {
7390 AskQuestionPopDown();
7392 AskQuestionReplyAction(w, NULL, NULL, NULL);
7396 void AskQuestion(title, question, replyPrefix, pr)
7397 char *title, *question, *replyPrefix;
7401 Widget popup, layout, dialog, edit;
7407 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7408 pendingReplyPR = pr;
7411 XtSetArg(args[i], XtNresizable, True); i++;
7412 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7413 askQuestionShell = popup =
7414 XtCreatePopupShell(title, transientShellWidgetClass,
7415 shellWidget, args, i);
7418 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7419 layoutArgs, XtNumber(layoutArgs));
7422 XtSetArg(args[i], XtNlabel, question); i++;
7423 XtSetArg(args[i], XtNvalue, ""); i++;
7424 XtSetArg(args[i], XtNborderWidth, 0); i++;
7425 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7428 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7429 (XtPointer) dialog);
7430 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7431 (XtPointer) dialog);
7433 XtRealizeWidget(popup);
7434 CatchDeleteWindow(popup, "AskQuestionPopDown");
7436 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7437 &x, &y, &win_x, &win_y, &mask);
7439 XtSetArg(args[0], XtNx, x - 10);
7440 XtSetArg(args[1], XtNy, y - 30);
7441 XtSetValues(popup, args, 2);
7443 XtPopup(popup, XtGrabExclusive);
7444 askQuestionUp = True;
7446 edit = XtNameToWidget(dialog, "*value");
7447 XtSetKeyboardFocus(popup, edit);
7455 if (*name == NULLCHAR) {
7457 } else if (strcmp(name, "$") == 0) {
7458 putc(BELLCHAR, stderr);
7461 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7469 PlaySound(appData.soundMove);
7475 PlaySound(appData.soundIcsWin);
7481 PlaySound(appData.soundIcsLoss);
7487 PlaySound(appData.soundIcsDraw);
7491 PlayIcsUnfinishedSound()
7493 PlaySound(appData.soundIcsUnfinished);
7499 PlaySound(appData.soundIcsAlarm);
7505 system("stty echo");
7511 system("stty -echo");
7515 Colorize(cc, continuation)
7520 int count, outCount, error;
7522 if (textColors[(int)cc].bg > 0) {
7523 if (textColors[(int)cc].fg > 0) {
7524 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7525 textColors[(int)cc].fg, textColors[(int)cc].bg);
7527 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7528 textColors[(int)cc].bg);
7531 if (textColors[(int)cc].fg > 0) {
7532 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7533 textColors[(int)cc].fg);
7535 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7538 count = strlen(buf);
7539 outCount = OutputToProcess(NoProc, buf, count, &error);
7540 if (outCount < count) {
7541 DisplayFatalError(_("Error writing to display"), error, 1);
7544 if (continuation) return;
7547 PlaySound(appData.soundShout);
7550 PlaySound(appData.soundSShout);
7553 PlaySound(appData.soundChannel1);
7556 PlaySound(appData.soundChannel);
7559 PlaySound(appData.soundKibitz);
7562 PlaySound(appData.soundTell);
7564 case ColorChallenge:
7565 PlaySound(appData.soundChallenge);
7568 PlaySound(appData.soundRequest);
7571 PlaySound(appData.soundSeek);
7582 return getpwuid(getuid())->pw_name;
7586 ExpandPathName(path)
7589 static char static_buf[4*MSG_SIZ];
7590 char *d, *s, buf[4*MSG_SIZ];
7596 while (*s && isspace(*s))
7605 if (*(s+1) == '/') {
7606 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7610 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7611 *strchr(buf, '/') = 0;
7612 pwd = getpwnam(buf);
7615 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7619 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7620 strcat(d, strchr(s+1, '/'));
7624 safeStrCpy(d, s, 4*MSG_SIZ );
7631 static char host_name[MSG_SIZ];
7633 #if HAVE_GETHOSTNAME
7634 gethostname(host_name, MSG_SIZ);
7636 #else /* not HAVE_GETHOSTNAME */
7637 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7638 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7640 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7642 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7643 #endif /* not HAVE_GETHOSTNAME */
7646 XtIntervalId delayedEventTimerXID = 0;
7647 DelayedEventCallback delayedEventCallback = 0;
7652 delayedEventTimerXID = 0;
7653 delayedEventCallback();
7657 ScheduleDelayedEvent(cb, millisec)
7658 DelayedEventCallback cb; long millisec;
7660 if(delayedEventTimerXID && delayedEventCallback == cb)
7661 // [HGM] alive: replace, rather than add or flush identical event
7662 XtRemoveTimeOut(delayedEventTimerXID);
7663 delayedEventCallback = cb;
7664 delayedEventTimerXID =
7665 XtAppAddTimeOut(appContext, millisec,
7666 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7669 DelayedEventCallback
7672 if (delayedEventTimerXID) {
7673 return delayedEventCallback;
7680 CancelDelayedEvent()
7682 if (delayedEventTimerXID) {
7683 XtRemoveTimeOut(delayedEventTimerXID);
7684 delayedEventTimerXID = 0;
7688 XtIntervalId loadGameTimerXID = 0;
7690 int LoadGameTimerRunning()
7692 return loadGameTimerXID != 0;
7695 int StopLoadGameTimer()
7697 if (loadGameTimerXID != 0) {
7698 XtRemoveTimeOut(loadGameTimerXID);
7699 loadGameTimerXID = 0;
7707 LoadGameTimerCallback(arg, id)
7711 loadGameTimerXID = 0;
7716 StartLoadGameTimer(millisec)
7720 XtAppAddTimeOut(appContext, millisec,
7721 (XtTimerCallbackProc) LoadGameTimerCallback,
7725 XtIntervalId analysisClockXID = 0;
7728 AnalysisClockCallback(arg, id)
7732 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7733 || appData.icsEngineAnalyze) { // [DM]
7734 AnalysisPeriodicEvent(0);
7735 StartAnalysisClock();
7740 StartAnalysisClock()
7743 XtAppAddTimeOut(appContext, 2000,
7744 (XtTimerCallbackProc) AnalysisClockCallback,
7748 XtIntervalId clockTimerXID = 0;
7750 int ClockTimerRunning()
7752 return clockTimerXID != 0;
7755 int StopClockTimer()
7757 if (clockTimerXID != 0) {
7758 XtRemoveTimeOut(clockTimerXID);
7767 ClockTimerCallback(arg, id)
7776 StartClockTimer(millisec)
7780 XtAppAddTimeOut(appContext, millisec,
7781 (XtTimerCallbackProc) ClockTimerCallback,
7786 DisplayTimerLabel(w, color, timer, highlight)
7795 /* check for low time warning */
7796 Pixel foregroundOrWarningColor = timerForegroundPixel;
7799 appData.lowTimeWarning &&
7800 (timer / 1000) < appData.icsAlarmTime)
7801 foregroundOrWarningColor = lowTimeWarningColor;
7803 if (appData.clockMode) {
7804 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7805 XtSetArg(args[0], XtNlabel, buf);
7807 snprintf(buf, MSG_SIZ, "%s ", color);
7808 XtSetArg(args[0], XtNlabel, buf);
7813 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7814 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7816 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7817 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7820 XtSetValues(w, args, 3);
7824 DisplayWhiteClock(timeRemaining, highlight)
7830 if(appData.noGUI) return;
7831 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7832 if (highlight && iconPixmap == bIconPixmap) {
7833 iconPixmap = wIconPixmap;
7834 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7835 XtSetValues(shellWidget, args, 1);
7840 DisplayBlackClock(timeRemaining, highlight)
7846 if(appData.noGUI) return;
7847 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7848 if (highlight && iconPixmap == wIconPixmap) {
7849 iconPixmap = bIconPixmap;
7850 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7851 XtSetValues(shellWidget, args, 1);
7869 int StartChildProcess(cmdLine, dir, pr)
7876 int to_prog[2], from_prog[2];
7880 if (appData.debugMode) {
7881 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7884 /* We do NOT feed the cmdLine to the shell; we just
7885 parse it into blank-separated arguments in the
7886 most simple-minded way possible.
7889 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7892 while(*p == ' ') p++;
7894 if(*p == '"' || *p == '\'')
7895 p = strchr(++argv[i-1], *p);
7896 else p = strchr(p, ' ');
7897 if (p == NULL) break;
7902 SetUpChildIO(to_prog, from_prog);
7904 if ((pid = fork()) == 0) {
7906 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7907 close(to_prog[1]); // first close the unused pipe ends
7908 close(from_prog[0]);
7909 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7910 dup2(from_prog[1], 1);
7911 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7912 close(from_prog[1]); // and closing again loses one of the pipes!
7913 if(fileno(stderr) >= 2) // better safe than sorry...
7914 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7916 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7921 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7923 execvp(argv[0], argv);
7925 /* If we get here, exec failed */
7930 /* Parent process */
7932 close(from_prog[1]);
7934 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7937 cp->fdFrom = from_prog[0];
7938 cp->fdTo = to_prog[1];
7943 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7944 static RETSIGTYPE AlarmCallBack(int n)
7950 DestroyChildProcess(pr, signalType)
7954 ChildProc *cp = (ChildProc *) pr;
7956 if (cp->kind != CPReal) return;
7958 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7959 signal(SIGALRM, AlarmCallBack);
7961 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7962 kill(cp->pid, SIGKILL); // kill it forcefully
7963 wait((int *) 0); // and wait again
7967 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7969 /* Process is exiting either because of the kill or because of
7970 a quit command sent by the backend; either way, wait for it to die.
7979 InterruptChildProcess(pr)
7982 ChildProc *cp = (ChildProc *) pr;
7984 if (cp->kind != CPReal) return;
7985 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7988 int OpenTelnet(host, port, pr)
7993 char cmdLine[MSG_SIZ];
7995 if (port[0] == NULLCHAR) {
7996 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7998 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
8000 return StartChildProcess(cmdLine, "", pr);
8003 int OpenTCP(host, port, pr)
8009 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
8010 #else /* !OMIT_SOCKETS */
8012 struct sockaddr_in sa;
8014 unsigned short uport;
8017 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
8021 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8022 sa.sin_family = AF_INET;
8023 sa.sin_addr.s_addr = INADDR_ANY;
8024 uport = (unsigned short) 0;
8025 sa.sin_port = htons(uport);
8026 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
8030 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8031 if (!(hp = gethostbyname(host))) {
8033 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
8034 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
8035 hp->h_addrtype = AF_INET;
8037 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8038 hp->h_addr_list[0] = (char *) malloc(4);
8039 hp->h_addr_list[0][0] = b0;
8040 hp->h_addr_list[0][1] = b1;
8041 hp->h_addr_list[0][2] = b2;
8042 hp->h_addr_list[0][3] = b3;
8047 sa.sin_family = hp->h_addrtype;
8048 uport = (unsigned short) atoi(port);
8049 sa.sin_port = htons(uport);
8050 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8052 if (connect(s, (struct sockaddr *) &sa,
8053 sizeof(struct sockaddr_in)) < 0) {
8057 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8064 #endif /* !OMIT_SOCKETS */
8069 int OpenCommPort(name, pr)
8076 fd = open(name, 2, 0);
8077 if (fd < 0) return errno;
8079 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8089 int OpenLoopback(pr)
8095 SetUpChildIO(to, from);
8097 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8100 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8107 int OpenRcmd(host, user, cmd, pr)
8108 char *host, *user, *cmd;
8111 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8115 #define INPUT_SOURCE_BUF_SIZE 8192
8124 char buf[INPUT_SOURCE_BUF_SIZE];
8129 DoInputCallback(closure, source, xid)
8134 InputSource *is = (InputSource *) closure;
8139 if (is->lineByLine) {
8140 count = read(is->fd, is->unused,
8141 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8143 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8146 is->unused += count;
8148 while (p < is->unused) {
8149 q = memchr(p, '\n', is->unused - p);
8150 if (q == NULL) break;
8152 (is->func)(is, is->closure, p, q - p, 0);
8156 while (p < is->unused) {
8161 # if HAVE_LIBREADLINE
8162 /* check if input is from stdin, if yes, use gnu-readline */
8163 if( is->fd==fileno(stdin) )
8165 /* to clear the line */
8168 /* read from stdin */
8169 rl_callback_read_char();
8171 /* redisplay the current line, check special case for login and password */
8172 if(sending_ICS_password)
8174 int i; char buf[MSG_SIZ];
8178 /* blank the password */
8179 count = strlen(rl_line_buffer);
8182 printf("PROBLEM with readline\n");
8185 for(i=0;i<count;i++)
8189 printf("\rpassword: %s",buf);
8191 else if (sending_ICS_login)
8193 /* show login prompt */
8194 count = strlen(rl_line_buffer);
8195 printf("\rlogin: %s",rl_line_buffer);
8198 rl_reset_line_state();
8200 if(readline_complete)
8202 /* copy into XBoards buffer */
8203 count = strlen(readline_buffer);
8204 if (count>INPUT_SOURCE_BUF_SIZE-1)
8206 printf("PROBLEM with readline\n");
8207 count = INPUT_SOURCE_BUF_SIZE;
8209 strncpy(is->buf,readline_buffer,count);
8210 is->buf[count]='\n';count++;
8212 /* reset gnu-readline state */
8213 free(readline_buffer);
8214 readline_buffer=NULL;
8215 readline_complete=0;
8221 (is->func)(is, is->closure, is->buf, count, error);
8223 /* are we done with the password? */
8224 if(sending_ICS_password)
8225 sending_ICS_password=0;
8226 if(sending_ICS_login)
8227 sending_ICS_login=0;
8232 /* input not from stdin, use default method */
8233 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8238 (is->func)(is, is->closure, is->buf, count, error);
8240 #else /* no readline support */
8241 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8246 (is->func)(is, is->closure, is->buf, count, error);
8252 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8259 ChildProc *cp = (ChildProc *) pr;
8261 is = (InputSource *) calloc(1, sizeof(InputSource));
8262 is->lineByLine = lineByLine;
8266 is->fd = fileno(stdin);
8268 is->kind = cp->kind;
8269 is->fd = cp->fdFrom;
8272 is->unused = is->buf;
8275 is->xid = XtAppAddInput(appContext, is->fd,
8276 (XtPointer) (XtInputReadMask),
8277 (XtInputCallbackProc) DoInputCallback,
8279 is->closure = closure;
8280 return (InputSourceRef) is;
8284 RemoveInputSource(isr)
8287 InputSource *is = (InputSource *) isr;
8289 if (is->xid == 0) return;
8290 XtRemoveInput(is->xid);
8294 int OutputToProcess(pr, message, count, outError)
8300 static int line = 0;
8301 ChildProc *cp = (ChildProc *) pr;
8307 if (appData.noJoin || !appData.useInternalWrap)
8308 outCount = fwrite(message, 1, count, stdout);
8311 int width = get_term_width();
8312 int len = wrap(NULL, message, count, width, &line);
8313 char *msg = malloc(len);
8317 outCount = fwrite(message, 1, count, stdout);
8320 dbgchk = wrap(msg, message, count, width, &line);
8321 if (dbgchk != len && appData.debugMode)
8322 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8323 outCount = fwrite(msg, 1, dbgchk, stdout);
8328 # if HAVE_LIBREADLINE
8329 /* readline support */
8330 if(strlen(rl_line_buffer))
8331 printf("\n> %s",rl_line_buffer);
8336 outCount = write(cp->fdTo, message, count);
8346 /* Output message to process, with "ms" milliseconds of delay
8347 between each character. This is needed when sending the logon
8348 script to ICC, which for some reason doesn't like the
8349 instantaneous send. */
8350 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8357 ChildProc *cp = (ChildProc *) pr;
8362 r = write(cp->fdTo, message++, 1);
8375 /**** Animation code by Hugh Fisher, DCS, ANU.
8377 Known problem: if a window overlapping the board is
8378 moved away while a piece is being animated underneath,
8379 the newly exposed area won't be updated properly.
8380 I can live with this.
8382 Known problem: if you look carefully at the animation
8383 of pieces in mono mode, they are being drawn as solid
8384 shapes without interior detail while moving. Fixing
8385 this would be a major complication for minimal return.
8388 /* Masks for XPM pieces. Black and white pieces can have
8389 different shapes, but in the interest of retaining my
8390 sanity pieces must have the same outline on both light
8391 and dark squares, and all pieces must use the same
8392 background square colors/images. */
8394 static int xpmDone = 0;
8397 CreateAnimMasks (pieceDepth)
8404 unsigned long plane;
8407 /* Need a bitmap just to get a GC with right depth */
8408 buf = XCreatePixmap(xDisplay, xBoardWindow,
8410 values.foreground = 1;
8411 values.background = 0;
8412 /* Don't use XtGetGC, not read only */
8413 maskGC = XCreateGC(xDisplay, buf,
8414 GCForeground | GCBackground, &values);
8415 XFreePixmap(xDisplay, buf);
8417 buf = XCreatePixmap(xDisplay, xBoardWindow,
8418 squareSize, squareSize, pieceDepth);
8419 values.foreground = XBlackPixel(xDisplay, xScreen);
8420 values.background = XWhitePixel(xDisplay, xScreen);
8421 bufGC = XCreateGC(xDisplay, buf,
8422 GCForeground | GCBackground, &values);
8424 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8425 /* Begin with empty mask */
8426 if(!xpmDone) // [HGM] pieces: keep using existing
8427 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8428 squareSize, squareSize, 1);
8429 XSetFunction(xDisplay, maskGC, GXclear);
8430 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8431 0, 0, squareSize, squareSize);
8433 /* Take a copy of the piece */
8438 XSetFunction(xDisplay, bufGC, GXcopy);
8439 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8441 0, 0, squareSize, squareSize, 0, 0);
8443 /* XOR the background (light) over the piece */
8444 XSetFunction(xDisplay, bufGC, GXxor);
8446 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8447 0, 0, squareSize, squareSize, 0, 0);
8449 XSetForeground(xDisplay, bufGC, lightSquareColor);
8450 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8453 /* We now have an inverted piece image with the background
8454 erased. Construct mask by just selecting all the non-zero
8455 pixels - no need to reconstruct the original image. */
8456 XSetFunction(xDisplay, maskGC, GXor);
8458 /* Might be quicker to download an XImage and create bitmap
8459 data from it rather than this N copies per piece, but it
8460 only takes a fraction of a second and there is a much
8461 longer delay for loading the pieces. */
8462 for (n = 0; n < pieceDepth; n ++) {
8463 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8464 0, 0, squareSize, squareSize,
8470 XFreePixmap(xDisplay, buf);
8471 XFreeGC(xDisplay, bufGC);
8472 XFreeGC(xDisplay, maskGC);
8476 InitAnimState (anim, info)
8478 XWindowAttributes * info;
8483 /* Each buffer is square size, same depth as window */
8484 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8485 squareSize, squareSize, info->depth);
8486 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8487 squareSize, squareSize, info->depth);
8489 /* Create a plain GC for blitting */
8490 mask = GCForeground | GCBackground | GCFunction |
8491 GCPlaneMask | GCGraphicsExposures;
8492 values.foreground = XBlackPixel(xDisplay, xScreen);
8493 values.background = XWhitePixel(xDisplay, xScreen);
8494 values.function = GXcopy;
8495 values.plane_mask = AllPlanes;
8496 values.graphics_exposures = False;
8497 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8499 /* Piece will be copied from an existing context at
8500 the start of each new animation/drag. */
8501 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8503 /* Outline will be a read-only copy of an existing */
8504 anim->outlineGC = None;
8510 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8511 XWindowAttributes info;
8513 if (xpmDone && gameInfo.variant == old) return;
8514 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8515 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8517 InitAnimState(&game, &info);
8518 InitAnimState(&player, &info);
8520 /* For XPM pieces, we need bitmaps to use as masks. */
8522 CreateAnimMasks(info.depth);
8528 static Boolean frameWaiting;
8530 static RETSIGTYPE FrameAlarm (sig)
8533 frameWaiting = False;
8534 /* In case System-V style signals. Needed?? */
8535 signal(SIGALRM, FrameAlarm);
8542 struct itimerval delay;
8544 XSync(xDisplay, False);
8547 frameWaiting = True;
8548 signal(SIGALRM, FrameAlarm);
8549 delay.it_interval.tv_sec =
8550 delay.it_value.tv_sec = time / 1000;
8551 delay.it_interval.tv_usec =
8552 delay.it_value.tv_usec = (time % 1000) * 1000;
8553 setitimer(ITIMER_REAL, &delay, NULL);
8554 while (frameWaiting) pause();
8555 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8556 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8557 setitimer(ITIMER_REAL, &delay, NULL);
8567 XSync(xDisplay, False);
8569 usleep(time * 1000);
8574 /* Convert board position to corner of screen rect and color */
8577 ScreenSquare(column, row, pt, color)
8578 int column; int row; XPoint * pt; int * color;
8581 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8582 pt->y = lineGap + row * (squareSize + lineGap);
8584 pt->x = lineGap + column * (squareSize + lineGap);
8585 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8587 *color = SquareColor(row, column);
8590 /* Convert window coords to square */
8593 BoardSquare(x, y, column, row)
8594 int x; int y; int * column; int * row;
8596 *column = EventToSquare(x, BOARD_WIDTH);
8597 if (flipView && *column >= 0)
8598 *column = BOARD_WIDTH - 1 - *column;
8599 *row = EventToSquare(y, BOARD_HEIGHT);
8600 if (!flipView && *row >= 0)
8601 *row = BOARD_HEIGHT - 1 - *row;
8606 #undef Max /* just in case */
8608 #define Max(a, b) ((a) > (b) ? (a) : (b))
8609 #define Min(a, b) ((a) < (b) ? (a) : (b))
8612 SetRect(rect, x, y, width, height)
8613 XRectangle * rect; int x; int y; int width; int height;
8617 rect->width = width;
8618 rect->height = height;
8621 /* Test if two frames overlap. If they do, return
8622 intersection rect within old and location of
8623 that rect within new. */
8626 Intersect(old, new, size, area, pt)
8627 XPoint * old; XPoint * new;
8628 int size; XRectangle * area; XPoint * pt;
8630 if (old->x > new->x + size || new->x > old->x + size ||
8631 old->y > new->y + size || new->y > old->y + size) {
8634 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8635 size - abs(old->x - new->x), size - abs(old->y - new->y));
8636 pt->x = Max(old->x - new->x, 0);
8637 pt->y = Max(old->y - new->y, 0);
8642 /* For two overlapping frames, return the rect(s)
8643 in the old that do not intersect with the new. */
8646 CalcUpdateRects(old, new, size, update, nUpdates)
8647 XPoint * old; XPoint * new; int size;
8648 XRectangle update[]; int * nUpdates;
8652 /* If old = new (shouldn't happen) then nothing to draw */
8653 if (old->x == new->x && old->y == new->y) {
8657 /* Work out what bits overlap. Since we know the rects
8658 are the same size we don't need a full intersect calc. */
8660 /* Top or bottom edge? */
8661 if (new->y > old->y) {
8662 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8664 } else if (old->y > new->y) {
8665 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8666 size, old->y - new->y);
8669 /* Left or right edge - don't overlap any update calculated above. */
8670 if (new->x > old->x) {
8671 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8672 new->x - old->x, size - abs(new->y - old->y));
8674 } else if (old->x > new->x) {
8675 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8676 old->x - new->x, size - abs(new->y - old->y));
8683 /* Generate a series of frame coords from start->mid->finish.
8684 The movement rate doubles until the half way point is
8685 reached, then halves back down to the final destination,
8686 which gives a nice slow in/out effect. The algorithmn
8687 may seem to generate too many intermediates for short
8688 moves, but remember that the purpose is to attract the
8689 viewers attention to the piece about to be moved and
8690 then to where it ends up. Too few frames would be less
8694 Tween(start, mid, finish, factor, frames, nFrames)
8695 XPoint * start; XPoint * mid;
8696 XPoint * finish; int factor;
8697 XPoint frames[]; int * nFrames;
8699 int fraction, n, count;
8703 /* Slow in, stepping 1/16th, then 1/8th, ... */
8705 for (n = 0; n < factor; n++)
8707 for (n = 0; n < factor; n++) {
8708 frames[count].x = start->x + (mid->x - start->x) / fraction;
8709 frames[count].y = start->y + (mid->y - start->y) / fraction;
8711 fraction = fraction / 2;
8715 frames[count] = *mid;
8718 /* Slow out, stepping 1/2, then 1/4, ... */
8720 for (n = 0; n < factor; n++) {
8721 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8722 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8724 fraction = fraction * 2;
8729 /* Draw a piece on the screen without disturbing what's there */
8732 SelectGCMask(piece, clip, outline, mask)
8733 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8737 /* Bitmap for piece being moved. */
8738 if (appData.monoMode) {
8739 *mask = *pieceToSolid(piece);
8740 } else if (useImages) {
8742 *mask = xpmMask[piece];
8744 *mask = ximMaskPm[piece];
8747 *mask = *pieceToSolid(piece);
8750 /* GC for piece being moved. Square color doesn't matter, but
8751 since it gets modified we make a copy of the original. */
8753 if (appData.monoMode)
8758 if (appData.monoMode)
8763 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8765 /* Outline only used in mono mode and is not modified */
8767 *outline = bwPieceGC;
8769 *outline = wbPieceGC;
8773 OverlayPiece(piece, clip, outline, dest)
8774 ChessSquare piece; GC clip; GC outline; Drawable dest;
8779 /* Draw solid rectangle which will be clipped to shape of piece */
8780 XFillRectangle(xDisplay, dest, clip,
8781 0, 0, squareSize, squareSize);
8782 if (appData.monoMode)
8783 /* Also draw outline in contrasting color for black
8784 on black / white on white cases */
8785 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8786 0, 0, squareSize, squareSize, 0, 0, 1);
8788 /* Copy the piece */
8793 if(appData.upsideDown && flipView) kind ^= 2;
8794 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8796 0, 0, squareSize, squareSize,
8801 /* Animate the movement of a single piece */
8804 BeginAnimation(anim, piece, startColor, start)
8812 /* The old buffer is initialised with the start square (empty) */
8813 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8814 anim->prevFrame = *start;
8816 /* The piece will be drawn using its own bitmap as a matte */
8817 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8818 XSetClipMask(xDisplay, anim->pieceGC, mask);
8822 AnimationFrame(anim, frame, piece)
8827 XRectangle updates[4];
8832 /* Save what we are about to draw into the new buffer */
8833 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8834 frame->x, frame->y, squareSize, squareSize,
8837 /* Erase bits of the previous frame */
8838 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8839 /* Where the new frame overlapped the previous,
8840 the contents in newBuf are wrong. */
8841 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8842 overlap.x, overlap.y,
8843 overlap.width, overlap.height,
8845 /* Repaint the areas in the old that don't overlap new */
8846 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8847 for (i = 0; i < count; i++)
8848 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8849 updates[i].x - anim->prevFrame.x,
8850 updates[i].y - anim->prevFrame.y,
8851 updates[i].width, updates[i].height,
8852 updates[i].x, updates[i].y);
8854 /* Easy when no overlap */
8855 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8856 0, 0, squareSize, squareSize,
8857 anim->prevFrame.x, anim->prevFrame.y);
8860 /* Save this frame for next time round */
8861 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8862 0, 0, squareSize, squareSize,
8864 anim->prevFrame = *frame;
8866 /* Draw piece over original screen contents, not current,
8867 and copy entire rect. Wipes out overlapping piece images. */
8868 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8869 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8870 0, 0, squareSize, squareSize,
8871 frame->x, frame->y);
8875 EndAnimation (anim, finish)
8879 XRectangle updates[4];
8884 /* The main code will redraw the final square, so we
8885 only need to erase the bits that don't overlap. */
8886 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8887 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8888 for (i = 0; i < count; i++)
8889 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8890 updates[i].x - anim->prevFrame.x,
8891 updates[i].y - anim->prevFrame.y,
8892 updates[i].width, updates[i].height,
8893 updates[i].x, updates[i].y);
8895 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8896 0, 0, squareSize, squareSize,
8897 anim->prevFrame.x, anim->prevFrame.y);
8902 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8904 ChessSquare piece; int startColor;
8905 XPoint * start; XPoint * finish;
8906 XPoint frames[]; int nFrames;
8910 BeginAnimation(anim, piece, startColor, start);
8911 for (n = 0; n < nFrames; n++) {
8912 AnimationFrame(anim, &(frames[n]), piece);
8913 FrameDelay(appData.animSpeed);
8915 EndAnimation(anim, finish);
8918 /* Main control logic for deciding what to animate and how */
8921 AnimateMove(board, fromX, fromY, toX, toY)
8930 XPoint start, finish, mid;
8931 XPoint frames[kFactor * 2 + 1];
8932 int nFrames, startColor, endColor;
8934 /* Are we animating? */
8935 if (!appData.animate || appData.blindfold)
8938 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8939 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8940 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8942 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8943 piece = board[fromY][fromX];
8944 if (piece >= EmptySquare) return;
8949 hop = (piece == WhiteKnight || piece == BlackKnight);
8952 if (appData.debugMode) {
8953 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8954 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8955 piece, fromX, fromY, toX, toY); }
8957 ScreenSquare(fromX, fromY, &start, &startColor);
8958 ScreenSquare(toX, toY, &finish, &endColor);
8961 /* Knight: make diagonal movement then straight */
8962 if (abs(toY - fromY) < abs(toX - fromX)) {
8963 mid.x = start.x + (finish.x - start.x) / 2;
8967 mid.y = start.y + (finish.y - start.y) / 2;
8970 mid.x = start.x + (finish.x - start.x) / 2;
8971 mid.y = start.y + (finish.y - start.y) / 2;
8974 /* Don't use as many frames for very short moves */
8975 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8976 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8978 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8979 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8981 /* Be sure end square is redrawn */
8982 damage[0][toY][toX] = True;
8986 DragPieceBegin(x, y)
8989 int boardX, boardY, color;
8992 /* Are we animating? */
8993 if (!appData.animateDragging || appData.blindfold)
8996 /* Figure out which square we start in and the
8997 mouse position relative to top left corner. */
8998 BoardSquare(x, y, &boardX, &boardY);
8999 player.startBoardX = boardX;
9000 player.startBoardY = boardY;
9001 ScreenSquare(boardX, boardY, &corner, &color);
9002 player.startSquare = corner;
9003 player.startColor = color;
9004 /* As soon as we start dragging, the piece will jump slightly to
9005 be centered over the mouse pointer. */
9006 player.mouseDelta.x = squareSize/2;
9007 player.mouseDelta.y = squareSize/2;
9008 /* Initialise animation */
9009 player.dragPiece = PieceForSquare(boardX, boardY);
9011 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
9012 player.dragActive = True;
9013 BeginAnimation(&player, player.dragPiece, color, &corner);
9014 /* Mark this square as needing to be redrawn. Note that
9015 we don't remove the piece though, since logically (ie
9016 as seen by opponent) the move hasn't been made yet. */
9017 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
9018 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
9019 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
9020 corner.x, corner.y, squareSize, squareSize,
9021 0, 0); // [HGM] zh: unstack in stead of grab
9022 damage[0][boardY][boardX] = True;
9024 player.dragActive = False;
9034 /* Are we animating? */
9035 if (!appData.animateDragging || appData.blindfold)
9039 if (! player.dragActive)
9041 /* Move piece, maintaining same relative position
9042 of mouse within square */
9043 corner.x = x - player.mouseDelta.x;
9044 corner.y = y - player.mouseDelta.y;
9045 AnimationFrame(&player, &corner, player.dragPiece);
9047 if (appData.highlightDragging) {
9049 BoardSquare(x, y, &boardX, &boardY);
9050 SetHighlights(fromX, fromY, boardX, boardY);
9059 int boardX, boardY, color;
9062 /* Are we animating? */
9063 if (!appData.animateDragging || appData.blindfold)
9067 if (! player.dragActive)
9069 /* Last frame in sequence is square piece is
9070 placed on, which may not match mouse exactly. */
9071 BoardSquare(x, y, &boardX, &boardY);
9072 ScreenSquare(boardX, boardY, &corner, &color);
9073 EndAnimation(&player, &corner);
9075 /* Be sure end square is redrawn */
9076 damage[0][boardY][boardX] = True;
9078 /* This prevents weird things happening with fast successive
9079 clicks which on my Sun at least can cause motion events
9080 without corresponding press/release. */
9081 player.dragActive = False;
9084 /* Handle expose event while piece being dragged */
9089 if (!player.dragActive || appData.blindfold)
9092 /* What we're doing: logically, the move hasn't been made yet,
9093 so the piece is still in it's original square. But visually
9094 it's being dragged around the board. So we erase the square
9095 that the piece is on and draw it at the last known drag point. */
9096 BlankSquare(player.startSquare.x, player.startSquare.y,
9097 player.startColor, EmptySquare, xBoardWindow, 1);
9098 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9099 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9102 #include <sys/ioctl.h>
9103 int get_term_width()
9105 int fd, default_width;
9108 default_width = 79; // this is FICS default anyway...
9110 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9112 if (!ioctl(fd, TIOCGSIZE, &win))
9113 default_width = win.ts_cols;
9114 #elif defined(TIOCGWINSZ)
9116 if (!ioctl(fd, TIOCGWINSZ, &win))
9117 default_width = win.ws_col;
9119 return default_width;
9125 static int old_width = 0;
9126 int new_width = get_term_width();
9128 if (old_width != new_width)
9129 ics_printf("set width %d\n", new_width);
9130 old_width = new_width;
9133 void NotifyFrontendLogin()
9138 # if HAVE_LIBREADLINE
9140 ReadlineCompleteHandler(char* ptr)
9142 /* make gnu-readline keep the history */
9143 readline_buffer = ptr;
9144 readline_complete = 1;
9146 if (ptr && *ptr && !sending_ICS_password && !sending_ICS_login)