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
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
192 #include "frontend.h"
194 #include "backendz.h"
198 #include "xgamelist.h"
199 #include "xhistory.h"
200 #include "xedittags.h"
203 // must be moved to xengineoutput.h
205 void EngineOutputProc P((Widget w, XEvent *event,
206 String *prms, Cardinal *nprms));
207 void EvalGraphProc P((Widget w, XEvent *event,
208 String *prms, Cardinal *nprms));
215 #define usleep(t) _sleep2(((t)+500)/1000)
219 # define _(s) gettext (s)
220 # define N_(s) gettext_noop (s)
236 int main P((int argc, char **argv));
237 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
238 char *init_path, char *mode, int (*show_entry)(), char **name_return));
239 RETSIGTYPE CmailSigHandler P((int sig));
240 RETSIGTYPE IntSigHandler P((int sig));
241 RETSIGTYPE TermSizeSigHandler P((int sig));
242 void CreateGCs P((void));
243 void CreateXIMPieces P((void));
244 void CreateXPMPieces P((void));
245 void CreateXPMBoard P((char *s, int n));
246 void CreatePieces P((void));
247 void CreatePieceMenus P((void));
248 Widget CreateMenuBar P((Menu *mb));
249 Widget CreateButtonBar P ((MenuItem *mi));
250 char *FindFont P((char *pattern, int targetPxlSize));
251 void PieceMenuPopup P((Widget w, XEvent *event,
252 String *params, Cardinal *num_params));
253 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
254 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
255 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
256 u_int wreq, u_int hreq));
257 void CreateGrid P((void));
258 int EventToSquare P((int x, int limit));
259 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
260 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
261 void HandleUserMove P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void AnimateUserMove P((Widget w, XEvent * event,
264 String * params, Cardinal * nParams));
265 void HandlePV P((Widget w, XEvent * event,
266 String * params, Cardinal * nParams));
267 void SelectPV P((Widget w, XEvent * event,
268 String * params, Cardinal * nParams));
269 void StopPV P((Widget w, XEvent * event,
270 String * params, Cardinal * nParams));
271 void WhiteClock P((Widget w, XEvent *event,
272 String *prms, Cardinal *nprms));
273 void BlackClock P((Widget w, XEvent *event,
274 String *prms, Cardinal *nprms));
275 void DrawPositionProc P((Widget w, XEvent *event,
276 String *prms, Cardinal *nprms));
277 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
279 void CommentClick P((Widget w, XEvent * event,
280 String * params, Cardinal * nParams));
281 void CommentPopUp P((char *title, char *label));
282 void CommentPopDown P((void));
283 void CommentCallback P((Widget w, XtPointer client_data,
284 XtPointer call_data));
285 void ICSInputBoxPopUp P((void));
286 void ICSInputBoxPopDown P((void));
287 void FileNamePopUp P((char *label, char *def,
288 FileProc proc, char *openMode));
289 void FileNamePopDown P((void));
290 void FileNameCallback P((Widget w, XtPointer client_data,
291 XtPointer call_data));
292 void FileNameAction P((Widget w, XEvent *event,
293 String *prms, Cardinal *nprms));
294 void AskQuestionReplyAction P((Widget w, XEvent *event,
295 String *prms, Cardinal *nprms));
296 void AskQuestionProc P((Widget w, XEvent *event,
297 String *prms, Cardinal *nprms));
298 void AskQuestionPopDown P((void));
299 void PromotionPopDown P((void));
300 void PromotionCallback P((Widget w, XtPointer client_data,
301 XtPointer call_data));
302 void EditCommentPopDown P((void));
303 void EditCommentCallback P((Widget w, XtPointer client_data,
304 XtPointer call_data));
305 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
306 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
307 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
308 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
310 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
312 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
314 void LoadPositionProc P((Widget w, XEvent *event,
315 String *prms, Cardinal *nprms));
316 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
318 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
320 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
322 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
324 void PastePositionProc P((Widget w, XEvent *event, String *prms,
326 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
329 void SavePositionProc P((Widget w, XEvent *event,
330 String *prms, Cardinal *nprms));
331 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
334 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
338 void MachineWhiteProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AnalyzeModeProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AnalyzeFileProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
346 void IcsClientProc P((Widget w, XEvent *event, String *prms,
348 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void EditPositionProc P((Widget w, XEvent *event,
350 String *prms, Cardinal *nprms));
351 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void EditCommentProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void IcsInputBoxProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void StopObservingProc P((Widget w, XEvent *event, String *prms,
372 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
374 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
383 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
385 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
388 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
390 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
392 void AutocommProc P((Widget w, XEvent *event, String *prms,
394 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void AutobsProc P((Widget w, XEvent *event, String *prms,
398 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
403 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
406 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
408 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
410 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
412 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
414 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
416 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
418 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
420 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
422 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
426 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
428 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
430 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
432 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void DisplayMove P((int moveNumber));
444 void DisplayTitle P((char *title));
445 void ICSInitScript P((void));
446 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
447 void ErrorPopUp P((char *title, char *text, int modal));
448 void ErrorPopDown P((void));
449 static char *ExpandPathName P((char *path));
450 static void CreateAnimVars P((void));
451 static void DragPieceMove P((int x, int y));
452 static void DrawDragPiece P((void));
453 char *ModeToWidgetName P((GameMode mode));
454 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void GameListOptionsPopDown P(());
463 void ShufflePopDown P(());
464 void EnginePopDown P(());
465 void UciPopDown P(());
466 void TimeControlPopDown P(());
467 void NewVariantPopDown P(());
468 void SettingsPopDown P(());
469 void update_ics_width P(());
470 int get_term_width P(());
471 int CopyMemoProc P(());
473 * XBoard depends on Xt R4 or higher
475 int xtVersion = XtSpecificationRelease;
480 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
481 jailSquareColor, highlightSquareColor, premoveHighlightColor;
482 Pixel lowTimeWarningColor;
483 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
484 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
485 wjPieceGC, bjPieceGC, prelineGC, countGC;
486 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
487 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
488 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
489 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
490 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
491 ICSInputShell, fileNameShell, askQuestionShell;
492 Widget historyShell, evalGraphShell, gameListShell;
493 int hOffset; // [HGM] dual
494 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
495 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
496 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
497 Font clockFontID, coordFontID, countFontID;
498 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
499 XtAppContext appContext;
501 char *oldICSInteractionTitle;
505 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
507 Position commentX = -1, commentY = -1;
508 Dimension commentW, commentH;
509 typedef unsigned int BoardSize;
511 Boolean chessProgram;
513 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
514 int squareSize, smallLayout = 0, tinyLayout = 0,
515 marginW, marginH, // [HGM] for run-time resizing
516 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
517 ICSInputBoxUp = False, askQuestionUp = False,
518 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
519 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
520 Pixel timerForegroundPixel, timerBackgroundPixel;
521 Pixel buttonForegroundPixel, buttonBackgroundPixel;
522 char *chessDir, *programName, *programVersion,
523 *gameCopyFilename, *gamePasteFilename;
524 Boolean alwaysOnTop = False;
525 Boolean saveSettingsOnExit;
526 char *settingsFileName;
527 char *icsTextMenuString;
529 char *firstChessProgramNames;
530 char *secondChessProgramNames;
532 WindowPlacement wpMain;
533 WindowPlacement wpConsole;
534 WindowPlacement wpComment;
535 WindowPlacement wpMoveHistory;
536 WindowPlacement wpEvalGraph;
537 WindowPlacement wpEngineOutput;
538 WindowPlacement wpGameList;
539 WindowPlacement wpTags;
543 Pixmap pieceBitmap[2][(int)BlackPawn];
544 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
545 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
546 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
547 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
548 Pixmap xpmBoardBitmap[2];
549 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
550 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
551 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
552 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
553 XImage *ximLightSquare, *ximDarkSquare;
556 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
557 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
559 #define White(piece) ((int)(piece) < (int)BlackPawn)
561 /* Variables for doing smooth animation. This whole thing
562 would be much easier if the board was double-buffered,
563 but that would require a fairly major rewrite. */
568 GC blitGC, pieceGC, outlineGC;
569 XPoint startSquare, prevFrame, mouseDelta;
573 int startBoardX, startBoardY;
576 /* There can be two pieces being animated at once: a player
577 can begin dragging a piece before the remote opponent has moved. */
579 static AnimState game, player;
581 /* Bitmaps for use as masks when drawing XPM pieces.
582 Need one for each black and white piece. */
583 static Pixmap xpmMask[BlackKing + 1];
585 /* This magic number is the number of intermediate frames used
586 in each half of the animation. For short moves it's reduced
587 by 1. The total number of frames will be factor * 2 + 1. */
590 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
592 MenuItem fileMenu[] = {
593 {N_("New Game"), ResetProc},
594 {N_("New Shuffle Game ..."), ShuffleMenuProc},
595 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
596 {"----", NothingProc},
597 {N_("Load Game"), LoadGameProc},
598 {N_("Load Next Game"), LoadNextGameProc},
599 {N_("Load Previous Game"), LoadPrevGameProc},
600 {N_("Reload Same Game"), ReloadGameProc},
601 {N_("Save Game"), SaveGameProc},
602 {"----", NothingProc},
603 {N_("Copy Game"), CopyGameProc},
604 {N_("Paste Game"), PasteGameProc},
605 {"----", NothingProc},
606 {N_("Load Position"), LoadPositionProc},
607 {N_("Load Next Position"), LoadNextPositionProc},
608 {N_("Load Previous Position"), LoadPrevPositionProc},
609 {N_("Reload Same Position"), ReloadPositionProc},
610 {N_("Save Position"), SavePositionProc},
611 {"----", NothingProc},
612 {N_("Copy Position"), CopyPositionProc},
613 {N_("Paste Position"), PastePositionProc},
614 {"----", NothingProc},
615 {N_("Mail Move"), MailMoveProc},
616 {N_("Reload CMail Message"), ReloadCmailMsgProc},
617 {"----", NothingProc},
618 {N_("Exit"), QuitProc},
622 MenuItem modeMenu[] = {
623 {N_("Machine White"), MachineWhiteProc},
624 {N_("Machine Black"), MachineBlackProc},
625 {N_("Two Machines"), TwoMachinesProc},
626 {N_("Analysis Mode"), AnalyzeModeProc},
627 {N_("Analyze File"), AnalyzeFileProc },
628 {N_("ICS Client"), IcsClientProc},
629 {N_("Edit Game"), EditGameProc},
630 {N_("Edit Position"), EditPositionProc},
631 {N_("Training"), TrainingProc},
632 {"----", NothingProc},
633 {N_("Show Engine Output"), EngineOutputProc},
634 {N_("Show Evaluation Graph"), EvalGraphProc},
635 {N_("Show Game List"), ShowGameListProc},
636 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
637 {"----", NothingProc},
638 {N_("Edit Tags"), EditTagsProc},
639 {N_("Edit Comment"), EditCommentProc},
640 {N_("ICS Input Box"), IcsInputBoxProc},
641 {N_("Pause"), PauseProc},
645 MenuItem actionMenu[] = {
646 {N_("Accept"), AcceptProc},
647 {N_("Decline"), DeclineProc},
648 {N_("Rematch"), RematchProc},
649 {"----", NothingProc},
650 {N_("Call Flag"), CallFlagProc},
651 {N_("Draw"), DrawProc},
652 {N_("Adjourn"), AdjournProc},
653 {N_("Abort"), AbortProc},
654 {N_("Resign"), ResignProc},
655 {"----", NothingProc},
656 {N_("Stop Observing"), StopObservingProc},
657 {N_("Stop Examining"), StopExaminingProc},
658 {N_("Upload to Examine"), UploadProc},
659 {"----", NothingProc},
660 {N_("Adjudicate to White"), AdjuWhiteProc},
661 {N_("Adjudicate to Black"), AdjuBlackProc},
662 {N_("Adjudicate Draw"), AdjuDrawProc},
666 MenuItem stepMenu[] = {
667 {N_("Backward"), BackwardProc},
668 {N_("Forward"), ForwardProc},
669 {N_("Back to Start"), ToStartProc},
670 {N_("Forward to End"), ToEndProc},
671 {N_("Revert"), RevertProc},
672 {N_("Annotate"), AnnotateProc},
673 {N_("Truncate Game"), TruncateGameProc},
674 {"----", NothingProc},
675 {N_("Move Now"), MoveNowProc},
676 {N_("Retract Move"), RetractMoveProc},
680 MenuItem optionsMenu[] = {
681 {N_("Flip View"), FlipViewProc},
682 {"----", NothingProc},
683 {N_("Adjudications ..."), EngineMenuProc},
684 {N_("General Settings ..."), UciMenuProc},
685 {N_("Engine #1 Settings ..."), FirstSettingsProc},
686 {N_("Engine #2 Settings ..."), SecondSettingsProc},
687 {N_("Time Control ..."), TimeControlProc},
688 {N_("Game List ..."), GameListOptionsPopUp},
689 {"----", NothingProc},
690 {N_("Always Queen"), AlwaysQueenProc},
691 {N_("Animate Dragging"), AnimateDraggingProc},
692 {N_("Animate Moving"), AnimateMovingProc},
693 {N_("Auto Comment"), AutocommProc},
694 {N_("Auto Flag"), AutoflagProc},
695 {N_("Auto Flip View"), AutoflipProc},
696 {N_("Auto Observe"), AutobsProc},
697 {N_("Auto Raise Board"), AutoraiseProc},
698 {N_("Auto Save"), AutosaveProc},
699 {N_("Blindfold"), BlindfoldProc},
700 {N_("Flash Moves"), FlashMovesProc},
701 {N_("Get Move List"), GetMoveListProc},
703 {N_("Highlight Dragging"), HighlightDraggingProc},
705 {N_("Highlight Last Move"), HighlightLastMoveProc},
706 {N_("Move Sound"), MoveSoundProc},
707 {N_("ICS Alarm"), IcsAlarmProc},
708 {N_("Old Save Style"), OldSaveStyleProc},
709 {N_("Periodic Updates"), PeriodicUpdatesProc},
710 {N_("Ponder Next Move"), PonderNextMoveProc},
711 {N_("Popup Exit Message"), PopupExitMessageProc},
712 {N_("Popup Move Errors"), PopupMoveErrorsProc},
713 {N_("Premove"), PremoveProc},
714 {N_("Quiet Play"), QuietPlayProc},
715 {N_("Show Coords"), ShowCoordsProc},
716 {N_("Hide Thinking"), HideThinkingProc},
717 {N_("Test Legality"), TestLegalityProc},
718 {"----", NothingProc},
719 {N_("Save Settings Now"), SaveSettingsProc},
720 {N_("Save Settings on Exit"), SaveOnExitProc},
724 MenuItem helpMenu[] = {
725 {N_("Info XBoard"), InfoProc},
726 {N_("Man XBoard"), ManProc},
727 {"----", NothingProc},
728 {N_("Hint"), HintProc},
729 {N_("Book"), BookProc},
730 {"----", NothingProc},
731 {N_("About XBoard"), AboutProc},
736 {N_("File"), fileMenu},
737 {N_("Mode"), modeMenu},
738 {N_("Action"), actionMenu},
739 {N_("Step"), stepMenu},
740 {N_("Options"), optionsMenu},
741 {N_("Help"), helpMenu},
745 #define PAUSE_BUTTON N_("P")
746 MenuItem buttonBar[] = {
749 {PAUSE_BUTTON, PauseProc},
755 #define PIECE_MENU_SIZE 18
756 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
757 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
758 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
759 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
760 N_("Empty square"), N_("Clear board") },
761 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
762 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
763 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
764 N_("Empty square"), N_("Clear board") }
766 /* must be in same order as PieceMenuStrings! */
767 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
768 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
769 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
770 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
771 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
772 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
773 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
774 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
775 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
778 #define DROP_MENU_SIZE 6
779 String dropMenuStrings[DROP_MENU_SIZE] = {
780 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
782 /* must be in same order as PieceMenuStrings! */
783 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
784 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
785 WhiteRook, WhiteQueen
793 DropMenuEnables dmEnables[] = {
811 { XtNborderWidth, 0 },
812 { XtNdefaultDistance, 0 },
816 { XtNborderWidth, 0 },
817 { XtNresizable, (XtArgVal) True },
821 { XtNborderWidth, 0 },
827 { XtNjustify, (XtArgVal) XtJustifyRight },
828 { XtNlabel, (XtArgVal) "..." },
829 { XtNresizable, (XtArgVal) True },
830 { XtNresize, (XtArgVal) False }
833 Arg messageArgs[] = {
834 { XtNjustify, (XtArgVal) XtJustifyLeft },
835 { XtNlabel, (XtArgVal) "..." },
836 { XtNresizable, (XtArgVal) True },
837 { XtNresize, (XtArgVal) False }
841 { XtNborderWidth, 0 },
842 { XtNjustify, (XtArgVal) XtJustifyLeft }
845 XtResource clientResources[] = {
846 { "flashCount", "flashCount", XtRInt, sizeof(int),
847 XtOffset(AppDataPtr, flashCount), XtRImmediate,
848 (XtPointer) FLASH_COUNT },
851 XrmOptionDescRec shellOptions[] = {
852 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
853 { "-flash", "flashCount", XrmoptionNoArg, "3" },
854 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
857 XtActionsRec boardActions[] = {
858 { "DrawPosition", DrawPositionProc },
859 { "HandleUserMove", HandleUserMove },
860 { "AnimateUserMove", AnimateUserMove },
861 { "HandlePV", HandlePV },
862 { "SelectPV", SelectPV },
863 { "StopPV", StopPV },
864 { "FileNameAction", FileNameAction },
865 { "AskQuestionProc", AskQuestionProc },
866 { "AskQuestionReplyAction", AskQuestionReplyAction },
867 { "PieceMenuPopup", PieceMenuPopup },
868 { "WhiteClock", WhiteClock },
869 { "BlackClock", BlackClock },
870 { "Iconify", Iconify },
871 { "ResetProc", ResetProc },
872 { "NewVariantProc", NewVariantProc },
873 { "LoadGameProc", LoadGameProc },
874 { "LoadNextGameProc", LoadNextGameProc },
875 { "LoadPrevGameProc", LoadPrevGameProc },
876 { "LoadSelectedProc", LoadSelectedProc },
877 { "SetFilterProc", SetFilterProc },
878 { "ReloadGameProc", ReloadGameProc },
879 { "LoadPositionProc", LoadPositionProc },
880 { "LoadNextPositionProc", LoadNextPositionProc },
881 { "LoadPrevPositionProc", LoadPrevPositionProc },
882 { "ReloadPositionProc", ReloadPositionProc },
883 { "CopyPositionProc", CopyPositionProc },
884 { "PastePositionProc", PastePositionProc },
885 { "CopyGameProc", CopyGameProc },
886 { "PasteGameProc", PasteGameProc },
887 { "SaveGameProc", SaveGameProc },
888 { "SavePositionProc", SavePositionProc },
889 { "MailMoveProc", MailMoveProc },
890 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
891 { "QuitProc", QuitProc },
892 { "MachineWhiteProc", MachineWhiteProc },
893 { "MachineBlackProc", MachineBlackProc },
894 { "AnalysisModeProc", AnalyzeModeProc },
895 { "AnalyzeFileProc", AnalyzeFileProc },
896 { "TwoMachinesProc", TwoMachinesProc },
897 { "IcsClientProc", IcsClientProc },
898 { "EditGameProc", EditGameProc },
899 { "EditPositionProc", EditPositionProc },
900 { "TrainingProc", EditPositionProc },
901 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
902 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
903 { "ShowGameListProc", ShowGameListProc },
904 { "ShowMoveListProc", HistoryShowProc},
905 { "EditTagsProc", EditCommentProc },
906 { "EditCommentProc", EditCommentProc },
907 { "IcsAlarmProc", IcsAlarmProc },
908 { "IcsInputBoxProc", IcsInputBoxProc },
909 { "PauseProc", PauseProc },
910 { "AcceptProc", AcceptProc },
911 { "DeclineProc", DeclineProc },
912 { "RematchProc", RematchProc },
913 { "CallFlagProc", CallFlagProc },
914 { "DrawProc", DrawProc },
915 { "AdjournProc", AdjournProc },
916 { "AbortProc", AbortProc },
917 { "ResignProc", ResignProc },
918 { "AdjuWhiteProc", AdjuWhiteProc },
919 { "AdjuBlackProc", AdjuBlackProc },
920 { "AdjuDrawProc", AdjuDrawProc },
921 { "EnterKeyProc", EnterKeyProc },
922 { "UpKeyProc", UpKeyProc },
923 { "DownKeyProc", DownKeyProc },
924 { "StopObservingProc", StopObservingProc },
925 { "StopExaminingProc", StopExaminingProc },
926 { "UploadProc", UploadProc },
927 { "BackwardProc", BackwardProc },
928 { "ForwardProc", ForwardProc },
929 { "ToStartProc", ToStartProc },
930 { "ToEndProc", ToEndProc },
931 { "RevertProc", RevertProc },
932 { "AnnotateProc", AnnotateProc },
933 { "TruncateGameProc", TruncateGameProc },
934 { "MoveNowProc", MoveNowProc },
935 { "RetractMoveProc", RetractMoveProc },
936 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
937 { "UciMenuProc", (XtActionProc) UciMenuProc },
938 { "TimeControlProc", (XtActionProc) TimeControlProc },
939 { "AlwaysQueenProc", AlwaysQueenProc },
940 { "AnimateDraggingProc", AnimateDraggingProc },
941 { "AnimateMovingProc", AnimateMovingProc },
942 { "AutoflagProc", AutoflagProc },
943 { "AutoflipProc", AutoflipProc },
944 { "AutobsProc", AutobsProc },
945 { "AutoraiseProc", AutoraiseProc },
946 { "AutosaveProc", AutosaveProc },
947 { "BlindfoldProc", BlindfoldProc },
948 { "FlashMovesProc", FlashMovesProc },
949 { "FlipViewProc", FlipViewProc },
950 { "GetMoveListProc", GetMoveListProc },
952 { "HighlightDraggingProc", HighlightDraggingProc },
954 { "HighlightLastMoveProc", HighlightLastMoveProc },
955 { "IcsAlarmProc", IcsAlarmProc },
956 { "MoveSoundProc", MoveSoundProc },
957 { "OldSaveStyleProc", OldSaveStyleProc },
958 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
959 { "PonderNextMoveProc", PonderNextMoveProc },
960 { "PopupExitMessageProc", PopupExitMessageProc },
961 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
962 { "PremoveProc", PremoveProc },
963 { "QuietPlayProc", QuietPlayProc },
964 { "ShowCoordsProc", ShowCoordsProc },
965 { "ShowThinkingProc", ShowThinkingProc },
966 { "HideThinkingProc", HideThinkingProc },
967 { "TestLegalityProc", TestLegalityProc },
968 { "SaveSettingsProc", SaveSettingsProc },
969 { "SaveOnExitProc", SaveOnExitProc },
970 { "InfoProc", InfoProc },
971 { "ManProc", ManProc },
972 { "HintProc", HintProc },
973 { "BookProc", BookProc },
974 { "AboutGameProc", AboutGameProc },
975 { "AboutProc", AboutProc },
976 { "DebugProc", DebugProc },
977 { "NothingProc", NothingProc },
978 { "CommentClick", (XtActionProc) CommentClick },
979 { "CommentPopDown", (XtActionProc) CommentPopDown },
980 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
981 { "TagsPopDown", (XtActionProc) TagsPopDown },
982 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
983 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
984 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
985 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
986 { "GameListPopDown", (XtActionProc) GameListPopDown },
987 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
988 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
989 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
990 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
991 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
992 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
993 { "EnginePopDown", (XtActionProc) EnginePopDown },
994 { "UciPopDown", (XtActionProc) UciPopDown },
995 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
996 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
997 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
998 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1001 char globalTranslations[] =
1002 ":<Key>F9: ResignProc() \n \
1003 :Ctrl<Key>n: ResetProc() \n \
1004 :Meta<Key>V: NewVariantProc() \n \
1005 :Ctrl<Key>o: LoadGameProc() \n \
1006 :Meta<Key>Next: LoadNextGameProc() \n \
1007 :Meta<Key>Prior: LoadPrevGameProc() \n \
1008 :Ctrl<Key>s: SaveGameProc() \n \
1009 :Ctrl<Key>c: CopyGameProc() \n \
1010 :Ctrl<Key>v: PasteGameProc() \n \
1011 :Ctrl<Key>O: LoadPositionProc() \n \
1012 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1013 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1014 :Ctrl<Key>S: SavePositionProc() \n \
1015 :Ctrl<Key>C: CopyPositionProc() \n \
1016 :Ctrl<Key>V: PastePositionProc() \n \
1017 :Ctrl<Key>q: QuitProc() \n \
1018 :Ctrl<Key>w: MachineWhiteProc() \n \
1019 :Ctrl<Key>b: MachineBlackProc() \n \
1020 :Ctrl<Key>t: TwoMachinesProc() \n \
1021 :Ctrl<Key>a: AnalysisModeProc() \n \
1022 :Ctrl<Key>f: AnalyzeFileProc() \n \
1023 :Ctrl<Key>e: EditGameProc() \n \
1024 :Ctrl<Key>E: EditPositionProc() \n \
1025 :Meta<Key>O: EngineOutputProc() \n \
1026 :Meta<Key>E: EvalGraphProc() \n \
1027 :Meta<Key>G: ShowGameListProc() \n \
1028 :Meta<Key>H: ShowMoveListProc() \n \
1029 :<Key>Pause: PauseProc() \n \
1030 :<Key>F3: AcceptProc() \n \
1031 :<Key>F4: DeclineProc() \n \
1032 :<Key>F12: RematchProc() \n \
1033 :<Key>F5: CallFlagProc() \n \
1034 :<Key>F6: DrawProc() \n \
1035 :<Key>F7: AdjournProc() \n \
1036 :<Key>F8: AbortProc() \n \
1037 :<Key>F10: StopObservingProc() \n \
1038 :<Key>F11: StopExaminingProc() \n \
1039 :Meta Ctrl<Key>F12: DebugProc() \n \
1040 :Meta<Key>End: ToEndProc() \n \
1041 :Meta<Key>Right: ForwardProc() \n \
1042 :Meta<Key>Home: ToStartProc() \n \
1043 :Meta<Key>Left: BackwardProc() \n \
1044 :Ctrl<Key>m: MoveNowProc() \n \
1045 :Ctrl<Key>x: RetractMoveProc() \n \
1046 :Meta<Key>J: EngineMenuProc() \n \
1047 :Meta<Key>U: UciMenuProc() \n \
1048 :Meta<Key>T: TimeControlProc() \n \
1049 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1050 :Ctrl<Key>F: AutoflagProc() \n \
1051 :Ctrl<Key>A: AnimateMovingProc() \n \
1052 :Ctrl<Key>P: PonderNextMoveProc() \n \
1053 :Ctrl<Key>L: TestLegalityProc() \n \
1054 :Ctrl<Key>H: HideThinkingProc() \n \
1055 :<Key>-: Iconify() \n \
1056 :<Key>F1: ManProc() \n \
1057 :<Key>F2: FlipViewProc() \n \
1058 <KeyDown>.: BackwardProc() \n \
1059 <KeyUp>.: ForwardProc() \n \
1060 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1061 \"Send to chess program:\",,1) \n \
1062 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1063 \"Send to second chess program:\",,2) \n";
1065 char boardTranslations[] =
1066 "<Btn1Down>: HandleUserMove(0) \n \
1067 Shift<Btn1Up>: HandleUserMove(1) \n \
1068 <Btn1Up>: HandleUserMove(0) \n \
1069 <Btn1Motion>: AnimateUserMove() \n \
1070 <Btn3Motion>: HandlePV() \n \
1071 <Btn3Up>: PieceMenuPopup(menuB) \n \
1072 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1073 PieceMenuPopup(menuB) \n \
1074 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1075 PieceMenuPopup(menuW) \n \
1076 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1077 PieceMenuPopup(menuW) \n \
1078 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1079 PieceMenuPopup(menuB) \n";
1081 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1082 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1084 char ICSInputTranslations[] =
1085 "<Key>Up: UpKeyProc() \n "
1086 "<Key>Down: DownKeyProc() \n "
1087 "<Key>Return: EnterKeyProc() \n";
1089 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1090 // as the widget is destroyed before the up-click can call extend-end
1091 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1093 String xboardResources[] = {
1094 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1095 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1096 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1101 /* Max possible square size */
1102 #define MAXSQSIZE 256
1104 static int xpm_avail[MAXSQSIZE];
1106 #ifdef HAVE_DIR_STRUCT
1108 /* Extract piece size from filename */
1110 xpm_getsize(name, len, ext)
1121 if ((p=strchr(name, '.')) == NULL ||
1122 StrCaseCmp(p+1, ext) != 0)
1128 while (*p && isdigit(*p))
1135 /* Setup xpm_avail */
1137 xpm_getavail(dirname, ext)
1145 for (i=0; i<MAXSQSIZE; ++i)
1148 if (appData.debugMode)
1149 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1151 dir = opendir(dirname);
1154 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1155 programName, dirname);
1159 while ((ent=readdir(dir)) != NULL) {
1160 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1161 if (i > 0 && i < MAXSQSIZE)
1171 xpm_print_avail(fp, ext)
1177 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1178 for (i=1; i<MAXSQSIZE; ++i) {
1184 /* Return XPM piecesize closest to size */
1186 xpm_closest_to(dirname, size, ext)
1192 int sm_diff = MAXSQSIZE;
1196 xpm_getavail(dirname, ext);
1198 if (appData.debugMode)
1199 xpm_print_avail(stderr, ext);
1201 for (i=1; i<MAXSQSIZE; ++i) {
1204 diff = (diff<0) ? -diff : diff;
1205 if (diff < sm_diff) {
1213 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1219 #else /* !HAVE_DIR_STRUCT */
1220 /* If we are on a system without a DIR struct, we can't
1221 read the directory, so we can't collect a list of
1222 filenames, etc., so we can't do any size-fitting. */
1224 xpm_closest_to(dirname, size, ext)
1229 fprintf(stderr, _("\
1230 Warning: No DIR structure found on this system --\n\
1231 Unable to autosize for XPM/XIM pieces.\n\
1232 Please report this error to frankm@hiwaay.net.\n\
1233 Include system type & operating system in message.\n"));
1236 #endif /* HAVE_DIR_STRUCT */
1238 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1239 "magenta", "cyan", "white" };
1243 TextColors textColors[(int)NColorClasses];
1245 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1247 parse_color(str, which)
1251 char *p, buf[100], *d;
1254 if (strlen(str) > 99) /* watch bounds on buf */
1259 for (i=0; i<which; ++i) {
1266 /* Could be looking at something like:
1268 .. in which case we want to stop on a comma also */
1269 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1273 return -1; /* Use default for empty field */
1276 if (which == 2 || isdigit(*p))
1279 while (*p && isalpha(*p))
1284 for (i=0; i<8; ++i) {
1285 if (!StrCaseCmp(buf, cnames[i]))
1286 return which? (i+40) : (i+30);
1288 if (!StrCaseCmp(buf, "default")) return -1;
1290 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1295 parse_cpair(cc, str)
1299 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1300 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1305 /* bg and attr are optional */
1306 textColors[(int)cc].bg = parse_color(str, 1);
1307 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1308 textColors[(int)cc].attr = 0;
1314 /* Arrange to catch delete-window events */
1315 Atom wm_delete_window;
1317 CatchDeleteWindow(Widget w, String procname)
1320 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1321 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1322 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1329 XtSetArg(args[0], XtNiconic, False);
1330 XtSetValues(shellWidget, args, 1);
1332 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1335 //---------------------------------------------------------------------------------------------------------
1336 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1339 #define CW_USEDEFAULT (1<<31)
1340 #define ICS_TEXT_MENU_SIZE 90
1341 #define DEBUG_FILE "xboard.debug"
1342 #define SetCurrentDirectory chdir
1343 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1347 // these two must some day move to frontend.h, when they are implemented
1348 Boolean GameListIsUp();
1350 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1353 // front-end part of option handling
1355 // [HGM] This platform-dependent table provides the location for storing the color info
1356 extern char *crWhite, * crBlack;
1360 &appData.whitePieceColor,
1361 &appData.blackPieceColor,
1362 &appData.lightSquareColor,
1363 &appData.darkSquareColor,
1364 &appData.highlightSquareColor,
1365 &appData.premoveHighlightColor,
1366 &appData.lowTimeWarningColor,
1377 // [HGM] font: keep a font for each square size, even non-stndard ones
1378 #define NUM_SIZES 18
1379 #define MAX_SIZE 130
1380 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1381 char *fontTable[NUM_FONTS][MAX_SIZE];
1384 ParseFont(char *name, int number)
1385 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1387 if(sscanf(name, "size%d:", &size)) {
1388 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1389 // defer processing it until we know if it matches our board size
1390 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1391 fontTable[number][size] = strdup(strchr(name, ':')+1);
1392 fontValid[number][size] = True;
1397 case 0: // CLOCK_FONT
1398 appData.clockFont = strdup(name);
1400 case 1: // MESSAGE_FONT
1401 appData.font = strdup(name);
1403 case 2: // COORD_FONT
1404 appData.coordFont = strdup(name);
1409 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1414 { // only 2 fonts currently
1415 appData.clockFont = CLOCK_FONT_NAME;
1416 appData.coordFont = COORD_FONT_NAME;
1417 appData.font = DEFAULT_FONT_NAME;
1422 { // no-op, until we identify the code for this already in XBoard and move it here
1426 ParseColor(int n, char *name)
1427 { // in XBoard, just copy the color-name string
1428 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1432 ParseTextAttribs(ColorClass cc, char *s)
1434 (&appData.colorShout)[cc] = strdup(s);
1438 ParseBoardSize(void *addr, char *name)
1440 appData.boardSize = strdup(name);
1445 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1449 SetCommPortDefaults()
1450 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1453 // [HGM] args: these three cases taken out to stay in front-end
1455 SaveFontArg(FILE *f, ArgDescriptor *ad)
1458 int i, n = (int)ad->argLoc;
1460 case 0: // CLOCK_FONT
1461 name = appData.clockFont;
1463 case 1: // MESSAGE_FONT
1464 name = appData.font;
1466 case 2: // COORD_FONT
1467 name = appData.coordFont;
1472 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1473 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1474 fontTable[n][squareSize] = strdup(name);
1475 fontValid[n][squareSize] = True;
1478 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1479 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1484 { // nothing to do, as the sounds are at all times represented by their text-string names already
1488 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1489 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1490 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1494 SaveColor(FILE *f, ArgDescriptor *ad)
1495 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1496 if(colorVariable[(int)ad->argLoc])
1497 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1501 SaveBoardSize(FILE *f, char *name, void *addr)
1502 { // wrapper to shield back-end from BoardSize & sizeInfo
1503 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1507 ParseCommPortSettings(char *s)
1508 { // no such option in XBoard (yet)
1511 extern Widget engineOutputShell;
1512 extern Widget tagsShell, editTagsShell;
1514 GetActualPlacement(Widget wg, WindowPlacement *wp)
1524 XtSetArg(args[i], XtNx, &x); i++;
1525 XtSetArg(args[i], XtNy, &y); i++;
1526 XtSetArg(args[i], XtNwidth, &w); i++;
1527 XtSetArg(args[i], XtNheight, &h); i++;
1528 XtGetValues(wg, args, i);
1537 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1538 // In XBoard this will have to wait until awareness of window parameters is implemented
1539 GetActualPlacement(shellWidget, &wpMain);
1540 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1541 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1542 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1543 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1544 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1545 else GetActualPlacement(editShell, &wpComment);
1546 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1547 else GetActualPlacement(editTagsShell, &wpTags);
1551 PrintCommPortSettings(FILE *f, char *name)
1552 { // This option does not exist in XBoard
1556 MySearchPath(char *installDir, char *name, char *fullname)
1557 { // just append installDir and name. Perhaps ExpandPath should be used here?
1558 name = ExpandPathName(name);
1559 if(name && name[0] == '/')
1560 safeStrCpy(fullname, name, MSG_SIZ );
1562 sprintf(fullname, "%s%c%s", installDir, '/', name);
1568 MyGetFullPathName(char *name, char *fullname)
1569 { // should use ExpandPath?
1570 name = ExpandPathName(name);
1571 safeStrCpy(fullname, name, MSG_SIZ );
1576 EnsureOnScreen(int *x, int *y, int minX, int minY)
1583 { // [HGM] args: allows testing if main window is realized from back-end
1584 return xBoardWindow != 0;
1588 PopUpStartupDialog()
1589 { // start menu not implemented in XBoard
1593 ConvertToLine(int argc, char **argv)
1595 static char line[128*1024], buf[1024];
1599 for(i=1; i<argc; i++)
1601 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1602 && argv[i][0] != '{' )
1603 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1605 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1606 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1609 line[strlen(line)-1] = NULLCHAR;
1613 //--------------------------------------------------------------------------------------------
1615 extern Boolean twoBoards, partnerUp;
1618 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1620 #define BoardSize int
1621 void InitDrawingSizes(BoardSize boardSize, int flags)
1622 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1623 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1625 XtGeometryResult gres;
1628 if(!formWidget) return;
1631 * Enable shell resizing.
1633 shellArgs[0].value = (XtArgVal) &w;
1634 shellArgs[1].value = (XtArgVal) &h;
1635 XtGetValues(shellWidget, shellArgs, 2);
1637 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1638 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1639 XtSetValues(shellWidget, &shellArgs[2], 4);
1641 XtSetArg(args[0], XtNdefaultDistance, &sep);
1642 XtGetValues(formWidget, args, 1);
1644 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1645 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1647 hOffset = boardWidth + 10;
1648 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1649 secondSegments[i] = gridSegments[i];
1650 secondSegments[i].x1 += hOffset;
1651 secondSegments[i].x2 += hOffset;
1654 XtSetArg(args[0], XtNwidth, boardWidth);
1655 XtSetArg(args[1], XtNheight, boardHeight);
1656 XtSetValues(boardWidget, args, 2);
1658 timerWidth = (boardWidth - sep) / 2;
1659 XtSetArg(args[0], XtNwidth, timerWidth);
1660 XtSetValues(whiteTimerWidget, args, 1);
1661 XtSetValues(blackTimerWidget, args, 1);
1663 XawFormDoLayout(formWidget, False);
1665 if (appData.titleInWindow) {
1667 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1668 XtSetArg(args[i], XtNheight, &h); i++;
1669 XtGetValues(titleWidget, args, i);
1671 w = boardWidth - 2*bor;
1673 XtSetArg(args[0], XtNwidth, &w);
1674 XtGetValues(menuBarWidget, args, 1);
1675 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1678 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1679 if (gres != XtGeometryYes && appData.debugMode) {
1681 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1682 programName, gres, w, h, wr, hr);
1686 XawFormDoLayout(formWidget, True);
1689 * Inhibit shell resizing.
1691 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1692 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1693 shellArgs[4].value = shellArgs[2].value = w;
1694 shellArgs[5].value = shellArgs[3].value = h;
1695 XtSetValues(shellWidget, &shellArgs[0], 6);
1697 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1700 for(i=0; i<4; i++) {
1702 for(p=0; p<=(int)WhiteKing; p++)
1703 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1704 if(gameInfo.variant == VariantShogi) {
1705 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1706 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1707 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1708 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1709 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1712 if(gameInfo.variant == VariantGothic) {
1713 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1716 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1717 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1718 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1721 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1722 for(p=0; p<=(int)WhiteKing; p++)
1723 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1724 if(gameInfo.variant == VariantShogi) {
1725 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1726 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1727 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1728 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1729 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1732 if(gameInfo.variant == VariantGothic) {
1733 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1736 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1737 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1738 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1743 for(i=0; i<2; i++) {
1745 for(p=0; p<=(int)WhiteKing; p++)
1746 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1747 if(gameInfo.variant == VariantShogi) {
1748 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1749 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1750 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1751 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1752 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1755 if(gameInfo.variant == VariantGothic) {
1756 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1759 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1760 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1761 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1776 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1777 XSetWindowAttributes window_attributes;
1779 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1780 XrmValue vFrom, vTo;
1781 XtGeometryResult gres;
1784 int forceMono = False;
1786 srandom(time(0)); // [HGM] book: make random truly random
1788 setbuf(stdout, NULL);
1789 setbuf(stderr, NULL);
1792 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1793 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1797 programName = strrchr(argv[0], '/');
1798 if (programName == NULL)
1799 programName = argv[0];
1804 XtSetLanguageProc(NULL, NULL, NULL);
1805 bindtextdomain(PACKAGE, LOCALEDIR);
1806 textdomain(PACKAGE);
1810 XtAppInitialize(&appContext, "XBoard", shellOptions,
1811 XtNumber(shellOptions),
1812 &argc, argv, xboardResources, NULL, 0);
1813 appData.boardSize = "";
1814 InitAppData(ConvertToLine(argc, argv));
1816 if (p == NULL) p = "/tmp";
1817 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1818 gameCopyFilename = (char*) malloc(i);
1819 gamePasteFilename = (char*) malloc(i);
1820 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1821 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1823 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1824 clientResources, XtNumber(clientResources),
1827 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1828 static char buf[MSG_SIZ];
1829 EscapeExpand(buf, appData.initString);
1830 appData.initString = strdup(buf);
1831 EscapeExpand(buf, appData.secondInitString);
1832 appData.secondInitString = strdup(buf);
1833 EscapeExpand(buf, appData.firstComputerString);
1834 appData.firstComputerString = strdup(buf);
1835 EscapeExpand(buf, appData.secondComputerString);
1836 appData.secondComputerString = strdup(buf);
1839 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1842 if (chdir(chessDir) != 0) {
1843 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1849 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1850 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1851 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1852 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1855 setbuf(debugFP, NULL);
1858 /* [HGM,HR] make sure board size is acceptable */
1859 if(appData.NrFiles > BOARD_FILES ||
1860 appData.NrRanks > BOARD_RANKS )
1861 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1864 /* This feature does not work; animation needs a rewrite */
1865 appData.highlightDragging = FALSE;
1869 xDisplay = XtDisplay(shellWidget);
1870 xScreen = DefaultScreen(xDisplay);
1871 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1873 gameInfo.variant = StringToVariant(appData.variant);
1874 InitPosition(FALSE);
1877 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1879 if (isdigit(appData.boardSize[0])) {
1880 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1881 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1882 &fontPxlSize, &smallLayout, &tinyLayout);
1884 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1885 programName, appData.boardSize);
1889 /* Find some defaults; use the nearest known size */
1890 SizeDefaults *szd, *nearest;
1891 int distance = 99999;
1892 nearest = szd = sizeDefaults;
1893 while (szd->name != NULL) {
1894 if (abs(szd->squareSize - squareSize) < distance) {
1896 distance = abs(szd->squareSize - squareSize);
1897 if (distance == 0) break;
1901 if (i < 2) lineGap = nearest->lineGap;
1902 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1903 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1904 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1905 if (i < 6) smallLayout = nearest->smallLayout;
1906 if (i < 7) tinyLayout = nearest->tinyLayout;
1909 SizeDefaults *szd = sizeDefaults;
1910 if (*appData.boardSize == NULLCHAR) {
1911 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1912 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1915 if (szd->name == NULL) szd--;
1916 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1918 while (szd->name != NULL &&
1919 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1920 if (szd->name == NULL) {
1921 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1922 programName, appData.boardSize);
1926 squareSize = szd->squareSize;
1927 lineGap = szd->lineGap;
1928 clockFontPxlSize = szd->clockFontPxlSize;
1929 coordFontPxlSize = szd->coordFontPxlSize;
1930 fontPxlSize = szd->fontPxlSize;
1931 smallLayout = szd->smallLayout;
1932 tinyLayout = szd->tinyLayout;
1933 // [HGM] font: use defaults from settings file if available and not overruled
1935 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1936 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1937 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1938 appData.font = fontTable[MESSAGE_FONT][squareSize];
1939 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1940 appData.coordFont = fontTable[COORD_FONT][squareSize];
1942 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1943 if (strlen(appData.pixmapDirectory) > 0) {
1944 p = ExpandPathName(appData.pixmapDirectory);
1946 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1947 appData.pixmapDirectory);
1950 if (appData.debugMode) {
1951 fprintf(stderr, _("\
1952 XBoard square size (hint): %d\n\
1953 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1955 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1956 if (appData.debugMode) {
1957 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1960 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1962 /* [HR] height treated separately (hacked) */
1963 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1964 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1965 if (appData.showJail == 1) {
1966 /* Jail on top and bottom */
1967 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1968 XtSetArg(boardArgs[2], XtNheight,
1969 boardHeight + 2*(lineGap + squareSize));
1970 } else if (appData.showJail == 2) {
1972 XtSetArg(boardArgs[1], XtNwidth,
1973 boardWidth + 2*(lineGap + squareSize));
1974 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1977 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1978 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1982 * Determine what fonts to use.
1984 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1985 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1986 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1987 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1988 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1989 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1990 appData.font = FindFont(appData.font, fontPxlSize);
1991 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1992 countFontStruct = XQueryFont(xDisplay, countFontID);
1993 // appData.font = FindFont(appData.font, fontPxlSize);
1995 xdb = XtDatabase(xDisplay);
1996 XrmPutStringResource(&xdb, "*font", appData.font);
1999 * Detect if there are not enough colors available and adapt.
2001 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2002 appData.monoMode = True;
2005 if (!appData.monoMode) {
2006 vFrom.addr = (caddr_t) appData.lightSquareColor;
2007 vFrom.size = strlen(appData.lightSquareColor);
2008 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2009 if (vTo.addr == NULL) {
2010 appData.monoMode = True;
2013 lightSquareColor = *(Pixel *) vTo.addr;
2016 if (!appData.monoMode) {
2017 vFrom.addr = (caddr_t) appData.darkSquareColor;
2018 vFrom.size = strlen(appData.darkSquareColor);
2019 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2020 if (vTo.addr == NULL) {
2021 appData.monoMode = True;
2024 darkSquareColor = *(Pixel *) vTo.addr;
2027 if (!appData.monoMode) {
2028 vFrom.addr = (caddr_t) appData.whitePieceColor;
2029 vFrom.size = strlen(appData.whitePieceColor);
2030 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2031 if (vTo.addr == NULL) {
2032 appData.monoMode = True;
2035 whitePieceColor = *(Pixel *) vTo.addr;
2038 if (!appData.monoMode) {
2039 vFrom.addr = (caddr_t) appData.blackPieceColor;
2040 vFrom.size = strlen(appData.blackPieceColor);
2041 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2042 if (vTo.addr == NULL) {
2043 appData.monoMode = True;
2046 blackPieceColor = *(Pixel *) vTo.addr;
2050 if (!appData.monoMode) {
2051 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2052 vFrom.size = strlen(appData.highlightSquareColor);
2053 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2054 if (vTo.addr == NULL) {
2055 appData.monoMode = True;
2058 highlightSquareColor = *(Pixel *) vTo.addr;
2062 if (!appData.monoMode) {
2063 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2064 vFrom.size = strlen(appData.premoveHighlightColor);
2065 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2066 if (vTo.addr == NULL) {
2067 appData.monoMode = True;
2070 premoveHighlightColor = *(Pixel *) vTo.addr;
2075 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2078 if (appData.bitmapDirectory == NULL ||
2079 appData.bitmapDirectory[0] == NULLCHAR)
2080 appData.bitmapDirectory = DEF_BITMAP_DIR;
2083 if (appData.lowTimeWarning && !appData.monoMode) {
2084 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2085 vFrom.size = strlen(appData.lowTimeWarningColor);
2086 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2087 if (vTo.addr == NULL)
2088 appData.monoMode = True;
2090 lowTimeWarningColor = *(Pixel *) vTo.addr;
2093 if (appData.monoMode && appData.debugMode) {
2094 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2095 (unsigned long) XWhitePixel(xDisplay, xScreen),
2096 (unsigned long) XBlackPixel(xDisplay, xScreen));
2099 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2100 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2101 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2102 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2103 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2104 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2105 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2106 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2107 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2108 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2110 if (appData.colorize) {
2112 _("%s: can't parse color names; disabling colorization\n"),
2115 appData.colorize = FALSE;
2117 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2118 textColors[ColorNone].attr = 0;
2120 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2126 layoutName = "tinyLayout";
2127 } else if (smallLayout) {
2128 layoutName = "smallLayout";
2130 layoutName = "normalLayout";
2132 /* Outer layoutWidget is there only to provide a name for use in
2133 resources that depend on the layout style */
2135 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2136 layoutArgs, XtNumber(layoutArgs));
2138 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2139 formArgs, XtNumber(formArgs));
2140 XtSetArg(args[0], XtNdefaultDistance, &sep);
2141 XtGetValues(formWidget, args, 1);
2144 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2145 XtSetArg(args[0], XtNtop, XtChainTop);
2146 XtSetArg(args[1], XtNbottom, XtChainTop);
2147 XtSetArg(args[2], XtNright, XtChainLeft);
2148 XtSetValues(menuBarWidget, args, 3);
2150 widgetList[j++] = whiteTimerWidget =
2151 XtCreateWidget("whiteTime", labelWidgetClass,
2152 formWidget, timerArgs, XtNumber(timerArgs));
2153 XtSetArg(args[0], XtNfont, clockFontStruct);
2154 XtSetArg(args[1], XtNtop, XtChainTop);
2155 XtSetArg(args[2], XtNbottom, XtChainTop);
2156 XtSetValues(whiteTimerWidget, args, 3);
2158 widgetList[j++] = blackTimerWidget =
2159 XtCreateWidget("blackTime", labelWidgetClass,
2160 formWidget, timerArgs, XtNumber(timerArgs));
2161 XtSetArg(args[0], XtNfont, clockFontStruct);
2162 XtSetArg(args[1], XtNtop, XtChainTop);
2163 XtSetArg(args[2], XtNbottom, XtChainTop);
2164 XtSetValues(blackTimerWidget, args, 3);
2166 if (appData.titleInWindow) {
2167 widgetList[j++] = titleWidget =
2168 XtCreateWidget("title", labelWidgetClass, formWidget,
2169 titleArgs, XtNumber(titleArgs));
2170 XtSetArg(args[0], XtNtop, XtChainTop);
2171 XtSetArg(args[1], XtNbottom, XtChainTop);
2172 XtSetValues(titleWidget, args, 2);
2175 if (appData.showButtonBar) {
2176 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2177 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2178 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2179 XtSetArg(args[2], XtNtop, XtChainTop);
2180 XtSetArg(args[3], XtNbottom, XtChainTop);
2181 XtSetValues(buttonBarWidget, args, 4);
2184 widgetList[j++] = messageWidget =
2185 XtCreateWidget("message", labelWidgetClass, formWidget,
2186 messageArgs, XtNumber(messageArgs));
2187 XtSetArg(args[0], XtNtop, XtChainTop);
2188 XtSetArg(args[1], XtNbottom, XtChainTop);
2189 XtSetValues(messageWidget, args, 2);
2191 widgetList[j++] = boardWidget =
2192 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2193 XtNumber(boardArgs));
2195 XtManageChildren(widgetList, j);
2197 timerWidth = (boardWidth - sep) / 2;
2198 XtSetArg(args[0], XtNwidth, timerWidth);
2199 XtSetValues(whiteTimerWidget, args, 1);
2200 XtSetValues(blackTimerWidget, args, 1);
2202 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2203 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2204 XtGetValues(whiteTimerWidget, args, 2);
2206 if (appData.showButtonBar) {
2207 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2208 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2209 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2213 * formWidget uses these constraints but they are stored
2217 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2218 XtSetValues(menuBarWidget, args, i);
2219 if (appData.titleInWindow) {
2222 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2223 XtSetValues(whiteTimerWidget, args, i);
2225 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2226 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2227 XtSetValues(blackTimerWidget, args, i);
2229 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2230 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2231 XtSetValues(titleWidget, args, i);
2233 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2234 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2235 XtSetValues(messageWidget, args, i);
2236 if (appData.showButtonBar) {
2238 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2239 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2240 XtSetValues(buttonBarWidget, args, i);
2244 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2245 XtSetValues(whiteTimerWidget, args, i);
2247 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2248 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2249 XtSetValues(blackTimerWidget, args, i);
2251 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2252 XtSetValues(titleWidget, args, i);
2254 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2255 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2256 XtSetValues(messageWidget, args, i);
2257 if (appData.showButtonBar) {
2259 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2260 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2261 XtSetValues(buttonBarWidget, args, i);
2266 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2267 XtSetValues(whiteTimerWidget, args, i);
2269 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2270 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2271 XtSetValues(blackTimerWidget, args, i);
2273 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2274 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2275 XtSetValues(messageWidget, args, i);
2276 if (appData.showButtonBar) {
2278 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2279 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2280 XtSetValues(buttonBarWidget, args, i);
2284 XtSetArg(args[0], XtNfromVert, messageWidget);
2285 XtSetArg(args[1], XtNtop, XtChainTop);
2286 XtSetArg(args[2], XtNbottom, XtChainBottom);
2287 XtSetArg(args[3], XtNleft, XtChainLeft);
2288 XtSetArg(args[4], XtNright, XtChainRight);
2289 XtSetValues(boardWidget, args, 5);
2291 XtRealizeWidget(shellWidget);
2294 XtSetArg(args[0], XtNx, wpMain.x);
2295 XtSetArg(args[1], XtNy, wpMain.y);
2296 XtSetValues(shellWidget, args, 2);
2300 * Correct the width of the message and title widgets.
2301 * It is not known why some systems need the extra fudge term.
2302 * The value "2" is probably larger than needed.
2304 XawFormDoLayout(formWidget, False);
2306 #define WIDTH_FUDGE 2
2308 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2309 XtSetArg(args[i], XtNheight, &h); i++;
2310 XtGetValues(messageWidget, args, i);
2311 if (appData.showButtonBar) {
2313 XtSetArg(args[i], XtNwidth, &w); i++;
2314 XtGetValues(buttonBarWidget, args, i);
2315 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2317 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2320 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2321 if (gres != XtGeometryYes && appData.debugMode) {
2322 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2323 programName, gres, w, h, wr, hr);
2326 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2327 /* The size used for the child widget in layout lags one resize behind
2328 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2330 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2331 if (gres != XtGeometryYes && appData.debugMode) {
2332 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2333 programName, gres, w, h, wr, hr);
2336 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2337 XtSetArg(args[1], XtNright, XtChainRight);
2338 XtSetValues(messageWidget, args, 2);
2340 if (appData.titleInWindow) {
2342 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2343 XtSetArg(args[i], XtNheight, &h); i++;
2344 XtGetValues(titleWidget, args, i);
2346 w = boardWidth - 2*bor;
2348 XtSetArg(args[0], XtNwidth, &w);
2349 XtGetValues(menuBarWidget, args, 1);
2350 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2353 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2354 if (gres != XtGeometryYes && appData.debugMode) {
2356 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2357 programName, gres, w, h, wr, hr);
2360 XawFormDoLayout(formWidget, True);
2362 xBoardWindow = XtWindow(boardWidget);
2364 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2365 // not need to go into InitDrawingSizes().
2369 * Create X checkmark bitmap and initialize option menu checks.
2371 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2372 checkmark_bits, checkmark_width, checkmark_height);
2373 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2374 if (appData.alwaysPromoteToQueen) {
2375 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2378 if (appData.animateDragging) {
2379 XtSetValues(XtNameToWidget(menuBarWidget,
2380 "menuOptions.Animate Dragging"),
2383 if (appData.animate) {
2384 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2387 if (appData.autoComment) {
2388 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2391 if (appData.autoCallFlag) {
2392 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2395 if (appData.autoFlipView) {
2396 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2399 if (appData.autoObserve) {
2400 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2403 if (appData.autoRaiseBoard) {
2404 XtSetValues(XtNameToWidget(menuBarWidget,
2405 "menuOptions.Auto Raise Board"), args, 1);
2407 if (appData.autoSaveGames) {
2408 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2411 if (appData.saveGameFile[0] != NULLCHAR) {
2412 /* Can't turn this off from menu */
2413 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2415 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2419 if (appData.blindfold) {
2420 XtSetValues(XtNameToWidget(menuBarWidget,
2421 "menuOptions.Blindfold"), args, 1);
2423 if (appData.flashCount > 0) {
2424 XtSetValues(XtNameToWidget(menuBarWidget,
2425 "menuOptions.Flash Moves"),
2428 if (appData.getMoveList) {
2429 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2433 if (appData.highlightDragging) {
2434 XtSetValues(XtNameToWidget(menuBarWidget,
2435 "menuOptions.Highlight Dragging"),
2439 if (appData.highlightLastMove) {
2440 XtSetValues(XtNameToWidget(menuBarWidget,
2441 "menuOptions.Highlight Last Move"),
2444 if (appData.icsAlarm) {
2445 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2448 if (appData.ringBellAfterMoves) {
2449 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2452 if (appData.oldSaveStyle) {
2453 XtSetValues(XtNameToWidget(menuBarWidget,
2454 "menuOptions.Old Save Style"), args, 1);
2456 if (appData.periodicUpdates) {
2457 XtSetValues(XtNameToWidget(menuBarWidget,
2458 "menuOptions.Periodic Updates"), args, 1);
2460 if (appData.ponderNextMove) {
2461 XtSetValues(XtNameToWidget(menuBarWidget,
2462 "menuOptions.Ponder Next Move"), args, 1);
2464 if (appData.popupExitMessage) {
2465 XtSetValues(XtNameToWidget(menuBarWidget,
2466 "menuOptions.Popup Exit Message"), args, 1);
2468 if (appData.popupMoveErrors) {
2469 XtSetValues(XtNameToWidget(menuBarWidget,
2470 "menuOptions.Popup Move Errors"), args, 1);
2472 if (appData.premove) {
2473 XtSetValues(XtNameToWidget(menuBarWidget,
2474 "menuOptions.Premove"), args, 1);
2476 if (appData.quietPlay) {
2477 XtSetValues(XtNameToWidget(menuBarWidget,
2478 "menuOptions.Quiet Play"), args, 1);
2480 if (appData.showCoords) {
2481 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2484 if (appData.hideThinkingFromHuman) {
2485 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2488 if (appData.testLegality) {
2489 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2492 if (saveSettingsOnExit) {
2493 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2500 ReadBitmap(&wIconPixmap, "icon_white.bm",
2501 icon_white_bits, icon_white_width, icon_white_height);
2502 ReadBitmap(&bIconPixmap, "icon_black.bm",
2503 icon_black_bits, icon_black_width, icon_black_height);
2504 iconPixmap = wIconPixmap;
2506 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2507 XtSetValues(shellWidget, args, i);
2510 * Create a cursor for the board widget.
2512 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2513 XChangeWindowAttributes(xDisplay, xBoardWindow,
2514 CWCursor, &window_attributes);
2517 * Inhibit shell resizing.
2519 shellArgs[0].value = (XtArgVal) &w;
2520 shellArgs[1].value = (XtArgVal) &h;
2521 XtGetValues(shellWidget, shellArgs, 2);
2522 shellArgs[4].value = shellArgs[2].value = w;
2523 shellArgs[5].value = shellArgs[3].value = h;
2524 XtSetValues(shellWidget, &shellArgs[2], 4);
2525 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2526 marginH = h - boardHeight;
2528 CatchDeleteWindow(shellWidget, "QuitProc");
2533 if (appData.bitmapDirectory[0] != NULLCHAR) {
2537 CreateXPMBoard(appData.liteBackTextureFile, 1);
2538 CreateXPMBoard(appData.darkBackTextureFile, 0);
2542 /* Create regular pieces */
2543 if (!useImages) CreatePieces();
2548 if (appData.animate || appData.animateDragging)
2551 XtAugmentTranslations(formWidget,
2552 XtParseTranslationTable(globalTranslations));
2553 XtAugmentTranslations(boardWidget,
2554 XtParseTranslationTable(boardTranslations));
2555 XtAugmentTranslations(whiteTimerWidget,
2556 XtParseTranslationTable(whiteTranslations));
2557 XtAugmentTranslations(blackTimerWidget,
2558 XtParseTranslationTable(blackTranslations));
2560 /* Why is the following needed on some versions of X instead
2561 * of a translation? */
2562 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2563 (XtEventHandler) EventProc, NULL);
2566 /* [AS] Restore layout */
2567 if( wpMoveHistory.visible ) {
2571 if( wpEvalGraph.visible )
2576 if( wpEngineOutput.visible ) {
2577 EngineOutputPopUp();
2582 if (errorExitStatus == -1) {
2583 if (appData.icsActive) {
2584 /* We now wait until we see "login:" from the ICS before
2585 sending the logon script (problems with timestamp otherwise) */
2586 /*ICSInitScript();*/
2587 if (appData.icsInputBox) ICSInputBoxPopUp();
2591 signal(SIGWINCH, TermSizeSigHandler);
2593 signal(SIGINT, IntSigHandler);
2594 signal(SIGTERM, IntSigHandler);
2595 if (*appData.cmailGameName != NULLCHAR) {
2596 signal(SIGUSR1, CmailSigHandler);
2599 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2601 XtSetKeyboardFocus(shellWidget, formWidget);
2603 XtAppMainLoop(appContext);
2604 if (appData.debugMode) fclose(debugFP); // [DM] debug
2611 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2612 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2614 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2615 unlink(gameCopyFilename);
2616 unlink(gamePasteFilename);
2619 RETSIGTYPE TermSizeSigHandler(int sig)
2632 CmailSigHandler(sig)
2638 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2640 /* Activate call-back function CmailSigHandlerCallBack() */
2641 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2643 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2647 CmailSigHandlerCallBack(isr, closure, message, count, error)
2655 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2657 /**** end signal code ****/
2663 /* try to open the icsLogon script, either in the location given
2664 * or in the users HOME directory
2671 f = fopen(appData.icsLogon, "r");
2674 homedir = getenv("HOME");
2675 if (homedir != NULL)
2677 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2678 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2679 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2680 f = fopen(buf, "r");
2685 ProcessICSInitScript(f);
2687 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2696 EditCommentPopDown();
2711 if (!menuBarWidget) return;
2712 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2714 DisplayError("menuStep.Revert", 0);
2716 XtSetSensitive(w, !grey);
2718 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2720 DisplayError("menuStep.Annotate", 0);
2722 XtSetSensitive(w, !grey);
2727 SetMenuEnables(enab)
2731 if (!menuBarWidget) return;
2732 while (enab->name != NULL) {
2733 w = XtNameToWidget(menuBarWidget, enab->name);
2735 DisplayError(enab->name, 0);
2737 XtSetSensitive(w, enab->value);
2743 Enables icsEnables[] = {
2744 { "menuFile.Mail Move", False },
2745 { "menuFile.Reload CMail Message", False },
2746 { "menuMode.Machine Black", False },
2747 { "menuMode.Machine White", False },
2748 { "menuMode.Analysis Mode", False },
2749 { "menuMode.Analyze File", False },
2750 { "menuMode.Two Machines", False },
2752 { "menuHelp.Hint", False },
2753 { "menuHelp.Book", False },
2754 { "menuStep.Move Now", False },
2755 { "menuOptions.Periodic Updates", False },
2756 { "menuOptions.Hide Thinking", False },
2757 { "menuOptions.Ponder Next Move", False },
2759 { "menuStep.Annotate", False },
2763 Enables ncpEnables[] = {
2764 { "menuFile.Mail Move", False },
2765 { "menuFile.Reload CMail Message", False },
2766 { "menuMode.Machine White", False },
2767 { "menuMode.Machine Black", False },
2768 { "menuMode.Analysis Mode", False },
2769 { "menuMode.Analyze File", False },
2770 { "menuMode.Two Machines", False },
2771 { "menuMode.ICS Client", False },
2772 { "menuMode.ICS Input Box", False },
2773 { "Action", False },
2774 { "menuStep.Revert", False },
2775 { "menuStep.Annotate", False },
2776 { "menuStep.Move Now", False },
2777 { "menuStep.Retract Move", False },
2778 { "menuOptions.Auto Comment", False },
2779 { "menuOptions.Auto Flag", False },
2780 { "menuOptions.Auto Flip View", False },
2781 { "menuOptions.Auto Observe", False },
2782 { "menuOptions.Auto Raise Board", False },
2783 { "menuOptions.Get Move List", False },
2784 { "menuOptions.ICS Alarm", False },
2785 { "menuOptions.Move Sound", False },
2786 { "menuOptions.Quiet Play", False },
2787 { "menuOptions.Hide Thinking", False },
2788 { "menuOptions.Periodic Updates", False },
2789 { "menuOptions.Ponder Next Move", False },
2790 { "menuHelp.Hint", False },
2791 { "menuHelp.Book", False },
2795 Enables gnuEnables[] = {
2796 { "menuMode.ICS Client", False },
2797 { "menuMode.ICS Input Box", False },
2798 { "menuAction.Accept", False },
2799 { "menuAction.Decline", False },
2800 { "menuAction.Rematch", False },
2801 { "menuAction.Adjourn", False },
2802 { "menuAction.Stop Examining", False },
2803 { "menuAction.Stop Observing", False },
2804 { "menuAction.Upload to Examine", False },
2805 { "menuStep.Revert", False },
2806 { "menuStep.Annotate", False },
2807 { "menuOptions.Auto Comment", False },
2808 { "menuOptions.Auto Observe", False },
2809 { "menuOptions.Auto Raise Board", False },
2810 { "menuOptions.Get Move List", False },
2811 { "menuOptions.Premove", False },
2812 { "menuOptions.Quiet Play", False },
2814 /* The next two options rely on SetCmailMode being called *after* */
2815 /* SetGNUMode so that when GNU is being used to give hints these */
2816 /* menu options are still available */
2818 { "menuFile.Mail Move", False },
2819 { "menuFile.Reload CMail Message", False },
2823 Enables cmailEnables[] = {
2825 { "menuAction.Call Flag", False },
2826 { "menuAction.Draw", True },
2827 { "menuAction.Adjourn", False },
2828 { "menuAction.Abort", False },
2829 { "menuAction.Stop Observing", False },
2830 { "menuAction.Stop Examining", False },
2831 { "menuFile.Mail Move", True },
2832 { "menuFile.Reload CMail Message", True },
2836 Enables trainingOnEnables[] = {
2837 { "menuMode.Edit Comment", False },
2838 { "menuMode.Pause", False },
2839 { "menuStep.Forward", False },
2840 { "menuStep.Backward", False },
2841 { "menuStep.Forward to End", False },
2842 { "menuStep.Back to Start", False },
2843 { "menuStep.Move Now", False },
2844 { "menuStep.Truncate Game", False },
2848 Enables trainingOffEnables[] = {
2849 { "menuMode.Edit Comment", True },
2850 { "menuMode.Pause", True },
2851 { "menuStep.Forward", True },
2852 { "menuStep.Backward", True },
2853 { "menuStep.Forward to End", True },
2854 { "menuStep.Back to Start", True },
2855 { "menuStep.Move Now", True },
2856 { "menuStep.Truncate Game", True },
2860 Enables machineThinkingEnables[] = {
2861 { "menuFile.Load Game", False },
2862 { "menuFile.Load Next Game", False },
2863 { "menuFile.Load Previous Game", False },
2864 { "menuFile.Reload Same Game", False },
2865 { "menuFile.Paste Game", False },
2866 { "menuFile.Load Position", False },
2867 { "menuFile.Load Next Position", False },
2868 { "menuFile.Load Previous Position", False },
2869 { "menuFile.Reload Same Position", False },
2870 { "menuFile.Paste Position", False },
2871 { "menuMode.Machine White", False },
2872 { "menuMode.Machine Black", False },
2873 { "menuMode.Two Machines", False },
2874 { "menuStep.Retract Move", False },
2878 Enables userThinkingEnables[] = {
2879 { "menuFile.Load Game", True },
2880 { "menuFile.Load Next Game", True },
2881 { "menuFile.Load Previous Game", True },
2882 { "menuFile.Reload Same Game", True },
2883 { "menuFile.Paste Game", True },
2884 { "menuFile.Load Position", True },
2885 { "menuFile.Load Next Position", True },
2886 { "menuFile.Load Previous Position", True },
2887 { "menuFile.Reload Same Position", True },
2888 { "menuFile.Paste Position", True },
2889 { "menuMode.Machine White", True },
2890 { "menuMode.Machine Black", True },
2891 { "menuMode.Two Machines", True },
2892 { "menuStep.Retract Move", True },
2898 SetMenuEnables(icsEnables);
2901 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2902 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2909 SetMenuEnables(ncpEnables);
2915 SetMenuEnables(gnuEnables);
2921 SetMenuEnables(cmailEnables);
2927 SetMenuEnables(trainingOnEnables);
2928 if (appData.showButtonBar) {
2929 XtSetSensitive(buttonBarWidget, False);
2935 SetTrainingModeOff()
2937 SetMenuEnables(trainingOffEnables);
2938 if (appData.showButtonBar) {
2939 XtSetSensitive(buttonBarWidget, True);
2944 SetUserThinkingEnables()
2946 if (appData.noChessProgram) return;
2947 SetMenuEnables(userThinkingEnables);
2951 SetMachineThinkingEnables()
2953 if (appData.noChessProgram) return;
2954 SetMenuEnables(machineThinkingEnables);
2956 case MachinePlaysBlack:
2957 case MachinePlaysWhite:
2958 case TwoMachinesPlay:
2959 XtSetSensitive(XtNameToWidget(menuBarWidget,
2960 ModeToWidgetName(gameMode)), True);
2967 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2968 #define HISTORY_SIZE 64
\r
2969 static char *history[HISTORY_SIZE];
\r
2970 int histIn = 0, histP = 0;
\r
2973 SaveInHistory(char *cmd)
\r
2975 if (history[histIn] != NULL) {
\r
2976 free(history[histIn]);
\r
2977 history[histIn] = NULL;
\r
2979 if (*cmd == NULLCHAR) return;
\r
2980 history[histIn] = StrSave(cmd);
\r
2981 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2982 if (history[histIn] != NULL) {
\r
2983 free(history[histIn]);
\r
2984 history[histIn] = NULL;
\r
2990 PrevInHistory(char *cmd)
\r
2993 if (histP == histIn) {
\r
2994 if (history[histIn] != NULL) free(history[histIn]);
\r
2995 history[histIn] = StrSave(cmd);
\r
2997 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2998 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3000 return history[histP];
\r
3006 if (histP == histIn) return NULL;
\r
3007 histP = (histP + 1) % HISTORY_SIZE;
\r
3008 return history[histP];
\r
3010 // end of borrowed code
\r
3012 #define Abs(n) ((n)<0 ? -(n) : (n))
3015 * Find a font that matches "pattern" that is as close as
3016 * possible to the targetPxlSize. Prefer fonts that are k
3017 * pixels smaller to fonts that are k pixels larger. The
3018 * pattern must be in the X Consortium standard format,
3019 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3020 * The return value should be freed with XtFree when no
3024 FindFont(pattern, targetPxlSize)
3028 char **fonts, *p, *best, *scalable, *scalableTail;
3029 int i, j, nfonts, minerr, err, pxlSize;
3032 char **missing_list;
3034 char *def_string, *base_fnt_lst, strInt[3];
3036 XFontStruct **fnt_list;
3038 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3039 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3040 p = strstr(pattern, "--");
3041 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3042 strcat(base_fnt_lst, strInt);
3043 strcat(base_fnt_lst, strchr(p + 2, '-'));
3045 if ((fntSet = XCreateFontSet(xDisplay,
3049 &def_string)) == NULL) {
3051 fprintf(stderr, _("Unable to create font set.\n"));
3055 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3057 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3059 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3060 programName, pattern);
3068 for (i=0; i<nfonts; i++) {
3071 if (*p != '-') continue;
3073 if (*p == NULLCHAR) break;
3074 if (*p++ == '-') j++;
3076 if (j < 7) continue;
3079 scalable = fonts[i];
3082 err = pxlSize - targetPxlSize;
3083 if (Abs(err) < Abs(minerr) ||
3084 (minerr > 0 && err < 0 && -err == minerr)) {
3090 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3091 /* If the error is too big and there is a scalable font,
3092 use the scalable font. */
3093 int headlen = scalableTail - scalable;
3094 p = (char *) XtMalloc(strlen(scalable) + 10);
3095 while (isdigit(*scalableTail)) scalableTail++;
3096 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3098 p = (char *) XtMalloc(strlen(best) + 2);
3099 safeStrCpy(p, best, strlen(best)+1 );
3101 if (appData.debugMode) {
3102 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3103 pattern, targetPxlSize, p);
3106 if (missing_count > 0)
3107 XFreeStringList(missing_list);
3108 XFreeFontSet(xDisplay, fntSet);
3110 XFreeFontNames(fonts);
3117 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3118 | GCBackground | GCFunction | GCPlaneMask;
3119 XGCValues gc_values;
3122 gc_values.plane_mask = AllPlanes;
3123 gc_values.line_width = lineGap;
3124 gc_values.line_style = LineSolid;
3125 gc_values.function = GXcopy;
3127 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3128 gc_values.background = XBlackPixel(xDisplay, xScreen);
3129 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3131 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3132 gc_values.background = XWhitePixel(xDisplay, xScreen);
3133 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3134 XSetFont(xDisplay, coordGC, coordFontID);
3136 // [HGM] make font for holdings counts (white on black0
3137 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3138 gc_values.background = XBlackPixel(xDisplay, xScreen);
3139 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3140 XSetFont(xDisplay, countGC, countFontID);
3142 if (appData.monoMode) {
3143 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3144 gc_values.background = XWhitePixel(xDisplay, xScreen);
3145 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3147 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3148 gc_values.background = XBlackPixel(xDisplay, xScreen);
3149 lightSquareGC = wbPieceGC
3150 = XtGetGC(shellWidget, value_mask, &gc_values);
3152 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3153 gc_values.background = XWhitePixel(xDisplay, xScreen);
3154 darkSquareGC = bwPieceGC
3155 = XtGetGC(shellWidget, value_mask, &gc_values);
3157 if (DefaultDepth(xDisplay, xScreen) == 1) {
3158 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3159 gc_values.function = GXcopyInverted;
3160 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3161 gc_values.function = GXcopy;
3162 if (XBlackPixel(xDisplay, xScreen) == 1) {
3163 bwPieceGC = darkSquareGC;
3164 wbPieceGC = copyInvertedGC;
3166 bwPieceGC = copyInvertedGC;
3167 wbPieceGC = lightSquareGC;
3171 gc_values.foreground = highlightSquareColor;
3172 gc_values.background = highlightSquareColor;
3173 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3175 gc_values.foreground = premoveHighlightColor;
3176 gc_values.background = premoveHighlightColor;
3177 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3179 gc_values.foreground = lightSquareColor;
3180 gc_values.background = darkSquareColor;
3181 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3183 gc_values.foreground = darkSquareColor;
3184 gc_values.background = lightSquareColor;
3185 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3187 gc_values.foreground = jailSquareColor;
3188 gc_values.background = jailSquareColor;
3189 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3191 gc_values.foreground = whitePieceColor;
3192 gc_values.background = darkSquareColor;
3193 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3195 gc_values.foreground = whitePieceColor;
3196 gc_values.background = lightSquareColor;
3197 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3199 gc_values.foreground = whitePieceColor;
3200 gc_values.background = jailSquareColor;
3201 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3203 gc_values.foreground = blackPieceColor;
3204 gc_values.background = darkSquareColor;
3205 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3207 gc_values.foreground = blackPieceColor;
3208 gc_values.background = lightSquareColor;
3209 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3211 gc_values.foreground = blackPieceColor;
3212 gc_values.background = jailSquareColor;
3213 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3217 void loadXIM(xim, xmask, filename, dest, mask)
3230 fp = fopen(filename, "rb");
3232 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3239 for (y=0; y<h; ++y) {
3240 for (x=0; x<h; ++x) {
3245 XPutPixel(xim, x, y, blackPieceColor);
3247 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3250 XPutPixel(xim, x, y, darkSquareColor);
3252 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3255 XPutPixel(xim, x, y, whitePieceColor);
3257 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3260 XPutPixel(xim, x, y, lightSquareColor);
3262 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3268 /* create Pixmap of piece */
3269 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3271 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3274 /* create Pixmap of clipmask
3275 Note: We assume the white/black pieces have the same
3276 outline, so we make only 6 masks. This is okay
3277 since the XPM clipmask routines do the same. */
3279 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3281 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3284 /* now create the 1-bit version */
3285 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3288 values.foreground = 1;
3289 values.background = 0;
3291 /* Don't use XtGetGC, not read only */
3292 maskGC = XCreateGC(xDisplay, *mask,
3293 GCForeground | GCBackground, &values);
3294 XCopyPlane(xDisplay, temp, *mask, maskGC,
3295 0, 0, squareSize, squareSize, 0, 0, 1);
3296 XFreePixmap(xDisplay, temp);
3301 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3303 void CreateXIMPieces()
3308 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3313 /* The XSynchronize calls were copied from CreatePieces.
3314 Not sure if needed, but can't hurt */
3315 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3318 /* temp needed by loadXIM() */
3319 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3320 0, 0, ss, ss, AllPlanes, XYPixmap);
3322 if (strlen(appData.pixmapDirectory) == 0) {
3326 if (appData.monoMode) {
3327 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3331 fprintf(stderr, _("\nLoading XIMs...\n"));
3333 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3334 fprintf(stderr, "%d", piece+1);
3335 for (kind=0; kind<4; kind++) {
3336 fprintf(stderr, ".");
3337 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3338 ExpandPathName(appData.pixmapDirectory),
3339 piece <= (int) WhiteKing ? "" : "w",
3340 pieceBitmapNames[piece],
3342 ximPieceBitmap[kind][piece] =
3343 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3344 0, 0, ss, ss, AllPlanes, XYPixmap);
3345 if (appData.debugMode)
3346 fprintf(stderr, _("(File:%s:) "), buf);
3347 loadXIM(ximPieceBitmap[kind][piece],
3349 &(xpmPieceBitmap2[kind][piece]),
3350 &(ximMaskPm2[piece]));
3351 if(piece <= (int)WhiteKing)
3352 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3354 fprintf(stderr," ");
3356 /* Load light and dark squares */
3357 /* If the LSQ and DSQ pieces don't exist, we will
3358 draw them with solid squares. */
3359 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3360 if (access(buf, 0) != 0) {
3364 fprintf(stderr, _("light square "));
3366 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3367 0, 0, ss, ss, AllPlanes, XYPixmap);
3368 if (appData.debugMode)
3369 fprintf(stderr, _("(File:%s:) "), buf);
3371 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3372 fprintf(stderr, _("dark square "));
3373 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3374 ExpandPathName(appData.pixmapDirectory), ss);
3375 if (appData.debugMode)
3376 fprintf(stderr, _("(File:%s:) "), buf);
3378 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3379 0, 0, ss, ss, AllPlanes, XYPixmap);
3380 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3381 xpmJailSquare = xpmLightSquare;
3383 fprintf(stderr, _("Done.\n"));
3385 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3389 void CreateXPMBoard(char *s, int kind)
3393 if(s == NULL || *s == 0 || *s == '*') return;
3394 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3395 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3399 void CreateXPMPieces()
3403 u_int ss = squareSize;
3405 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3406 XpmColorSymbol symbols[4];
3408 /* The XSynchronize calls were copied from CreatePieces.
3409 Not sure if needed, but can't hurt */
3410 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3412 /* Setup translations so piece colors match square colors */
3413 symbols[0].name = "light_piece";
3414 symbols[0].value = appData.whitePieceColor;
3415 symbols[1].name = "dark_piece";
3416 symbols[1].value = appData.blackPieceColor;
3417 symbols[2].name = "light_square";
3418 symbols[2].value = appData.lightSquareColor;
3419 symbols[3].name = "dark_square";
3420 symbols[3].value = appData.darkSquareColor;
3422 attr.valuemask = XpmColorSymbols;
3423 attr.colorsymbols = symbols;
3424 attr.numsymbols = 4;
3426 if (appData.monoMode) {
3427 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3431 if (strlen(appData.pixmapDirectory) == 0) {
3432 XpmPieces* pieces = builtInXpms;
3435 while (pieces->size != squareSize && pieces->size) pieces++;
3436 if (!pieces->size) {
3437 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3440 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3441 for (kind=0; kind<4; kind++) {
3443 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3444 pieces->xpm[piece][kind],
3445 &(xpmPieceBitmap2[kind][piece]),
3446 NULL, &attr)) != 0) {
3447 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3451 if(piece <= (int) WhiteKing)
3452 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3456 xpmJailSquare = xpmLightSquare;
3460 fprintf(stderr, _("\nLoading XPMs...\n"));
3463 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3464 fprintf(stderr, "%d ", piece+1);
3465 for (kind=0; kind<4; kind++) {
3466 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3467 ExpandPathName(appData.pixmapDirectory),
3468 piece > (int) WhiteKing ? "w" : "",
3469 pieceBitmapNames[piece],
3471 if (appData.debugMode) {
3472 fprintf(stderr, _("(File:%s:) "), buf);
3474 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3475 &(xpmPieceBitmap2[kind][piece]),
3476 NULL, &attr)) != 0) {
3477 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3478 // [HGM] missing: read of unorthodox piece failed; substitute King.
3479 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3480 ExpandPathName(appData.pixmapDirectory),
3482 if (appData.debugMode) {
3483 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3485 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3486 &(xpmPieceBitmap2[kind][piece]),
3490 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3495 if(piece <= (int) WhiteKing)
3496 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3499 /* Load light and dark squares */
3500 /* If the LSQ and DSQ pieces don't exist, we will
3501 draw them with solid squares. */
3502 fprintf(stderr, _("light square "));
3503 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3504 if (access(buf, 0) != 0) {
3508 if (appData.debugMode)
3509 fprintf(stderr, _("(File:%s:) "), buf);
3511 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3512 &xpmLightSquare, NULL, &attr)) != 0) {
3513 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3516 fprintf(stderr, _("dark square "));
3517 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3518 ExpandPathName(appData.pixmapDirectory), ss);
3519 if (appData.debugMode) {
3520 fprintf(stderr, _("(File:%s:) "), buf);
3522 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3523 &xpmDarkSquare, NULL, &attr)) != 0) {
3524 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3528 xpmJailSquare = xpmLightSquare;
3529 fprintf(stderr, _("Done.\n"));
3531 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3534 #endif /* HAVE_LIBXPM */
3537 /* No built-in bitmaps */
3542 u_int ss = squareSize;
3544 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3547 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3548 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3549 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3550 pieceBitmapNames[piece],
3551 ss, kind == SOLID ? 's' : 'o');
3552 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3553 if(piece <= (int)WhiteKing)
3554 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3558 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3562 /* With built-in bitmaps */
3565 BuiltInBits* bib = builtInBits;
3568 u_int ss = squareSize;
3570 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3573 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3575 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3576 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3577 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3578 pieceBitmapNames[piece],
3579 ss, kind == SOLID ? 's' : 'o');
3580 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3581 bib->bits[kind][piece], ss, ss);
3582 if(piece <= (int)WhiteKing)
3583 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3587 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3592 void ReadBitmap(pm, name, bits, wreq, hreq)
3595 unsigned char bits[];
3601 char msg[MSG_SIZ], fullname[MSG_SIZ];
3603 if (*appData.bitmapDirectory != NULLCHAR) {
3604 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3605 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3606 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3607 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3608 &w, &h, pm, &x_hot, &y_hot);
3609 fprintf(stderr, "load %s\n", name);
3610 if (errcode != BitmapSuccess) {
3612 case BitmapOpenFailed:
3613 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3615 case BitmapFileInvalid:
3616 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3618 case BitmapNoMemory:
3619 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3623 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3627 fprintf(stderr, _("%s: %s...using built-in\n"),
3629 } else if (w != wreq || h != hreq) {
3631 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3632 programName, fullname, w, h, wreq, hreq);
3638 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3647 if (lineGap == 0) return;
3649 /* [HR] Split this into 2 loops for non-square boards. */
3651 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3652 gridSegments[i].x1 = 0;
3653 gridSegments[i].x2 =
3654 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3655 gridSegments[i].y1 = gridSegments[i].y2
3656 = lineGap / 2 + (i * (squareSize + lineGap));
3659 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3660 gridSegments[j + i].y1 = 0;
3661 gridSegments[j + i].y2 =
3662 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3663 gridSegments[j + i].x1 = gridSegments[j + i].x2
3664 = lineGap / 2 + (j * (squareSize + lineGap));
3668 static void MenuBarSelect(w, addr, index)
3673 XtActionProc proc = (XtActionProc) addr;
3675 (proc)(NULL, NULL, NULL, NULL);
3678 void CreateMenuBarPopup(parent, name, mb)
3688 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3691 XtSetArg(args[j], XtNleftMargin, 20); j++;
3692 XtSetArg(args[j], XtNrightMargin, 20); j++;
3694 while (mi->string != NULL) {
3695 if (strcmp(mi->string, "----") == 0) {
3696 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3699 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3700 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3702 XtAddCallback(entry, XtNcallback,
3703 (XtCallbackProc) MenuBarSelect,
3704 (caddr_t) mi->proc);
3710 Widget CreateMenuBar(mb)
3714 Widget anchor, menuBar;
3716 char menuName[MSG_SIZ];
3719 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3720 XtSetArg(args[j], XtNvSpace, 0); j++;
3721 XtSetArg(args[j], XtNborderWidth, 0); j++;
3722 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3723 formWidget, args, j);
3725 while (mb->name != NULL) {
3726 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3727 strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
3729 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3732 shortName[0] = _(mb->name)[0];
3733 shortName[1] = NULLCHAR;
3734 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3737 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3740 XtSetArg(args[j], XtNborderWidth, 0); j++;
3741 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3743 CreateMenuBarPopup(menuBar, menuName, mb);
3749 Widget CreateButtonBar(mi)
3753 Widget button, buttonBar;
3757 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3759 XtSetArg(args[j], XtNhSpace, 0); j++;
3761 XtSetArg(args[j], XtNborderWidth, 0); j++;
3762 XtSetArg(args[j], XtNvSpace, 0); j++;
3763 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3764 formWidget, args, j);
3766 while (mi->string != NULL) {
3769 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3770 XtSetArg(args[j], XtNborderWidth, 0); j++;
3772 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3773 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3774 buttonBar, args, j);
3775 XtAddCallback(button, XtNcallback,
3776 (XtCallbackProc) MenuBarSelect,
3777 (caddr_t) mi->proc);
3784 CreatePieceMenu(name, color)
3791 ChessSquare selection;
3793 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3794 boardWidget, args, 0);
3796 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3797 String item = pieceMenuStrings[color][i];
3799 if (strcmp(item, "----") == 0) {
3800 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3803 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3804 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3806 selection = pieceMenuTranslation[color][i];
3807 XtAddCallback(entry, XtNcallback,
3808 (XtCallbackProc) PieceMenuSelect,
3809 (caddr_t) selection);
3810 if (selection == WhitePawn || selection == BlackPawn) {
3811 XtSetArg(args[0], XtNpopupOnEntry, entry);
3812 XtSetValues(menu, args, 1);
3825 ChessSquare selection;
3827 whitePieceMenu = CreatePieceMenu("menuW", 0);
3828 blackPieceMenu = CreatePieceMenu("menuB", 1);
3830 XtRegisterGrabAction(PieceMenuPopup, True,
3831 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3832 GrabModeAsync, GrabModeAsync);
3834 XtSetArg(args[0], XtNlabel, _("Drop"));
3835 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3836 boardWidget, args, 1);
3837 for (i = 0; i < DROP_MENU_SIZE; i++) {
3838 String item = dropMenuStrings[i];
3840 if (strcmp(item, "----") == 0) {
3841 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3844 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3845 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3847 selection = dropMenuTranslation[i];
3848 XtAddCallback(entry, XtNcallback,
3849 (XtCallbackProc) DropMenuSelect,
3850 (caddr_t) selection);
3855 void SetupDropMenu()
3863 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3864 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3865 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3866 dmEnables[i].piece);
3867 XtSetSensitive(entry, p != NULL || !appData.testLegality
3868 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3869 && !appData.icsActive));
3871 while (p && *p++ == dmEnables[i].piece) count++;
3872 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3874 XtSetArg(args[j], XtNlabel, label); j++;
3875 XtSetValues(entry, args, j);
3879 void PieceMenuPopup(w, event, params, num_params)
3883 Cardinal *num_params;
3885 String whichMenu; int menuNr;
3886 if (event->type == ButtonRelease)
3887 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3888 else if (event->type == ButtonPress)
3889 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3891 case 0: whichMenu = params[0]; break;
3892 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3894 case -1: if (errorUp) ErrorPopDown();
3897 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3900 static void PieceMenuSelect(w, piece, junk)
3905 if (pmFromX < 0 || pmFromY < 0) return;
3906 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3909 static void DropMenuSelect(w, piece, junk)
3914 if (pmFromX < 0 || pmFromY < 0) return;
3915 DropMenuEvent(piece, pmFromX, pmFromY);
3918 void WhiteClock(w, event, prms, nprms)
3924 if (gameMode == EditPosition || gameMode == IcsExamining) {
3925 SetWhiteToPlayEvent();
3926 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3931 void BlackClock(w, event, prms, nprms)
3937 if (gameMode == EditPosition || gameMode == IcsExamining) {
3938 SetBlackToPlayEvent();
3939 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3946 * If the user selects on a border boundary, return -1; if off the board,
3947 * return -2. Otherwise map the event coordinate to the square.
3949 int EventToSquare(x, limit)
3957 if ((x % (squareSize + lineGap)) >= squareSize)
3959 x /= (squareSize + lineGap);
3965 static void do_flash_delay(msec)
3971 static void drawHighlight(file, rank, gc)
3977 if (lineGap == 0 || appData.blindfold) return;
3980 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3981 (squareSize + lineGap);
3982 y = lineGap/2 + rank * (squareSize + lineGap);
3984 x = lineGap/2 + file * (squareSize + lineGap);
3985 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3986 (squareSize + lineGap);
3989 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3990 squareSize+lineGap, squareSize+lineGap);
3993 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3994 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3997 SetHighlights(fromX, fromY, toX, toY)
3998 int fromX, fromY, toX, toY;
4000 if (hi1X != fromX || hi1Y != fromY) {
4001 if (hi1X >= 0 && hi1Y >= 0) {
4002 drawHighlight(hi1X, hi1Y, lineGC);
4004 } // [HGM] first erase both, then draw new!
4005 if (hi2X != toX || hi2Y != toY) {
4006 if (hi2X >= 0 && hi2Y >= 0) {
4007 drawHighlight(hi2X, hi2Y, lineGC);
4010 if (hi1X != fromX || hi1Y != fromY) {
4011 if (fromX >= 0 && fromY >= 0) {
4012 drawHighlight(fromX, fromY, highlineGC);
4015 if (hi2X != toX || hi2Y != toY) {
4016 if (toX >= 0 && toY >= 0) {
4017 drawHighlight(toX, toY, highlineGC);
4029 SetHighlights(-1, -1, -1, -1);
4034 SetPremoveHighlights(fromX, fromY, toX, toY)
4035 int fromX, fromY, toX, toY;
4037 if (pm1X != fromX || pm1Y != fromY) {
4038 if (pm1X >= 0 && pm1Y >= 0) {
4039 drawHighlight(pm1X, pm1Y, lineGC);
4041 if (fromX >= 0 && fromY >= 0) {
4042 drawHighlight(fromX, fromY, prelineGC);
4045 if (pm2X != toX || pm2Y != toY) {
4046 if (pm2X >= 0 && pm2Y >= 0) {
4047 drawHighlight(pm2X, pm2Y, lineGC);
4049 if (toX >= 0 && toY >= 0) {
4050 drawHighlight(toX, toY, prelineGC);
4060 ClearPremoveHighlights()
4062 SetPremoveHighlights(-1, -1, -1, -1);
4065 static int CutOutSquare(x, y, x0, y0, kind)
4066 int x, y, *x0, *y0, kind;
4068 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4069 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4071 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4072 if(textureW[kind] < W*squareSize)
4073 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4075 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4076 if(textureH[kind] < H*squareSize)
4077 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4079 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4083 static void BlankSquare(x, y, color, piece, dest, fac)
4084 int x, y, color, fac;
4087 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4089 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4090 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4091 squareSize, squareSize, x*fac, y*fac);
4093 if (useImages && useImageSqs) {
4097 pm = xpmLightSquare;
4102 case 2: /* neutral */
4107 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4108 squareSize, squareSize, x*fac, y*fac);
4118 case 2: /* neutral */
4123 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4128 I split out the routines to draw a piece so that I could
4129 make a generic flash routine.
4131 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4133 int square_color, x, y;
4136 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4137 switch (square_color) {
4139 case 2: /* neutral */
4141 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4142 ? *pieceToOutline(piece)
4143 : *pieceToSolid(piece),
4144 dest, bwPieceGC, 0, 0,
4145 squareSize, squareSize, x, y);
4148 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4149 ? *pieceToSolid(piece)
4150 : *pieceToOutline(piece),
4151 dest, wbPieceGC, 0, 0,
4152 squareSize, squareSize, x, y);
4157 static void monoDrawPiece(piece, square_color, x, y, dest)
4159 int square_color, x, y;
4162 switch (square_color) {
4164 case 2: /* neutral */
4166 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4167 ? *pieceToOutline(piece)
4168 : *pieceToSolid(piece),
4169 dest, bwPieceGC, 0, 0,
4170 squareSize, squareSize, x, y, 1);
4173 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4174 ? *pieceToSolid(piece)
4175 : *pieceToOutline(piece),
4176 dest, wbPieceGC, 0, 0,
4177 squareSize, squareSize, x, y, 1);
4182 static void colorDrawPiece(piece, square_color, x, y, dest)
4184 int square_color, x, y;
4187 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4188 switch (square_color) {
4190 XCopyPlane(xDisplay, *pieceToSolid(piece),
4191 dest, (int) piece < (int) BlackPawn
4192 ? wlPieceGC : blPieceGC, 0, 0,
4193 squareSize, squareSize, x, y, 1);
4196 XCopyPlane(xDisplay, *pieceToSolid(piece),
4197 dest, (int) piece < (int) BlackPawn
4198 ? wdPieceGC : bdPieceGC, 0, 0,
4199 squareSize, squareSize, x, y, 1);
4201 case 2: /* neutral */
4203 XCopyPlane(xDisplay, *pieceToSolid(piece),
4204 dest, (int) piece < (int) BlackPawn
4205 ? wjPieceGC : bjPieceGC, 0, 0,
4206 squareSize, squareSize, x, y, 1);
4211 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4213 int square_color, x, y;
4216 int kind, p = piece;
4218 switch (square_color) {
4220 case 2: /* neutral */
4222 if ((int)piece < (int) BlackPawn) {
4230 if ((int)piece < (int) BlackPawn) {
4238 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4239 if(useTexture & square_color+1) {
4240 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4241 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4242 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4243 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4244 XSetClipMask(xDisplay, wlPieceGC, None);
4245 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4247 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4248 dest, wlPieceGC, 0, 0,
4249 squareSize, squareSize, x, y);
4252 typedef void (*DrawFunc)();
4254 DrawFunc ChooseDrawFunc()
4256 if (appData.monoMode) {
4257 if (DefaultDepth(xDisplay, xScreen) == 1) {
4258 return monoDrawPiece_1bit;
4260 return monoDrawPiece;
4264 return colorDrawPieceImage;
4266 return colorDrawPiece;
4270 /* [HR] determine square color depending on chess variant. */
4271 static int SquareColor(row, column)
4276 if (gameInfo.variant == VariantXiangqi) {
4277 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4279 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4281 } else if (row <= 4) {
4287 square_color = ((column + row) % 2) == 1;
4290 /* [hgm] holdings: next line makes all holdings squares light */
4291 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4293 return square_color;
4296 void DrawSquare(row, column, piece, do_flash)
4297 int row, column, do_flash;
4300 int square_color, x, y, direction, font_ascent, font_descent;
4303 XCharStruct overall;
4307 /* Calculate delay in milliseconds (2-delays per complete flash) */
4308 flash_delay = 500 / appData.flashRate;
4311 x = lineGap + ((BOARD_WIDTH-1)-column) *
4312 (squareSize + lineGap);
4313 y = lineGap + row * (squareSize + lineGap);
4315 x = lineGap + column * (squareSize + lineGap);
4316 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4317 (squareSize + lineGap);
4320 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4322 square_color = SquareColor(row, column);
4324 if ( // [HGM] holdings: blank out area between board and holdings
4325 column == BOARD_LEFT-1 || column == BOARD_RGHT
4326 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4327 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4328 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4330 // [HGM] print piece counts next to holdings
4331 string[1] = NULLCHAR;
4332 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4333 string[0] = '0' + piece;
4334 XTextExtents(countFontStruct, string, 1, &direction,
4335 &font_ascent, &font_descent, &overall);
4336 if (appData.monoMode) {
4337 XDrawImageString(xDisplay, xBoardWindow, countGC,
4338 x + squareSize - overall.width - 2,
4339 y + font_ascent + 1, string, 1);
4341 XDrawString(xDisplay, xBoardWindow, countGC,
4342 x + squareSize - overall.width - 2,
4343 y + font_ascent + 1, string, 1);
4346 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4347 string[0] = '0' + piece;
4348 XTextExtents(countFontStruct, string, 1, &direction,
4349 &font_ascent, &font_descent, &overall);
4350 if (appData.monoMode) {
4351 XDrawImageString(xDisplay, xBoardWindow, countGC,
4352 x + 2, y + font_ascent + 1, string, 1);
4354 XDrawString(xDisplay, xBoardWindow, countGC,
4355 x + 2, y + font_ascent + 1, string, 1);
4359 if (piece == EmptySquare || appData.blindfold) {
4360 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4362 drawfunc = ChooseDrawFunc();
4363 if (do_flash && appData.flashCount > 0) {
4364 for (i=0; i<appData.flashCount; ++i) {
4366 drawfunc(piece, square_color, x, y, xBoardWindow);
4367 XSync(xDisplay, False);
4368 do_flash_delay(flash_delay);
4370 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4371 XSync(xDisplay, False);
4372 do_flash_delay(flash_delay);
4375 drawfunc(piece, square_color, x, y, xBoardWindow);
4379 string[1] = NULLCHAR;
4380 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4381 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4382 string[0] = 'a' + column - BOARD_LEFT;
4383 XTextExtents(coordFontStruct, string, 1, &direction,
4384 &font_ascent, &font_descent, &overall);
4385 if (appData.monoMode) {
4386 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4387 x + squareSize - overall.width - 2,
4388 y + squareSize - font_descent - 1, string, 1);
4390 XDrawString(xDisplay, xBoardWindow, coordGC,
4391 x + squareSize - overall.width - 2,
4392 y + squareSize - font_descent - 1, string, 1);
4395 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4396 string[0] = ONE + row;
4397 XTextExtents(coordFontStruct, string, 1, &direction,
4398 &font_ascent, &font_descent, &overall);
4399 if (appData.monoMode) {
4400 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4401 x + 2, y + font_ascent + 1, string, 1);
4403 XDrawString(xDisplay, xBoardWindow, coordGC,
4404 x + 2, y + font_ascent + 1, string, 1);
4407 if(!partnerUp && marker[row][column]) {
4408 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4409 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4414 /* Why is this needed on some versions of X? */
4415 void EventProc(widget, unused, event)
4420 if (!XtIsRealized(widget))
4423 switch (event->type) {
4425 if (event->xexpose.count > 0) return; /* no clipping is done */
4426 XDrawPosition(widget, True, NULL);
4427 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4428 flipView = !flipView; partnerUp = !partnerUp;
4429 XDrawPosition(widget, True, NULL);
4430 flipView = !flipView; partnerUp = !partnerUp;
4434 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4441 void DrawPosition(fullRedraw, board)
4442 /*Boolean*/int fullRedraw;
4445 XDrawPosition(boardWidget, fullRedraw, board);
4448 /* Returns 1 if there are "too many" differences between b1 and b2
4449 (i.e. more than 1 move was made) */
4450 static int too_many_diffs(b1, b2)
4456 for (i=0; i<BOARD_HEIGHT; ++i) {
4457 for (j=0; j<BOARD_WIDTH; ++j) {
4458 if (b1[i][j] != b2[i][j]) {
4459 if (++c > 4) /* Castling causes 4 diffs */
4468 /* Matrix describing castling maneuvers */
4469 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4470 static int castling_matrix[4][5] = {
4471 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4472 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4473 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4474 { 7, 7, 4, 5, 6 } /* 0-0, black */
4477 /* Checks whether castling occurred. If it did, *rrow and *rcol
4478 are set to the destination (row,col) of the rook that moved.
4480 Returns 1 if castling occurred, 0 if not.
4482 Note: Only handles a max of 1 castling move, so be sure
4483 to call too_many_diffs() first.
4485 static int check_castle_draw(newb, oldb, rrow, rcol)
4492 /* For each type of castling... */
4493 for (i=0; i<4; ++i) {
4494 r = castling_matrix[i];
4496 /* Check the 4 squares involved in the castling move */
4498 for (j=1; j<=4; ++j) {
4499 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4506 /* All 4 changed, so it must be a castling move */
4515 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4516 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4518 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4521 void DrawSeekBackground( int left, int top, int right, int bottom )
4523 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4526 void DrawSeekText(char *buf, int x, int y)
4528 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4531 void DrawSeekDot(int x, int y, int colorNr)
4533 int square = colorNr & 0x80;
4536 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4538 XFillRectangle(xDisplay, xBoardWindow, color,
4539 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4541 XFillArc(xDisplay, xBoardWindow, color,
4542 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4545 static int damage[2][BOARD_RANKS][BOARD_FILES];
4548 * event handler for redrawing the board
4550 void XDrawPosition(w, repaint, board)
4552 /*Boolean*/int repaint;
4556 static int lastFlipView = 0;
4557 static int lastBoardValid[2] = {0, 0};
4558 static Board lastBoard[2];
4561 int nr = twoBoards*partnerUp;
4563 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4565 if (board == NULL) {
4566 if (!lastBoardValid[nr]) return;
4567 board = lastBoard[nr];
4569 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4570 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4571 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4576 * It would be simpler to clear the window with XClearWindow()
4577 * but this causes a very distracting flicker.
4580 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4582 /* If too much changes (begin observing new game, etc.), don't
4584 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4586 /* Special check for castling so we don't flash both the king
4587 and the rook (just flash the king). */
4589 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4590 /* Draw rook with NO flashing. King will be drawn flashing later */
4591 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4592 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4596 /* First pass -- Draw (newly) empty squares and repair damage.
4597 This prevents you from having a piece show up twice while it
4598 is flashing on its new square */
4599 for (i = 0; i < BOARD_HEIGHT; i++)
4600 for (j = 0; j < BOARD_WIDTH; j++)
4601 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4602 || damage[nr][i][j]) {
4603 DrawSquare(i, j, board[i][j], 0);
4604 damage[nr][i][j] = False;
4607 /* Second pass -- Draw piece(s) in new position and flash them */
4608 for (i = 0; i < BOARD_HEIGHT; i++)
4609 for (j = 0; j < BOARD_WIDTH; j++)
4610 if (board[i][j] != lastBoard[nr][i][j]) {
4611 DrawSquare(i, j, board[i][j], do_flash);
4615 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4616 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4617 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4619 for (i = 0; i < BOARD_HEIGHT; i++)
4620 for (j = 0; j < BOARD_WIDTH; j++) {
4621 DrawSquare(i, j, board[i][j], 0);
4622 damage[nr][i][j] = False;
4626 CopyBoard(lastBoard[nr], board);
4627 lastBoardValid[nr] = 1;
4628 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4629 lastFlipView = flipView;
4631 /* Draw highlights */
4632 if (pm1X >= 0 && pm1Y >= 0) {
4633 drawHighlight(pm1X, pm1Y, prelineGC);
4635 if (pm2X >= 0 && pm2Y >= 0) {
4636 drawHighlight(pm2X, pm2Y, prelineGC);
4638 if (hi1X >= 0 && hi1Y >= 0) {
4639 drawHighlight(hi1X, hi1Y, highlineGC);
4641 if (hi2X >= 0 && hi2Y >= 0) {
4642 drawHighlight(hi2X, hi2Y, highlineGC);
4645 /* If piece being dragged around board, must redraw that too */
4648 XSync(xDisplay, False);
4653 * event handler for redrawing the board
4655 void DrawPositionProc(w, event, prms, nprms)
4661 XDrawPosition(w, True, NULL);
4666 * event handler for parsing user moves
4668 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4669 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4670 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4671 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4672 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4673 // and at the end FinishMove() to perform the move after optional promotion popups.
4674 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4675 void HandleUserMove(w, event, prms, nprms)
4681 if (w != boardWidget || errorExitStatus != -1) return;
4682 if(nprms) shiftKey = !strcmp(prms[0], "1");
4685 if (event->type == ButtonPress) {
4686 XtPopdown(promotionShell);
4687 XtDestroyWidget(promotionShell);
4688 promotionUp = False;
4696 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4697 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4698 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4701 void AnimateUserMove (Widget w, XEvent * event,
4702 String * params, Cardinal * nParams)
4704 DragPieceMove(event->xmotion.x, event->xmotion.y);
4707 void HandlePV (Widget w, XEvent * event,
4708 String * params, Cardinal * nParams)
4709 { // [HGM] pv: walk PV
4710 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4713 Widget CommentCreate(name, text, mutable, callback, lines)
4715 int /*Boolean*/ mutable;
4716 XtCallbackProc callback;
4720 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4725 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4726 XtGetValues(boardWidget, args, j);
4729 XtSetArg(args[j], XtNresizable, True); j++;
4732 XtCreatePopupShell(name, topLevelShellWidgetClass,
4733 shellWidget, args, j);
4736 XtCreatePopupShell(name, transientShellWidgetClass,
4737 shellWidget, args, j);
4740 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4741 layoutArgs, XtNumber(layoutArgs));
4743 XtCreateManagedWidget("form", formWidgetClass, layout,
4744 formArgs, XtNumber(formArgs));
4748 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4749 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4751 XtSetArg(args[j], XtNstring, text); j++;
4752 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4753 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4754 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4755 XtSetArg(args[j], XtNright, XtChainRight); j++;
4756 XtSetArg(args[j], XtNresizable, True); j++;
4757 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4758 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4759 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4760 XtSetArg(args[j], XtNautoFill, True); j++;
4761 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4763 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4764 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4768 XtSetArg(args[j], XtNfromVert, edit); j++;
4769 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4770 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4771 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4772 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4774 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4775 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4778 XtSetArg(args[j], XtNfromVert, edit); j++;
4779 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4780 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4781 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4782 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4783 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4785 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4786 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4789 XtSetArg(args[j], XtNfromVert, edit); j++;
4790 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4791 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4792 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4793 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4794 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4796 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4797 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4800 XtSetArg(args[j], XtNfromVert, edit); j++;
4801 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4802 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4803 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4804 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4806 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4807 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4810 XtSetArg(args[j], XtNfromVert, edit); j++;
4811 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4812 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4813 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4814 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4815 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4817 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4818 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4821 XtRealizeWidget(shell);
4823 if (commentX == -1) {
4826 Dimension pw_height;
4827 Dimension ew_height;
4830 XtSetArg(args[j], XtNheight, &ew_height); j++;
4831 XtGetValues(edit, args, j);
4834 XtSetArg(args[j], XtNheight, &pw_height); j++;
4835 XtGetValues(shell, args, j);
4836 commentH = pw_height + (lines - 1) * ew_height;
4837 commentW = bw_width - 16;
4839 XSync(xDisplay, False);
4841 /* This code seems to tickle an X bug if it is executed too soon
4842 after xboard starts up. The coordinates get transformed as if
4843 the main window was positioned at (0, 0).
4845 XtTranslateCoords(shellWidget,
4846 (bw_width - commentW) / 2, 0 - commentH / 2,
4847 &commentX, &commentY);
4849 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4850 RootWindowOfScreen(XtScreen(shellWidget)),
4851 (bw_width - commentW) / 2, 0 - commentH / 2,
4856 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4859 if(wpComment.width > 0) {
4860 commentX = wpComment.x;
4861 commentY = wpComment.y;
4862 commentW = wpComment.width;
4863 commentH = wpComment.height;
4867 XtSetArg(args[j], XtNheight, commentH); j++;
4868 XtSetArg(args[j], XtNwidth, commentW); j++;
4869 XtSetArg(args[j], XtNx, commentX); j++;
4870 XtSetArg(args[j], XtNy, commentY); j++;
4871 XtSetValues(shell, args, j);
4872 XtSetKeyboardFocus(shell, edit);
4877 /* Used for analysis window and ICS input window */
4878 Widget MiscCreate(name, text, mutable, callback, lines)
4880 int /*Boolean*/ mutable;
4881 XtCallbackProc callback;
4885 Widget shell, layout, form, edit;
4887 Dimension bw_width, pw_height, ew_height, w, h;
4893 XtSetArg(args[j], XtNresizable, True); j++;
4896 XtCreatePopupShell(name, topLevelShellWidgetClass,
4897 shellWidget, args, j);
4900 XtCreatePopupShell(name, transientShellWidgetClass,
4901 shellWidget, args, j);
4904 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4905 layoutArgs, XtNumber(layoutArgs));
4907 XtCreateManagedWidget("form", formWidgetClass, layout,
4908 formArgs, XtNumber(formArgs));
4912 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4913 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4915 XtSetArg(args[j], XtNstring, text); j++;
4916 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4917 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4918 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4919 XtSetArg(args[j], XtNright, XtChainRight); j++;
4920 XtSetArg(args[j], XtNresizable, True); j++;
4921 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4922 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4923 XtSetArg(args[j], XtNautoFill, True); j++;
4924 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4926 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4928 XtRealizeWidget(shell);
4931 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4932 XtGetValues(boardWidget, args, j);
4935 XtSetArg(args[j], XtNheight, &ew_height); j++;
4936 XtGetValues(edit, args, j);
4939 XtSetArg(args[j], XtNheight, &pw_height); j++;
4940 XtGetValues(shell, args, j);
4941 h = pw_height + (lines - 1) * ew_height;
4944 XSync(xDisplay, False);
4946 /* This code seems to tickle an X bug if it is executed too soon
4947 after xboard starts up. The coordinates get transformed as if
4948 the main window was positioned at (0, 0).
4950 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4952 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4953 RootWindowOfScreen(XtScreen(shellWidget)),
4954 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4958 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4961 XtSetArg(args[j], XtNheight, h); j++;
4962 XtSetArg(args[j], XtNwidth, w); j++;
4963 XtSetArg(args[j], XtNx, x); j++;
4964 XtSetArg(args[j], XtNy, y); j++;
4965 XtSetValues(shell, args, j);
4971 static int savedIndex; /* gross that this is global */
4973 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4976 XawTextPosition index, dummy;
4979 XawTextGetSelectionPos(w, &index, &dummy);
4980 XtSetArg(arg, XtNstring, &val);
4981 XtGetValues(w, &arg, 1);
4982 ReplaceComment(savedIndex, val);
4983 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4984 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4987 void EditCommentPopUp(index, title, text)
4996 if (text == NULL) text = "";
4998 if (editShell == NULL) {
5000 CommentCreate(title, text, True, EditCommentCallback, 4);
5001 XtRealizeWidget(editShell);
5002 CatchDeleteWindow(editShell, "EditCommentPopDown");
5004 edit = XtNameToWidget(editShell, "*form.text");
5006 XtSetArg(args[j], XtNstring, text); j++;
5007 XtSetValues(edit, args, j);
5009 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5010 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5011 XtSetValues(editShell, args, j);
5014 XtPopup(editShell, XtGrabNone);
5018 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5019 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5023 void EditCommentCallback(w, client_data, call_data)
5025 XtPointer client_data, call_data;
5033 XtSetArg(args[j], XtNlabel, &name); j++;
5034 XtGetValues(w, args, j);
5036 if (strcmp(name, _("ok")) == 0) {
5037 edit = XtNameToWidget(editShell, "*form.text");
5039 XtSetArg(args[j], XtNstring, &val); j++;
5040 XtGetValues(edit, args, j);
5041 ReplaceComment(savedIndex, val);
5042 EditCommentPopDown();
5043 } else if (strcmp(name, _("cancel")) == 0) {
5044 EditCommentPopDown();
5045 } else if (strcmp(name, _("clear")) == 0) {
5046 edit = XtNameToWidget(editShell, "*form.text");
5047 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5048 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5052 void EditCommentPopDown()
5057 if (!editUp) return;
5059 XtSetArg(args[j], XtNx, &commentX); j++;
5060 XtSetArg(args[j], XtNy, &commentY); j++;
5061 XtSetArg(args[j], XtNheight, &commentH); j++;
5062 XtSetArg(args[j], XtNwidth, &commentW); j++;
5063 XtGetValues(editShell, args, j);
5064 XtPopdown(editShell);
5067 XtSetArg(args[j], XtNleftBitmap, None); j++;
5068 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5072 void ICSInputBoxPopUp()
5077 char *title = _("ICS Input");
5080 if (ICSInputShell == NULL) {
5081 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5082 tr = XtParseTranslationTable(ICSInputTranslations);
5083 edit = XtNameToWidget(ICSInputShell, "*form.text");
5084 XtOverrideTranslations(edit, tr);
5085 XtRealizeWidget(ICSInputShell);
5086 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5089 edit = XtNameToWidget(ICSInputShell, "*form.text");
5091 XtSetArg(args[j], XtNstring, ""); j++;
5092 XtSetValues(edit, args, j);
5094 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5095 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5096 XtSetValues(ICSInputShell, args, j);
5099 XtPopup(ICSInputShell, XtGrabNone);
5100 XtSetKeyboardFocus(ICSInputShell, edit);
5102 ICSInputBoxUp = True;
5104 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5105 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5109 void ICSInputSendText()
5116 edit = XtNameToWidget(ICSInputShell, "*form.text");
5118 XtSetArg(args[j], XtNstring, &val); j++;
5119 XtGetValues(edit, args, j);
5121 SendMultiLineToICS(val);
5122 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5123 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5126 void ICSInputBoxPopDown()
5131 if (!ICSInputBoxUp) return;
5133 XtPopdown(ICSInputShell);
5134 ICSInputBoxUp = False;
5136 XtSetArg(args[j], XtNleftBitmap, None); j++;
5137 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5141 void CommentPopUp(title, text)
5148 savedIndex = currentMove; // [HGM] vari
5149 if (commentShell == NULL) {
5151 CommentCreate(title, text, False, CommentCallback, 4);
5152 XtRealizeWidget(commentShell);
5153 CatchDeleteWindow(commentShell, "CommentPopDown");
5155 edit = XtNameToWidget(commentShell, "*form.text");
5157 XtSetArg(args[j], XtNstring, text); j++;
5158 XtSetValues(edit, args, j);
5160 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5161 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5162 XtSetValues(commentShell, args, j);
5165 XtPopup(commentShell, XtGrabNone);
5166 XSync(xDisplay, False);
5171 void CommentCallback(w, client_data, call_data)
5173 XtPointer client_data, call_data;
5180 XtSetArg(args[j], XtNlabel, &name); j++;
5181 XtGetValues(w, args, j);
5183 if (strcmp(name, _("close")) == 0) {
5185 } else if (strcmp(name, _("edit")) == 0) {
5192 void CommentPopDown()
5197 if (!commentUp) return;
5199 XtSetArg(args[j], XtNx, &commentX); j++;
5200 XtSetArg(args[j], XtNy, &commentY); j++;
5201 XtSetArg(args[j], XtNwidth, &commentW); j++;
5202 XtSetArg(args[j], XtNheight, &commentH); j++;
5203 XtGetValues(commentShell, args, j);
5204 XtPopdown(commentShell);
5205 XSync(xDisplay, False);
5209 void FileNamePopUp(label, def, proc, openMode)
5215 fileProc = proc; /* I can't see a way not */
5216 fileOpenMode = openMode; /* to use globals here */
5217 { // [HGM] use file-selector dialog stolen from Ghostview
5219 int index; // this is not supported yet
5221 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5222 def, openMode, NULL, &name))
5223 (void) (*fileProc)(f, index=0, name);
5227 void FileNamePopDown()
5229 if (!filenameUp) return;
5230 XtPopdown(fileNameShell);
5231 XtDestroyWidget(fileNameShell);
5236 void FileNameCallback(w, client_data, call_data)
5238 XtPointer client_data, call_data;
5243 XtSetArg(args[0], XtNlabel, &name);
5244 XtGetValues(w, args, 1);
5246 if (strcmp(name, _("cancel")) == 0) {
5251 FileNameAction(w, NULL, NULL, NULL);
5254 void FileNameAction(w, event, prms, nprms)
5266 name = XawDialogGetValueString(w = XtParent(w));
5268 if ((name != NULL) && (*name != NULLCHAR)) {
5269 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5270 XtPopdown(w = XtParent(XtParent(w)));
5274 p = strrchr(buf, ' ');
5281 fullname = ExpandPathName(buf);
5283 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5286 f = fopen(fullname, fileOpenMode);
5288 DisplayError(_("Failed to open file"), errno);
5290 (void) (*fileProc)(f, index, buf);
5297 XtPopdown(w = XtParent(XtParent(w)));
5303 void PromotionPopUp()
5306 Widget dialog, layout;
5308 Dimension bw_width, pw_width;
5312 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5313 XtGetValues(boardWidget, args, j);
5316 XtSetArg(args[j], XtNresizable, True); j++;
5317 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5319 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5320 shellWidget, args, j);
5322 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5323 layoutArgs, XtNumber(layoutArgs));
5326 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5327 XtSetArg(args[j], XtNborderWidth, 0); j++;
5328 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5331 if(gameInfo.variant != VariantShogi) {
5332 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5333 (XtPointer) dialog);
5334 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5335 (XtPointer) dialog);
5336 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5337 (XtPointer) dialog);
5338 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5339 (XtPointer) dialog);
5340 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5341 gameInfo.variant == VariantGiveaway) {
5342 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5343 (XtPointer) dialog);
5345 if(gameInfo.variant == VariantCapablanca ||
5346 gameInfo.variant == VariantGothic ||
5347 gameInfo.variant == VariantCapaRandom) {
5348 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5349 (XtPointer) dialog);
5350 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5351 (XtPointer) dialog);
5353 } else // [HGM] shogi
5355 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5356 (XtPointer) dialog);
5357 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5358 (XtPointer) dialog);
5360 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5361 (XtPointer) dialog);
5363 XtRealizeWidget(promotionShell);
5364 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5367 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5368 XtGetValues(promotionShell, args, j);
5370 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5371 lineGap + squareSize/3 +
5372 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5373 0 : 6*(squareSize + lineGap)), &x, &y);
5376 XtSetArg(args[j], XtNx, x); j++;
5377 XtSetArg(args[j], XtNy, y); j++;
5378 XtSetValues(promotionShell, args, j);
5380 XtPopup(promotionShell, XtGrabNone);
5385 void PromotionPopDown()
5387 if (!promotionUp) return;
5388 XtPopdown(promotionShell);
5389 XtDestroyWidget(promotionShell);
5390 promotionUp = False;
5393 void PromotionCallback(w, client_data, call_data)
5395 XtPointer client_data, call_data;
5401 XtSetArg(args[0], XtNlabel, &name);
5402 XtGetValues(w, args, 1);
5406 if (fromX == -1) return;
5408 if (strcmp(name, _("cancel")) == 0) {
5412 } else if (strcmp(name, _("Knight")) == 0) {
5414 } else if (strcmp(name, _("Promote")) == 0) {
5416 } else if (strcmp(name, _("Defer")) == 0) {
5419 promoChar = ToLower(name[0]);
5422 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5424 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5425 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5430 void ErrorCallback(w, client_data, call_data)
5432 XtPointer client_data, call_data;
5435 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5437 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5443 if (!errorUp) return;
5445 XtPopdown(errorShell);
5446 XtDestroyWidget(errorShell);
5447 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5450 void ErrorPopUp(title, label, modal)
5451 char *title, *label;
5455 Widget dialog, layout;
5459 Dimension bw_width, pw_width;
5460 Dimension pw_height;
5464 XtSetArg(args[i], XtNresizable, True); i++;
5465 XtSetArg(args[i], XtNtitle, title); i++;
5467 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5468 shellWidget, args, i);
5470 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5471 layoutArgs, XtNumber(layoutArgs));
5474 XtSetArg(args[i], XtNlabel, label); i++;
5475 XtSetArg(args[i], XtNborderWidth, 0); i++;
5476 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5479 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5481 XtRealizeWidget(errorShell);
5482 CatchDeleteWindow(errorShell, "ErrorPopDown");
5485 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5486 XtGetValues(boardWidget, args, i);
5488 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5489 XtSetArg(args[i], XtNheight, &pw_height); i++;
5490 XtGetValues(errorShell, args, i);
5493 /* This code seems to tickle an X bug if it is executed too soon
5494 after xboard starts up. The coordinates get transformed as if
5495 the main window was positioned at (0, 0).
5497 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5498 0 - pw_height + squareSize / 3, &x, &y);
5500 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5501 RootWindowOfScreen(XtScreen(boardWidget)),
5502 (bw_width - pw_width) / 2,
5503 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5507 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5510 XtSetArg(args[i], XtNx, x); i++;
5511 XtSetArg(args[i], XtNy, y); i++;
5512 XtSetValues(errorShell, args, i);
5515 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5518 /* Disable all user input other than deleting the window */
5519 static int frozen = 0;
5523 /* Grab by a widget that doesn't accept input */
5524 XtAddGrab(messageWidget, TRUE, FALSE);
5528 /* Undo a FreezeUI */
5531 if (!frozen) return;
5532 XtRemoveGrab(messageWidget);
5536 char *ModeToWidgetName(mode)
5540 case BeginningOfGame:
5541 if (appData.icsActive)
5542 return "menuMode.ICS Client";
5543 else if (appData.noChessProgram ||
5544 *appData.cmailGameName != NULLCHAR)
5545 return "menuMode.Edit Game";
5547 return "menuMode.Machine Black";
5548 case MachinePlaysBlack:
5549 return "menuMode.Machine Black";
5550 case MachinePlaysWhite:
5551 return "menuMode.Machine White";
5553 return "menuMode.Analysis Mode";
5555 return "menuMode.Analyze File";
5556 case TwoMachinesPlay:
5557 return "menuMode.Two Machines";
5559 return "menuMode.Edit Game";
5560 case PlayFromGameFile:
5561 return "menuFile.Load Game";
5563 return "menuMode.Edit Position";
5565 return "menuMode.Training";
5566 case IcsPlayingWhite:
5567 case IcsPlayingBlack:
5571 return "menuMode.ICS Client";
5578 void ModeHighlight()
5581 static int oldPausing = FALSE;
5582 static GameMode oldmode = (GameMode) -1;
5585 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5587 if (pausing != oldPausing) {
5588 oldPausing = pausing;
5590 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5592 XtSetArg(args[0], XtNleftBitmap, None);
5594 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5597 if (appData.showButtonBar) {
5598 /* Always toggle, don't set. Previous code messes up when
5599 invoked while the button is pressed, as releasing it
5600 toggles the state again. */
5603 XtSetArg(args[0], XtNbackground, &oldbg);
5604 XtSetArg(args[1], XtNforeground, &oldfg);
5605 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5607 XtSetArg(args[0], XtNbackground, oldfg);
5608 XtSetArg(args[1], XtNforeground, oldbg);
5610 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5614 wname = ModeToWidgetName(oldmode);
5615 if (wname != NULL) {
5616 XtSetArg(args[0], XtNleftBitmap, None);
5617 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5619 wname = ModeToWidgetName(gameMode);
5620 if (wname != NULL) {
5621 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5622 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5626 /* Maybe all the enables should be handled here, not just this one */
5627 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5628 gameMode == Training || gameMode == PlayFromGameFile);
5633 * Button/menu procedures
5635 void ResetProc(w, event, prms, nprms)
5644 int LoadGamePopUp(f, gameNumber, title)
5649 cmailMsgLoaded = FALSE;
5650 if (gameNumber == 0) {
5651 int error = GameListBuild(f);
5653 DisplayError(_("Cannot build game list"), error);
5654 } else if (!ListEmpty(&gameList) &&
5655 ((ListGame *) gameList.tailPred)->number > 1) {
5656 GameListPopUp(f, title);
5662 return LoadGame(f, gameNumber, title, FALSE);
5665 void LoadGameProc(w, event, prms, nprms)
5671 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5674 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5677 void LoadNextGameProc(w, event, prms, nprms)
5686 void LoadPrevGameProc(w, event, prms, nprms)
5695 void ReloadGameProc(w, event, prms, nprms)
5704 void LoadNextPositionProc(w, event, prms, nprms)
5713 void LoadPrevPositionProc(w, event, prms, nprms)
5722 void ReloadPositionProc(w, event, prms, nprms)
5731 void LoadPositionProc(w, event, prms, nprms)
5737 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5740 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5743 void SaveGameProc(w, event, prms, nprms)
5749 FileNamePopUp(_("Save game file name?"),
5750 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5754 void SavePositionProc(w, event, prms, nprms)
5760 FileNamePopUp(_("Save position file name?"),
5761 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5765 void ReloadCmailMsgProc(w, event, prms, nprms)
5771 ReloadCmailMsgEvent(FALSE);
5774 void MailMoveProc(w, event, prms, nprms)
5783 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5784 char *selected_fen_position=NULL;
5787 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5788 Atom *type_return, XtPointer *value_return,
5789 unsigned long *length_return, int *format_return)
5791 char *selection_tmp;
5793 if (!selected_fen_position) return False; /* should never happen */
5794 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5795 /* note: since no XtSelectionDoneProc was registered, Xt will
5796 * automatically call XtFree on the value returned. So have to
5797 * make a copy of it allocated with XtMalloc */
5798 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5799 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5801 *value_return=selection_tmp;
5802 *length_return=strlen(selection_tmp);
5803 *type_return=*target;
5804 *format_return = 8; /* bits per byte */
5806 } else if (*target == XA_TARGETS(xDisplay)) {
5807 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5808 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5809 targets_tmp[1] = XA_STRING;
5810 *value_return = targets_tmp;
5811 *type_return = XA_ATOM;
5813 *format_return = 8 * sizeof(Atom);
5814 if (*format_return > 32) {
5815 *length_return *= *format_return / 32;
5816 *format_return = 32;
5824 /* note: when called from menu all parameters are NULL, so no clue what the
5825 * Widget which was clicked on was, or what the click event was
5827 void CopyPositionProc(w, event, prms, nprms)
5834 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5835 * have a notion of a position that is selected but not copied.
5836 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5838 if(gameMode == EditPosition) EditPositionDone(TRUE);
5839 if (selected_fen_position) free(selected_fen_position);
5840 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5841 if (!selected_fen_position) return;
5842 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5844 SendPositionSelection,
5845 NULL/* lose_ownership_proc */ ,
5846 NULL/* transfer_done_proc */);
5847 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5849 SendPositionSelection,
5850 NULL/* lose_ownership_proc */ ,
5851 NULL/* transfer_done_proc */);
5854 /* function called when the data to Paste is ready */
5856 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5857 Atom *type, XtPointer value, unsigned long *len, int *format)
5860 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5861 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5862 EditPositionPasteFEN(fenstr);
5866 /* called when Paste Position button is pressed,
5867 * all parameters will be NULL */
5868 void PastePositionProc(w, event, prms, nprms)
5874 XtGetSelectionValue(menuBarWidget,
5875 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5876 /* (XtSelectionCallbackProc) */ PastePositionCB,
5877 NULL, /* client_data passed to PastePositionCB */
5879 /* better to use the time field from the event that triggered the
5880 * call to this function, but that isn't trivial to get
5888 SendGameSelection(Widget w, Atom *selection, Atom *target,
5889 Atom *type_return, XtPointer *value_return,
5890 unsigned long *length_return, int *format_return)
5892 char *selection_tmp;
5894 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5895 FILE* f = fopen(gameCopyFilename, "r");
5898 if (f == NULL) return False;
5902 selection_tmp = XtMalloc(len + 1);
5903 count = fread(selection_tmp, 1, len, f);
5905 XtFree(selection_tmp);
5908 selection_tmp[len] = NULLCHAR;
5909 *value_return = selection_tmp;
5910 *length_return = len;
5911 *type_return = *target;
5912 *format_return = 8; /* bits per byte */
5914 } else if (*target == XA_TARGETS(xDisplay)) {
5915 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5916 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5917 targets_tmp[1] = XA_STRING;
5918 *value_return = targets_tmp;
5919 *type_return = XA_ATOM;
5921 *format_return = 8 * sizeof(Atom);
5922 if (*format_return > 32) {
5923 *length_return *= *format_return / 32;
5924 *format_return = 32;
5932 /* note: when called from menu all parameters are NULL, so no clue what the
5933 * Widget which was clicked on was, or what the click event was
5935 void CopyGameProc(w, event, prms, nprms)
5943 ret = SaveGameToFile(gameCopyFilename, FALSE);
5947 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5948 * have a notion of a game that is selected but not copied.
5949 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5951 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5954 NULL/* lose_ownership_proc */ ,
5955 NULL/* transfer_done_proc */);
5956 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5959 NULL/* lose_ownership_proc */ ,
5960 NULL/* transfer_done_proc */);
5963 /* function called when the data to Paste is ready */
5965 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5966 Atom *type, XtPointer value, unsigned long *len, int *format)
5969 if (value == NULL || *len == 0) {
5970 return; /* nothing had been selected to copy */
5972 f = fopen(gamePasteFilename, "w");
5974 DisplayError(_("Can't open temp file"), errno);
5977 fwrite(value, 1, *len, f);
5980 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5983 /* called when Paste Game button is pressed,
5984 * all parameters will be NULL */
5985 void PasteGameProc(w, event, prms, nprms)
5991 XtGetSelectionValue(menuBarWidget,
5992 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5993 /* (XtSelectionCallbackProc) */ PasteGameCB,
5994 NULL, /* client_data passed to PasteGameCB */
5996 /* better to use the time field from the event that triggered the
5997 * call to this function, but that isn't trivial to get
6007 SaveGameProc(NULL, NULL, NULL, NULL);
6011 void QuitProc(w, event, prms, nprms)
6020 void PauseProc(w, event, prms, nprms)
6030 void MachineBlackProc(w, event, prms, nprms)
6036 MachineBlackEvent();
6039 void MachineWhiteProc(w, event, prms, nprms)
6045 MachineWhiteEvent();
6048 void AnalyzeModeProc(w, event, prms, nprms)
6056 if (!first.analysisSupport) {
6057 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6058 DisplayError(buf, 0);
6061 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6062 if (appData.icsActive) {
6063 if (gameMode != IcsObserving) {
6064 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6065 DisplayError(buf, 0);
6067 if (appData.icsEngineAnalyze) {
6068 if (appData.debugMode)
6069 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6075 /* if enable, use want disable icsEngineAnalyze */
6076 if (appData.icsEngineAnalyze) {
6081 appData.icsEngineAnalyze = TRUE;
6082 if (appData.debugMode)
6083 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6085 if (!appData.showThinking)
6086 ShowThinkingProc(w,event,prms,nprms);
6091 void AnalyzeFileProc(w, event, prms, nprms)
6097 if (!first.analysisSupport) {
6099 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6100 DisplayError(buf, 0);
6105 if (!appData.showThinking)
6106 ShowThinkingProc(w,event,prms,nprms);
6109 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6110 AnalysisPeriodicEvent(1);
6113 void TwoMachinesProc(w, event, prms, nprms)
6122 void IcsClientProc(w, event, prms, nprms)
6131 void EditGameProc(w, event, prms, nprms)
6140 void EditPositionProc(w, event, prms, nprms)
6146 EditPositionEvent();
6149 void TrainingProc(w, event, prms, nprms)
6158 void EditCommentProc(w, event, prms, nprms)
6165 EditCommentPopDown();
6171 void IcsInputBoxProc(w, event, prms, nprms)
6177 if (ICSInputBoxUp) {
6178 ICSInputBoxPopDown();
6184 void AcceptProc(w, event, prms, nprms)
6193 void DeclineProc(w, event, prms, nprms)
6202 void RematchProc(w, event, prms, nprms)
6211 void CallFlagProc(w, event, prms, nprms)
6220 void DrawProc(w, event, prms, nprms)
6229 void AbortProc(w, event, prms, nprms)
6238 void AdjournProc(w, event, prms, nprms)
6247 void ResignProc(w, event, prms, nprms)
6256 void AdjuWhiteProc(w, event, prms, nprms)
6262 UserAdjudicationEvent(+1);
6265 void AdjuBlackProc(w, event, prms, nprms)
6271 UserAdjudicationEvent(-1);
6274 void AdjuDrawProc(w, event, prms, nprms)
6280 UserAdjudicationEvent(0);
6283 void EnterKeyProc(w, event, prms, nprms)
6289 if (ICSInputBoxUp == True)
6293 void UpKeyProc(w, event, prms, nprms)
6298 { // [HGM] input: let up-arrow recall previous line from history
6305 if (!ICSInputBoxUp) return;
6306 edit = XtNameToWidget(ICSInputShell, "*form.text");
6308 XtSetArg(args[j], XtNstring, &val); j++;
6309 XtGetValues(edit, args, j);
6310 val = PrevInHistory(val);
6311 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6312 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6314 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6315 XawTextReplace(edit, 0, 0, &t);
6316 XawTextSetInsertionPoint(edit, 9999);
6320 void DownKeyProc(w, event, prms, nprms)
6325 { // [HGM] input: let down-arrow recall next line from history
6330 if (!ICSInputBoxUp) return;
6331 edit = XtNameToWidget(ICSInputShell, "*form.text");
6332 val = NextInHistory();
6333 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6334 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6336 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6337 XawTextReplace(edit, 0, 0, &t);
6338 XawTextSetInsertionPoint(edit, 9999);
6342 void StopObservingProc(w, event, prms, nprms)
6348 StopObservingEvent();
6351 void StopExaminingProc(w, event, prms, nprms)
6357 StopExaminingEvent();
6360 void UploadProc(w, event, prms, nprms)
6370 void ForwardProc(w, event, prms, nprms)
6380 void BackwardProc(w, event, prms, nprms)
6389 void ToStartProc(w, event, prms, nprms)
6398 void ToEndProc(w, event, prms, nprms)
6407 void RevertProc(w, event, prms, nprms)
6416 void AnnotateProc(w, event, prms, nprms)
6425 void TruncateGameProc(w, event, prms, nprms)
6431 TruncateGameEvent();
6433 void RetractMoveProc(w, event, prms, nprms)
6442 void MoveNowProc(w, event, prms, nprms)
6452 void AlwaysQueenProc(w, event, prms, nprms)
6460 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6462 if (appData.alwaysPromoteToQueen) {
6463 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6465 XtSetArg(args[0], XtNleftBitmap, None);
6467 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6471 void AnimateDraggingProc(w, event, prms, nprms)
6479 appData.animateDragging = !appData.animateDragging;
6481 if (appData.animateDragging) {
6482 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6485 XtSetArg(args[0], XtNleftBitmap, None);
6487 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6491 void AnimateMovingProc(w, event, prms, nprms)
6499 appData.animate = !appData.animate;
6501 if (appData.animate) {
6502 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6505 XtSetArg(args[0], XtNleftBitmap, None);
6507 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6511 void AutocommProc(w, event, prms, nprms)
6519 appData.autoComment = !appData.autoComment;
6521 if (appData.autoComment) {
6522 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6524 XtSetArg(args[0], XtNleftBitmap, None);
6526 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6531 void AutoflagProc(w, event, prms, nprms)
6539 appData.autoCallFlag = !appData.autoCallFlag;
6541 if (appData.autoCallFlag) {
6542 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6544 XtSetArg(args[0], XtNleftBitmap, None);
6546 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6550 void AutoflipProc(w, event, prms, nprms)
6558 appData.autoFlipView = !appData.autoFlipView;
6560 if (appData.autoFlipView) {
6561 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6563 XtSetArg(args[0], XtNleftBitmap, None);
6565 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6569 void AutobsProc(w, event, prms, nprms)
6577 appData.autoObserve = !appData.autoObserve;
6579 if (appData.autoObserve) {
6580 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6582 XtSetArg(args[0], XtNleftBitmap, None);
6584 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6588 void AutoraiseProc(w, event, prms, nprms)
6596 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6598 if (appData.autoRaiseBoard) {
6599 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6601 XtSetArg(args[0], XtNleftBitmap, None);
6603 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6607 void AutosaveProc(w, event, prms, nprms)
6615 appData.autoSaveGames = !appData.autoSaveGames;
6617 if (appData.autoSaveGames) {
6618 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6620 XtSetArg(args[0], XtNleftBitmap, None);
6622 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6626 void BlindfoldProc(w, event, prms, nprms)
6634 appData.blindfold = !appData.blindfold;
6636 if (appData.blindfold) {
6637 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6639 XtSetArg(args[0], XtNleftBitmap, None);
6641 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6644 DrawPosition(True, NULL);
6647 void TestLegalityProc(w, event, prms, nprms)
6655 appData.testLegality = !appData.testLegality;
6657 if (appData.testLegality) {
6658 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6660 XtSetArg(args[0], XtNleftBitmap, None);
6662 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6667 void FlashMovesProc(w, event, prms, nprms)
6675 if (appData.flashCount == 0) {
6676 appData.flashCount = 3;
6678 appData.flashCount = -appData.flashCount;
6681 if (appData.flashCount > 0) {
6682 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6684 XtSetArg(args[0], XtNleftBitmap, None);
6686 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6690 void FlipViewProc(w, event, prms, nprms)
6696 flipView = !flipView;
6697 DrawPosition(True, NULL);
6700 void GetMoveListProc(w, event, prms, nprms)
6708 appData.getMoveList = !appData.getMoveList;
6710 if (appData.getMoveList) {
6711 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6714 XtSetArg(args[0], XtNleftBitmap, None);
6716 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6721 void HighlightDraggingProc(w, event, prms, nprms)
6729 appData.highlightDragging = !appData.highlightDragging;
6731 if (appData.highlightDragging) {
6732 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6734 XtSetArg(args[0], XtNleftBitmap, None);
6736 XtSetValues(XtNameToWidget(menuBarWidget,
6737 "menuOptions.Highlight Dragging"), args, 1);
6741 void HighlightLastMoveProc(w, event, prms, nprms)
6749 appData.highlightLastMove = !appData.highlightLastMove;
6751 if (appData.highlightLastMove) {
6752 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6754 XtSetArg(args[0], XtNleftBitmap, None);
6756 XtSetValues(XtNameToWidget(menuBarWidget,
6757 "menuOptions.Highlight Last Move"), args, 1);
6760 void IcsAlarmProc(w, event, prms, nprms)
6768 appData.icsAlarm = !appData.icsAlarm;
6770 if (appData.icsAlarm) {
6771 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6773 XtSetArg(args[0], XtNleftBitmap, None);
6775 XtSetValues(XtNameToWidget(menuBarWidget,
6776 "menuOptions.ICS Alarm"), args, 1);
6779 void MoveSoundProc(w, event, prms, nprms)
6787 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6789 if (appData.ringBellAfterMoves) {
6790 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6792 XtSetArg(args[0], XtNleftBitmap, None);
6794 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6799 void OldSaveStyleProc(w, event, prms, nprms)
6807 appData.oldSaveStyle = !appData.oldSaveStyle;
6809 if (appData.oldSaveStyle) {
6810 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6812 XtSetArg(args[0], XtNleftBitmap, None);
6814 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6818 void PeriodicUpdatesProc(w, event, prms, nprms)
6826 PeriodicUpdatesEvent(!appData.periodicUpdates);
6828 if (appData.periodicUpdates) {
6829 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6831 XtSetArg(args[0], XtNleftBitmap, None);
6833 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6837 void PonderNextMoveProc(w, event, prms, nprms)
6845 PonderNextMoveEvent(!appData.ponderNextMove);
6847 if (appData.ponderNextMove) {
6848 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6850 XtSetArg(args[0], XtNleftBitmap, None);
6852 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6856 void PopupExitMessageProc(w, event, prms, nprms)
6864 appData.popupExitMessage = !appData.popupExitMessage;
6866 if (appData.popupExitMessage) {
6867 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6869 XtSetArg(args[0], XtNleftBitmap, None);
6871 XtSetValues(XtNameToWidget(menuBarWidget,
6872 "menuOptions.Popup Exit Message"), args, 1);
6875 void PopupMoveErrorsProc(w, event, prms, nprms)
6883 appData.popupMoveErrors = !appData.popupMoveErrors;
6885 if (appData.popupMoveErrors) {
6886 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6888 XtSetArg(args[0], XtNleftBitmap, None);
6890 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6894 void PremoveProc(w, event, prms, nprms)
6902 appData.premove = !appData.premove;
6904 if (appData.premove) {
6905 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6907 XtSetArg(args[0], XtNleftBitmap, None);
6909 XtSetValues(XtNameToWidget(menuBarWidget,
6910 "menuOptions.Premove"), args, 1);
6913 void QuietPlayProc(w, event, prms, nprms)
6921 appData.quietPlay = !appData.quietPlay;
6923 if (appData.quietPlay) {
6924 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6926 XtSetArg(args[0], XtNleftBitmap, None);
6928 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6932 void ShowCoordsProc(w, event, prms, nprms)
6940 appData.showCoords = !appData.showCoords;
6942 if (appData.showCoords) {
6943 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6945 XtSetArg(args[0], XtNleftBitmap, None);
6947 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6950 DrawPosition(True, NULL);
6953 void ShowThinkingProc(w, event, prms, nprms)
6959 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6960 ShowThinkingEvent();
6963 void HideThinkingProc(w, event, prms, nprms)
6971 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6972 ShowThinkingEvent();
6974 if (appData.hideThinkingFromHuman) {
6975 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6977 XtSetArg(args[0], XtNleftBitmap, None);
6979 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6983 void SaveOnExitProc(w, event, prms, nprms)
6991 saveSettingsOnExit = !saveSettingsOnExit;
6993 if (saveSettingsOnExit) {
6994 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6996 XtSetArg(args[0], XtNleftBitmap, None);
6998 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
7002 void SaveSettingsProc(w, event, prms, nprms)
7008 SaveSettings(settingsFileName);
7011 void InfoProc(w, event, prms, nprms)
7018 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
7023 void ManProc(w, event, prms, nprms)
7031 if (nprms && *nprms > 0)
7035 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7039 void HintProc(w, event, prms, nprms)
7048 void BookProc(w, event, prms, nprms)
7057 void AboutProc(w, event, prms, nprms)
7065 char *zippy = " (with Zippy code)";
7069 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7070 programVersion, zippy,
7071 "Copyright 1991 Digital Equipment Corporation",
7072 "Enhancements Copyright 1992-2009 Free Software Foundation",
7073 "Enhancements Copyright 2005 Alessandro Scotti",
7074 PACKAGE, " is free software and carries NO WARRANTY;",
7075 "see the file COPYING for more information.");
7076 ErrorPopUp(_("About XBoard"), buf, FALSE);
7079 void DebugProc(w, event, prms, nprms)
7085 appData.debugMode = !appData.debugMode;
7088 void AboutGameProc(w, event, prms, nprms)
7097 void NothingProc(w, event, prms, nprms)
7106 void Iconify(w, event, prms, nprms)
7115 XtSetArg(args[0], XtNiconic, True);
7116 XtSetValues(shellWidget, args, 1);
7119 void DisplayMessage(message, extMessage)
7120 char *message, *extMessage;
7122 /* display a message in the message widget */
7131 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7136 message = extMessage;
7140 /* need to test if messageWidget already exists, since this function
7141 can also be called during the startup, if for example a Xresource
7142 is not set up correctly */
7145 XtSetArg(arg, XtNlabel, message);
7146 XtSetValues(messageWidget, &arg, 1);
7152 void DisplayTitle(text)
7157 char title[MSG_SIZ];
7160 if (text == NULL) text = "";
7162 if (appData.titleInWindow) {
7164 XtSetArg(args[i], XtNlabel, text); i++;
7165 XtSetValues(titleWidget, args, i);
7168 if (*text != NULLCHAR) {
7169 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7170 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7171 } else if (appData.icsActive) {
7172 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7173 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7174 } else if (appData.cmailGameName[0] != NULLCHAR) {
7175 snprintf(icon, sizeof(icon), "%s", "CMail");
7176 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7178 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7179 } else if (gameInfo.variant == VariantGothic) {
7180 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7181 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7184 } else if (gameInfo.variant == VariantFalcon) {
7185 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7186 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7188 } else if (appData.noChessProgram) {
7189 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7190 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7192 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7193 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7196 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7197 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7198 XtSetValues(shellWidget, args, i);
7203 DisplayError(message, error)
7210 if (appData.debugMode || appData.matchMode) {
7211 fprintf(stderr, "%s: %s\n", programName, message);
7214 if (appData.debugMode || appData.matchMode) {
7215 fprintf(stderr, "%s: %s: %s\n",
7216 programName, message, strerror(error));
7218 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7221 ErrorPopUp(_("Error"), message, FALSE);
7225 void DisplayMoveError(message)
7230 DrawPosition(FALSE, NULL);
7231 if (appData.debugMode || appData.matchMode) {
7232 fprintf(stderr, "%s: %s\n", programName, message);
7234 if (appData.popupMoveErrors) {
7235 ErrorPopUp(_("Error"), message, FALSE);
7237 DisplayMessage(message, "");
7242 void DisplayFatalError(message, error, status)
7248 errorExitStatus = status;
7250 fprintf(stderr, "%s: %s\n", programName, message);
7252 fprintf(stderr, "%s: %s: %s\n",
7253 programName, message, strerror(error));
7254 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7257 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7258 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7264 void DisplayInformation(message)
7268 ErrorPopUp(_("Information"), message, TRUE);
7271 void DisplayNote(message)
7275 ErrorPopUp(_("Note"), message, FALSE);
7279 NullXErrorCheck(dpy, error_event)
7281 XErrorEvent *error_event;
7286 void DisplayIcsInteractionTitle(message)
7289 if (oldICSInteractionTitle == NULL) {
7290 /* Magic to find the old window title, adapted from vim */
7291 char *wina = getenv("WINDOWID");
7293 Window win = (Window) atoi(wina);
7294 Window root, parent, *children;
7295 unsigned int nchildren;
7296 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7298 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7299 if (!XQueryTree(xDisplay, win, &root, &parent,
7300 &children, &nchildren)) break;
7301 if (children) XFree((void *)children);
7302 if (parent == root || parent == 0) break;
7305 XSetErrorHandler(oldHandler);
7307 if (oldICSInteractionTitle == NULL) {
7308 oldICSInteractionTitle = "xterm";
7311 printf("\033]0;%s\007", message);
7315 char pendingReplyPrefix[MSG_SIZ];
7316 ProcRef pendingReplyPR;
7318 void AskQuestionProc(w, event, prms, nprms)
7325 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7329 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7332 void AskQuestionPopDown()
7334 if (!askQuestionUp) return;
7335 XtPopdown(askQuestionShell);
7336 XtDestroyWidget(askQuestionShell);
7337 askQuestionUp = False;
7340 void AskQuestionReplyAction(w, event, prms, nprms)
7350 reply = XawDialogGetValueString(w = XtParent(w));
7351 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7352 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7353 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7354 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7355 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7356 AskQuestionPopDown();
7358 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7361 void AskQuestionCallback(w, client_data, call_data)
7363 XtPointer client_data, call_data;
7368 XtSetArg(args[0], XtNlabel, &name);
7369 XtGetValues(w, args, 1);
7371 if (strcmp(name, _("cancel")) == 0) {
7372 AskQuestionPopDown();
7374 AskQuestionReplyAction(w, NULL, NULL, NULL);
7378 void AskQuestion(title, question, replyPrefix, pr)
7379 char *title, *question, *replyPrefix;
7383 Widget popup, layout, dialog, edit;
7389 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7390 pendingReplyPR = pr;
7393 XtSetArg(args[i], XtNresizable, True); i++;
7394 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7395 askQuestionShell = popup =
7396 XtCreatePopupShell(title, transientShellWidgetClass,
7397 shellWidget, args, i);
7400 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7401 layoutArgs, XtNumber(layoutArgs));
7404 XtSetArg(args[i], XtNlabel, question); i++;
7405 XtSetArg(args[i], XtNvalue, ""); i++;
7406 XtSetArg(args[i], XtNborderWidth, 0); i++;
7407 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7410 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7411 (XtPointer) dialog);
7412 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7413 (XtPointer) dialog);
7415 XtRealizeWidget(popup);
7416 CatchDeleteWindow(popup, "AskQuestionPopDown");
7418 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7419 &x, &y, &win_x, &win_y, &mask);
7421 XtSetArg(args[0], XtNx, x - 10);
7422 XtSetArg(args[1], XtNy, y - 30);
7423 XtSetValues(popup, args, 2);
7425 XtPopup(popup, XtGrabExclusive);
7426 askQuestionUp = True;
7428 edit = XtNameToWidget(dialog, "*value");
7429 XtSetKeyboardFocus(popup, edit);
7437 if (*name == NULLCHAR) {
7439 } else if (strcmp(name, "$") == 0) {
7440 putc(BELLCHAR, stderr);
7443 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7451 PlaySound(appData.soundMove);
7457 PlaySound(appData.soundIcsWin);
7463 PlaySound(appData.soundIcsLoss);
7469 PlaySound(appData.soundIcsDraw);
7473 PlayIcsUnfinishedSound()
7475 PlaySound(appData.soundIcsUnfinished);
7481 PlaySound(appData.soundIcsAlarm);
7487 system("stty echo");
7493 system("stty -echo");
7497 Colorize(cc, continuation)
7502 int count, outCount, error;
7504 if (textColors[(int)cc].bg > 0) {
7505 if (textColors[(int)cc].fg > 0) {
7506 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7507 textColors[(int)cc].fg, textColors[(int)cc].bg);
7509 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7510 textColors[(int)cc].bg);
7513 if (textColors[(int)cc].fg > 0) {
7514 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7515 textColors[(int)cc].fg);
7517 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7520 count = strlen(buf);
7521 outCount = OutputToProcess(NoProc, buf, count, &error);
7522 if (outCount < count) {
7523 DisplayFatalError(_("Error writing to display"), error, 1);
7526 if (continuation) return;
7529 PlaySound(appData.soundShout);
7532 PlaySound(appData.soundSShout);
7535 PlaySound(appData.soundChannel1);
7538 PlaySound(appData.soundChannel);
7541 PlaySound(appData.soundKibitz);
7544 PlaySound(appData.soundTell);
7546 case ColorChallenge:
7547 PlaySound(appData.soundChallenge);
7550 PlaySound(appData.soundRequest);
7553 PlaySound(appData.soundSeek);
7564 return getpwuid(getuid())->pw_name;
7568 ExpandPathName(path)
7571 static char static_buf[4*MSG_SIZ];
7572 char *d, *s, buf[4*MSG_SIZ];
7578 while (*s && isspace(*s))
7587 if (*(s+1) == '/') {
7588 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7592 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7593 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7594 pwd = getpwnam(buf);
7597 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7601 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7602 strcat(d, strchr(s+1, '/'));
7606 safeStrCpy(d, s, 4*MSG_SIZ );
7613 static char host_name[MSG_SIZ];
7615 #if HAVE_GETHOSTNAME
7616 gethostname(host_name, MSG_SIZ);
7618 #else /* not HAVE_GETHOSTNAME */
7619 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7620 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7622 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7624 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7625 #endif /* not HAVE_GETHOSTNAME */
7628 XtIntervalId delayedEventTimerXID = 0;
7629 DelayedEventCallback delayedEventCallback = 0;
7634 delayedEventTimerXID = 0;
7635 delayedEventCallback();
7639 ScheduleDelayedEvent(cb, millisec)
7640 DelayedEventCallback cb; long millisec;
7642 if(delayedEventTimerXID && delayedEventCallback == cb)
7643 // [HGM] alive: replace, rather than add or flush identical event
7644 XtRemoveTimeOut(delayedEventTimerXID);
7645 delayedEventCallback = cb;
7646 delayedEventTimerXID =
7647 XtAppAddTimeOut(appContext, millisec,
7648 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7651 DelayedEventCallback
7654 if (delayedEventTimerXID) {
7655 return delayedEventCallback;
7662 CancelDelayedEvent()
7664 if (delayedEventTimerXID) {
7665 XtRemoveTimeOut(delayedEventTimerXID);
7666 delayedEventTimerXID = 0;
7670 XtIntervalId loadGameTimerXID = 0;
7672 int LoadGameTimerRunning()
7674 return loadGameTimerXID != 0;
7677 int StopLoadGameTimer()
7679 if (loadGameTimerXID != 0) {
7680 XtRemoveTimeOut(loadGameTimerXID);
7681 loadGameTimerXID = 0;
7689 LoadGameTimerCallback(arg, id)
7693 loadGameTimerXID = 0;
7698 StartLoadGameTimer(millisec)
7702 XtAppAddTimeOut(appContext, millisec,
7703 (XtTimerCallbackProc) LoadGameTimerCallback,
7707 XtIntervalId analysisClockXID = 0;
7710 AnalysisClockCallback(arg, id)
7714 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7715 || appData.icsEngineAnalyze) { // [DM]
7716 AnalysisPeriodicEvent(0);
7717 StartAnalysisClock();
7722 StartAnalysisClock()
7725 XtAppAddTimeOut(appContext, 2000,
7726 (XtTimerCallbackProc) AnalysisClockCallback,
7730 XtIntervalId clockTimerXID = 0;
7732 int ClockTimerRunning()
7734 return clockTimerXID != 0;
7737 int StopClockTimer()
7739 if (clockTimerXID != 0) {
7740 XtRemoveTimeOut(clockTimerXID);
7749 ClockTimerCallback(arg, id)
7758 StartClockTimer(millisec)
7762 XtAppAddTimeOut(appContext, millisec,
7763 (XtTimerCallbackProc) ClockTimerCallback,
7768 DisplayTimerLabel(w, color, timer, highlight)
7777 /* check for low time warning */
7778 Pixel foregroundOrWarningColor = timerForegroundPixel;
7781 appData.lowTimeWarning &&
7782 (timer / 1000) < appData.icsAlarmTime)
7783 foregroundOrWarningColor = lowTimeWarningColor;
7785 if (appData.clockMode) {
7786 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7787 XtSetArg(args[0], XtNlabel, buf);
7789 snprintf(buf, MSG_SIZ, "%s ", color);
7790 XtSetArg(args[0], XtNlabel, buf);
7795 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7796 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7798 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7799 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7802 XtSetValues(w, args, 3);
7806 DisplayWhiteClock(timeRemaining, highlight)
7812 if(appData.noGUI) return;
7813 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7814 if (highlight && iconPixmap == bIconPixmap) {
7815 iconPixmap = wIconPixmap;
7816 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7817 XtSetValues(shellWidget, args, 1);
7822 DisplayBlackClock(timeRemaining, highlight)
7828 if(appData.noGUI) return;
7829 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7830 if (highlight && iconPixmap == wIconPixmap) {
7831 iconPixmap = bIconPixmap;
7832 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7833 XtSetValues(shellWidget, args, 1);
7851 int StartChildProcess(cmdLine, dir, pr)
7858 int to_prog[2], from_prog[2];
7862 if (appData.debugMode) {
7863 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7866 /* We do NOT feed the cmdLine to the shell; we just
7867 parse it into blank-separated arguments in the
7868 most simple-minded way possible.
7871 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7874 while(*p == ' ') p++;
7876 if(*p == '"' || *p == '\'')
7877 p = strchr(++argv[i-1], *p);
7878 else p = strchr(p, ' ');
7879 if (p == NULL) break;
7884 SetUpChildIO(to_prog, from_prog);
7886 if ((pid = fork()) == 0) {
7888 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7889 close(to_prog[1]); // first close the unused pipe ends
7890 close(from_prog[0]);
7891 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7892 dup2(from_prog[1], 1);
7893 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7894 close(from_prog[1]); // and closing again loses one of the pipes!
7895 if(fileno(stderr) >= 2) // better safe than sorry...
7896 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7898 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7903 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7905 execvp(argv[0], argv);
7907 /* If we get here, exec failed */
7912 /* Parent process */
7914 close(from_prog[1]);
7916 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7919 cp->fdFrom = from_prog[0];
7920 cp->fdTo = to_prog[1];
7925 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7926 static RETSIGTYPE AlarmCallBack(int n)
7932 DestroyChildProcess(pr, signalType)
7936 ChildProc *cp = (ChildProc *) pr;
7938 if (cp->kind != CPReal) return;
7940 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7941 signal(SIGALRM, AlarmCallBack);
7943 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7944 kill(cp->pid, SIGKILL); // kill it forcefully
7945 wait((int *) 0); // and wait again
7949 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7951 /* Process is exiting either because of the kill or because of
7952 a quit command sent by the backend; either way, wait for it to die.
7961 InterruptChildProcess(pr)
7964 ChildProc *cp = (ChildProc *) pr;
7966 if (cp->kind != CPReal) return;
7967 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7970 int OpenTelnet(host, port, pr)
7975 char cmdLine[MSG_SIZ];
7977 if (port[0] == NULLCHAR) {
7978 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7980 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7982 return StartChildProcess(cmdLine, "", pr);
7985 int OpenTCP(host, port, pr)
7991 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7992 #else /* !OMIT_SOCKETS */
7994 struct sockaddr_in sa;
7996 unsigned short uport;
7999 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
8003 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8004 sa.sin_family = AF_INET;
8005 sa.sin_addr.s_addr = INADDR_ANY;
8006 uport = (unsigned short) 0;
8007 sa.sin_port = htons(uport);
8008 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
8012 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
8013 if (!(hp = gethostbyname(host))) {
8015 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
8016 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
8017 hp->h_addrtype = AF_INET;
8019 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
8020 hp->h_addr_list[0] = (char *) malloc(4);
8021 hp->h_addr_list[0][0] = b0;
8022 hp->h_addr_list[0][1] = b1;
8023 hp->h_addr_list[0][2] = b2;
8024 hp->h_addr_list[0][3] = b3;
8029 sa.sin_family = hp->h_addrtype;
8030 uport = (unsigned short) atoi(port);
8031 sa.sin_port = htons(uport);
8032 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8034 if (connect(s, (struct sockaddr *) &sa,
8035 sizeof(struct sockaddr_in)) < 0) {
8039 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8046 #endif /* !OMIT_SOCKETS */
8051 int OpenCommPort(name, pr)
8058 fd = open(name, 2, 0);
8059 if (fd < 0) return errno;
8061 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8071 int OpenLoopback(pr)
8077 SetUpChildIO(to, from);
8079 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8082 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8089 int OpenRcmd(host, user, cmd, pr)
8090 char *host, *user, *cmd;
8093 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8097 #define INPUT_SOURCE_BUF_SIZE 8192
8106 char buf[INPUT_SOURCE_BUF_SIZE];
8111 DoInputCallback(closure, source, xid)
8116 InputSource *is = (InputSource *) closure;
8121 if (is->lineByLine) {
8122 count = read(is->fd, is->unused,
8123 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8125 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8128 is->unused += count;
8130 while (p < is->unused) {
8131 q = memchr(p, '\n', is->unused - p);
8132 if (q == NULL) break;
8134 (is->func)(is, is->closure, p, q - p, 0);
8138 while (p < is->unused) {
8143 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8148 (is->func)(is, is->closure, is->buf, count, error);
8152 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8159 ChildProc *cp = (ChildProc *) pr;
8161 is = (InputSource *) calloc(1, sizeof(InputSource));
8162 is->lineByLine = lineByLine;
8166 is->fd = fileno(stdin);
8168 is->kind = cp->kind;
8169 is->fd = cp->fdFrom;
8172 is->unused = is->buf;
8175 is->xid = XtAppAddInput(appContext, is->fd,
8176 (XtPointer) (XtInputReadMask),
8177 (XtInputCallbackProc) DoInputCallback,
8179 is->closure = closure;
8180 return (InputSourceRef) is;
8184 RemoveInputSource(isr)
8187 InputSource *is = (InputSource *) isr;
8189 if (is->xid == 0) return;
8190 XtRemoveInput(is->xid);
8194 int OutputToProcess(pr, message, count, outError)
8200 static int line = 0;
8201 ChildProc *cp = (ChildProc *) pr;
8206 if (appData.noJoin || !appData.useInternalWrap)
8207 outCount = fwrite(message, 1, count, stdout);
8210 int width = get_term_width();
8211 int len = wrap(NULL, message, count, width, &line);
8212 char *msg = malloc(len);
8216 outCount = fwrite(message, 1, count, stdout);
8219 dbgchk = wrap(msg, message, count, width, &line);
8220 if (dbgchk != len && appData.debugMode)
8221 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8222 outCount = fwrite(msg, 1, dbgchk, stdout);
8228 outCount = write(cp->fdTo, message, count);
8238 /* Output message to process, with "ms" milliseconds of delay
8239 between each character. This is needed when sending the logon
8240 script to ICC, which for some reason doesn't like the
8241 instantaneous send. */
8242 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8249 ChildProc *cp = (ChildProc *) pr;
8254 r = write(cp->fdTo, message++, 1);
8267 /**** Animation code by Hugh Fisher, DCS, ANU.
8269 Known problem: if a window overlapping the board is
8270 moved away while a piece is being animated underneath,
8271 the newly exposed area won't be updated properly.
8272 I can live with this.
8274 Known problem: if you look carefully at the animation
8275 of pieces in mono mode, they are being drawn as solid
8276 shapes without interior detail while moving. Fixing
8277 this would be a major complication for minimal return.
8280 /* Masks for XPM pieces. Black and white pieces can have
8281 different shapes, but in the interest of retaining my
8282 sanity pieces must have the same outline on both light
8283 and dark squares, and all pieces must use the same
8284 background square colors/images. */
8286 static int xpmDone = 0;
8289 CreateAnimMasks (pieceDepth)
8296 unsigned long plane;
8299 /* Need a bitmap just to get a GC with right depth */
8300 buf = XCreatePixmap(xDisplay, xBoardWindow,
8302 values.foreground = 1;
8303 values.background = 0;
8304 /* Don't use XtGetGC, not read only */
8305 maskGC = XCreateGC(xDisplay, buf,
8306 GCForeground | GCBackground, &values);
8307 XFreePixmap(xDisplay, buf);
8309 buf = XCreatePixmap(xDisplay, xBoardWindow,
8310 squareSize, squareSize, pieceDepth);
8311 values.foreground = XBlackPixel(xDisplay, xScreen);
8312 values.background = XWhitePixel(xDisplay, xScreen);
8313 bufGC = XCreateGC(xDisplay, buf,
8314 GCForeground | GCBackground, &values);
8316 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8317 /* Begin with empty mask */
8318 if(!xpmDone) // [HGM] pieces: keep using existing
8319 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8320 squareSize, squareSize, 1);
8321 XSetFunction(xDisplay, maskGC, GXclear);
8322 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8323 0, 0, squareSize, squareSize);
8325 /* Take a copy of the piece */
8330 XSetFunction(xDisplay, bufGC, GXcopy);
8331 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8333 0, 0, squareSize, squareSize, 0, 0);
8335 /* XOR the background (light) over the piece */
8336 XSetFunction(xDisplay, bufGC, GXxor);
8338 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8339 0, 0, squareSize, squareSize, 0, 0);
8341 XSetForeground(xDisplay, bufGC, lightSquareColor);
8342 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8345 /* We now have an inverted piece image with the background
8346 erased. Construct mask by just selecting all the non-zero
8347 pixels - no need to reconstruct the original image. */
8348 XSetFunction(xDisplay, maskGC, GXor);
8350 /* Might be quicker to download an XImage and create bitmap
8351 data from it rather than this N copies per piece, but it
8352 only takes a fraction of a second and there is a much
8353 longer delay for loading the pieces. */
8354 for (n = 0; n < pieceDepth; n ++) {
8355 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8356 0, 0, squareSize, squareSize,
8362 XFreePixmap(xDisplay, buf);
8363 XFreeGC(xDisplay, bufGC);
8364 XFreeGC(xDisplay, maskGC);
8368 InitAnimState (anim, info)
8370 XWindowAttributes * info;
8375 /* Each buffer is square size, same depth as window */
8376 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8377 squareSize, squareSize, info->depth);
8378 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8379 squareSize, squareSize, info->depth);
8381 /* Create a plain GC for blitting */
8382 mask = GCForeground | GCBackground | GCFunction |
8383 GCPlaneMask | GCGraphicsExposures;
8384 values.foreground = XBlackPixel(xDisplay, xScreen);
8385 values.background = XWhitePixel(xDisplay, xScreen);
8386 values.function = GXcopy;
8387 values.plane_mask = AllPlanes;
8388 values.graphics_exposures = False;
8389 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8391 /* Piece will be copied from an existing context at
8392 the start of each new animation/drag. */
8393 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8395 /* Outline will be a read-only copy of an existing */
8396 anim->outlineGC = None;
8402 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8403 XWindowAttributes info;
8405 if (xpmDone && gameInfo.variant == old) return;
8406 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8407 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8409 InitAnimState(&game, &info);
8410 InitAnimState(&player, &info);
8412 /* For XPM pieces, we need bitmaps to use as masks. */
8414 CreateAnimMasks(info.depth);
8420 static Boolean frameWaiting;
8422 static RETSIGTYPE FrameAlarm (sig)
8425 frameWaiting = False;
8426 /* In case System-V style signals. Needed?? */
8427 signal(SIGALRM, FrameAlarm);
8434 struct itimerval delay;
8436 XSync(xDisplay, False);
8439 frameWaiting = True;
8440 signal(SIGALRM, FrameAlarm);
8441 delay.it_interval.tv_sec =
8442 delay.it_value.tv_sec = time / 1000;
8443 delay.it_interval.tv_usec =
8444 delay.it_value.tv_usec = (time % 1000) * 1000;
8445 setitimer(ITIMER_REAL, &delay, NULL);
8446 while (frameWaiting) pause();
8447 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8448 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8449 setitimer(ITIMER_REAL, &delay, NULL);
8459 XSync(xDisplay, False);
8461 usleep(time * 1000);
8466 /* Convert board position to corner of screen rect and color */
8469 ScreenSquare(column, row, pt, color)
8470 int column; int row; XPoint * pt; int * color;
8473 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8474 pt->y = lineGap + row * (squareSize + lineGap);
8476 pt->x = lineGap + column * (squareSize + lineGap);
8477 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8479 *color = SquareColor(row, column);
8482 /* Convert window coords to square */
8485 BoardSquare(x, y, column, row)
8486 int x; int y; int * column; int * row;
8488 *column = EventToSquare(x, BOARD_WIDTH);
8489 if (flipView && *column >= 0)
8490 *column = BOARD_WIDTH - 1 - *column;
8491 *row = EventToSquare(y, BOARD_HEIGHT);
8492 if (!flipView && *row >= 0)
8493 *row = BOARD_HEIGHT - 1 - *row;
8498 #undef Max /* just in case */
8500 #define Max(a, b) ((a) > (b) ? (a) : (b))
8501 #define Min(a, b) ((a) < (b) ? (a) : (b))
8504 SetRect(rect, x, y, width, height)
8505 XRectangle * rect; int x; int y; int width; int height;
8509 rect->width = width;
8510 rect->height = height;
8513 /* Test if two frames overlap. If they do, return
8514 intersection rect within old and location of
8515 that rect within new. */
8518 Intersect(old, new, size, area, pt)
8519 XPoint * old; XPoint * new;
8520 int size; XRectangle * area; XPoint * pt;
8522 if (old->x > new->x + size || new->x > old->x + size ||
8523 old->y > new->y + size || new->y > old->y + size) {
8526 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8527 size - abs(old->x - new->x), size - abs(old->y - new->y));
8528 pt->x = Max(old->x - new->x, 0);
8529 pt->y = Max(old->y - new->y, 0);
8534 /* For two overlapping frames, return the rect(s)
8535 in the old that do not intersect with the new. */
8538 CalcUpdateRects(old, new, size, update, nUpdates)
8539 XPoint * old; XPoint * new; int size;
8540 XRectangle update[]; int * nUpdates;
8544 /* If old = new (shouldn't happen) then nothing to draw */
8545 if (old->x == new->x && old->y == new->y) {
8549 /* Work out what bits overlap. Since we know the rects
8550 are the same size we don't need a full intersect calc. */
8552 /* Top or bottom edge? */
8553 if (new->y > old->y) {
8554 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8556 } else if (old->y > new->y) {
8557 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8558 size, old->y - new->y);
8561 /* Left or right edge - don't overlap any update calculated above. */
8562 if (new->x > old->x) {
8563 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8564 new->x - old->x, size - abs(new->y - old->y));
8566 } else if (old->x > new->x) {
8567 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8568 old->x - new->x, size - abs(new->y - old->y));
8575 /* Generate a series of frame coords from start->mid->finish.
8576 The movement rate doubles until the half way point is
8577 reached, then halves back down to the final destination,
8578 which gives a nice slow in/out effect. The algorithmn
8579 may seem to generate too many intermediates for short
8580 moves, but remember that the purpose is to attract the
8581 viewers attention to the piece about to be moved and
8582 then to where it ends up. Too few frames would be less
8586 Tween(start, mid, finish, factor, frames, nFrames)
8587 XPoint * start; XPoint * mid;
8588 XPoint * finish; int factor;
8589 XPoint frames[]; int * nFrames;
8591 int fraction, n, count;
8595 /* Slow in, stepping 1/16th, then 1/8th, ... */
8597 for (n = 0; n < factor; n++)
8599 for (n = 0; n < factor; n++) {
8600 frames[count].x = start->x + (mid->x - start->x) / fraction;
8601 frames[count].y = start->y + (mid->y - start->y) / fraction;
8603 fraction = fraction / 2;
8607 frames[count] = *mid;
8610 /* Slow out, stepping 1/2, then 1/4, ... */
8612 for (n = 0; n < factor; n++) {
8613 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8614 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8616 fraction = fraction * 2;
8621 /* Draw a piece on the screen without disturbing what's there */
8624 SelectGCMask(piece, clip, outline, mask)
8625 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8629 /* Bitmap for piece being moved. */
8630 if (appData.monoMode) {
8631 *mask = *pieceToSolid(piece);
8632 } else if (useImages) {
8634 *mask = xpmMask[piece];
8636 *mask = ximMaskPm[piece];
8639 *mask = *pieceToSolid(piece);
8642 /* GC for piece being moved. Square color doesn't matter, but
8643 since it gets modified we make a copy of the original. */
8645 if (appData.monoMode)
8650 if (appData.monoMode)
8655 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8657 /* Outline only used in mono mode and is not modified */
8659 *outline = bwPieceGC;
8661 *outline = wbPieceGC;
8665 OverlayPiece(piece, clip, outline, dest)
8666 ChessSquare piece; GC clip; GC outline; Drawable dest;
8671 /* Draw solid rectangle which will be clipped to shape of piece */
8672 XFillRectangle(xDisplay, dest, clip,
8673 0, 0, squareSize, squareSize);
8674 if (appData.monoMode)
8675 /* Also draw outline in contrasting color for black
8676 on black / white on white cases */
8677 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8678 0, 0, squareSize, squareSize, 0, 0, 1);
8680 /* Copy the piece */
8685 if(appData.upsideDown && flipView) kind ^= 2;
8686 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8688 0, 0, squareSize, squareSize,
8693 /* Animate the movement of a single piece */
8696 BeginAnimation(anim, piece, startColor, start)
8704 /* The old buffer is initialised with the start square (empty) */
8705 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8706 anim->prevFrame = *start;
8708 /* The piece will be drawn using its own bitmap as a matte */
8709 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8710 XSetClipMask(xDisplay, anim->pieceGC, mask);
8714 AnimationFrame(anim, frame, piece)
8719 XRectangle updates[4];
8724 /* Save what we are about to draw into the new buffer */
8725 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8726 frame->x, frame->y, squareSize, squareSize,
8729 /* Erase bits of the previous frame */
8730 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8731 /* Where the new frame overlapped the previous,
8732 the contents in newBuf are wrong. */
8733 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8734 overlap.x, overlap.y,
8735 overlap.width, overlap.height,
8737 /* Repaint the areas in the old that don't overlap new */
8738 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8739 for (i = 0; i < count; i++)
8740 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8741 updates[i].x - anim->prevFrame.x,
8742 updates[i].y - anim->prevFrame.y,
8743 updates[i].width, updates[i].height,
8744 updates[i].x, updates[i].y);
8746 /* Easy when no overlap */
8747 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8748 0, 0, squareSize, squareSize,
8749 anim->prevFrame.x, anim->prevFrame.y);
8752 /* Save this frame for next time round */
8753 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8754 0, 0, squareSize, squareSize,
8756 anim->prevFrame = *frame;
8758 /* Draw piece over original screen contents, not current,
8759 and copy entire rect. Wipes out overlapping piece images. */
8760 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8761 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8762 0, 0, squareSize, squareSize,
8763 frame->x, frame->y);
8767 EndAnimation (anim, finish)
8771 XRectangle updates[4];
8776 /* The main code will redraw the final square, so we
8777 only need to erase the bits that don't overlap. */
8778 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8779 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8780 for (i = 0; i < count; i++)
8781 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8782 updates[i].x - anim->prevFrame.x,
8783 updates[i].y - anim->prevFrame.y,
8784 updates[i].width, updates[i].height,
8785 updates[i].x, updates[i].y);
8787 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8788 0, 0, squareSize, squareSize,
8789 anim->prevFrame.x, anim->prevFrame.y);
8794 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8796 ChessSquare piece; int startColor;
8797 XPoint * start; XPoint * finish;
8798 XPoint frames[]; int nFrames;
8802 BeginAnimation(anim, piece, startColor, start);
8803 for (n = 0; n < nFrames; n++) {
8804 AnimationFrame(anim, &(frames[n]), piece);
8805 FrameDelay(appData.animSpeed);
8807 EndAnimation(anim, finish);
8811 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8814 ChessSquare piece = board[fromY][toY];
8815 board[fromY][toY] = EmptySquare;
8816 DrawPosition(FALSE, board);
8818 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8819 y = lineGap + toY * (squareSize + lineGap);
8821 x = lineGap + toX * (squareSize + lineGap);
8822 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8824 for(i=1; i<4*kFactor; i++) {
8825 int r = squareSize * 9 * i/(20*kFactor - 5);
8826 XFillArc(xDisplay, xBoardWindow, highlineGC,
8827 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8828 FrameDelay(appData.animSpeed);
8830 board[fromY][toY] = piece;
8833 /* Main control logic for deciding what to animate and how */
8836 AnimateMove(board, fromX, fromY, toX, toY)
8845 XPoint start, finish, mid;
8846 XPoint frames[kFactor * 2 + 1];
8847 int nFrames, startColor, endColor;
8849 /* Are we animating? */
8850 if (!appData.animate || appData.blindfold)
8853 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8854 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8855 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8857 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8858 piece = board[fromY][fromX];
8859 if (piece >= EmptySquare) return;
8864 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8867 if (appData.debugMode) {
8868 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8869 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8870 piece, fromX, fromY, toX, toY); }
8872 ScreenSquare(fromX, fromY, &start, &startColor);
8873 ScreenSquare(toX, toY, &finish, &endColor);
8876 /* Knight: make straight movement then diagonal */
8877 if (abs(toY - fromY) < abs(toX - fromX)) {
8878 mid.x = start.x + (finish.x - start.x) / 2;
8882 mid.y = start.y + (finish.y - start.y) / 2;
8885 mid.x = start.x + (finish.x - start.x) / 2;
8886 mid.y = start.y + (finish.y - start.y) / 2;
8889 /* Don't use as many frames for very short moves */
8890 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8891 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8893 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8894 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8895 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8897 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8898 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8901 /* Be sure end square is redrawn */
8902 damage[0][toY][toX] = True;
8906 DragPieceBegin(x, y)
8909 int boardX, boardY, color;
8912 /* Are we animating? */
8913 if (!appData.animateDragging || appData.blindfold)
8916 /* Figure out which square we start in and the
8917 mouse position relative to top left corner. */
8918 BoardSquare(x, y, &boardX, &boardY);
8919 player.startBoardX = boardX;
8920 player.startBoardY = boardY;
8921 ScreenSquare(boardX, boardY, &corner, &color);
8922 player.startSquare = corner;
8923 player.startColor = color;
8924 /* As soon as we start dragging, the piece will jump slightly to
8925 be centered over the mouse pointer. */
8926 player.mouseDelta.x = squareSize/2;
8927 player.mouseDelta.y = squareSize/2;
8928 /* Initialise animation */
8929 player.dragPiece = PieceForSquare(boardX, boardY);
8931 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8932 player.dragActive = True;
8933 BeginAnimation(&player, player.dragPiece, color, &corner);
8934 /* Mark this square as needing to be redrawn. Note that
8935 we don't remove the piece though, since logically (ie
8936 as seen by opponent) the move hasn't been made yet. */
8937 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8938 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8939 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8940 corner.x, corner.y, squareSize, squareSize,
8941 0, 0); // [HGM] zh: unstack in stead of grab
8942 if(gatingPiece != EmptySquare) {
8943 /* Kludge alert: When gating we want the introduced
8944 piece to appear on the from square. To generate an
8945 image of it, we draw it on the board, copy the image,
8946 and draw the original piece again. */
8947 ChessSquare piece = boards[currentMove][boardY][boardX];
8948 DrawSquare(boardY, boardX, gatingPiece, 0);
8949 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8950 corner.x, corner.y, squareSize, squareSize, 0, 0);
8951 DrawSquare(boardY, boardX, piece, 0);
8953 damage[0][boardY][boardX] = True;
8955 player.dragActive = False;
8965 /* Are we animating? */
8966 if (!appData.animateDragging || appData.blindfold)
8970 if (! player.dragActive)
8972 /* Move piece, maintaining same relative position
8973 of mouse within square */
8974 corner.x = x - player.mouseDelta.x;
8975 corner.y = y - player.mouseDelta.y;
8976 AnimationFrame(&player, &corner, player.dragPiece);
8978 if (appData.highlightDragging) {
8980 BoardSquare(x, y, &boardX, &boardY);
8981 SetHighlights(fromX, fromY, boardX, boardY);
8990 int boardX, boardY, color;
8993 /* Are we animating? */
8994 if (!appData.animateDragging || appData.blindfold)
8998 if (! player.dragActive)
9000 /* Last frame in sequence is square piece is
9001 placed on, which may not match mouse exactly. */
9002 BoardSquare(x, y, &boardX, &boardY);
9003 ScreenSquare(boardX, boardY, &corner, &color);
9004 EndAnimation(&player, &corner);
9006 /* Be sure end square is redrawn */
9007 damage[0][boardY][boardX] = True;
9009 /* This prevents weird things happening with fast successive
9010 clicks which on my Sun at least can cause motion events
9011 without corresponding press/release. */
9012 player.dragActive = False;
9015 /* Handle expose event while piece being dragged */
9020 if (!player.dragActive || appData.blindfold)
9023 /* What we're doing: logically, the move hasn't been made yet,
9024 so the piece is still in it's original square. But visually
9025 it's being dragged around the board. So we erase the square
9026 that the piece is on and draw it at the last known drag point. */
9027 BlankSquare(player.startSquare.x, player.startSquare.y,
9028 player.startColor, EmptySquare, xBoardWindow, 1);
9029 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9030 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9033 #include <sys/ioctl.h>
9034 int get_term_width()
9036 int fd, default_width;
9039 default_width = 79; // this is FICS default anyway...
9041 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9043 if (!ioctl(fd, TIOCGSIZE, &win))
9044 default_width = win.ts_cols;
9045 #elif defined(TIOCGWINSZ)
9047 if (!ioctl(fd, TIOCGWINSZ, &win))
9048 default_width = win.ws_col;
9050 return default_width;
9056 static int old_width = 0;
9057 int new_width = get_term_width();
9059 if (old_width != new_width)
9060 ics_printf("set width %d\n", new_width);
9061 old_width = new_width;
9064 void NotifyFrontendLogin()