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"
197 #include "xgamelist.h"
198 #include "xhistory.h"
199 #include "xedittags.h"
202 // must be moved to xengineoutput.h
204 void EngineOutputProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
206 void EvalGraphProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
214 #define usleep(t) _sleep2(((t)+500)/1000)
218 # define _(s) gettext (s)
219 # define N_(s) gettext_noop (s)
235 int main P((int argc, char **argv));
236 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
237 char *init_path, char *mode, int (*show_entry)(), char **name_return));
238 RETSIGTYPE CmailSigHandler P((int sig));
239 RETSIGTYPE IntSigHandler P((int sig));
240 RETSIGTYPE TermSizeSigHandler P((int sig));
241 void CreateGCs P((void));
242 void CreateXIMPieces P((void));
243 void CreateXPMPieces P((void));
244 void CreatePieces P((void));
245 void CreatePieceMenus P((void));
246 Widget CreateMenuBar P((Menu *mb));
247 Widget CreateButtonBar P ((MenuItem *mi));
248 char *FindFont P((char *pattern, int targetPxlSize));
249 void PieceMenuPopup P((Widget w, XEvent *event,
250 String *params, Cardinal *num_params));
251 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
252 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
253 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
254 u_int wreq, u_int hreq));
255 void CreateGrid P((void));
256 int EventToSquare P((int x, int limit));
257 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
258 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
259 void HandleUserMove P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void AnimateUserMove P((Widget w, XEvent * event,
262 String * params, Cardinal * nParams));
263 void HandlePV P((Widget w, XEvent * event,
264 String * params, Cardinal * nParams));
265 void WhiteClock P((Widget w, XEvent *event,
266 String *prms, Cardinal *nprms));
267 void BlackClock P((Widget w, XEvent *event,
268 String *prms, Cardinal *nprms));
269 void DrawPositionProc P((Widget w, XEvent *event,
270 String *prms, Cardinal *nprms));
271 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
273 void CommentPopUp P((char *title, char *label));
274 void CommentPopDown P((void));
275 void CommentCallback P((Widget w, XtPointer client_data,
276 XtPointer call_data));
277 void ICSInputBoxPopUp P((void));
278 void ICSInputBoxPopDown P((void));
279 void FileNamePopUp P((char *label, char *def,
280 FileProc proc, char *openMode));
281 void FileNamePopDown P((void));
282 void FileNameCallback P((Widget w, XtPointer client_data,
283 XtPointer call_data));
284 void FileNameAction P((Widget w, XEvent *event,
285 String *prms, Cardinal *nprms));
286 void AskQuestionReplyAction P((Widget w, XEvent *event,
287 String *prms, Cardinal *nprms));
288 void AskQuestionProc P((Widget w, XEvent *event,
289 String *prms, Cardinal *nprms));
290 void AskQuestionPopDown P((void));
291 void PromotionPopDown P((void));
292 void PromotionCallback P((Widget w, XtPointer client_data,
293 XtPointer call_data));
294 void EditCommentPopDown P((void));
295 void EditCommentCallback P((Widget w, XtPointer client_data,
296 XtPointer call_data));
297 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
298 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
299 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
300 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
302 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
304 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
306 void LoadPositionProc P((Widget w, XEvent *event,
307 String *prms, Cardinal *nprms));
308 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
310 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
312 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
314 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
316 void PastePositionProc P((Widget w, XEvent *event, String *prms,
318 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void SavePositionProc P((Widget w, XEvent *event,
322 String *prms, Cardinal *nprms));
323 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
324 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
326 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
330 void MachineWhiteProc P((Widget w, XEvent *event,
331 String *prms, Cardinal *nprms));
332 void AnalyzeModeProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void AnalyzeFileProc P((Widget w, XEvent *event,
335 String *prms, Cardinal *nprms));
336 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
338 void IcsClientProc P((Widget w, XEvent *event, String *prms,
340 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void EditPositionProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void EditCommentProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void IcsInputBoxProc P((Widget w, XEvent *event,
347 String *prms, Cardinal *nprms));
348 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void StopObservingProc P((Widget w, XEvent *event, String *prms,
364 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
366 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
374 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
376 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
379 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
381 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
383 void AutocommProc P((Widget w, XEvent *event, String *prms,
385 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void AutobsProc P((Widget w, XEvent *event, String *prms,
389 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
394 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
397 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
399 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
401 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
405 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
407 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
409 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
411 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
413 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
417 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
419 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
421 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
423 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void DisplayMove P((int moveNumber));
435 void DisplayTitle P((char *title));
436 void ICSInitScript P((void));
437 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
438 void ErrorPopUp P((char *title, char *text, int modal));
439 void ErrorPopDown P((void));
440 static char *ExpandPathName P((char *path));
441 static void CreateAnimVars P((void));
442 static void DragPieceMove P((int x, int y));
443 static void DrawDragPiece P((void));
444 char *ModeToWidgetName P((GameMode mode));
445 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void GameListOptionsPopDown P(());
454 void ShufflePopDown P(());
455 void EnginePopDown P(());
456 void UciPopDown P(());
457 void TimeControlPopDown P(());
458 void NewVariantPopDown P(());
459 void SettingsPopDown P(());
460 void update_ics_width P(());
461 int get_term_width P(());
462 int CopyMemoProc P(());
464 * XBoard depends on Xt R4 or higher
466 int xtVersion = XtSpecificationRelease;
471 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
472 jailSquareColor, highlightSquareColor, premoveHighlightColor;
473 Pixel lowTimeWarningColor;
474 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
475 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
476 wjPieceGC, bjPieceGC, prelineGC, countGC;
477 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
478 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
479 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
480 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
481 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
482 ICSInputShell, fileNameShell, askQuestionShell;
483 Widget historyShell, evalGraphShell, gameListShell;
484 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
485 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
486 Font clockFontID, coordFontID, countFontID;
487 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
488 XtAppContext appContext;
490 char *oldICSInteractionTitle;
494 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
496 Position commentX = -1, commentY = -1;
497 Dimension commentW, commentH;
498 typedef unsigned int BoardSize;
500 Boolean chessProgram;
502 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
503 int squareSize, smallLayout = 0, tinyLayout = 0,
504 marginW, marginH, // [HGM] for run-time resizing
505 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
506 ICSInputBoxUp = False, askQuestionUp = False,
507 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
508 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
509 Pixel timerForegroundPixel, timerBackgroundPixel;
510 Pixel buttonForegroundPixel, buttonBackgroundPixel;
511 char *chessDir, *programName, *programVersion,
512 *gameCopyFilename, *gamePasteFilename;
513 Boolean alwaysOnTop = False;
514 Boolean saveSettingsOnExit;
515 char *settingsFileName;
516 char *icsTextMenuString;
518 char *firstChessProgramNames;
519 char *secondChessProgramNames;
521 WindowPlacement wpMain;
522 WindowPlacement wpConsole;
523 WindowPlacement wpComment;
524 WindowPlacement wpMoveHistory;
525 WindowPlacement wpEvalGraph;
526 WindowPlacement wpEngineOutput;
527 WindowPlacement wpGameList;
528 WindowPlacement wpTags;
532 Pixmap pieceBitmap[2][(int)BlackPawn];
533 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
534 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
535 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
536 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
537 int useImages, useImageSqs;
538 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
539 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
540 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
541 XImage *ximLightSquare, *ximDarkSquare;
544 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
545 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
547 #define White(piece) ((int)(piece) < (int)BlackPawn)
549 /* Variables for doing smooth animation. This whole thing
550 would be much easier if the board was double-buffered,
551 but that would require a fairly major rewrite. */
556 GC blitGC, pieceGC, outlineGC;
557 XPoint startSquare, prevFrame, mouseDelta;
561 int startBoardX, startBoardY;
564 /* There can be two pieces being animated at once: a player
565 can begin dragging a piece before the remote opponent has moved. */
567 static AnimState game, player;
569 /* Bitmaps for use as masks when drawing XPM pieces.
570 Need one for each black and white piece. */
571 static Pixmap xpmMask[BlackKing + 1];
573 /* This magic number is the number of intermediate frames used
574 in each half of the animation. For short moves it's reduced
575 by 1. The total number of frames will be factor * 2 + 1. */
578 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
580 MenuItem fileMenu[] = {
581 {N_("New Game"), ResetProc},
582 {N_("New Shuffle Game ..."), ShuffleMenuProc},
583 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
584 {"----", NothingProc},
585 {N_("Load Game"), LoadGameProc},
586 {N_("Load Next Game"), LoadNextGameProc},
587 {N_("Load Previous Game"), LoadPrevGameProc},
588 {N_("Reload Same Game"), ReloadGameProc},
589 {N_("Save Game"), SaveGameProc},
590 {"----", NothingProc},
591 {N_("Copy Game"), CopyGameProc},
592 {N_("Paste Game"), PasteGameProc},
593 {"----", NothingProc},
594 {N_("Load Position"), LoadPositionProc},
595 {N_("Load Next Position"), LoadNextPositionProc},
596 {N_("Load Previous Position"), LoadPrevPositionProc},
597 {N_("Reload Same Position"), ReloadPositionProc},
598 {N_("Save Position"), SavePositionProc},
599 {"----", NothingProc},
600 {N_("Copy Position"), CopyPositionProc},
601 {N_("Paste Position"), PastePositionProc},
602 {"----", NothingProc},
603 {N_("Mail Move"), MailMoveProc},
604 {N_("Reload CMail Message"), ReloadCmailMsgProc},
605 {"----", NothingProc},
606 {N_("Exit"), QuitProc},
610 MenuItem modeMenu[] = {
611 {N_("Machine White"), MachineWhiteProc},
612 {N_("Machine Black"), MachineBlackProc},
613 {N_("Two Machines"), TwoMachinesProc},
614 {N_("Analysis Mode"), AnalyzeModeProc},
615 {N_("Analyze File"), AnalyzeFileProc },
616 {N_("ICS Client"), IcsClientProc},
617 {N_("Edit Game"), EditGameProc},
618 {N_("Edit Position"), EditPositionProc},
619 {N_("Training"), TrainingProc},
620 {"----", NothingProc},
621 {N_("Show Engine Output"), EngineOutputProc},
622 {N_("Show Evaluation Graph"), EvalGraphProc},
623 {N_("Show Game List"), ShowGameListProc},
624 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
625 {"----", NothingProc},
626 {N_("Edit Tags"), EditTagsProc},
627 {N_("Edit Comment"), EditCommentProc},
628 {N_("ICS Input Box"), IcsInputBoxProc},
629 {N_("Pause"), PauseProc},
633 MenuItem actionMenu[] = {
634 {N_("Accept"), AcceptProc},
635 {N_("Decline"), DeclineProc},
636 {N_("Rematch"), RematchProc},
637 {"----", NothingProc},
638 {N_("Call Flag"), CallFlagProc},
639 {N_("Draw"), DrawProc},
640 {N_("Adjourn"), AdjournProc},
641 {N_("Abort"), AbortProc},
642 {N_("Resign"), ResignProc},
643 {"----", NothingProc},
644 {N_("Stop Observing"), StopObservingProc},
645 {N_("Stop Examining"), StopExaminingProc},
646 {N_("Upload to Examine"), UploadProc},
647 {"----", NothingProc},
648 {N_("Adjudicate to White"), AdjuWhiteProc},
649 {N_("Adjudicate to Black"), AdjuBlackProc},
650 {N_("Adjudicate Draw"), AdjuDrawProc},
654 MenuItem stepMenu[] = {
655 {N_("Backward"), BackwardProc},
656 {N_("Forward"), ForwardProc},
657 {N_("Back to Start"), ToStartProc},
658 {N_("Forward to End"), ToEndProc},
659 {N_("Revert"), RevertProc},
660 {N_("Truncate Game"), TruncateGameProc},
661 {"----", NothingProc},
662 {N_("Move Now"), MoveNowProc},
663 {N_("Retract Move"), RetractMoveProc},
667 MenuItem optionsMenu[] = {
668 {N_("Flip View"), FlipViewProc},
669 {"----", NothingProc},
670 {N_("Adjudications ..."), EngineMenuProc},
671 {N_("General Settings ..."), UciMenuProc},
672 {N_("Engine #1 Settings ..."), FirstSettingsProc},
673 {N_("Engine #2 Settings ..."), SecondSettingsProc},
674 {N_("Time Control ..."), TimeControlProc},
675 {N_("Game List ..."), GameListOptionsPopUp},
676 {"----", NothingProc},
677 {N_("Always Queen"), AlwaysQueenProc},
678 {N_("Animate Dragging"), AnimateDraggingProc},
679 {N_("Animate Moving"), AnimateMovingProc},
680 {N_("Auto Comment"), AutocommProc},
681 {N_("Auto Flag"), AutoflagProc},
682 {N_("Auto Flip View"), AutoflipProc},
683 {N_("Auto Observe"), AutobsProc},
684 {N_("Auto Raise Board"), AutoraiseProc},
685 {N_("Auto Save"), AutosaveProc},
686 {N_("Blindfold"), BlindfoldProc},
687 {N_("Flash Moves"), FlashMovesProc},
688 {N_("Get Move List"), GetMoveListProc},
690 {N_("Highlight Dragging"), HighlightDraggingProc},
692 {N_("Highlight Last Move"), HighlightLastMoveProc},
693 {N_("Move Sound"), MoveSoundProc},
694 {N_("ICS Alarm"), IcsAlarmProc},
695 {N_("Old Save Style"), OldSaveStyleProc},
696 {N_("Periodic Updates"), PeriodicUpdatesProc},
697 {N_("Ponder Next Move"), PonderNextMoveProc},
698 {N_("Popup Exit Message"), PopupExitMessageProc},
699 {N_("Popup Move Errors"), PopupMoveErrorsProc},
700 {N_("Premove"), PremoveProc},
701 {N_("Quiet Play"), QuietPlayProc},
702 {N_("Show Coords"), ShowCoordsProc},
703 {N_("Hide Thinking"), HideThinkingProc},
704 {N_("Test Legality"), TestLegalityProc},
705 {"----", NothingProc},
706 {N_("Save Settings Now"), SaveSettingsProc},
707 {N_("Save Settings on Exit"), SaveOnExitProc},
711 MenuItem helpMenu[] = {
712 {N_("Info XBoard"), InfoProc},
713 {N_("Man XBoard"), ManProc},
714 {"----", NothingProc},
715 {N_("Hint"), HintProc},
716 {N_("Book"), BookProc},
717 {"----", NothingProc},
718 {N_("About XBoard"), AboutProc},
723 {N_("File"), fileMenu},
724 {N_("Mode"), modeMenu},
725 {N_("Action"), actionMenu},
726 {N_("Step"), stepMenu},
727 {N_("Options"), optionsMenu},
728 {N_("Help"), helpMenu},
732 #define PAUSE_BUTTON N_("P")
733 MenuItem buttonBar[] = {
736 {PAUSE_BUTTON, PauseProc},
742 #define PIECE_MENU_SIZE 18
743 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
744 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
745 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
746 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
747 N_("Empty square"), N_("Clear board") },
748 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
749 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
750 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
751 N_("Empty square"), N_("Clear board") }
753 /* must be in same order as PieceMenuStrings! */
754 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
755 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
756 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
757 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
758 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
759 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
760 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
761 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
762 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
765 #define DROP_MENU_SIZE 6
766 String dropMenuStrings[DROP_MENU_SIZE] = {
767 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
769 /* must be in same order as PieceMenuStrings! */
770 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
771 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
772 WhiteRook, WhiteQueen
780 DropMenuEnables dmEnables[] = {
798 { XtNborderWidth, 0 },
799 { XtNdefaultDistance, 0 },
803 { XtNborderWidth, 0 },
804 { XtNresizable, (XtArgVal) True },
808 { XtNborderWidth, 0 },
814 { XtNjustify, (XtArgVal) XtJustifyRight },
815 { XtNlabel, (XtArgVal) "..." },
816 { XtNresizable, (XtArgVal) True },
817 { XtNresize, (XtArgVal) False }
820 Arg messageArgs[] = {
821 { XtNjustify, (XtArgVal) XtJustifyLeft },
822 { XtNlabel, (XtArgVal) "..." },
823 { XtNresizable, (XtArgVal) True },
824 { XtNresize, (XtArgVal) False }
828 { XtNborderWidth, 0 },
829 { XtNjustify, (XtArgVal) XtJustifyLeft }
832 XtResource clientResources[] = {
833 { "flashCount", "flashCount", XtRInt, sizeof(int),
834 XtOffset(AppDataPtr, flashCount), XtRImmediate,
835 (XtPointer) FLASH_COUNT },
838 XrmOptionDescRec shellOptions[] = {
839 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
840 { "-flash", "flashCount", XrmoptionNoArg, "3" },
841 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
844 XtActionsRec boardActions[] = {
845 { "DrawPosition", DrawPositionProc },
846 { "HandleUserMove", HandleUserMove },
847 { "AnimateUserMove", AnimateUserMove },
848 { "HandlePV", HandlePV },
849 { "UnLoadPV", UnLoadPV },
850 { "FileNameAction", FileNameAction },
851 { "AskQuestionProc", AskQuestionProc },
852 { "AskQuestionReplyAction", AskQuestionReplyAction },
853 { "PieceMenuPopup", PieceMenuPopup },
854 { "WhiteClock", WhiteClock },
855 { "BlackClock", BlackClock },
856 { "Iconify", Iconify },
857 { "ResetProc", ResetProc },
858 { "LoadGameProc", LoadGameProc },
859 { "LoadNextGameProc", LoadNextGameProc },
860 { "LoadPrevGameProc", LoadPrevGameProc },
861 { "LoadSelectedProc", LoadSelectedProc },
862 { "SetFilterProc", SetFilterProc },
863 { "ReloadGameProc", ReloadGameProc },
864 { "LoadPositionProc", LoadPositionProc },
865 { "LoadNextPositionProc", LoadNextPositionProc },
866 { "LoadPrevPositionProc", LoadPrevPositionProc },
867 { "ReloadPositionProc", ReloadPositionProc },
868 { "CopyPositionProc", CopyPositionProc },
869 { "PastePositionProc", PastePositionProc },
870 { "CopyGameProc", CopyGameProc },
871 { "PasteGameProc", PasteGameProc },
872 { "SaveGameProc", SaveGameProc },
873 { "SavePositionProc", SavePositionProc },
874 { "MailMoveProc", MailMoveProc },
875 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
876 { "QuitProc", QuitProc },
877 { "MachineWhiteProc", MachineWhiteProc },
878 { "MachineBlackProc", MachineBlackProc },
879 { "AnalysisModeProc", AnalyzeModeProc },
880 { "AnalyzeFileProc", AnalyzeFileProc },
881 { "TwoMachinesProc", TwoMachinesProc },
882 { "IcsClientProc", IcsClientProc },
883 { "EditGameProc", EditGameProc },
884 { "EditPositionProc", EditPositionProc },
885 { "TrainingProc", EditPositionProc },
886 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
887 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
888 { "ShowGameListProc", ShowGameListProc },
889 { "ShowMoveListProc", HistoryShowProc},
890 { "EditTagsProc", EditCommentProc },
891 { "EditCommentProc", EditCommentProc },
892 { "IcsAlarmProc", IcsAlarmProc },
893 { "IcsInputBoxProc", IcsInputBoxProc },
894 { "PauseProc", PauseProc },
895 { "AcceptProc", AcceptProc },
896 { "DeclineProc", DeclineProc },
897 { "RematchProc", RematchProc },
898 { "CallFlagProc", CallFlagProc },
899 { "DrawProc", DrawProc },
900 { "AdjournProc", AdjournProc },
901 { "AbortProc", AbortProc },
902 { "ResignProc", ResignProc },
903 { "AdjuWhiteProc", AdjuWhiteProc },
904 { "AdjuBlackProc", AdjuBlackProc },
905 { "AdjuDrawProc", AdjuDrawProc },
906 { "EnterKeyProc", EnterKeyProc },
907 { "UpKeyProc", UpKeyProc },
908 { "DownKeyProc", DownKeyProc },
909 { "StopObservingProc", StopObservingProc },
910 { "StopExaminingProc", StopExaminingProc },
911 { "UploadProc", UploadProc },
912 { "BackwardProc", BackwardProc },
913 { "ForwardProc", ForwardProc },
914 { "ToStartProc", ToStartProc },
915 { "ToEndProc", ToEndProc },
916 { "RevertProc", RevertProc },
917 { "TruncateGameProc", TruncateGameProc },
918 { "MoveNowProc", MoveNowProc },
919 { "RetractMoveProc", RetractMoveProc },
920 { "AlwaysQueenProc", AlwaysQueenProc },
921 { "AnimateDraggingProc", AnimateDraggingProc },
922 { "AnimateMovingProc", AnimateMovingProc },
923 { "AutoflagProc", AutoflagProc },
924 { "AutoflipProc", AutoflipProc },
925 { "AutobsProc", AutobsProc },
926 { "AutoraiseProc", AutoraiseProc },
927 { "AutosaveProc", AutosaveProc },
928 { "BlindfoldProc", BlindfoldProc },
929 { "FlashMovesProc", FlashMovesProc },
930 { "FlipViewProc", FlipViewProc },
931 { "GetMoveListProc", GetMoveListProc },
933 { "HighlightDraggingProc", HighlightDraggingProc },
935 { "HighlightLastMoveProc", HighlightLastMoveProc },
936 { "IcsAlarmProc", IcsAlarmProc },
937 { "MoveSoundProc", MoveSoundProc },
938 { "OldSaveStyleProc", OldSaveStyleProc },
939 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
940 { "PonderNextMoveProc", PonderNextMoveProc },
941 { "PopupExitMessageProc", PopupExitMessageProc },
942 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
943 { "PremoveProc", PremoveProc },
944 { "QuietPlayProc", QuietPlayProc },
945 { "ShowCoordsProc", ShowCoordsProc },
946 { "ShowThinkingProc", ShowThinkingProc },
947 { "HideThinkingProc", HideThinkingProc },
948 { "TestLegalityProc", TestLegalityProc },
949 { "SaveSettingsProc", SaveSettingsProc },
950 { "SaveOnExitProc", SaveOnExitProc },
951 { "InfoProc", InfoProc },
952 { "ManProc", ManProc },
953 { "HintProc", HintProc },
954 { "BookProc", BookProc },
955 { "AboutGameProc", AboutGameProc },
956 { "AboutProc", AboutProc },
957 { "DebugProc", DebugProc },
958 { "NothingProc", NothingProc },
959 { "CommentPopDown", (XtActionProc) CommentPopDown },
960 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
961 { "TagsPopDown", (XtActionProc) TagsPopDown },
962 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
963 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
964 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
965 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
966 { "GameListPopDown", (XtActionProc) GameListPopDown },
967 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
968 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
969 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
970 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
971 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
972 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
973 { "EnginePopDown", (XtActionProc) EnginePopDown },
974 { "UciPopDown", (XtActionProc) UciPopDown },
975 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
976 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
977 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
978 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
981 char globalTranslations[] =
982 ":<Key>R: ResignProc() \n \
983 :<Key>r: ResetProc() \n \
984 :<Key>g: LoadGameProc() \n \
985 :<Key>N: LoadNextGameProc() \n \
986 :<Key>P: LoadPrevGameProc() \n \
987 :<Key>Q: QuitProc() \n \
988 :<Key>F: ToEndProc() \n \
989 :<Key>f: ForwardProc() \n \
990 :<Key>B: ToStartProc() \n \
991 :<Key>b: BackwardProc() \n \
992 :<Key>p: PauseProc() \n \
993 :<Key>d: DrawProc() \n \
994 :<Key>t: CallFlagProc() \n \
995 :<Key>i: Iconify() \n \
996 :<Key>c: Iconify() \n \
997 :<Key>v: FlipViewProc() \n \
998 <KeyDown>Control_L: BackwardProc() \n \
999 <KeyUp>Control_L: ForwardProc() \n \
1000 <KeyDown>Control_R: BackwardProc() \n \
1001 <KeyUp>Control_R: ForwardProc() \n \
1002 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1003 \"Send to chess program:\",,1) \n \
1004 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1005 \"Send to second chess program:\",,2) \n";
1007 char boardTranslations[] =
1008 "<Btn1Down>: HandleUserMove() \n \
1009 <Btn1Up>: HandleUserMove() \n \
1010 <Btn1Motion>: AnimateUserMove() \n \
1011 <Btn3Motion>: HandlePV() \n \
1012 <Btn3Up>: PieceMenuPopup(menuB) \n \
1013 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1014 PieceMenuPopup(menuB) \n \
1015 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1016 PieceMenuPopup(menuW) \n \
1017 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1018 PieceMenuPopup(menuW) \n \
1019 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1020 PieceMenuPopup(menuB) \n";
1022 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1023 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1025 char ICSInputTranslations[] =
1026 "<Key>Up: UpKeyProc() \n "
1027 "<Key>Down: DownKeyProc() \n "
1028 "<Key>Return: EnterKeyProc() \n";
1030 String xboardResources[] = {
1031 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1032 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1033 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1038 /* Max possible square size */
1039 #define MAXSQSIZE 256
1041 static int xpm_avail[MAXSQSIZE];
1043 #ifdef HAVE_DIR_STRUCT
1045 /* Extract piece size from filename */
1047 xpm_getsize(name, len, ext)
1058 if ((p=strchr(name, '.')) == NULL ||
1059 StrCaseCmp(p+1, ext) != 0)
1065 while (*p && isdigit(*p))
1072 /* Setup xpm_avail */
1074 xpm_getavail(dirname, ext)
1082 for (i=0; i<MAXSQSIZE; ++i)
1085 if (appData.debugMode)
1086 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1088 dir = opendir(dirname);
1091 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1092 programName, dirname);
1096 while ((ent=readdir(dir)) != NULL) {
1097 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1098 if (i > 0 && i < MAXSQSIZE)
1108 xpm_print_avail(fp, ext)
1114 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1115 for (i=1; i<MAXSQSIZE; ++i) {
1121 /* Return XPM piecesize closest to size */
1123 xpm_closest_to(dirname, size, ext)
1129 int sm_diff = MAXSQSIZE;
1133 xpm_getavail(dirname, ext);
1135 if (appData.debugMode)
1136 xpm_print_avail(stderr, ext);
1138 for (i=1; i<MAXSQSIZE; ++i) {
1141 diff = (diff<0) ? -diff : diff;
1142 if (diff < sm_diff) {
1150 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1156 #else /* !HAVE_DIR_STRUCT */
1157 /* If we are on a system without a DIR struct, we can't
1158 read the directory, so we can't collect a list of
1159 filenames, etc., so we can't do any size-fitting. */
1161 xpm_closest_to(dirname, size, ext)
1166 fprintf(stderr, _("\
1167 Warning: No DIR structure found on this system --\n\
1168 Unable to autosize for XPM/XIM pieces.\n\
1169 Please report this error to frankm@hiwaay.net.\n\
1170 Include system type & operating system in message.\n"));
1173 #endif /* HAVE_DIR_STRUCT */
1175 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1176 "magenta", "cyan", "white" };
1180 TextColors textColors[(int)NColorClasses];
1182 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1184 parse_color(str, which)
1188 char *p, buf[100], *d;
1191 if (strlen(str) > 99) /* watch bounds on buf */
1196 for (i=0; i<which; ++i) {
1203 /* Could be looking at something like:
1205 .. in which case we want to stop on a comma also */
1206 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1210 return -1; /* Use default for empty field */
1213 if (which == 2 || isdigit(*p))
1216 while (*p && isalpha(*p))
1221 for (i=0; i<8; ++i) {
1222 if (!StrCaseCmp(buf, cnames[i]))
1223 return which? (i+40) : (i+30);
1225 if (!StrCaseCmp(buf, "default")) return -1;
1227 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1232 parse_cpair(cc, str)
1236 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1237 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1242 /* bg and attr are optional */
1243 textColors[(int)cc].bg = parse_color(str, 1);
1244 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1245 textColors[(int)cc].attr = 0;
1251 /* Arrange to catch delete-window events */
1252 Atom wm_delete_window;
1254 CatchDeleteWindow(Widget w, String procname)
1257 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1258 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1259 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1266 XtSetArg(args[0], XtNiconic, False);
1267 XtSetValues(shellWidget, args, 1);
1269 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1272 //---------------------------------------------------------------------------------------------------------
1273 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1276 #define CW_USEDEFAULT (1<<31)
1277 #define ICS_TEXT_MENU_SIZE 90
1278 #define DEBUG_FILE "xboard.debug"
1279 #define SetCurrentDirectory chdir
1280 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1284 // these two must some day move to frontend.h, when they are implemented
1285 Boolean GameListIsUp();
1287 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1290 // front-end part of option handling
1292 // [HGM] This platform-dependent table provides the location for storing the color info
1293 extern char *crWhite, * crBlack;
1297 &appData.whitePieceColor,
1298 &appData.blackPieceColor,
1299 &appData.lightSquareColor,
1300 &appData.darkSquareColor,
1301 &appData.highlightSquareColor,
1302 &appData.premoveHighlightColor,
1303 &appData.lowTimeWarningColor,
1314 // [HGM] font: keep a font for each square size, even non-stndard ones
1315 #define NUM_SIZES 18
1316 #define MAX_SIZE 130
1317 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1318 char *fontTable[NUM_FONTS][MAX_SIZE];
1321 ParseFont(char *name, int number)
1322 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1324 if(sscanf(name, "size%d:", &size)) {
1325 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1326 // defer processing it until we know if it matches our board size
1327 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1328 fontTable[number][size] = strdup(strchr(name, ':')+1);
1329 fontValid[number][size] = True;
1334 case 0: // CLOCK_FONT
1335 appData.clockFont = strdup(name);
1337 case 1: // MESSAGE_FONT
1338 appData.font = strdup(name);
1340 case 2: // COORD_FONT
1341 appData.coordFont = strdup(name);
1346 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1351 { // only 2 fonts currently
1352 appData.clockFont = CLOCK_FONT_NAME;
1353 appData.coordFont = COORD_FONT_NAME;
1354 appData.font = DEFAULT_FONT_NAME;
1359 { // no-op, until we identify the code for this already in XBoard and move it here
1363 ParseColor(int n, char *name)
1364 { // in XBoard, just copy the color-name string
1365 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1369 ParseTextAttribs(ColorClass cc, char *s)
1371 (&appData.colorShout)[cc] = strdup(s);
1375 ParseBoardSize(void *addr, char *name)
1377 appData.boardSize = strdup(name);
1382 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1386 SetCommPortDefaults()
1387 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1390 // [HGM] args: these three cases taken out to stay in front-end
1392 SaveFontArg(FILE *f, ArgDescriptor *ad)
1394 char *name, buf[MSG_SIZ];
1395 int i, n = (int)ad->argLoc;
1397 case 0: // CLOCK_FONT
1398 name = appData.clockFont;
1400 case 1: // MESSAGE_FONT
1401 name = appData.font;
1403 case 2: // COORD_FONT
1404 name = appData.coordFont;
1409 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1410 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1411 fontTable[n][squareSize] = strdup(name);
1412 fontValid[n][squareSize] = True;
1415 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1416 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1421 { // nothing to do, as the sounds are at all times represented by their text-string names already
1425 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1426 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1427 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1431 SaveColor(FILE *f, ArgDescriptor *ad)
1432 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1433 if(colorVariable[(int)ad->argLoc])
1434 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1438 SaveBoardSize(FILE *f, char *name, void *addr)
1439 { // wrapper to shield back-end from BoardSize & sizeInfo
1440 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1444 ParseCommPortSettings(char *s)
1445 { // no such option in XBoard (yet)
1448 extern Widget engineOutputShell;
1449 extern Widget tagsShell, editTagsShell;
1451 GetActualPlacement(Widget wg, WindowPlacement *wp)
1461 XtSetArg(args[i], XtNx, &x); i++;
1462 XtSetArg(args[i], XtNy, &y); i++;
1463 XtSetArg(args[i], XtNwidth, &w); i++;
1464 XtSetArg(args[i], XtNheight, &h); i++;
1465 XtGetValues(wg, args, i);
1474 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1475 // In XBoard this will have to wait until awareness of window parameters is implemented
1476 GetActualPlacement(shellWidget, &wpMain);
1477 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1478 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1479 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1480 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1481 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1482 else GetActualPlacement(editShell, &wpComment);
1483 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1484 else GetActualPlacement(editTagsShell, &wpTags);
1488 PrintCommPortSettings(FILE *f, char *name)
1489 { // This option does not exist in XBoard
1493 MySearchPath(char *installDir, char *name, char *fullname)
1494 { // just append installDir and name. Perhaps ExpandPath should be used here?
1495 name = ExpandPathName(name);
1496 if(name && name[0] == '/') strcpy(fullname, name); else {
1497 sprintf(fullname, "%s%c%s", installDir, '/', name);
1503 MyGetFullPathName(char *name, char *fullname)
1504 { // should use ExpandPath?
1505 name = ExpandPathName(name);
1506 strcpy(fullname, name);
1511 EnsureOnScreen(int *x, int *y, int minX, int minY)
1518 { // [HGM] args: allows testing if main window is realized from back-end
1519 return xBoardWindow != 0;
1523 PopUpStartupDialog()
1524 { // start menu not implemented in XBoard
1527 ConvertToLine(int argc, char **argv)
1529 static char line[128*1024], buf[1024];
1533 for(i=1; i<argc; i++) {
1534 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1535 && argv[i][0] != '{' )
1536 sprintf(buf, "{%s} ", argv[i]);
1537 else sprintf(buf, "%s ", argv[i]);
1540 line[strlen(line)-1] = NULLCHAR;
1544 //--------------------------------------------------------------------------------------------
1547 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1549 #define BoardSize int
1550 void InitDrawingSizes(BoardSize boardSize, int flags)
1551 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1552 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1554 XtGeometryResult gres;
1557 if(!formWidget) return;
1560 * Enable shell resizing.
1562 shellArgs[0].value = (XtArgVal) &w;
1563 shellArgs[1].value = (XtArgVal) &h;
1564 XtGetValues(shellWidget, shellArgs, 2);
1566 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1567 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1568 XtSetValues(shellWidget, &shellArgs[2], 4);
1570 XtSetArg(args[0], XtNdefaultDistance, &sep);
1571 XtGetValues(formWidget, args, 1);
1573 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1574 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1577 XtSetArg(args[0], XtNwidth, boardWidth);
1578 XtSetArg(args[1], XtNheight, boardHeight);
1579 XtSetValues(boardWidget, args, 2);
1581 timerWidth = (boardWidth - sep) / 2;
1582 XtSetArg(args[0], XtNwidth, timerWidth);
1583 XtSetValues(whiteTimerWidget, args, 1);
1584 XtSetValues(blackTimerWidget, args, 1);
1586 XawFormDoLayout(formWidget, False);
1588 if (appData.titleInWindow) {
1590 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1591 XtSetArg(args[i], XtNheight, &h); i++;
1592 XtGetValues(titleWidget, args, i);
1594 w = boardWidth - 2*bor;
1596 XtSetArg(args[0], XtNwidth, &w);
1597 XtGetValues(menuBarWidget, args, 1);
1598 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1601 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1602 if (gres != XtGeometryYes && appData.debugMode) {
1604 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1605 programName, gres, w, h, wr, hr);
1609 XawFormDoLayout(formWidget, True);
1612 * Inhibit shell resizing.
1614 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1615 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1616 shellArgs[4].value = shellArgs[2].value = w;
1617 shellArgs[5].value = shellArgs[3].value = h;
1618 XtSetValues(shellWidget, &shellArgs[0], 6);
1620 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1623 for(i=0; i<4; i++) {
1625 for(p=0; p<=(int)WhiteKing; p++)
1626 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1627 if(gameInfo.variant == VariantShogi) {
1628 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1629 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1630 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1631 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1632 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1635 if(gameInfo.variant == VariantGothic) {
1636 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1640 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1641 for(p=0; p<=(int)WhiteKing; p++)
1642 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1643 if(gameInfo.variant == VariantShogi) {
1644 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1645 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1646 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1647 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1648 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1651 if(gameInfo.variant == VariantGothic) {
1652 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1658 for(i=0; i<2; i++) {
1660 for(p=0; p<=(int)WhiteKing; p++)
1661 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1662 if(gameInfo.variant == VariantShogi) {
1663 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1664 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1665 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1666 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1667 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1670 if(gameInfo.variant == VariantGothic) {
1671 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1682 void EscapeExpand(char *p, char *q)
1683 { // [HGM] initstring: routine to shape up string arguments
1684 while(*p++ = *q++) if(p[-1] == '\\')
1686 case 'n': p[-1] = '\n'; break;
1687 case 'r': p[-1] = '\r'; break;
1688 case 't': p[-1] = '\t'; break;
1689 case '\\': p[-1] = '\\'; break;
1690 case 0: *p = 0; return;
1691 default: p[-1] = q[-1]; break;
1700 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1701 XSetWindowAttributes window_attributes;
1703 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1704 XrmValue vFrom, vTo;
1705 XtGeometryResult gres;
1708 int forceMono = False;
1710 srandom(time(0)); // [HGM] book: make random truly random
1712 setbuf(stdout, NULL);
1713 setbuf(stderr, NULL);
1716 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1717 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1721 programName = strrchr(argv[0], '/');
1722 if (programName == NULL)
1723 programName = argv[0];
1728 XtSetLanguageProc(NULL, NULL, NULL);
1729 bindtextdomain(PACKAGE, LOCALEDIR);
1730 textdomain(PACKAGE);
1734 XtAppInitialize(&appContext, "XBoard", shellOptions,
1735 XtNumber(shellOptions),
1736 &argc, argv, xboardResources, NULL, 0);
1737 appData.boardSize = "";
1738 InitAppData(ConvertToLine(argc, argv));
1740 if (p == NULL) p = "/tmp";
1741 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1742 gameCopyFilename = (char*) malloc(i);
1743 gamePasteFilename = (char*) malloc(i);
1744 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1745 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1747 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1748 clientResources, XtNumber(clientResources),
1751 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1752 static char buf[MSG_SIZ];
1753 EscapeExpand(buf, appData.initString);
1754 appData.initString = strdup(buf);
1755 EscapeExpand(buf, appData.secondInitString);
1756 appData.secondInitString = strdup(buf);
1757 EscapeExpand(buf, appData.firstComputerString);
1758 appData.firstComputerString = strdup(buf);
1759 EscapeExpand(buf, appData.secondComputerString);
1760 appData.secondComputerString = strdup(buf);
1763 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1766 if (chdir(chessDir) != 0) {
1767 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1773 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1774 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1775 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1776 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1779 setbuf(debugFP, NULL);
1782 /* [HGM,HR] make sure board size is acceptable */
1783 if(appData.NrFiles > BOARD_FILES ||
1784 appData.NrRanks > BOARD_RANKS )
1785 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1788 /* This feature does not work; animation needs a rewrite */
1789 appData.highlightDragging = FALSE;
1793 xDisplay = XtDisplay(shellWidget);
1794 xScreen = DefaultScreen(xDisplay);
1795 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1797 gameInfo.variant = StringToVariant(appData.variant);
1798 InitPosition(FALSE);
1801 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1803 if (isdigit(appData.boardSize[0])) {
1804 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1805 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1806 &fontPxlSize, &smallLayout, &tinyLayout);
1808 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1809 programName, appData.boardSize);
1813 /* Find some defaults; use the nearest known size */
1814 SizeDefaults *szd, *nearest;
1815 int distance = 99999;
1816 nearest = szd = sizeDefaults;
1817 while (szd->name != NULL) {
1818 if (abs(szd->squareSize - squareSize) < distance) {
1820 distance = abs(szd->squareSize - squareSize);
1821 if (distance == 0) break;
1825 if (i < 2) lineGap = nearest->lineGap;
1826 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1827 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1828 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1829 if (i < 6) smallLayout = nearest->smallLayout;
1830 if (i < 7) tinyLayout = nearest->tinyLayout;
1833 SizeDefaults *szd = sizeDefaults;
1834 if (*appData.boardSize == NULLCHAR) {
1835 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1836 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1839 if (szd->name == NULL) szd--;
1840 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1842 while (szd->name != NULL &&
1843 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1844 if (szd->name == NULL) {
1845 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1846 programName, appData.boardSize);
1850 squareSize = szd->squareSize;
1851 lineGap = szd->lineGap;
1852 clockFontPxlSize = szd->clockFontPxlSize;
1853 coordFontPxlSize = szd->coordFontPxlSize;
1854 fontPxlSize = szd->fontPxlSize;
1855 smallLayout = szd->smallLayout;
1856 tinyLayout = szd->tinyLayout;
1857 // [HGM] font: use defaults from settings file if available and not overruled
1859 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1860 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1861 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1862 appData.font = fontTable[MESSAGE_FONT][squareSize];
1863 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1864 appData.coordFont = fontTable[COORD_FONT][squareSize];
1866 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1867 if (strlen(appData.pixmapDirectory) > 0) {
1868 p = ExpandPathName(appData.pixmapDirectory);
1870 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1871 appData.pixmapDirectory);
1874 if (appData.debugMode) {
1875 fprintf(stderr, _("\
1876 XBoard square size (hint): %d\n\
1877 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1879 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1880 if (appData.debugMode) {
1881 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1885 /* [HR] height treated separately (hacked) */
1886 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1887 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1888 if (appData.showJail == 1) {
1889 /* Jail on top and bottom */
1890 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1891 XtSetArg(boardArgs[2], XtNheight,
1892 boardHeight + 2*(lineGap + squareSize));
1893 } else if (appData.showJail == 2) {
1895 XtSetArg(boardArgs[1], XtNwidth,
1896 boardWidth + 2*(lineGap + squareSize));
1897 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1900 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1901 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1905 * Determine what fonts to use.
1907 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1908 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1909 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1910 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1911 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1912 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1913 appData.font = FindFont(appData.font, fontPxlSize);
1914 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1915 countFontStruct = XQueryFont(xDisplay, countFontID);
1916 // appData.font = FindFont(appData.font, fontPxlSize);
1918 xdb = XtDatabase(xDisplay);
1919 XrmPutStringResource(&xdb, "*font", appData.font);
1922 * Detect if there are not enough colors available and adapt.
1924 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1925 appData.monoMode = True;
1928 if (!appData.monoMode) {
1929 vFrom.addr = (caddr_t) appData.lightSquareColor;
1930 vFrom.size = strlen(appData.lightSquareColor);
1931 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1932 if (vTo.addr == NULL) {
1933 appData.monoMode = True;
1936 lightSquareColor = *(Pixel *) vTo.addr;
1939 if (!appData.monoMode) {
1940 vFrom.addr = (caddr_t) appData.darkSquareColor;
1941 vFrom.size = strlen(appData.darkSquareColor);
1942 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1943 if (vTo.addr == NULL) {
1944 appData.monoMode = True;
1947 darkSquareColor = *(Pixel *) vTo.addr;
1950 if (!appData.monoMode) {
1951 vFrom.addr = (caddr_t) appData.whitePieceColor;
1952 vFrom.size = strlen(appData.whitePieceColor);
1953 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1954 if (vTo.addr == NULL) {
1955 appData.monoMode = True;
1958 whitePieceColor = *(Pixel *) vTo.addr;
1961 if (!appData.monoMode) {
1962 vFrom.addr = (caddr_t) appData.blackPieceColor;
1963 vFrom.size = strlen(appData.blackPieceColor);
1964 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1965 if (vTo.addr == NULL) {
1966 appData.monoMode = True;
1969 blackPieceColor = *(Pixel *) vTo.addr;
1973 if (!appData.monoMode) {
1974 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1975 vFrom.size = strlen(appData.highlightSquareColor);
1976 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1977 if (vTo.addr == NULL) {
1978 appData.monoMode = True;
1981 highlightSquareColor = *(Pixel *) vTo.addr;
1985 if (!appData.monoMode) {
1986 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1987 vFrom.size = strlen(appData.premoveHighlightColor);
1988 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1989 if (vTo.addr == NULL) {
1990 appData.monoMode = True;
1993 premoveHighlightColor = *(Pixel *) vTo.addr;
1998 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2001 if (appData.bitmapDirectory == NULL ||
2002 appData.bitmapDirectory[0] == NULLCHAR)
2003 appData.bitmapDirectory = DEF_BITMAP_DIR;
2006 if (appData.lowTimeWarning && !appData.monoMode) {
2007 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2008 vFrom.size = strlen(appData.lowTimeWarningColor);
2009 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2010 if (vTo.addr == NULL)
2011 appData.monoMode = True;
2013 lowTimeWarningColor = *(Pixel *) vTo.addr;
2016 if (appData.monoMode && appData.debugMode) {
2017 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2018 (unsigned long) XWhitePixel(xDisplay, xScreen),
2019 (unsigned long) XBlackPixel(xDisplay, xScreen));
2022 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2023 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2024 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2025 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2026 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2027 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2028 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2029 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2030 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2031 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2033 if (appData.colorize) {
2035 _("%s: can't parse color names; disabling colorization\n"),
2038 appData.colorize = FALSE;
2040 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2041 textColors[ColorNone].attr = 0;
2043 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2049 layoutName = "tinyLayout";
2050 } else if (smallLayout) {
2051 layoutName = "smallLayout";
2053 layoutName = "normalLayout";
2055 /* Outer layoutWidget is there only to provide a name for use in
2056 resources that depend on the layout style */
2058 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2059 layoutArgs, XtNumber(layoutArgs));
2061 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2062 formArgs, XtNumber(formArgs));
2063 XtSetArg(args[0], XtNdefaultDistance, &sep);
2064 XtGetValues(formWidget, args, 1);
2067 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2068 XtSetArg(args[0], XtNtop, XtChainTop);
2069 XtSetArg(args[1], XtNbottom, XtChainTop);
2070 XtSetArg(args[2], XtNright, XtChainLeft);
2071 XtSetValues(menuBarWidget, args, 3);
2073 widgetList[j++] = whiteTimerWidget =
2074 XtCreateWidget("whiteTime", labelWidgetClass,
2075 formWidget, timerArgs, XtNumber(timerArgs));
2076 XtSetArg(args[0], XtNfont, clockFontStruct);
2077 XtSetArg(args[1], XtNtop, XtChainTop);
2078 XtSetArg(args[2], XtNbottom, XtChainTop);
2079 XtSetValues(whiteTimerWidget, args, 3);
2081 widgetList[j++] = blackTimerWidget =
2082 XtCreateWidget("blackTime", labelWidgetClass,
2083 formWidget, timerArgs, XtNumber(timerArgs));
2084 XtSetArg(args[0], XtNfont, clockFontStruct);
2085 XtSetArg(args[1], XtNtop, XtChainTop);
2086 XtSetArg(args[2], XtNbottom, XtChainTop);
2087 XtSetValues(blackTimerWidget, args, 3);
2089 if (appData.titleInWindow) {
2090 widgetList[j++] = titleWidget =
2091 XtCreateWidget("title", labelWidgetClass, formWidget,
2092 titleArgs, XtNumber(titleArgs));
2093 XtSetArg(args[0], XtNtop, XtChainTop);
2094 XtSetArg(args[1], XtNbottom, XtChainTop);
2095 XtSetValues(titleWidget, args, 2);
2098 if (appData.showButtonBar) {
2099 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2100 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2101 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2102 XtSetArg(args[2], XtNtop, XtChainTop);
2103 XtSetArg(args[3], XtNbottom, XtChainTop);
2104 XtSetValues(buttonBarWidget, args, 4);
2107 widgetList[j++] = messageWidget =
2108 XtCreateWidget("message", labelWidgetClass, formWidget,
2109 messageArgs, XtNumber(messageArgs));
2110 XtSetArg(args[0], XtNtop, XtChainTop);
2111 XtSetArg(args[1], XtNbottom, XtChainTop);
2112 XtSetValues(messageWidget, args, 2);
2114 widgetList[j++] = boardWidget =
2115 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2116 XtNumber(boardArgs));
2118 XtManageChildren(widgetList, j);
2120 timerWidth = (boardWidth - sep) / 2;
2121 XtSetArg(args[0], XtNwidth, timerWidth);
2122 XtSetValues(whiteTimerWidget, args, 1);
2123 XtSetValues(blackTimerWidget, args, 1);
2125 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2126 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2127 XtGetValues(whiteTimerWidget, args, 2);
2129 if (appData.showButtonBar) {
2130 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2131 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2132 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2136 * formWidget uses these constraints but they are stored
2140 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2141 XtSetValues(menuBarWidget, args, i);
2142 if (appData.titleInWindow) {
2145 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2146 XtSetValues(whiteTimerWidget, args, i);
2148 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2149 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2150 XtSetValues(blackTimerWidget, args, i);
2152 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2153 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2154 XtSetValues(titleWidget, args, i);
2156 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2157 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2158 XtSetValues(messageWidget, args, i);
2159 if (appData.showButtonBar) {
2161 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2162 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2163 XtSetValues(buttonBarWidget, args, i);
2167 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2168 XtSetValues(whiteTimerWidget, args, i);
2170 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2171 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2172 XtSetValues(blackTimerWidget, args, i);
2174 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2175 XtSetValues(titleWidget, args, i);
2177 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2178 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2179 XtSetValues(messageWidget, args, i);
2180 if (appData.showButtonBar) {
2182 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2183 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2184 XtSetValues(buttonBarWidget, args, i);
2189 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2190 XtSetValues(whiteTimerWidget, args, i);
2192 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2193 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2194 XtSetValues(blackTimerWidget, args, i);
2196 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2197 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2198 XtSetValues(messageWidget, args, i);
2199 if (appData.showButtonBar) {
2201 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2202 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2203 XtSetValues(buttonBarWidget, args, i);
2207 XtSetArg(args[0], XtNfromVert, messageWidget);
2208 XtSetArg(args[1], XtNtop, XtChainTop);
2209 XtSetArg(args[2], XtNbottom, XtChainBottom);
2210 XtSetArg(args[3], XtNleft, XtChainLeft);
2211 XtSetArg(args[4], XtNright, XtChainRight);
2212 XtSetValues(boardWidget, args, 5);
2214 XtRealizeWidget(shellWidget);
2217 XtSetArg(args[0], XtNx, wpMain.x);
2218 XtSetArg(args[1], XtNy, wpMain.y);
2219 XtSetValues(shellWidget, args, 2);
2223 * Correct the width of the message and title widgets.
2224 * It is not known why some systems need the extra fudge term.
2225 * The value "2" is probably larger than needed.
2227 XawFormDoLayout(formWidget, False);
2229 #define WIDTH_FUDGE 2
2231 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2232 XtSetArg(args[i], XtNheight, &h); i++;
2233 XtGetValues(messageWidget, args, i);
2234 if (appData.showButtonBar) {
2236 XtSetArg(args[i], XtNwidth, &w); i++;
2237 XtGetValues(buttonBarWidget, args, i);
2238 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2240 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2243 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2244 if (gres != XtGeometryYes && appData.debugMode) {
2245 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2246 programName, gres, w, h, wr, hr);
2249 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2250 /* The size used for the child widget in layout lags one resize behind
2251 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2253 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2254 if (gres != XtGeometryYes && appData.debugMode) {
2255 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2256 programName, gres, w, h, wr, hr);
2259 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2260 XtSetArg(args[1], XtNright, XtChainRight);
2261 XtSetValues(messageWidget, args, 2);
2263 if (appData.titleInWindow) {
2265 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2266 XtSetArg(args[i], XtNheight, &h); i++;
2267 XtGetValues(titleWidget, args, i);
2269 w = boardWidth - 2*bor;
2271 XtSetArg(args[0], XtNwidth, &w);
2272 XtGetValues(menuBarWidget, args, 1);
2273 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2276 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2277 if (gres != XtGeometryYes && appData.debugMode) {
2279 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2280 programName, gres, w, h, wr, hr);
2283 XawFormDoLayout(formWidget, True);
2285 xBoardWindow = XtWindow(boardWidget);
2287 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2288 // not need to go into InitDrawingSizes().
2292 * Create X checkmark bitmap and initialize option menu checks.
2294 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2295 checkmark_bits, checkmark_width, checkmark_height);
2296 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2297 if (appData.alwaysPromoteToQueen) {
2298 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2301 if (appData.animateDragging) {
2302 XtSetValues(XtNameToWidget(menuBarWidget,
2303 "menuOptions.Animate Dragging"),
2306 if (appData.animate) {
2307 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2310 if (appData.autoComment) {
2311 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2314 if (appData.autoCallFlag) {
2315 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2318 if (appData.autoFlipView) {
2319 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2322 if (appData.autoObserve) {
2323 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2326 if (appData.autoRaiseBoard) {
2327 XtSetValues(XtNameToWidget(menuBarWidget,
2328 "menuOptions.Auto Raise Board"), args, 1);
2330 if (appData.autoSaveGames) {
2331 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2334 if (appData.saveGameFile[0] != NULLCHAR) {
2335 /* Can't turn this off from menu */
2336 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2338 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2342 if (appData.blindfold) {
2343 XtSetValues(XtNameToWidget(menuBarWidget,
2344 "menuOptions.Blindfold"), args, 1);
2346 if (appData.flashCount > 0) {
2347 XtSetValues(XtNameToWidget(menuBarWidget,
2348 "menuOptions.Flash Moves"),
2351 if (appData.getMoveList) {
2352 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2356 if (appData.highlightDragging) {
2357 XtSetValues(XtNameToWidget(menuBarWidget,
2358 "menuOptions.Highlight Dragging"),
2362 if (appData.highlightLastMove) {
2363 XtSetValues(XtNameToWidget(menuBarWidget,
2364 "menuOptions.Highlight Last Move"),
2367 if (appData.icsAlarm) {
2368 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2371 if (appData.ringBellAfterMoves) {
2372 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2375 if (appData.oldSaveStyle) {
2376 XtSetValues(XtNameToWidget(menuBarWidget,
2377 "menuOptions.Old Save Style"), args, 1);
2379 if (appData.periodicUpdates) {
2380 XtSetValues(XtNameToWidget(menuBarWidget,
2381 "menuOptions.Periodic Updates"), args, 1);
2383 if (appData.ponderNextMove) {
2384 XtSetValues(XtNameToWidget(menuBarWidget,
2385 "menuOptions.Ponder Next Move"), args, 1);
2387 if (appData.popupExitMessage) {
2388 XtSetValues(XtNameToWidget(menuBarWidget,
2389 "menuOptions.Popup Exit Message"), args, 1);
2391 if (appData.popupMoveErrors) {
2392 XtSetValues(XtNameToWidget(menuBarWidget,
2393 "menuOptions.Popup Move Errors"), args, 1);
2395 if (appData.premove) {
2396 XtSetValues(XtNameToWidget(menuBarWidget,
2397 "menuOptions.Premove"), args, 1);
2399 if (appData.quietPlay) {
2400 XtSetValues(XtNameToWidget(menuBarWidget,
2401 "menuOptions.Quiet Play"), args, 1);
2403 if (appData.showCoords) {
2404 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2407 if (appData.hideThinkingFromHuman) {
2408 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2411 if (appData.testLegality) {
2412 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2415 if (saveSettingsOnExit) {
2416 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2423 ReadBitmap(&wIconPixmap, "icon_white.bm",
2424 icon_white_bits, icon_white_width, icon_white_height);
2425 ReadBitmap(&bIconPixmap, "icon_black.bm",
2426 icon_black_bits, icon_black_width, icon_black_height);
2427 iconPixmap = wIconPixmap;
2429 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2430 XtSetValues(shellWidget, args, i);
2433 * Create a cursor for the board widget.
2435 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2436 XChangeWindowAttributes(xDisplay, xBoardWindow,
2437 CWCursor, &window_attributes);
2440 * Inhibit shell resizing.
2442 shellArgs[0].value = (XtArgVal) &w;
2443 shellArgs[1].value = (XtArgVal) &h;
2444 XtGetValues(shellWidget, shellArgs, 2);
2445 shellArgs[4].value = shellArgs[2].value = w;
2446 shellArgs[5].value = shellArgs[3].value = h;
2447 XtSetValues(shellWidget, &shellArgs[2], 4);
2448 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2449 marginH = h - boardHeight;
2451 CatchDeleteWindow(shellWidget, "QuitProc");
2456 if (appData.bitmapDirectory[0] != NULLCHAR) {
2463 /* Create regular pieces */
2464 if (!useImages) CreatePieces();
2469 if (appData.animate || appData.animateDragging)
2472 XtAugmentTranslations(formWidget,
2473 XtParseTranslationTable(globalTranslations));
2474 XtAugmentTranslations(boardWidget,
2475 XtParseTranslationTable(boardTranslations));
2476 XtAugmentTranslations(whiteTimerWidget,
2477 XtParseTranslationTable(whiteTranslations));
2478 XtAugmentTranslations(blackTimerWidget,
2479 XtParseTranslationTable(blackTranslations));
2481 /* Why is the following needed on some versions of X instead
2482 * of a translation? */
2483 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2484 (XtEventHandler) EventProc, NULL);
2487 /* [AS] Restore layout */
2488 if( wpMoveHistory.visible ) {
2492 if( wpEvalGraph.visible )
2497 if( wpEngineOutput.visible ) {
2498 EngineOutputPopUp();
2503 if (errorExitStatus == -1) {
2504 if (appData.icsActive) {
2505 /* We now wait until we see "login:" from the ICS before
2506 sending the logon script (problems with timestamp otherwise) */
2507 /*ICSInitScript();*/
2508 if (appData.icsInputBox) ICSInputBoxPopUp();
2512 signal(SIGWINCH, TermSizeSigHandler);
2514 signal(SIGINT, IntSigHandler);
2515 signal(SIGTERM, IntSigHandler);
2516 if (*appData.cmailGameName != NULLCHAR) {
2517 signal(SIGUSR1, CmailSigHandler);
2520 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2523 XtAppMainLoop(appContext);
2524 if (appData.debugMode) fclose(debugFP); // [DM] debug
2531 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2532 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2534 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2535 unlink(gameCopyFilename);
2536 unlink(gamePasteFilename);
2539 RETSIGTYPE TermSizeSigHandler(int sig)
2552 CmailSigHandler(sig)
2558 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2560 /* Activate call-back function CmailSigHandlerCallBack() */
2561 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2563 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2567 CmailSigHandlerCallBack(isr, closure, message, count, error)
2575 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2577 /**** end signal code ****/
2587 f = fopen(appData.icsLogon, "r");
2593 strcat(buf, appData.icsLogon);
2594 f = fopen(buf, "r");
2598 ProcessICSInitScript(f);
2605 EditCommentPopDown();
2620 if (!menuBarWidget) return;
2621 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2623 DisplayError("menuStep.Revert", 0);
2625 XtSetSensitive(w, !grey);
2630 SetMenuEnables(enab)
2634 if (!menuBarWidget) return;
2635 while (enab->name != NULL) {
2636 w = XtNameToWidget(menuBarWidget, enab->name);
2638 DisplayError(enab->name, 0);
2640 XtSetSensitive(w, enab->value);
2646 Enables icsEnables[] = {
2647 { "menuFile.Mail Move", False },
2648 { "menuFile.Reload CMail Message", False },
2649 { "menuMode.Machine Black", False },
2650 { "menuMode.Machine White", False },
2651 { "menuMode.Analysis Mode", False },
2652 { "menuMode.Analyze File", False },
2653 { "menuMode.Two Machines", False },
2655 { "menuHelp.Hint", False },
2656 { "menuHelp.Book", False },
2657 { "menuStep.Move Now", False },
2658 { "menuOptions.Periodic Updates", False },
2659 { "menuOptions.Hide Thinking", False },
2660 { "menuOptions.Ponder Next Move", False },
2665 Enables ncpEnables[] = {
2666 { "menuFile.Mail Move", False },
2667 { "menuFile.Reload CMail Message", False },
2668 { "menuMode.Machine White", False },
2669 { "menuMode.Machine Black", False },
2670 { "menuMode.Analysis Mode", False },
2671 { "menuMode.Analyze File", False },
2672 { "menuMode.Two Machines", False },
2673 { "menuMode.ICS Client", False },
2674 { "menuMode.ICS Input Box", False },
2675 { "Action", False },
2676 { "menuStep.Revert", False },
2677 { "menuStep.Move Now", False },
2678 { "menuStep.Retract Move", False },
2679 { "menuOptions.Auto Comment", False },
2680 { "menuOptions.Auto Flag", False },
2681 { "menuOptions.Auto Flip View", False },
2682 { "menuOptions.Auto Observe", False },
2683 { "menuOptions.Auto Raise Board", False },
2684 { "menuOptions.Get Move List", False },
2685 { "menuOptions.ICS Alarm", False },
2686 { "menuOptions.Move Sound", False },
2687 { "menuOptions.Quiet Play", False },
2688 { "menuOptions.Hide Thinking", False },
2689 { "menuOptions.Periodic Updates", False },
2690 { "menuOptions.Ponder Next Move", False },
2691 { "menuHelp.Hint", False },
2692 { "menuHelp.Book", False },
2696 Enables gnuEnables[] = {
2697 { "menuMode.ICS Client", False },
2698 { "menuMode.ICS Input Box", False },
2699 { "menuAction.Accept", False },
2700 { "menuAction.Decline", False },
2701 { "menuAction.Rematch", False },
2702 { "menuAction.Adjourn", False },
2703 { "menuAction.Stop Examining", False },
2704 { "menuAction.Stop Observing", False },
2705 { "menuAction.Upload to Examine", False },
2706 { "menuStep.Revert", False },
2707 { "menuOptions.Auto Comment", False },
2708 { "menuOptions.Auto Observe", False },
2709 { "menuOptions.Auto Raise Board", False },
2710 { "menuOptions.Get Move List", False },
2711 { "menuOptions.Premove", False },
2712 { "menuOptions.Quiet Play", False },
2714 /* The next two options rely on SetCmailMode being called *after* */
2715 /* SetGNUMode so that when GNU is being used to give hints these */
2716 /* menu options are still available */
2718 { "menuFile.Mail Move", False },
2719 { "menuFile.Reload CMail Message", False },
2723 Enables cmailEnables[] = {
2725 { "menuAction.Call Flag", False },
2726 { "menuAction.Draw", True },
2727 { "menuAction.Adjourn", False },
2728 { "menuAction.Abort", False },
2729 { "menuAction.Stop Observing", False },
2730 { "menuAction.Stop Examining", False },
2731 { "menuFile.Mail Move", True },
2732 { "menuFile.Reload CMail Message", True },
2736 Enables trainingOnEnables[] = {
2737 { "menuMode.Edit Comment", False },
2738 { "menuMode.Pause", False },
2739 { "menuStep.Forward", False },
2740 { "menuStep.Backward", False },
2741 { "menuStep.Forward to End", False },
2742 { "menuStep.Back to Start", False },
2743 { "menuStep.Move Now", False },
2744 { "menuStep.Truncate Game", False },
2748 Enables trainingOffEnables[] = {
2749 { "menuMode.Edit Comment", True },
2750 { "menuMode.Pause", True },
2751 { "menuStep.Forward", True },
2752 { "menuStep.Backward", True },
2753 { "menuStep.Forward to End", True },
2754 { "menuStep.Back to Start", True },
2755 { "menuStep.Move Now", True },
2756 { "menuStep.Truncate Game", True },
2760 Enables machineThinkingEnables[] = {
2761 { "menuFile.Load Game", False },
2762 { "menuFile.Load Next Game", False },
2763 { "menuFile.Load Previous Game", False },
2764 { "menuFile.Reload Same Game", False },
2765 { "menuFile.Paste Game", False },
2766 { "menuFile.Load Position", False },
2767 { "menuFile.Load Next Position", False },
2768 { "menuFile.Load Previous Position", False },
2769 { "menuFile.Reload Same Position", False },
2770 { "menuFile.Paste Position", False },
2771 { "menuMode.Machine White", False },
2772 { "menuMode.Machine Black", False },
2773 { "menuMode.Two Machines", False },
2774 { "menuStep.Retract Move", False },
2778 Enables userThinkingEnables[] = {
2779 { "menuFile.Load Game", True },
2780 { "menuFile.Load Next Game", True },
2781 { "menuFile.Load Previous Game", True },
2782 { "menuFile.Reload Same Game", True },
2783 { "menuFile.Paste Game", True },
2784 { "menuFile.Load Position", True },
2785 { "menuFile.Load Next Position", True },
2786 { "menuFile.Load Previous Position", True },
2787 { "menuFile.Reload Same Position", True },
2788 { "menuFile.Paste Position", True },
2789 { "menuMode.Machine White", True },
2790 { "menuMode.Machine Black", True },
2791 { "menuMode.Two Machines", True },
2792 { "menuStep.Retract Move", True },
2798 SetMenuEnables(icsEnables);
2801 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2802 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2809 SetMenuEnables(ncpEnables);
2815 SetMenuEnables(gnuEnables);
2821 SetMenuEnables(cmailEnables);
2827 SetMenuEnables(trainingOnEnables);
2828 if (appData.showButtonBar) {
2829 XtSetSensitive(buttonBarWidget, False);
2835 SetTrainingModeOff()
2837 SetMenuEnables(trainingOffEnables);
2838 if (appData.showButtonBar) {
2839 XtSetSensitive(buttonBarWidget, True);
2844 SetUserThinkingEnables()
2846 if (appData.noChessProgram) return;
2847 SetMenuEnables(userThinkingEnables);
2851 SetMachineThinkingEnables()
2853 if (appData.noChessProgram) return;
2854 SetMenuEnables(machineThinkingEnables);
2856 case MachinePlaysBlack:
2857 case MachinePlaysWhite:
2858 case TwoMachinesPlay:
2859 XtSetSensitive(XtNameToWidget(menuBarWidget,
2860 ModeToWidgetName(gameMode)), True);
2867 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2868 #define HISTORY_SIZE 64
\r
2869 static char *history[HISTORY_SIZE];
\r
2870 int histIn = 0, histP = 0;
\r
2873 SaveInHistory(char *cmd)
\r
2875 if (history[histIn] != NULL) {
\r
2876 free(history[histIn]);
\r
2877 history[histIn] = NULL;
\r
2879 if (*cmd == NULLCHAR) return;
\r
2880 history[histIn] = StrSave(cmd);
\r
2881 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2882 if (history[histIn] != NULL) {
\r
2883 free(history[histIn]);
\r
2884 history[histIn] = NULL;
\r
2890 PrevInHistory(char *cmd)
\r
2893 if (histP == histIn) {
\r
2894 if (history[histIn] != NULL) free(history[histIn]);
\r
2895 history[histIn] = StrSave(cmd);
\r
2897 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2898 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2900 return history[histP];
\r
2906 if (histP == histIn) return NULL;
\r
2907 histP = (histP + 1) % HISTORY_SIZE;
\r
2908 return history[histP];
\r
2910 // end of borrowed code
\r
2912 #define Abs(n) ((n)<0 ? -(n) : (n))
2915 * Find a font that matches "pattern" that is as close as
2916 * possible to the targetPxlSize. Prefer fonts that are k
2917 * pixels smaller to fonts that are k pixels larger. The
2918 * pattern must be in the X Consortium standard format,
2919 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2920 * The return value should be freed with XtFree when no
2923 char *FindFont(pattern, targetPxlSize)
2927 char **fonts, *p, *best, *scalable, *scalableTail;
2928 int i, j, nfonts, minerr, err, pxlSize;
2931 char **missing_list;
2933 char *def_string, *base_fnt_lst, strInt[3];
2935 XFontStruct **fnt_list;
2937 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2938 sprintf(strInt, "%d", targetPxlSize);
2939 p = strstr(pattern, "--");
2940 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2941 strcat(base_fnt_lst, strInt);
2942 strcat(base_fnt_lst, strchr(p + 2, '-'));
2944 if ((fntSet = XCreateFontSet(xDisplay,
2948 &def_string)) == NULL) {
2950 fprintf(stderr, _("Unable to create font set.\n"));
2954 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2956 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2958 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2959 programName, pattern);
2967 for (i=0; i<nfonts; i++) {
2970 if (*p != '-') continue;
2972 if (*p == NULLCHAR) break;
2973 if (*p++ == '-') j++;
2975 if (j < 7) continue;
2978 scalable = fonts[i];
2981 err = pxlSize - targetPxlSize;
2982 if (Abs(err) < Abs(minerr) ||
2983 (minerr > 0 && err < 0 && -err == minerr)) {
2989 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2990 /* If the error is too big and there is a scalable font,
2991 use the scalable font. */
2992 int headlen = scalableTail - scalable;
2993 p = (char *) XtMalloc(strlen(scalable) + 10);
2994 while (isdigit(*scalableTail)) scalableTail++;
2995 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2997 p = (char *) XtMalloc(strlen(best) + 1);
3000 if (appData.debugMode) {
3001 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3002 pattern, targetPxlSize, p);
3005 if (missing_count > 0)
3006 XFreeStringList(missing_list);
3007 XFreeFontSet(xDisplay, fntSet);
3009 XFreeFontNames(fonts);
3016 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3017 | GCBackground | GCFunction | GCPlaneMask;
3018 XGCValues gc_values;
3021 gc_values.plane_mask = AllPlanes;
3022 gc_values.line_width = lineGap;
3023 gc_values.line_style = LineSolid;
3024 gc_values.function = GXcopy;
3026 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3027 gc_values.background = XBlackPixel(xDisplay, xScreen);
3028 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3030 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3031 gc_values.background = XWhitePixel(xDisplay, xScreen);
3032 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3033 XSetFont(xDisplay, coordGC, coordFontID);
3035 // [HGM] make font for holdings counts (white on black0
3036 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3037 gc_values.background = XBlackPixel(xDisplay, xScreen);
3038 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3039 XSetFont(xDisplay, countGC, countFontID);
3041 if (appData.monoMode) {
3042 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3043 gc_values.background = XWhitePixel(xDisplay, xScreen);
3044 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3046 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3047 gc_values.background = XBlackPixel(xDisplay, xScreen);
3048 lightSquareGC = wbPieceGC
3049 = XtGetGC(shellWidget, value_mask, &gc_values);
3051 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3052 gc_values.background = XWhitePixel(xDisplay, xScreen);
3053 darkSquareGC = bwPieceGC
3054 = XtGetGC(shellWidget, value_mask, &gc_values);
3056 if (DefaultDepth(xDisplay, xScreen) == 1) {
3057 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3058 gc_values.function = GXcopyInverted;
3059 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3060 gc_values.function = GXcopy;
3061 if (XBlackPixel(xDisplay, xScreen) == 1) {
3062 bwPieceGC = darkSquareGC;
3063 wbPieceGC = copyInvertedGC;
3065 bwPieceGC = copyInvertedGC;
3066 wbPieceGC = lightSquareGC;
3070 gc_values.foreground = highlightSquareColor;
3071 gc_values.background = highlightSquareColor;
3072 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3074 gc_values.foreground = premoveHighlightColor;
3075 gc_values.background = premoveHighlightColor;
3076 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3078 gc_values.foreground = lightSquareColor;
3079 gc_values.background = darkSquareColor;
3080 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3082 gc_values.foreground = darkSquareColor;
3083 gc_values.background = lightSquareColor;
3084 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3086 gc_values.foreground = jailSquareColor;
3087 gc_values.background = jailSquareColor;
3088 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3090 gc_values.foreground = whitePieceColor;
3091 gc_values.background = darkSquareColor;
3092 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3094 gc_values.foreground = whitePieceColor;
3095 gc_values.background = lightSquareColor;
3096 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3098 gc_values.foreground = whitePieceColor;
3099 gc_values.background = jailSquareColor;
3100 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3102 gc_values.foreground = blackPieceColor;
3103 gc_values.background = darkSquareColor;
3104 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3106 gc_values.foreground = blackPieceColor;
3107 gc_values.background = lightSquareColor;
3108 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3110 gc_values.foreground = blackPieceColor;
3111 gc_values.background = jailSquareColor;
3112 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3116 void loadXIM(xim, xmask, filename, dest, mask)
3129 fp = fopen(filename, "rb");
3131 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3138 for (y=0; y<h; ++y) {
3139 for (x=0; x<h; ++x) {
3144 XPutPixel(xim, x, y, blackPieceColor);
3146 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3149 XPutPixel(xim, x, y, darkSquareColor);
3151 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3154 XPutPixel(xim, x, y, whitePieceColor);
3156 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3159 XPutPixel(xim, x, y, lightSquareColor);
3161 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3167 /* create Pixmap of piece */
3168 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3170 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3173 /* create Pixmap of clipmask
3174 Note: We assume the white/black pieces have the same
3175 outline, so we make only 6 masks. This is okay
3176 since the XPM clipmask routines do the same. */
3178 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3180 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3183 /* now create the 1-bit version */
3184 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3187 values.foreground = 1;
3188 values.background = 0;
3190 /* Don't use XtGetGC, not read only */
3191 maskGC = XCreateGC(xDisplay, *mask,
3192 GCForeground | GCBackground, &values);
3193 XCopyPlane(xDisplay, temp, *mask, maskGC,
3194 0, 0, squareSize, squareSize, 0, 0, 1);
3195 XFreePixmap(xDisplay, temp);
3200 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3202 void CreateXIMPieces()
3207 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3212 /* The XSynchronize calls were copied from CreatePieces.
3213 Not sure if needed, but can't hurt */
3214 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3217 /* temp needed by loadXIM() */
3218 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3219 0, 0, ss, ss, AllPlanes, XYPixmap);
3221 if (strlen(appData.pixmapDirectory) == 0) {
3225 if (appData.monoMode) {
3226 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3230 fprintf(stderr, _("\nLoading XIMs...\n"));
3232 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3233 fprintf(stderr, "%d", piece+1);
3234 for (kind=0; kind<4; kind++) {
3235 fprintf(stderr, ".");
3236 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3237 ExpandPathName(appData.pixmapDirectory),
3238 piece <= (int) WhiteKing ? "" : "w",
3239 pieceBitmapNames[piece],
3241 ximPieceBitmap[kind][piece] =
3242 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3243 0, 0, ss, ss, AllPlanes, XYPixmap);
3244 if (appData.debugMode)
3245 fprintf(stderr, _("(File:%s:) "), buf);
3246 loadXIM(ximPieceBitmap[kind][piece],
3248 &(xpmPieceBitmap2[kind][piece]),
3249 &(ximMaskPm2[piece]));
3250 if(piece <= (int)WhiteKing)
3251 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3253 fprintf(stderr," ");
3255 /* Load light and dark squares */
3256 /* If the LSQ and DSQ pieces don't exist, we will
3257 draw them with solid squares. */
3258 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3259 if (access(buf, 0) != 0) {
3263 fprintf(stderr, _("light square "));
3265 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3266 0, 0, ss, ss, AllPlanes, XYPixmap);
3267 if (appData.debugMode)
3268 fprintf(stderr, _("(File:%s:) "), buf);
3270 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3271 fprintf(stderr, _("dark square "));
3272 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3273 ExpandPathName(appData.pixmapDirectory), ss);
3274 if (appData.debugMode)
3275 fprintf(stderr, _("(File:%s:) "), buf);
3277 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3278 0, 0, ss, ss, AllPlanes, XYPixmap);
3279 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3280 xpmJailSquare = xpmLightSquare;
3282 fprintf(stderr, _("Done.\n"));
3284 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3288 void CreateXPMPieces()
3292 u_int ss = squareSize;
3294 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3295 XpmColorSymbol symbols[4];
3297 /* The XSynchronize calls were copied from CreatePieces.
3298 Not sure if needed, but can't hurt */
3299 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3301 /* Setup translations so piece colors match square colors */
3302 symbols[0].name = "light_piece";
3303 symbols[0].value = appData.whitePieceColor;
3304 symbols[1].name = "dark_piece";
3305 symbols[1].value = appData.blackPieceColor;
3306 symbols[2].name = "light_square";
3307 symbols[2].value = appData.lightSquareColor;
3308 symbols[3].name = "dark_square";
3309 symbols[3].value = appData.darkSquareColor;
3311 attr.valuemask = XpmColorSymbols;
3312 attr.colorsymbols = symbols;
3313 attr.numsymbols = 4;
3315 if (appData.monoMode) {
3316 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3320 if (strlen(appData.pixmapDirectory) == 0) {
3321 XpmPieces* pieces = builtInXpms;
3324 while (pieces->size != squareSize && pieces->size) pieces++;
3325 if (!pieces->size) {
3326 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3329 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3330 for (kind=0; kind<4; kind++) {
3332 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3333 pieces->xpm[piece][kind],
3334 &(xpmPieceBitmap2[kind][piece]),
3335 NULL, &attr)) != 0) {
3336 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3340 if(piece <= (int) WhiteKing)
3341 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3345 xpmJailSquare = xpmLightSquare;
3349 fprintf(stderr, _("\nLoading XPMs...\n"));
3352 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3353 fprintf(stderr, "%d ", piece+1);
3354 for (kind=0; kind<4; kind++) {
3355 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3356 ExpandPathName(appData.pixmapDirectory),
3357 piece > (int) WhiteKing ? "w" : "",
3358 pieceBitmapNames[piece],
3360 if (appData.debugMode) {
3361 fprintf(stderr, _("(File:%s:) "), buf);
3363 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3364 &(xpmPieceBitmap2[kind][piece]),
3365 NULL, &attr)) != 0) {
3366 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3367 // [HGM] missing: read of unorthodox piece failed; substitute King.
3368 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3369 ExpandPathName(appData.pixmapDirectory),
3371 if (appData.debugMode) {
3372 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3374 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3375 &(xpmPieceBitmap2[kind][piece]),
3379 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3384 if(piece <= (int) WhiteKing)
3385 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3388 /* Load light and dark squares */
3389 /* If the LSQ and DSQ pieces don't exist, we will
3390 draw them with solid squares. */
3391 fprintf(stderr, _("light square "));
3392 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3393 if (access(buf, 0) != 0) {
3397 if (appData.debugMode)
3398 fprintf(stderr, _("(File:%s:) "), buf);
3400 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3401 &xpmLightSquare, NULL, &attr)) != 0) {
3402 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3405 fprintf(stderr, _("dark square "));
3406 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3407 ExpandPathName(appData.pixmapDirectory), ss);
3408 if (appData.debugMode) {
3409 fprintf(stderr, _("(File:%s:) "), buf);
3411 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3412 &xpmDarkSquare, NULL, &attr)) != 0) {
3413 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3417 xpmJailSquare = xpmLightSquare;
3418 fprintf(stderr, _("Done.\n"));
3420 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3423 #endif /* HAVE_LIBXPM */
3426 /* No built-in bitmaps */
3431 u_int ss = squareSize;
3433 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3436 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3437 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3438 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3439 pieceBitmapNames[piece],
3440 ss, kind == SOLID ? 's' : 'o');
3441 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3442 if(piece <= (int)WhiteKing)
3443 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3447 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3451 /* With built-in bitmaps */
3454 BuiltInBits* bib = builtInBits;
3457 u_int ss = squareSize;
3459 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3462 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3464 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3465 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3466 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3467 pieceBitmapNames[piece],
3468 ss, kind == SOLID ? 's' : 'o');
3469 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3470 bib->bits[kind][piece], ss, ss);
3471 if(piece <= (int)WhiteKing)
3472 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3476 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3481 void ReadBitmap(pm, name, bits, wreq, hreq)
3484 unsigned char bits[];
3490 char msg[MSG_SIZ], fullname[MSG_SIZ];
3492 if (*appData.bitmapDirectory != NULLCHAR) {
3493 strcpy(fullname, appData.bitmapDirectory);
3494 strcat(fullname, "/");
3495 strcat(fullname, name);
3496 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3497 &w, &h, pm, &x_hot, &y_hot);
3498 fprintf(stderr, "load %s\n", name);
3499 if (errcode != BitmapSuccess) {
3501 case BitmapOpenFailed:
3502 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3504 case BitmapFileInvalid:
3505 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3507 case BitmapNoMemory:
3508 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3512 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3516 fprintf(stderr, _("%s: %s...using built-in\n"),
3518 } else if (w != wreq || h != hreq) {
3520 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3521 programName, fullname, w, h, wreq, hreq);
3527 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3536 if (lineGap == 0) return;
3538 /* [HR] Split this into 2 loops for non-square boards. */
3540 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3541 gridSegments[i].x1 = 0;
3542 gridSegments[i].x2 =
3543 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3544 gridSegments[i].y1 = gridSegments[i].y2
3545 = lineGap / 2 + (i * (squareSize + lineGap));
3548 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3549 gridSegments[j + i].y1 = 0;
3550 gridSegments[j + i].y2 =
3551 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3552 gridSegments[j + i].x1 = gridSegments[j + i].x2
3553 = lineGap / 2 + (j * (squareSize + lineGap));
3557 static void MenuBarSelect(w, addr, index)
3562 XtActionProc proc = (XtActionProc) addr;
3564 (proc)(NULL, NULL, NULL, NULL);
3567 void CreateMenuBarPopup(parent, name, mb)
3577 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3580 XtSetArg(args[j], XtNleftMargin, 20); j++;
3581 XtSetArg(args[j], XtNrightMargin, 20); j++;
3583 while (mi->string != NULL) {
3584 if (strcmp(mi->string, "----") == 0) {
3585 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3588 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3589 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3591 XtAddCallback(entry, XtNcallback,
3592 (XtCallbackProc) MenuBarSelect,
3593 (caddr_t) mi->proc);
3599 Widget CreateMenuBar(mb)
3603 Widget anchor, menuBar;
3605 char menuName[MSG_SIZ];
3608 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3609 XtSetArg(args[j], XtNvSpace, 0); j++;
3610 XtSetArg(args[j], XtNborderWidth, 0); j++;
3611 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3612 formWidget, args, j);
3614 while (mb->name != NULL) {
3615 strcpy(menuName, "menu");
3616 strcat(menuName, mb->name);
3618 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3621 shortName[0] = _(mb->name)[0];
3622 shortName[1] = NULLCHAR;
3623 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3626 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3629 XtSetArg(args[j], XtNborderWidth, 0); j++;
3630 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3632 CreateMenuBarPopup(menuBar, menuName, mb);
3638 Widget CreateButtonBar(mi)
3642 Widget button, buttonBar;
3646 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3648 XtSetArg(args[j], XtNhSpace, 0); j++;
3650 XtSetArg(args[j], XtNborderWidth, 0); j++;
3651 XtSetArg(args[j], XtNvSpace, 0); j++;
3652 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3653 formWidget, args, j);
3655 while (mi->string != NULL) {
3658 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3659 XtSetArg(args[j], XtNborderWidth, 0); j++;
3661 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3662 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3663 buttonBar, args, j);
3664 XtAddCallback(button, XtNcallback,
3665 (XtCallbackProc) MenuBarSelect,
3666 (caddr_t) mi->proc);
3673 CreatePieceMenu(name, color)
3680 ChessSquare selection;
3682 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3683 boardWidget, args, 0);
3685 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3686 String item = pieceMenuStrings[color][i];
3688 if (strcmp(item, "----") == 0) {
3689 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3692 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3693 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3695 selection = pieceMenuTranslation[color][i];
3696 XtAddCallback(entry, XtNcallback,
3697 (XtCallbackProc) PieceMenuSelect,
3698 (caddr_t) selection);
3699 if (selection == WhitePawn || selection == BlackPawn) {
3700 XtSetArg(args[0], XtNpopupOnEntry, entry);
3701 XtSetValues(menu, args, 1);
3714 ChessSquare selection;
3716 whitePieceMenu = CreatePieceMenu("menuW", 0);
3717 blackPieceMenu = CreatePieceMenu("menuB", 1);
3719 XtRegisterGrabAction(PieceMenuPopup, True,
3720 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3721 GrabModeAsync, GrabModeAsync);
3723 XtSetArg(args[0], XtNlabel, _("Drop"));
3724 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3725 boardWidget, args, 1);
3726 for (i = 0; i < DROP_MENU_SIZE; i++) {
3727 String item = dropMenuStrings[i];
3729 if (strcmp(item, "----") == 0) {
3730 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3733 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3734 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3736 selection = dropMenuTranslation[i];
3737 XtAddCallback(entry, XtNcallback,
3738 (XtCallbackProc) DropMenuSelect,
3739 (caddr_t) selection);
3744 void SetupDropMenu()
3752 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3753 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3754 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3755 dmEnables[i].piece);
3756 XtSetSensitive(entry, p != NULL || !appData.testLegality
3757 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3758 && !appData.icsActive));
3760 while (p && *p++ == dmEnables[i].piece) count++;
3761 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3763 XtSetArg(args[j], XtNlabel, label); j++;
3764 XtSetValues(entry, args, j);
3768 void PieceMenuPopup(w, event, params, num_params)
3772 Cardinal *num_params;
3774 String whichMenu; int menuNr;
3775 if (event->type == ButtonRelease)
3776 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3777 else if (event->type == ButtonPress)
3778 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3780 case 0: whichMenu = params[0]; break;
3781 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3783 case -1: if (errorUp) ErrorPopDown();
3786 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3789 static void PieceMenuSelect(w, piece, junk)
3794 if (pmFromX < 0 || pmFromY < 0) return;
3795 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3798 static void DropMenuSelect(w, piece, junk)
3803 if (pmFromX < 0 || pmFromY < 0) return;
3804 DropMenuEvent(piece, pmFromX, pmFromY);
3807 void WhiteClock(w, event, prms, nprms)
3813 if (gameMode == EditPosition || gameMode == IcsExamining) {
3814 SetWhiteToPlayEvent();
3815 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3820 void BlackClock(w, event, prms, nprms)
3826 if (gameMode == EditPosition || gameMode == IcsExamining) {
3827 SetBlackToPlayEvent();
3828 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3835 * If the user selects on a border boundary, return -1; if off the board,
3836 * return -2. Otherwise map the event coordinate to the square.
3838 int EventToSquare(x, limit)
3846 if ((x % (squareSize + lineGap)) >= squareSize)
3848 x /= (squareSize + lineGap);
3854 static void do_flash_delay(msec)
3860 static void drawHighlight(file, rank, gc)
3866 if (lineGap == 0 || appData.blindfold) return;
3869 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3870 (squareSize + lineGap);
3871 y = lineGap/2 + rank * (squareSize + lineGap);
3873 x = lineGap/2 + file * (squareSize + lineGap);
3874 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3875 (squareSize + lineGap);
3878 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3879 squareSize+lineGap, squareSize+lineGap);
3882 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3883 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3886 SetHighlights(fromX, fromY, toX, toY)
3887 int fromX, fromY, toX, toY;
3889 if (hi1X != fromX || hi1Y != fromY) {
3890 if (hi1X >= 0 && hi1Y >= 0) {
3891 drawHighlight(hi1X, hi1Y, lineGC);
3893 } // [HGM] first erase both, then draw new!
3894 if (hi2X != toX || hi2Y != toY) {
3895 if (hi2X >= 0 && hi2Y >= 0) {
3896 drawHighlight(hi2X, hi2Y, lineGC);
3899 if (hi1X != fromX || hi1Y != fromY) {
3900 if (fromX >= 0 && fromY >= 0) {
3901 drawHighlight(fromX, fromY, highlineGC);
3904 if (hi2X != toX || hi2Y != toY) {
3905 if (toX >= 0 && toY >= 0) {
3906 drawHighlight(toX, toY, highlineGC);
3918 SetHighlights(-1, -1, -1, -1);
3923 SetPremoveHighlights(fromX, fromY, toX, toY)
3924 int fromX, fromY, toX, toY;
3926 if (pm1X != fromX || pm1Y != fromY) {
3927 if (pm1X >= 0 && pm1Y >= 0) {
3928 drawHighlight(pm1X, pm1Y, lineGC);
3930 if (fromX >= 0 && fromY >= 0) {
3931 drawHighlight(fromX, fromY, prelineGC);
3934 if (pm2X != toX || pm2Y != toY) {
3935 if (pm2X >= 0 && pm2Y >= 0) {
3936 drawHighlight(pm2X, pm2Y, lineGC);
3938 if (toX >= 0 && toY >= 0) {
3939 drawHighlight(toX, toY, prelineGC);
3949 ClearPremoveHighlights()
3951 SetPremoveHighlights(-1, -1, -1, -1);
3954 static void BlankSquare(x, y, color, piece, dest)
3959 if (useImages && useImageSqs) {
3963 pm = xpmLightSquare;
3968 case 2: /* neutral */
3973 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3974 squareSize, squareSize, x, y);
3984 case 2: /* neutral */
3989 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3994 I split out the routines to draw a piece so that I could
3995 make a generic flash routine.
3997 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3999 int square_color, x, y;
4002 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4003 switch (square_color) {
4005 case 2: /* neutral */
4007 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4008 ? *pieceToOutline(piece)
4009 : *pieceToSolid(piece),
4010 dest, bwPieceGC, 0, 0,
4011 squareSize, squareSize, x, y);
4014 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4015 ? *pieceToSolid(piece)
4016 : *pieceToOutline(piece),
4017 dest, wbPieceGC, 0, 0,
4018 squareSize, squareSize, x, y);
4023 static void monoDrawPiece(piece, square_color, x, y, dest)
4025 int square_color, x, y;
4028 switch (square_color) {
4030 case 2: /* neutral */
4032 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4033 ? *pieceToOutline(piece)
4034 : *pieceToSolid(piece),
4035 dest, bwPieceGC, 0, 0,
4036 squareSize, squareSize, x, y, 1);
4039 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4040 ? *pieceToSolid(piece)
4041 : *pieceToOutline(piece),
4042 dest, wbPieceGC, 0, 0,
4043 squareSize, squareSize, x, y, 1);
4048 static void colorDrawPiece(piece, square_color, x, y, dest)
4050 int square_color, x, y;
4053 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4054 switch (square_color) {
4056 XCopyPlane(xDisplay, *pieceToSolid(piece),
4057 dest, (int) piece < (int) BlackPawn
4058 ? wlPieceGC : blPieceGC, 0, 0,
4059 squareSize, squareSize, x, y, 1);
4062 XCopyPlane(xDisplay, *pieceToSolid(piece),
4063 dest, (int) piece < (int) BlackPawn
4064 ? wdPieceGC : bdPieceGC, 0, 0,
4065 squareSize, squareSize, x, y, 1);
4067 case 2: /* neutral */
4069 XCopyPlane(xDisplay, *pieceToSolid(piece),
4070 dest, (int) piece < (int) BlackPawn
4071 ? wjPieceGC : bjPieceGC, 0, 0,
4072 squareSize, squareSize, x, y, 1);
4077 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4079 int square_color, x, y;
4084 switch (square_color) {
4086 case 2: /* neutral */
4088 if ((int)piece < (int) BlackPawn) {
4096 if ((int)piece < (int) BlackPawn) {
4104 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4105 dest, wlPieceGC, 0, 0,
4106 squareSize, squareSize, x, y);
4109 typedef void (*DrawFunc)();
4111 DrawFunc ChooseDrawFunc()
4113 if (appData.monoMode) {
4114 if (DefaultDepth(xDisplay, xScreen) == 1) {
4115 return monoDrawPiece_1bit;
4117 return monoDrawPiece;
4121 return colorDrawPieceImage;
4123 return colorDrawPiece;
4127 /* [HR] determine square color depending on chess variant. */
4128 static int SquareColor(row, column)
4133 if (gameInfo.variant == VariantXiangqi) {
4134 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4136 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4138 } else if (row <= 4) {
4144 square_color = ((column + row) % 2) == 1;
4147 /* [hgm] holdings: next line makes all holdings squares light */
4148 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4150 return square_color;
4153 void DrawSquare(row, column, piece, do_flash)
4154 int row, column, do_flash;
4157 int square_color, x, y, direction, font_ascent, font_descent;
4160 XCharStruct overall;
4164 /* Calculate delay in milliseconds (2-delays per complete flash) */
4165 flash_delay = 500 / appData.flashRate;
4168 x = lineGap + ((BOARD_WIDTH-1)-column) *
4169 (squareSize + lineGap);
4170 y = lineGap + row * (squareSize + lineGap);
4172 x = lineGap + column * (squareSize + lineGap);
4173 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4174 (squareSize + lineGap);
4177 square_color = SquareColor(row, column);
4179 if ( // [HGM] holdings: blank out area between board and holdings
4180 column == BOARD_LEFT-1 || column == BOARD_RGHT
4181 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4182 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4183 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4185 // [HGM] print piece counts next to holdings
4186 string[1] = NULLCHAR;
4187 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4188 string[0] = '0' + piece;
4189 XTextExtents(countFontStruct, string, 1, &direction,
4190 &font_ascent, &font_descent, &overall);
4191 if (appData.monoMode) {
4192 XDrawImageString(xDisplay, xBoardWindow, countGC,
4193 x + squareSize - overall.width - 2,
4194 y + font_ascent + 1, string, 1);
4196 XDrawString(xDisplay, xBoardWindow, countGC,
4197 x + squareSize - overall.width - 2,
4198 y + font_ascent + 1, string, 1);
4201 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4202 string[0] = '0' + piece;
4203 XTextExtents(countFontStruct, string, 1, &direction,
4204 &font_ascent, &font_descent, &overall);
4205 if (appData.monoMode) {
4206 XDrawImageString(xDisplay, xBoardWindow, countGC,
4207 x + 2, y + font_ascent + 1, string, 1);
4209 XDrawString(xDisplay, xBoardWindow, countGC,
4210 x + 2, y + font_ascent + 1, string, 1);
4214 if (piece == EmptySquare || appData.blindfold) {
4215 BlankSquare(x, y, square_color, piece, xBoardWindow);
4217 drawfunc = ChooseDrawFunc();
4218 if (do_flash && appData.flashCount > 0) {
4219 for (i=0; i<appData.flashCount; ++i) {
4221 drawfunc(piece, square_color, x, y, xBoardWindow);
4222 XSync(xDisplay, False);
4223 do_flash_delay(flash_delay);
4225 BlankSquare(x, y, square_color, piece, xBoardWindow);
4226 XSync(xDisplay, False);
4227 do_flash_delay(flash_delay);
4230 drawfunc(piece, square_color, x, y, xBoardWindow);
4234 string[1] = NULLCHAR;
4235 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4236 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4237 string[0] = 'a' + column - BOARD_LEFT;
4238 XTextExtents(coordFontStruct, string, 1, &direction,
4239 &font_ascent, &font_descent, &overall);
4240 if (appData.monoMode) {
4241 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4242 x + squareSize - overall.width - 2,
4243 y + squareSize - font_descent - 1, string, 1);
4245 XDrawString(xDisplay, xBoardWindow, coordGC,
4246 x + squareSize - overall.width - 2,
4247 y + squareSize - font_descent - 1, string, 1);
4250 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4251 string[0] = ONE + row;
4252 XTextExtents(coordFontStruct, string, 1, &direction,
4253 &font_ascent, &font_descent, &overall);
4254 if (appData.monoMode) {
4255 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4256 x + 2, y + font_ascent + 1, string, 1);
4258 XDrawString(xDisplay, xBoardWindow, coordGC,
4259 x + 2, y + font_ascent + 1, string, 1);
4262 if(marker[row][column]) {
4263 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4264 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4269 /* Why is this needed on some versions of X? */
4270 void EventProc(widget, unused, event)
4275 if (!XtIsRealized(widget))
4278 switch (event->type) {
4280 if (event->xexpose.count > 0) return; /* no clipping is done */
4281 XDrawPosition(widget, True, NULL);
4284 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4291 void DrawPosition(fullRedraw, board)
4292 /*Boolean*/int fullRedraw;
4295 XDrawPosition(boardWidget, fullRedraw, board);
4298 /* Returns 1 if there are "too many" differences between b1 and b2
4299 (i.e. more than 1 move was made) */
4300 static int too_many_diffs(b1, b2)
4306 for (i=0; i<BOARD_HEIGHT; ++i) {
4307 for (j=0; j<BOARD_WIDTH; ++j) {
4308 if (b1[i][j] != b2[i][j]) {
4309 if (++c > 4) /* Castling causes 4 diffs */
4318 /* Matrix describing castling maneuvers */
4319 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4320 static int castling_matrix[4][5] = {
4321 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4322 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4323 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4324 { 7, 7, 4, 5, 6 } /* 0-0, black */
4327 /* Checks whether castling occurred. If it did, *rrow and *rcol
4328 are set to the destination (row,col) of the rook that moved.
4330 Returns 1 if castling occurred, 0 if not.
4332 Note: Only handles a max of 1 castling move, so be sure
4333 to call too_many_diffs() first.
4335 static int check_castle_draw(newb, oldb, rrow, rcol)
4342 /* For each type of castling... */
4343 for (i=0; i<4; ++i) {
4344 r = castling_matrix[i];
4346 /* Check the 4 squares involved in the castling move */
4348 for (j=1; j<=4; ++j) {
4349 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4356 /* All 4 changed, so it must be a castling move */
4365 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4366 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4368 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4371 void DrawSeekBackground( int left, int top, int right, int bottom )
4373 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4376 void DrawSeekText(char *buf, int x, int y)
4378 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4381 void DrawSeekDot(int x, int y, int colorNr)
4383 int square = colorNr & 0x80;
4386 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4388 XFillRectangle(xDisplay, xBoardWindow, color,
4389 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4391 XFillArc(xDisplay, xBoardWindow, color,
4392 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4395 static int damage[BOARD_RANKS][BOARD_FILES];
4398 * event handler for redrawing the board
4400 void XDrawPosition(w, repaint, board)
4402 /*Boolean*/int repaint;
4406 static int lastFlipView = 0;
4407 static int lastBoardValid = 0;
4408 static Board lastBoard;
4412 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4414 if (board == NULL) {
4415 if (!lastBoardValid) return;
4418 if (!lastBoardValid || lastFlipView != flipView) {
4419 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4420 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4425 * It would be simpler to clear the window with XClearWindow()
4426 * but this causes a very distracting flicker.
4429 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4431 /* If too much changes (begin observing new game, etc.), don't
4433 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4435 /* Special check for castling so we don't flash both the king
4436 and the rook (just flash the king). */
4438 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4439 /* Draw rook with NO flashing. King will be drawn flashing later */
4440 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4441 lastBoard[rrow][rcol] = board[rrow][rcol];
4445 /* First pass -- Draw (newly) empty squares and repair damage.
4446 This prevents you from having a piece show up twice while it
4447 is flashing on its new square */
4448 for (i = 0; i < BOARD_HEIGHT; i++)
4449 for (j = 0; j < BOARD_WIDTH; j++)
4450 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4452 DrawSquare(i, j, board[i][j], 0);
4453 damage[i][j] = False;
4456 /* Second pass -- Draw piece(s) in new position and flash them */
4457 for (i = 0; i < BOARD_HEIGHT; i++)
4458 for (j = 0; j < BOARD_WIDTH; j++)
4459 if (board[i][j] != lastBoard[i][j]) {
4460 DrawSquare(i, j, board[i][j], do_flash);
4464 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4465 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4467 for (i = 0; i < BOARD_HEIGHT; i++)
4468 for (j = 0; j < BOARD_WIDTH; j++) {
4469 DrawSquare(i, j, board[i][j], 0);
4470 damage[i][j] = False;
4474 CopyBoard(lastBoard, board);
4476 lastFlipView = flipView;
4478 /* Draw highlights */
4479 if (pm1X >= 0 && pm1Y >= 0) {
4480 drawHighlight(pm1X, pm1Y, prelineGC);
4482 if (pm2X >= 0 && pm2Y >= 0) {
4483 drawHighlight(pm2X, pm2Y, prelineGC);
4485 if (hi1X >= 0 && hi1Y >= 0) {
4486 drawHighlight(hi1X, hi1Y, highlineGC);
4488 if (hi2X >= 0 && hi2Y >= 0) {
4489 drawHighlight(hi2X, hi2Y, highlineGC);
4492 /* If piece being dragged around board, must redraw that too */
4495 XSync(xDisplay, False);
4500 * event handler for redrawing the board
4502 void DrawPositionProc(w, event, prms, nprms)
4508 XDrawPosition(w, True, NULL);
4513 * event handler for parsing user moves
4515 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4516 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4517 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4518 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4519 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4520 // and at the end FinishMove() to perform the move after optional promotion popups.
4521 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4522 void HandleUserMove(w, event, prms, nprms)
4528 if (w != boardWidget || errorExitStatus != -1) return;
4531 if (event->type == ButtonPress) {
4532 XtPopdown(promotionShell);
4533 XtDestroyWidget(promotionShell);
4534 promotionUp = False;
4542 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4543 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4544 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4547 void AnimateUserMove (Widget w, XEvent * event,
4548 String * params, Cardinal * nParams)
4550 DragPieceMove(event->xmotion.x, event->xmotion.y);
4553 void HandlePV (Widget w, XEvent * event,
4554 String * params, Cardinal * nParams)
4555 { // [HGM] pv: walk PV
4556 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4559 Widget CommentCreate(name, text, mutable, callback, lines)
4561 int /*Boolean*/ mutable;
4562 XtCallbackProc callback;
4566 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4571 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4572 XtGetValues(boardWidget, args, j);
4575 XtSetArg(args[j], XtNresizable, True); j++;
4578 XtCreatePopupShell(name, topLevelShellWidgetClass,
4579 shellWidget, args, j);
4582 XtCreatePopupShell(name, transientShellWidgetClass,
4583 shellWidget, args, j);
4586 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4587 layoutArgs, XtNumber(layoutArgs));
4589 XtCreateManagedWidget("form", formWidgetClass, layout,
4590 formArgs, XtNumber(formArgs));
4594 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4595 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4597 XtSetArg(args[j], XtNstring, text); j++;
4598 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4599 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4600 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4601 XtSetArg(args[j], XtNright, XtChainRight); j++;
4602 XtSetArg(args[j], XtNresizable, True); j++;
4603 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4604 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4605 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4606 XtSetArg(args[j], XtNautoFill, True); j++;
4607 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4609 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4613 XtSetArg(args[j], XtNfromVert, edit); j++;
4614 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4615 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4616 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4617 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4619 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4620 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4623 XtSetArg(args[j], XtNfromVert, edit); j++;
4624 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4625 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4626 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4627 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4628 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4630 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4631 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4634 XtSetArg(args[j], XtNfromVert, edit); j++;
4635 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4636 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4637 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4638 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4639 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4641 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4642 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4645 XtSetArg(args[j], XtNfromVert, edit); j++;
4646 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4647 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4648 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4649 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4651 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4652 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4655 XtSetArg(args[j], XtNfromVert, edit); j++;
4656 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4657 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4658 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4659 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4660 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4662 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4663 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4666 XtRealizeWidget(shell);
4668 if (commentX == -1) {
4671 Dimension pw_height;
4672 Dimension ew_height;
4675 XtSetArg(args[j], XtNheight, &ew_height); j++;
4676 XtGetValues(edit, args, j);
4679 XtSetArg(args[j], XtNheight, &pw_height); j++;
4680 XtGetValues(shell, args, j);
4681 commentH = pw_height + (lines - 1) * ew_height;
4682 commentW = bw_width - 16;
4684 XSync(xDisplay, False);
4686 /* This code seems to tickle an X bug if it is executed too soon
4687 after xboard starts up. The coordinates get transformed as if
4688 the main window was positioned at (0, 0).
4690 XtTranslateCoords(shellWidget,
4691 (bw_width - commentW) / 2, 0 - commentH / 2,
4692 &commentX, &commentY);
4694 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4695 RootWindowOfScreen(XtScreen(shellWidget)),
4696 (bw_width - commentW) / 2, 0 - commentH / 2,
4701 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4704 if(wpComment.width > 0) {
4705 commentX = wpComment.x;
4706 commentY = wpComment.y;
4707 commentW = wpComment.width;
4708 commentH = wpComment.height;
4712 XtSetArg(args[j], XtNheight, commentH); j++;
4713 XtSetArg(args[j], XtNwidth, commentW); j++;
4714 XtSetArg(args[j], XtNx, commentX); j++;
4715 XtSetArg(args[j], XtNy, commentY); j++;
4716 XtSetValues(shell, args, j);
4717 XtSetKeyboardFocus(shell, edit);
4722 /* Used for analysis window and ICS input window */
4723 Widget MiscCreate(name, text, mutable, callback, lines)
4725 int /*Boolean*/ mutable;
4726 XtCallbackProc callback;
4730 Widget shell, layout, form, edit;
4732 Dimension bw_width, pw_height, ew_height, w, h;
4738 XtSetArg(args[j], XtNresizable, True); j++;
4741 XtCreatePopupShell(name, topLevelShellWidgetClass,
4742 shellWidget, args, j);
4745 XtCreatePopupShell(name, transientShellWidgetClass,
4746 shellWidget, args, j);
4749 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4750 layoutArgs, XtNumber(layoutArgs));
4752 XtCreateManagedWidget("form", formWidgetClass, layout,
4753 formArgs, XtNumber(formArgs));
4757 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4758 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4760 XtSetArg(args[j], XtNstring, text); j++;
4761 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4762 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4763 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4764 XtSetArg(args[j], XtNright, XtChainRight); j++;
4765 XtSetArg(args[j], XtNresizable, True); j++;
4766 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4767 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4768 XtSetArg(args[j], XtNautoFill, True); j++;
4769 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4771 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4773 XtRealizeWidget(shell);
4776 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4777 XtGetValues(boardWidget, args, j);
4780 XtSetArg(args[j], XtNheight, &ew_height); j++;
4781 XtGetValues(edit, args, j);
4784 XtSetArg(args[j], XtNheight, &pw_height); j++;
4785 XtGetValues(shell, args, j);
4786 h = pw_height + (lines - 1) * ew_height;
4789 XSync(xDisplay, False);
4791 /* This code seems to tickle an X bug if it is executed too soon
4792 after xboard starts up. The coordinates get transformed as if
4793 the main window was positioned at (0, 0).
4795 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4797 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4798 RootWindowOfScreen(XtScreen(shellWidget)),
4799 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4803 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4806 XtSetArg(args[j], XtNheight, h); j++;
4807 XtSetArg(args[j], XtNwidth, w); j++;
4808 XtSetArg(args[j], XtNx, x); j++;
4809 XtSetArg(args[j], XtNy, y); j++;
4810 XtSetValues(shell, args, j);
4816 static int savedIndex; /* gross that this is global */
4818 void EditCommentPopUp(index, title, text)
4827 if (text == NULL) text = "";
4829 if (editShell == NULL) {
4831 CommentCreate(title, text, True, EditCommentCallback, 4);
4832 XtRealizeWidget(editShell);
4833 CatchDeleteWindow(editShell, "EditCommentPopDown");
4835 edit = XtNameToWidget(editShell, "*form.text");
4837 XtSetArg(args[j], XtNstring, text); j++;
4838 XtSetValues(edit, args, j);
4840 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4841 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4842 XtSetValues(editShell, args, j);
4845 XtPopup(editShell, XtGrabNone);
4849 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4850 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4854 void EditCommentCallback(w, client_data, call_data)
4856 XtPointer client_data, call_data;
4864 XtSetArg(args[j], XtNlabel, &name); j++;
4865 XtGetValues(w, args, j);
4867 if (strcmp(name, _("ok")) == 0) {
4868 edit = XtNameToWidget(editShell, "*form.text");
4870 XtSetArg(args[j], XtNstring, &val); j++;
4871 XtGetValues(edit, args, j);
4872 ReplaceComment(savedIndex, val);
4873 EditCommentPopDown();
4874 } else if (strcmp(name, _("cancel")) == 0) {
4875 EditCommentPopDown();
4876 } else if (strcmp(name, _("clear")) == 0) {
4877 edit = XtNameToWidget(editShell, "*form.text");
4878 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4879 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4883 void EditCommentPopDown()
4888 if (!editUp) return;
4890 XtSetArg(args[j], XtNx, &commentX); j++;
4891 XtSetArg(args[j], XtNy, &commentY); j++;
4892 XtSetArg(args[j], XtNheight, &commentH); j++;
4893 XtSetArg(args[j], XtNwidth, &commentW); j++;
4894 XtGetValues(editShell, args, j);
4895 XtPopdown(editShell);
4898 XtSetArg(args[j], XtNleftBitmap, None); j++;
4899 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4903 void ICSInputBoxPopUp()
4908 char *title = _("ICS Input");
4911 if (ICSInputShell == NULL) {
4912 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4913 tr = XtParseTranslationTable(ICSInputTranslations);
4914 edit = XtNameToWidget(ICSInputShell, "*form.text");
4915 XtOverrideTranslations(edit, tr);
4916 XtRealizeWidget(ICSInputShell);
4917 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4920 edit = XtNameToWidget(ICSInputShell, "*form.text");
4922 XtSetArg(args[j], XtNstring, ""); j++;
4923 XtSetValues(edit, args, j);
4925 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4926 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4927 XtSetValues(ICSInputShell, args, j);
4930 XtPopup(ICSInputShell, XtGrabNone);
4931 XtSetKeyboardFocus(ICSInputShell, edit);
4933 ICSInputBoxUp = True;
4935 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4936 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4940 void ICSInputSendText()
4947 edit = XtNameToWidget(ICSInputShell, "*form.text");
4949 XtSetArg(args[j], XtNstring, &val); j++;
4950 XtGetValues(edit, args, j);
4952 SendMultiLineToICS(val);
4953 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4954 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4957 void ICSInputBoxPopDown()
4962 if (!ICSInputBoxUp) return;
4964 XtPopdown(ICSInputShell);
4965 ICSInputBoxUp = False;
4967 XtSetArg(args[j], XtNleftBitmap, None); j++;
4968 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4972 void CommentPopUp(title, text)
4979 if (commentShell == NULL) {
4981 CommentCreate(title, text, False, CommentCallback, 4);
4982 XtRealizeWidget(commentShell);
4983 CatchDeleteWindow(commentShell, "CommentPopDown");
4985 edit = XtNameToWidget(commentShell, "*form.text");
4987 XtSetArg(args[j], XtNstring, text); j++;
4988 XtSetValues(edit, args, j);
4990 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4991 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4992 XtSetValues(commentShell, args, j);
4995 XtPopup(commentShell, XtGrabNone);
4996 XSync(xDisplay, False);
5001 void CommentCallback(w, client_data, call_data)
5003 XtPointer client_data, call_data;
5010 XtSetArg(args[j], XtNlabel, &name); j++;
5011 XtGetValues(w, args, j);
5013 if (strcmp(name, _("close")) == 0) {
5015 } else if (strcmp(name, _("edit")) == 0) {
5022 void CommentPopDown()
5027 if (!commentUp) return;
5029 XtSetArg(args[j], XtNx, &commentX); j++;
5030 XtSetArg(args[j], XtNy, &commentY); j++;
5031 XtSetArg(args[j], XtNwidth, &commentW); j++;
5032 XtSetArg(args[j], XtNheight, &commentH); j++;
5033 XtGetValues(commentShell, args, j);
5034 XtPopdown(commentShell);
5035 XSync(xDisplay, False);
5039 void FileNamePopUp(label, def, proc, openMode)
5046 Widget popup, layout, dialog, edit;
5052 fileProc = proc; /* I can't see a way not */
5053 fileOpenMode = openMode; /* to use globals here */
5054 { // [HGM] use file-selector dialog stolen from Ghostview
5056 int index; // this is not supported yet
5058 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5059 NULL, openMode, NULL, &name))
5060 (void) (*fileProc)(f, index=0, name);
5064 void FileNamePopDown()
5066 if (!filenameUp) return;
5067 XtPopdown(fileNameShell);
5068 XtDestroyWidget(fileNameShell);
5073 void FileNameCallback(w, client_data, call_data)
5075 XtPointer client_data, call_data;
5080 XtSetArg(args[0], XtNlabel, &name);
5081 XtGetValues(w, args, 1);
5083 if (strcmp(name, _("cancel")) == 0) {
5088 FileNameAction(w, NULL, NULL, NULL);
5091 void FileNameAction(w, event, prms, nprms)
5103 name = XawDialogGetValueString(w = XtParent(w));
5105 if ((name != NULL) && (*name != NULLCHAR)) {
5107 XtPopdown(w = XtParent(XtParent(w)));
5111 p = strrchr(buf, ' ');
5118 fullname = ExpandPathName(buf);
5120 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5123 f = fopen(fullname, fileOpenMode);
5125 DisplayError(_("Failed to open file"), errno);
5127 (void) (*fileProc)(f, index, buf);
5134 XtPopdown(w = XtParent(XtParent(w)));
5140 void PromotionPopUp()
5143 Widget dialog, layout;
5145 Dimension bw_width, pw_width;
5149 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5150 XtGetValues(boardWidget, args, j);
5153 XtSetArg(args[j], XtNresizable, True); j++;
5154 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5156 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5157 shellWidget, args, j);
5159 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5160 layoutArgs, XtNumber(layoutArgs));
5163 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5164 XtSetArg(args[j], XtNborderWidth, 0); j++;
5165 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5168 if(gameInfo.variant != VariantShogi) {
5169 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5170 (XtPointer) dialog);
5171 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5172 (XtPointer) dialog);
5173 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5174 (XtPointer) dialog);
5175 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5176 (XtPointer) dialog);
5177 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5178 gameInfo.variant == VariantGiveaway) {
5179 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5180 (XtPointer) dialog);
5182 if(gameInfo.variant == VariantCapablanca ||
5183 gameInfo.variant == VariantGothic ||
5184 gameInfo.variant == VariantCapaRandom) {
5185 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5186 (XtPointer) dialog);
5187 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5188 (XtPointer) dialog);
5190 } else // [HGM] shogi
5192 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5193 (XtPointer) dialog);
5194 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5195 (XtPointer) dialog);
5197 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5198 (XtPointer) dialog);
5200 XtRealizeWidget(promotionShell);
5201 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5204 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5205 XtGetValues(promotionShell, args, j);
5207 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5208 lineGap + squareSize/3 +
5209 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5210 0 : 6*(squareSize + lineGap)), &x, &y);
5213 XtSetArg(args[j], XtNx, x); j++;
5214 XtSetArg(args[j], XtNy, y); j++;
5215 XtSetValues(promotionShell, args, j);
5217 XtPopup(promotionShell, XtGrabNone);
5222 void PromotionPopDown()
5224 if (!promotionUp) return;
5225 XtPopdown(promotionShell);
5226 XtDestroyWidget(promotionShell);
5227 promotionUp = False;
5230 void PromotionCallback(w, client_data, call_data)
5232 XtPointer client_data, call_data;
5238 XtSetArg(args[0], XtNlabel, &name);
5239 XtGetValues(w, args, 1);
5243 if (fromX == -1) return;
5245 if (strcmp(name, _("cancel")) == 0) {
5249 } else if (strcmp(name, _("Knight")) == 0) {
5251 } else if (strcmp(name, _("Promote")) == 0) {
5253 } else if (strcmp(name, _("Defer")) == 0) {
5256 promoChar = ToLower(name[0]);
5259 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5261 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5262 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5267 void ErrorCallback(w, client_data, call_data)
5269 XtPointer client_data, call_data;
5272 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5274 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5280 if (!errorUp) return;
5282 XtPopdown(errorShell);
5283 XtDestroyWidget(errorShell);
5284 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5287 void ErrorPopUp(title, label, modal)
5288 char *title, *label;
5292 Widget dialog, layout;
5296 Dimension bw_width, pw_width;
5297 Dimension pw_height;
5301 XtSetArg(args[i], XtNresizable, True); i++;
5302 XtSetArg(args[i], XtNtitle, title); i++;
5304 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5305 shellWidget, args, i);
5307 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5308 layoutArgs, XtNumber(layoutArgs));
5311 XtSetArg(args[i], XtNlabel, label); i++;
5312 XtSetArg(args[i], XtNborderWidth, 0); i++;
5313 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5316 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5318 XtRealizeWidget(errorShell);
5319 CatchDeleteWindow(errorShell, "ErrorPopDown");
5322 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5323 XtGetValues(boardWidget, args, i);
5325 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5326 XtSetArg(args[i], XtNheight, &pw_height); i++;
5327 XtGetValues(errorShell, args, i);
5330 /* This code seems to tickle an X bug if it is executed too soon
5331 after xboard starts up. The coordinates get transformed as if
5332 the main window was positioned at (0, 0).
5334 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5335 0 - pw_height + squareSize / 3, &x, &y);
5337 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5338 RootWindowOfScreen(XtScreen(boardWidget)),
5339 (bw_width - pw_width) / 2,
5340 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5344 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5347 XtSetArg(args[i], XtNx, x); i++;
5348 XtSetArg(args[i], XtNy, y); i++;
5349 XtSetValues(errorShell, args, i);
5352 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5355 /* Disable all user input other than deleting the window */
5356 static int frozen = 0;
5360 /* Grab by a widget that doesn't accept input */
5361 XtAddGrab(messageWidget, TRUE, FALSE);
5365 /* Undo a FreezeUI */
5368 if (!frozen) return;
5369 XtRemoveGrab(messageWidget);
5373 char *ModeToWidgetName(mode)
5377 case BeginningOfGame:
5378 if (appData.icsActive)
5379 return "menuMode.ICS Client";
5380 else if (appData.noChessProgram ||
5381 *appData.cmailGameName != NULLCHAR)
5382 return "menuMode.Edit Game";
5384 return "menuMode.Machine Black";
5385 case MachinePlaysBlack:
5386 return "menuMode.Machine Black";
5387 case MachinePlaysWhite:
5388 return "menuMode.Machine White";
5390 return "menuMode.Analysis Mode";
5392 return "menuMode.Analyze File";
5393 case TwoMachinesPlay:
5394 return "menuMode.Two Machines";
5396 return "menuMode.Edit Game";
5397 case PlayFromGameFile:
5398 return "menuFile.Load Game";
5400 return "menuMode.Edit Position";
5402 return "menuMode.Training";
5403 case IcsPlayingWhite:
5404 case IcsPlayingBlack:
5408 return "menuMode.ICS Client";
5415 void ModeHighlight()
5418 static int oldPausing = FALSE;
5419 static GameMode oldmode = (GameMode) -1;
5422 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5424 if (pausing != oldPausing) {
5425 oldPausing = pausing;
5427 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5429 XtSetArg(args[0], XtNleftBitmap, None);
5431 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5434 if (appData.showButtonBar) {
5435 /* Always toggle, don't set. Previous code messes up when
5436 invoked while the button is pressed, as releasing it
5437 toggles the state again. */
5440 XtSetArg(args[0], XtNbackground, &oldbg);
5441 XtSetArg(args[1], XtNforeground, &oldfg);
5442 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5444 XtSetArg(args[0], XtNbackground, oldfg);
5445 XtSetArg(args[1], XtNforeground, oldbg);
5447 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5451 wname = ModeToWidgetName(oldmode);
5452 if (wname != NULL) {
5453 XtSetArg(args[0], XtNleftBitmap, None);
5454 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5456 wname = ModeToWidgetName(gameMode);
5457 if (wname != NULL) {
5458 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5459 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5463 /* Maybe all the enables should be handled here, not just this one */
5464 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5465 gameMode == Training || gameMode == PlayFromGameFile);
5470 * Button/menu procedures
5472 void ResetProc(w, event, prms, nprms)
5481 int LoadGamePopUp(f, gameNumber, title)
5486 cmailMsgLoaded = FALSE;
5487 if (gameNumber == 0) {
5488 int error = GameListBuild(f);
5490 DisplayError(_("Cannot build game list"), error);
5491 } else if (!ListEmpty(&gameList) &&
5492 ((ListGame *) gameList.tailPred)->number > 1) {
5493 GameListPopUp(f, title);
5499 return LoadGame(f, gameNumber, title, FALSE);
5502 void LoadGameProc(w, event, prms, nprms)
5508 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5511 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5514 void LoadNextGameProc(w, event, prms, nprms)
5523 void LoadPrevGameProc(w, event, prms, nprms)
5532 void ReloadGameProc(w, event, prms, nprms)
5541 void LoadNextPositionProc(w, event, prms, nprms)
5550 void LoadPrevPositionProc(w, event, prms, nprms)
5559 void ReloadPositionProc(w, event, prms, nprms)
5568 void LoadPositionProc(w, event, prms, nprms)
5574 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5577 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5580 void SaveGameProc(w, event, prms, nprms)
5586 FileNamePopUp(_("Save game file name?"),
5587 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5591 void SavePositionProc(w, event, prms, nprms)
5597 FileNamePopUp(_("Save position file name?"),
5598 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5602 void ReloadCmailMsgProc(w, event, prms, nprms)
5608 ReloadCmailMsgEvent(FALSE);
5611 void MailMoveProc(w, event, prms, nprms)
5620 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5621 char *selected_fen_position=NULL;
5624 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5625 Atom *type_return, XtPointer *value_return,
5626 unsigned long *length_return, int *format_return)
5628 char *selection_tmp;
5630 if (!selected_fen_position) return False; /* should never happen */
5631 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5632 /* note: since no XtSelectionDoneProc was registered, Xt will
5633 * automatically call XtFree on the value returned. So have to
5634 * make a copy of it allocated with XtMalloc */
5635 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5636 strcpy(selection_tmp, selected_fen_position);
5638 *value_return=selection_tmp;
5639 *length_return=strlen(selection_tmp);
5640 *type_return=*target;
5641 *format_return = 8; /* bits per byte */
5643 } else if (*target == XA_TARGETS(xDisplay)) {
5644 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5645 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5646 targets_tmp[1] = XA_STRING;
5647 *value_return = targets_tmp;
5648 *type_return = XA_ATOM;
5650 *format_return = 8 * sizeof(Atom);
5651 if (*format_return > 32) {
5652 *length_return *= *format_return / 32;
5653 *format_return = 32;
5661 /* note: when called from menu all parameters are NULL, so no clue what the
5662 * Widget which was clicked on was, or what the click event was
5664 void CopyPositionProc(w, event, prms, nprms)
5671 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5672 * have a notion of a position that is selected but not copied.
5673 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5675 if(gameMode == EditPosition) EditPositionDone(TRUE);
5676 if (selected_fen_position) free(selected_fen_position);
5677 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5678 if (!selected_fen_position) return;
5679 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5681 SendPositionSelection,
5682 NULL/* lose_ownership_proc */ ,
5683 NULL/* transfer_done_proc */);
5684 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5686 SendPositionSelection,
5687 NULL/* lose_ownership_proc */ ,
5688 NULL/* transfer_done_proc */);
5691 /* function called when the data to Paste is ready */
5693 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5694 Atom *type, XtPointer value, unsigned long *len, int *format)
5697 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5698 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5699 EditPositionPasteFEN(fenstr);
5703 /* called when Paste Position button is pressed,
5704 * all parameters will be NULL */
5705 void PastePositionProc(w, event, prms, nprms)
5711 XtGetSelectionValue(menuBarWidget,
5712 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5713 /* (XtSelectionCallbackProc) */ PastePositionCB,
5714 NULL, /* client_data passed to PastePositionCB */
5716 /* better to use the time field from the event that triggered the
5717 * call to this function, but that isn't trivial to get
5725 SendGameSelection(Widget w, Atom *selection, Atom *target,
5726 Atom *type_return, XtPointer *value_return,
5727 unsigned long *length_return, int *format_return)
5729 char *selection_tmp;
5731 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5732 FILE* f = fopen(gameCopyFilename, "r");
5735 if (f == NULL) return False;
5739 selection_tmp = XtMalloc(len + 1);
5740 count = fread(selection_tmp, 1, len, f);
5742 XtFree(selection_tmp);
5745 selection_tmp[len] = NULLCHAR;
5746 *value_return = selection_tmp;
5747 *length_return = len;
5748 *type_return = *target;
5749 *format_return = 8; /* bits per byte */
5751 } else if (*target == XA_TARGETS(xDisplay)) {
5752 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5753 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5754 targets_tmp[1] = XA_STRING;
5755 *value_return = targets_tmp;
5756 *type_return = XA_ATOM;
5758 *format_return = 8 * sizeof(Atom);
5759 if (*format_return > 32) {
5760 *length_return *= *format_return / 32;
5761 *format_return = 32;
5769 /* note: when called from menu all parameters are NULL, so no clue what the
5770 * Widget which was clicked on was, or what the click event was
5772 void CopyGameProc(w, event, prms, nprms)
5780 ret = SaveGameToFile(gameCopyFilename, FALSE);
5784 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5785 * have a notion of a game that is selected but not copied.
5786 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5788 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5791 NULL/* lose_ownership_proc */ ,
5792 NULL/* transfer_done_proc */);
5793 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5796 NULL/* lose_ownership_proc */ ,
5797 NULL/* transfer_done_proc */);
5800 /* function called when the data to Paste is ready */
5802 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5803 Atom *type, XtPointer value, unsigned long *len, int *format)
5806 if (value == NULL || *len == 0) {
5807 return; /* nothing had been selected to copy */
5809 f = fopen(gamePasteFilename, "w");
5811 DisplayError(_("Can't open temp file"), errno);
5814 fwrite(value, 1, *len, f);
5817 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5820 /* called when Paste Game button is pressed,
5821 * all parameters will be NULL */
5822 void PasteGameProc(w, event, prms, nprms)
5828 XtGetSelectionValue(menuBarWidget,
5829 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5830 /* (XtSelectionCallbackProc) */ PasteGameCB,
5831 NULL, /* client_data passed to PasteGameCB */
5833 /* better to use the time field from the event that triggered the
5834 * call to this function, but that isn't trivial to get
5844 SaveGameProc(NULL, NULL, NULL, NULL);
5848 void QuitProc(w, event, prms, nprms)
5857 void PauseProc(w, event, prms, nprms)
5867 void MachineBlackProc(w, event, prms, nprms)
5873 MachineBlackEvent();
5876 void MachineWhiteProc(w, event, prms, nprms)
5882 MachineWhiteEvent();
5885 void AnalyzeModeProc(w, event, prms, nprms)
5893 if (!first.analysisSupport) {
5894 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5895 DisplayError(buf, 0);
5898 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5899 if (appData.icsActive) {
5900 if (gameMode != IcsObserving) {
5901 sprintf(buf,_("You are not observing a game"));
5902 DisplayError(buf, 0);
5904 if (appData.icsEngineAnalyze) {
5905 if (appData.debugMode)
5906 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5912 /* if enable, use want disable icsEngineAnalyze */
5913 if (appData.icsEngineAnalyze) {
5918 appData.icsEngineAnalyze = TRUE;
5919 if (appData.debugMode)
5920 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5922 if (!appData.showThinking)
5923 ShowThinkingProc(w,event,prms,nprms);
5928 void AnalyzeFileProc(w, event, prms, nprms)
5934 if (!first.analysisSupport) {
5936 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5937 DisplayError(buf, 0);
5942 if (!appData.showThinking)
5943 ShowThinkingProc(w,event,prms,nprms);
5946 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5947 AnalysisPeriodicEvent(1);
5950 void TwoMachinesProc(w, event, prms, nprms)
5959 void IcsClientProc(w, event, prms, nprms)
5968 void EditGameProc(w, event, prms, nprms)
5977 void EditPositionProc(w, event, prms, nprms)
5983 EditPositionEvent();
5986 void TrainingProc(w, event, prms, nprms)
5995 void EditCommentProc(w, event, prms, nprms)
6002 EditCommentPopDown();
6008 void IcsInputBoxProc(w, event, prms, nprms)
6014 if (ICSInputBoxUp) {
6015 ICSInputBoxPopDown();
6021 void AcceptProc(w, event, prms, nprms)
6030 void DeclineProc(w, event, prms, nprms)
6039 void RematchProc(w, event, prms, nprms)
6048 void CallFlagProc(w, event, prms, nprms)
6057 void DrawProc(w, event, prms, nprms)
6066 void AbortProc(w, event, prms, nprms)
6075 void AdjournProc(w, event, prms, nprms)
6084 void ResignProc(w, event, prms, nprms)
6093 void AdjuWhiteProc(w, event, prms, nprms)
6099 UserAdjudicationEvent(+1);
6102 void AdjuBlackProc(w, event, prms, nprms)
6108 UserAdjudicationEvent(-1);
6111 void AdjuDrawProc(w, event, prms, nprms)
6117 UserAdjudicationEvent(0);
6120 void EnterKeyProc(w, event, prms, nprms)
6126 if (ICSInputBoxUp == True)
6130 void UpKeyProc(w, event, prms, nprms)
6135 { // [HGM] input: let up-arrow recall previous line from history
6142 if (!ICSInputBoxUp) return;
6143 edit = XtNameToWidget(ICSInputShell, "*form.text");
6145 XtSetArg(args[j], XtNstring, &val); j++;
6146 XtGetValues(edit, args, j);
6147 val = PrevInHistory(val);
6148 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6149 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6151 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6152 XawTextReplace(edit, 0, 0, &t);
6153 XawTextSetInsertionPoint(edit, 9999);
6157 void DownKeyProc(w, event, prms, nprms)
6162 { // [HGM] input: let down-arrow recall next line from history
6167 if (!ICSInputBoxUp) return;
6168 edit = XtNameToWidget(ICSInputShell, "*form.text");
6169 val = NextInHistory();
6170 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6171 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6173 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6174 XawTextReplace(edit, 0, 0, &t);
6175 XawTextSetInsertionPoint(edit, 9999);
6179 void StopObservingProc(w, event, prms, nprms)
6185 StopObservingEvent();
6188 void StopExaminingProc(w, event, prms, nprms)
6194 StopExaminingEvent();
6197 void UploadProc(w, event, prms, nprms)
6207 void ForwardProc(w, event, prms, nprms)
6217 void BackwardProc(w, event, prms, nprms)
6226 void ToStartProc(w, event, prms, nprms)
6235 void ToEndProc(w, event, prms, nprms)
6244 void RevertProc(w, event, prms, nprms)
6253 void TruncateGameProc(w, event, prms, nprms)
6259 TruncateGameEvent();
6261 void RetractMoveProc(w, event, prms, nprms)
6270 void MoveNowProc(w, event, prms, nprms)
6280 void AlwaysQueenProc(w, event, prms, nprms)
6288 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6290 if (appData.alwaysPromoteToQueen) {
6291 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6293 XtSetArg(args[0], XtNleftBitmap, None);
6295 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6299 void AnimateDraggingProc(w, event, prms, nprms)
6307 appData.animateDragging = !appData.animateDragging;
6309 if (appData.animateDragging) {
6310 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6313 XtSetArg(args[0], XtNleftBitmap, None);
6315 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6319 void AnimateMovingProc(w, event, prms, nprms)
6327 appData.animate = !appData.animate;
6329 if (appData.animate) {
6330 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6333 XtSetArg(args[0], XtNleftBitmap, None);
6335 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6339 void AutocommProc(w, event, prms, nprms)
6347 appData.autoComment = !appData.autoComment;
6349 if (appData.autoComment) {
6350 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6352 XtSetArg(args[0], XtNleftBitmap, None);
6354 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6359 void AutoflagProc(w, event, prms, nprms)
6367 appData.autoCallFlag = !appData.autoCallFlag;
6369 if (appData.autoCallFlag) {
6370 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6372 XtSetArg(args[0], XtNleftBitmap, None);
6374 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6378 void AutoflipProc(w, event, prms, nprms)
6386 appData.autoFlipView = !appData.autoFlipView;
6388 if (appData.autoFlipView) {
6389 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6391 XtSetArg(args[0], XtNleftBitmap, None);
6393 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6397 void AutobsProc(w, event, prms, nprms)
6405 appData.autoObserve = !appData.autoObserve;
6407 if (appData.autoObserve) {
6408 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6410 XtSetArg(args[0], XtNleftBitmap, None);
6412 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6416 void AutoraiseProc(w, event, prms, nprms)
6424 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6426 if (appData.autoRaiseBoard) {
6427 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6429 XtSetArg(args[0], XtNleftBitmap, None);
6431 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6435 void AutosaveProc(w, event, prms, nprms)
6443 appData.autoSaveGames = !appData.autoSaveGames;
6445 if (appData.autoSaveGames) {
6446 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6448 XtSetArg(args[0], XtNleftBitmap, None);
6450 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6454 void BlindfoldProc(w, event, prms, nprms)
6462 appData.blindfold = !appData.blindfold;
6464 if (appData.blindfold) {
6465 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6467 XtSetArg(args[0], XtNleftBitmap, None);
6469 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6472 DrawPosition(True, NULL);
6475 void TestLegalityProc(w, event, prms, nprms)
6483 appData.testLegality = !appData.testLegality;
6485 if (appData.testLegality) {
6486 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6488 XtSetArg(args[0], XtNleftBitmap, None);
6490 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6495 void FlashMovesProc(w, event, prms, nprms)
6503 if (appData.flashCount == 0) {
6504 appData.flashCount = 3;
6506 appData.flashCount = -appData.flashCount;
6509 if (appData.flashCount > 0) {
6510 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6512 XtSetArg(args[0], XtNleftBitmap, None);
6514 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6518 void FlipViewProc(w, event, prms, nprms)
6524 flipView = !flipView;
6525 DrawPosition(True, NULL);
6528 void GetMoveListProc(w, event, prms, nprms)
6536 appData.getMoveList = !appData.getMoveList;
6538 if (appData.getMoveList) {
6539 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6542 XtSetArg(args[0], XtNleftBitmap, None);
6544 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6549 void HighlightDraggingProc(w, event, prms, nprms)
6557 appData.highlightDragging = !appData.highlightDragging;
6559 if (appData.highlightDragging) {
6560 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6562 XtSetArg(args[0], XtNleftBitmap, None);
6564 XtSetValues(XtNameToWidget(menuBarWidget,
6565 "menuOptions.Highlight Dragging"), args, 1);
6569 void HighlightLastMoveProc(w, event, prms, nprms)
6577 appData.highlightLastMove = !appData.highlightLastMove;
6579 if (appData.highlightLastMove) {
6580 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6582 XtSetArg(args[0], XtNleftBitmap, None);
6584 XtSetValues(XtNameToWidget(menuBarWidget,
6585 "menuOptions.Highlight Last Move"), args, 1);
6588 void IcsAlarmProc(w, event, prms, nprms)
6596 appData.icsAlarm = !appData.icsAlarm;
6598 if (appData.icsAlarm) {
6599 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6601 XtSetArg(args[0], XtNleftBitmap, None);
6603 XtSetValues(XtNameToWidget(menuBarWidget,
6604 "menuOptions.ICS Alarm"), args, 1);
6607 void MoveSoundProc(w, event, prms, nprms)
6615 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6617 if (appData.ringBellAfterMoves) {
6618 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6620 XtSetArg(args[0], XtNleftBitmap, None);
6622 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6627 void OldSaveStyleProc(w, event, prms, nprms)
6635 appData.oldSaveStyle = !appData.oldSaveStyle;
6637 if (appData.oldSaveStyle) {
6638 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6640 XtSetArg(args[0], XtNleftBitmap, None);
6642 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6646 void PeriodicUpdatesProc(w, event, prms, nprms)
6654 PeriodicUpdatesEvent(!appData.periodicUpdates);
6656 if (appData.periodicUpdates) {
6657 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6659 XtSetArg(args[0], XtNleftBitmap, None);
6661 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6665 void PonderNextMoveProc(w, event, prms, nprms)
6673 PonderNextMoveEvent(!appData.ponderNextMove);
6675 if (appData.ponderNextMove) {
6676 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6678 XtSetArg(args[0], XtNleftBitmap, None);
6680 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6684 void PopupExitMessageProc(w, event, prms, nprms)
6692 appData.popupExitMessage = !appData.popupExitMessage;
6694 if (appData.popupExitMessage) {
6695 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6697 XtSetArg(args[0], XtNleftBitmap, None);
6699 XtSetValues(XtNameToWidget(menuBarWidget,
6700 "menuOptions.Popup Exit Message"), args, 1);
6703 void PopupMoveErrorsProc(w, event, prms, nprms)
6711 appData.popupMoveErrors = !appData.popupMoveErrors;
6713 if (appData.popupMoveErrors) {
6714 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6716 XtSetArg(args[0], XtNleftBitmap, None);
6718 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6722 void PremoveProc(w, event, prms, nprms)
6730 appData.premove = !appData.premove;
6732 if (appData.premove) {
6733 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6735 XtSetArg(args[0], XtNleftBitmap, None);
6737 XtSetValues(XtNameToWidget(menuBarWidget,
6738 "menuOptions.Premove"), args, 1);
6741 void QuietPlayProc(w, event, prms, nprms)
6749 appData.quietPlay = !appData.quietPlay;
6751 if (appData.quietPlay) {
6752 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6754 XtSetArg(args[0], XtNleftBitmap, None);
6756 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6760 void ShowCoordsProc(w, event, prms, nprms)
6768 appData.showCoords = !appData.showCoords;
6770 if (appData.showCoords) {
6771 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6773 XtSetArg(args[0], XtNleftBitmap, None);
6775 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6778 DrawPosition(True, NULL);
6781 void ShowThinkingProc(w, event, prms, nprms)
6787 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6788 ShowThinkingEvent();
6791 void HideThinkingProc(w, event, prms, nprms)
6799 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6800 ShowThinkingEvent();
6802 if (appData.hideThinkingFromHuman) {
6803 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6805 XtSetArg(args[0], XtNleftBitmap, None);
6807 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6811 void SaveOnExitProc(w, event, prms, nprms)
6819 saveSettingsOnExit = !saveSettingsOnExit;
6821 if (saveSettingsOnExit) {
6822 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6824 XtSetArg(args[0], XtNleftBitmap, None);
6826 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6830 void SaveSettingsProc(w, event, prms, nprms)
6836 SaveSettings(settingsFileName);
6839 void InfoProc(w, event, prms, nprms)
6846 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6851 void ManProc(w, event, prms, nprms)
6859 if (nprms && *nprms > 0)
6863 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6867 void HintProc(w, event, prms, nprms)
6876 void BookProc(w, event, prms, nprms)
6885 void AboutProc(w, event, prms, nprms)
6893 char *zippy = " (with Zippy code)";
6897 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6898 programVersion, zippy,
6899 "Copyright 1991 Digital Equipment Corporation",
6900 "Enhancements Copyright 1992-2009 Free Software Foundation",
6901 "Enhancements Copyright 2005 Alessandro Scotti",
6902 PACKAGE, " is free software and carries NO WARRANTY;",
6903 "see the file COPYING for more information.");
6904 ErrorPopUp(_("About XBoard"), buf, FALSE);
6907 void DebugProc(w, event, prms, nprms)
6913 appData.debugMode = !appData.debugMode;
6916 void AboutGameProc(w, event, prms, nprms)
6925 void NothingProc(w, event, prms, nprms)
6934 void Iconify(w, event, prms, nprms)
6943 XtSetArg(args[0], XtNiconic, True);
6944 XtSetValues(shellWidget, args, 1);
6947 void DisplayMessage(message, extMessage)
6948 char *message, *extMessage;
6950 /* display a message in the message widget */
6959 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6964 message = extMessage;
6968 /* need to test if messageWidget already exists, since this function
6969 can also be called during the startup, if for example a Xresource
6970 is not set up correctly */
6973 XtSetArg(arg, XtNlabel, message);
6974 XtSetValues(messageWidget, &arg, 1);
6980 void DisplayTitle(text)
6985 char title[MSG_SIZ];
6988 if (text == NULL) text = "";
6990 if (appData.titleInWindow) {
6992 XtSetArg(args[i], XtNlabel, text); i++;
6993 XtSetValues(titleWidget, args, i);
6996 if (*text != NULLCHAR) {
6998 strcpy(title, text);
6999 } else if (appData.icsActive) {
7000 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7001 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7002 } else if (appData.cmailGameName[0] != NULLCHAR) {
7003 snprintf(icon, sizeof(icon), "%s", "CMail");
7004 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7006 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7007 } else if (gameInfo.variant == VariantGothic) {
7008 strcpy(icon, programName);
7009 strcpy(title, GOTHIC);
7012 } else if (gameInfo.variant == VariantFalcon) {
7013 strcpy(icon, programName);
7014 strcpy(title, FALCON);
7016 } else if (appData.noChessProgram) {
7017 strcpy(icon, programName);
7018 strcpy(title, programName);
7020 strcpy(icon, first.tidy);
7021 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7024 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7025 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7026 XtSetValues(shellWidget, args, i);
7030 void DisplayError(message, error)
7037 if (appData.debugMode || appData.matchMode) {
7038 fprintf(stderr, "%s: %s\n", programName, message);
7041 if (appData.debugMode || appData.matchMode) {
7042 fprintf(stderr, "%s: %s: %s\n",
7043 programName, message, strerror(error));
7045 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7048 ErrorPopUp(_("Error"), message, FALSE);
7052 void DisplayMoveError(message)
7057 DrawPosition(FALSE, NULL);
7058 if (appData.debugMode || appData.matchMode) {
7059 fprintf(stderr, "%s: %s\n", programName, message);
7061 if (appData.popupMoveErrors) {
7062 ErrorPopUp(_("Error"), message, FALSE);
7064 DisplayMessage(message, "");
7069 void DisplayFatalError(message, error, status)
7075 errorExitStatus = status;
7077 fprintf(stderr, "%s: %s\n", programName, message);
7079 fprintf(stderr, "%s: %s: %s\n",
7080 programName, message, strerror(error));
7081 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7084 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7085 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7091 void DisplayInformation(message)
7095 ErrorPopUp(_("Information"), message, TRUE);
7098 void DisplayNote(message)
7102 ErrorPopUp(_("Note"), message, FALSE);
7106 NullXErrorCheck(dpy, error_event)
7108 XErrorEvent *error_event;
7113 void DisplayIcsInteractionTitle(message)
7116 if (oldICSInteractionTitle == NULL) {
7117 /* Magic to find the old window title, adapted from vim */
7118 char *wina = getenv("WINDOWID");
7120 Window win = (Window) atoi(wina);
7121 Window root, parent, *children;
7122 unsigned int nchildren;
7123 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7125 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7126 if (!XQueryTree(xDisplay, win, &root, &parent,
7127 &children, &nchildren)) break;
7128 if (children) XFree((void *)children);
7129 if (parent == root || parent == 0) break;
7132 XSetErrorHandler(oldHandler);
7134 if (oldICSInteractionTitle == NULL) {
7135 oldICSInteractionTitle = "xterm";
7138 printf("\033]0;%s\007", message);
7142 char pendingReplyPrefix[MSG_SIZ];
7143 ProcRef pendingReplyPR;
7145 void AskQuestionProc(w, event, prms, nprms)
7152 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7156 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7159 void AskQuestionPopDown()
7161 if (!askQuestionUp) return;
7162 XtPopdown(askQuestionShell);
7163 XtDestroyWidget(askQuestionShell);
7164 askQuestionUp = False;
7167 void AskQuestionReplyAction(w, event, prms, nprms)
7177 reply = XawDialogGetValueString(w = XtParent(w));
7178 strcpy(buf, pendingReplyPrefix);
7179 if (*buf) strcat(buf, " ");
7182 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7183 AskQuestionPopDown();
7185 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7188 void AskQuestionCallback(w, client_data, call_data)
7190 XtPointer client_data, call_data;
7195 XtSetArg(args[0], XtNlabel, &name);
7196 XtGetValues(w, args, 1);
7198 if (strcmp(name, _("cancel")) == 0) {
7199 AskQuestionPopDown();
7201 AskQuestionReplyAction(w, NULL, NULL, NULL);
7205 void AskQuestion(title, question, replyPrefix, pr)
7206 char *title, *question, *replyPrefix;
7210 Widget popup, layout, dialog, edit;
7216 strcpy(pendingReplyPrefix, replyPrefix);
7217 pendingReplyPR = pr;
7220 XtSetArg(args[i], XtNresizable, True); i++;
7221 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7222 askQuestionShell = popup =
7223 XtCreatePopupShell(title, transientShellWidgetClass,
7224 shellWidget, args, i);
7227 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7228 layoutArgs, XtNumber(layoutArgs));
7231 XtSetArg(args[i], XtNlabel, question); i++;
7232 XtSetArg(args[i], XtNvalue, ""); i++;
7233 XtSetArg(args[i], XtNborderWidth, 0); i++;
7234 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7237 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7238 (XtPointer) dialog);
7239 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7240 (XtPointer) dialog);
7242 XtRealizeWidget(popup);
7243 CatchDeleteWindow(popup, "AskQuestionPopDown");
7245 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7246 &x, &y, &win_x, &win_y, &mask);
7248 XtSetArg(args[0], XtNx, x - 10);
7249 XtSetArg(args[1], XtNy, y - 30);
7250 XtSetValues(popup, args, 2);
7252 XtPopup(popup, XtGrabExclusive);
7253 askQuestionUp = True;
7255 edit = XtNameToWidget(dialog, "*value");
7256 XtSetKeyboardFocus(popup, edit);
7264 if (*name == NULLCHAR) {
7266 } else if (strcmp(name, "$") == 0) {
7267 putc(BELLCHAR, stderr);
7270 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7278 PlaySound(appData.soundMove);
7284 PlaySound(appData.soundIcsWin);
7290 PlaySound(appData.soundIcsLoss);
7296 PlaySound(appData.soundIcsDraw);
7300 PlayIcsUnfinishedSound()
7302 PlaySound(appData.soundIcsUnfinished);
7308 PlaySound(appData.soundIcsAlarm);
7314 system("stty echo");
7320 system("stty -echo");
7324 Colorize(cc, continuation)
7329 int count, outCount, error;
7331 if (textColors[(int)cc].bg > 0) {
7332 if (textColors[(int)cc].fg > 0) {
7333 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7334 textColors[(int)cc].fg, textColors[(int)cc].bg);
7336 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7337 textColors[(int)cc].bg);
7340 if (textColors[(int)cc].fg > 0) {
7341 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7342 textColors[(int)cc].fg);
7344 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7347 count = strlen(buf);
7348 outCount = OutputToProcess(NoProc, buf, count, &error);
7349 if (outCount < count) {
7350 DisplayFatalError(_("Error writing to display"), error, 1);
7353 if (continuation) return;
7356 PlaySound(appData.soundShout);
7359 PlaySound(appData.soundSShout);
7362 PlaySound(appData.soundChannel1);
7365 PlaySound(appData.soundChannel);
7368 PlaySound(appData.soundKibitz);
7371 PlaySound(appData.soundTell);
7373 case ColorChallenge:
7374 PlaySound(appData.soundChallenge);
7377 PlaySound(appData.soundRequest);
7380 PlaySound(appData.soundSeek);
7391 return getpwuid(getuid())->pw_name;
7394 static char *ExpandPathName(path)
7397 static char static_buf[2000];
7398 char *d, *s, buf[2000];
7404 while (*s && isspace(*s))
7413 if (*(s+1) == '/') {
7414 strcpy(d, getpwuid(getuid())->pw_dir);
7419 *strchr(buf, '/') = 0;
7420 pwd = getpwnam(buf);
7423 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7427 strcpy(d, pwd->pw_dir);
7428 strcat(d, strchr(s+1, '/'));
7439 static char host_name[MSG_SIZ];
7441 #if HAVE_GETHOSTNAME
7442 gethostname(host_name, MSG_SIZ);
7444 #else /* not HAVE_GETHOSTNAME */
7445 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7446 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7448 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7450 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7451 #endif /* not HAVE_GETHOSTNAME */
7454 XtIntervalId delayedEventTimerXID = 0;
7455 DelayedEventCallback delayedEventCallback = 0;
7460 delayedEventTimerXID = 0;
7461 delayedEventCallback();
7465 ScheduleDelayedEvent(cb, millisec)
7466 DelayedEventCallback cb; long millisec;
7468 if(delayedEventTimerXID && delayedEventCallback == cb)
7469 // [HGM] alive: replace, rather than add or flush identical event
7470 XtRemoveTimeOut(delayedEventTimerXID);
7471 delayedEventCallback = cb;
7472 delayedEventTimerXID =
7473 XtAppAddTimeOut(appContext, millisec,
7474 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7477 DelayedEventCallback
7480 if (delayedEventTimerXID) {
7481 return delayedEventCallback;
7488 CancelDelayedEvent()
7490 if (delayedEventTimerXID) {
7491 XtRemoveTimeOut(delayedEventTimerXID);
7492 delayedEventTimerXID = 0;
7496 XtIntervalId loadGameTimerXID = 0;
7498 int LoadGameTimerRunning()
7500 return loadGameTimerXID != 0;
7503 int StopLoadGameTimer()
7505 if (loadGameTimerXID != 0) {
7506 XtRemoveTimeOut(loadGameTimerXID);
7507 loadGameTimerXID = 0;
7515 LoadGameTimerCallback(arg, id)
7519 loadGameTimerXID = 0;
7524 StartLoadGameTimer(millisec)
7528 XtAppAddTimeOut(appContext, millisec,
7529 (XtTimerCallbackProc) LoadGameTimerCallback,
7533 XtIntervalId analysisClockXID = 0;
7536 AnalysisClockCallback(arg, id)
7540 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7541 || appData.icsEngineAnalyze) { // [DM]
7542 AnalysisPeriodicEvent(0);
7543 StartAnalysisClock();
7548 StartAnalysisClock()
7551 XtAppAddTimeOut(appContext, 2000,
7552 (XtTimerCallbackProc) AnalysisClockCallback,
7556 XtIntervalId clockTimerXID = 0;
7558 int ClockTimerRunning()
7560 return clockTimerXID != 0;
7563 int StopClockTimer()
7565 if (clockTimerXID != 0) {
7566 XtRemoveTimeOut(clockTimerXID);
7575 ClockTimerCallback(arg, id)
7584 StartClockTimer(millisec)
7588 XtAppAddTimeOut(appContext, millisec,
7589 (XtTimerCallbackProc) ClockTimerCallback,
7594 DisplayTimerLabel(w, color, timer, highlight)
7603 /* check for low time warning */
7604 Pixel foregroundOrWarningColor = timerForegroundPixel;
7607 appData.lowTimeWarning &&
7608 (timer / 1000) < appData.icsAlarmTime)
7609 foregroundOrWarningColor = lowTimeWarningColor;
7611 if (appData.clockMode) {
7612 sprintf(buf, "%s: %s", color, TimeString(timer));
7613 XtSetArg(args[0], XtNlabel, buf);
7615 sprintf(buf, "%s ", color);
7616 XtSetArg(args[0], XtNlabel, buf);
7621 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7622 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7624 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7625 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7628 XtSetValues(w, args, 3);
7632 DisplayWhiteClock(timeRemaining, highlight)
7638 if(appData.noGUI) return;
7639 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7640 if (highlight && iconPixmap == bIconPixmap) {
7641 iconPixmap = wIconPixmap;
7642 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7643 XtSetValues(shellWidget, args, 1);
7648 DisplayBlackClock(timeRemaining, highlight)
7654 if(appData.noGUI) return;
7655 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7656 if (highlight && iconPixmap == wIconPixmap) {
7657 iconPixmap = bIconPixmap;
7658 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7659 XtSetValues(shellWidget, args, 1);
7677 int StartChildProcess(cmdLine, dir, pr)
7684 int to_prog[2], from_prog[2];
7688 if (appData.debugMode) {
7689 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7692 /* We do NOT feed the cmdLine to the shell; we just
7693 parse it into blank-separated arguments in the
7694 most simple-minded way possible.
7697 strcpy(buf, cmdLine);
7700 while(*p == ' ') p++;
7702 if(*p == '"' || *p == '\'')
7703 p = strchr(++argv[i-1], *p);
7704 else p = strchr(p, ' ');
7705 if (p == NULL) break;
7710 SetUpChildIO(to_prog, from_prog);
7712 if ((pid = fork()) == 0) {
7714 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7715 close(to_prog[1]); // first close the unused pipe ends
7716 close(from_prog[0]);
7717 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7718 dup2(from_prog[1], 1);
7719 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7720 close(from_prog[1]); // and closing again loses one of the pipes!
7721 if(fileno(stderr) >= 2) // better safe than sorry...
7722 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7724 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7729 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7731 execvp(argv[0], argv);
7733 /* If we get here, exec failed */
7738 /* Parent process */
7740 close(from_prog[1]);
7742 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7745 cp->fdFrom = from_prog[0];
7746 cp->fdTo = to_prog[1];
7751 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7752 static RETSIGTYPE AlarmCallBack(int n)
7758 DestroyChildProcess(pr, signalType)
7762 ChildProc *cp = (ChildProc *) pr;
7764 if (cp->kind != CPReal) return;
7766 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7767 signal(SIGALRM, AlarmCallBack);
7769 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7770 kill(cp->pid, SIGKILL); // kill it forcefully
7771 wait((int *) 0); // and wait again
7775 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7777 /* Process is exiting either because of the kill or because of
7778 a quit command sent by the backend; either way, wait for it to die.
7787 InterruptChildProcess(pr)
7790 ChildProc *cp = (ChildProc *) pr;
7792 if (cp->kind != CPReal) return;
7793 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7796 int OpenTelnet(host, port, pr)
7801 char cmdLine[MSG_SIZ];
7803 if (port[0] == NULLCHAR) {
7804 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7806 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7808 return StartChildProcess(cmdLine, "", pr);
7811 int OpenTCP(host, port, pr)
7817 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7818 #else /* !OMIT_SOCKETS */
7820 struct sockaddr_in sa;
7822 unsigned short uport;
7825 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7829 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7830 sa.sin_family = AF_INET;
7831 sa.sin_addr.s_addr = INADDR_ANY;
7832 uport = (unsigned short) 0;
7833 sa.sin_port = htons(uport);
7834 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7838 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7839 if (!(hp = gethostbyname(host))) {
7841 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7842 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7843 hp->h_addrtype = AF_INET;
7845 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7846 hp->h_addr_list[0] = (char *) malloc(4);
7847 hp->h_addr_list[0][0] = b0;
7848 hp->h_addr_list[0][1] = b1;
7849 hp->h_addr_list[0][2] = b2;
7850 hp->h_addr_list[0][3] = b3;
7855 sa.sin_family = hp->h_addrtype;
7856 uport = (unsigned short) atoi(port);
7857 sa.sin_port = htons(uport);
7858 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7860 if (connect(s, (struct sockaddr *) &sa,
7861 sizeof(struct sockaddr_in)) < 0) {
7865 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7872 #endif /* !OMIT_SOCKETS */
7877 int OpenCommPort(name, pr)
7884 fd = open(name, 2, 0);
7885 if (fd < 0) return errno;
7887 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7897 int OpenLoopback(pr)
7903 SetUpChildIO(to, from);
7905 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7908 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7915 int OpenRcmd(host, user, cmd, pr)
7916 char *host, *user, *cmd;
7919 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7923 #define INPUT_SOURCE_BUF_SIZE 8192
7932 char buf[INPUT_SOURCE_BUF_SIZE];
7937 DoInputCallback(closure, source, xid)
7942 InputSource *is = (InputSource *) closure;
7947 if (is->lineByLine) {
7948 count = read(is->fd, is->unused,
7949 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7951 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7954 is->unused += count;
7956 while (p < is->unused) {
7957 q = memchr(p, '\n', is->unused - p);
7958 if (q == NULL) break;
7960 (is->func)(is, is->closure, p, q - p, 0);
7964 while (p < is->unused) {
7969 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7974 (is->func)(is, is->closure, is->buf, count, error);
7978 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7985 ChildProc *cp = (ChildProc *) pr;
7987 is = (InputSource *) calloc(1, sizeof(InputSource));
7988 is->lineByLine = lineByLine;
7992 is->fd = fileno(stdin);
7994 is->kind = cp->kind;
7995 is->fd = cp->fdFrom;
7998 is->unused = is->buf;
8001 is->xid = XtAppAddInput(appContext, is->fd,
8002 (XtPointer) (XtInputReadMask),
8003 (XtInputCallbackProc) DoInputCallback,
8005 is->closure = closure;
8006 return (InputSourceRef) is;
8010 RemoveInputSource(isr)
8013 InputSource *is = (InputSource *) isr;
8015 if (is->xid == 0) return;
8016 XtRemoveInput(is->xid);
8020 int OutputToProcess(pr, message, count, outError)
8026 static int line = 0;
8027 ChildProc *cp = (ChildProc *) pr;
8032 if (appData.noJoin || !appData.useInternalWrap)
8033 outCount = fwrite(message, 1, count, stdout);
8036 int width = get_term_width();
8037 int len = wrap(NULL, message, count, width, &line);
8038 char *msg = malloc(len);
8042 outCount = fwrite(message, 1, count, stdout);
8045 dbgchk = wrap(msg, message, count, width, &line);
8046 if (dbgchk != len && appData.debugMode)
8047 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8048 outCount = fwrite(msg, 1, dbgchk, stdout);
8054 outCount = write(cp->fdTo, message, count);
8064 /* Output message to process, with "ms" milliseconds of delay
8065 between each character. This is needed when sending the logon
8066 script to ICC, which for some reason doesn't like the
8067 instantaneous send. */
8068 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8075 ChildProc *cp = (ChildProc *) pr;
8080 r = write(cp->fdTo, message++, 1);
8093 /**** Animation code by Hugh Fisher, DCS, ANU.
8095 Known problem: if a window overlapping the board is
8096 moved away while a piece is being animated underneath,
8097 the newly exposed area won't be updated properly.
8098 I can live with this.
8100 Known problem: if you look carefully at the animation
8101 of pieces in mono mode, they are being drawn as solid
8102 shapes without interior detail while moving. Fixing
8103 this would be a major complication for minimal return.
8106 /* Masks for XPM pieces. Black and white pieces can have
8107 different shapes, but in the interest of retaining my
8108 sanity pieces must have the same outline on both light
8109 and dark squares, and all pieces must use the same
8110 background square colors/images. */
8112 static int xpmDone = 0;
8115 CreateAnimMasks (pieceDepth)
8122 unsigned long plane;
8125 /* Need a bitmap just to get a GC with right depth */
8126 buf = XCreatePixmap(xDisplay, xBoardWindow,
8128 values.foreground = 1;
8129 values.background = 0;
8130 /* Don't use XtGetGC, not read only */
8131 maskGC = XCreateGC(xDisplay, buf,
8132 GCForeground | GCBackground, &values);
8133 XFreePixmap(xDisplay, buf);
8135 buf = XCreatePixmap(xDisplay, xBoardWindow,
8136 squareSize, squareSize, pieceDepth);
8137 values.foreground = XBlackPixel(xDisplay, xScreen);
8138 values.background = XWhitePixel(xDisplay, xScreen);
8139 bufGC = XCreateGC(xDisplay, buf,
8140 GCForeground | GCBackground, &values);
8142 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8143 /* Begin with empty mask */
8144 if(!xpmDone) // [HGM] pieces: keep using existing
8145 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8146 squareSize, squareSize, 1);
8147 XSetFunction(xDisplay, maskGC, GXclear);
8148 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8149 0, 0, squareSize, squareSize);
8151 /* Take a copy of the piece */
8156 XSetFunction(xDisplay, bufGC, GXcopy);
8157 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8159 0, 0, squareSize, squareSize, 0, 0);
8161 /* XOR the background (light) over the piece */
8162 XSetFunction(xDisplay, bufGC, GXxor);
8164 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8165 0, 0, squareSize, squareSize, 0, 0);
8167 XSetForeground(xDisplay, bufGC, lightSquareColor);
8168 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8171 /* We now have an inverted piece image with the background
8172 erased. Construct mask by just selecting all the non-zero
8173 pixels - no need to reconstruct the original image. */
8174 XSetFunction(xDisplay, maskGC, GXor);
8176 /* Might be quicker to download an XImage and create bitmap
8177 data from it rather than this N copies per piece, but it
8178 only takes a fraction of a second and there is a much
8179 longer delay for loading the pieces. */
8180 for (n = 0; n < pieceDepth; n ++) {
8181 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8182 0, 0, squareSize, squareSize,
8188 XFreePixmap(xDisplay, buf);
8189 XFreeGC(xDisplay, bufGC);
8190 XFreeGC(xDisplay, maskGC);
8194 InitAnimState (anim, info)
8196 XWindowAttributes * info;
8201 /* Each buffer is square size, same depth as window */
8202 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8203 squareSize, squareSize, info->depth);
8204 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8205 squareSize, squareSize, info->depth);
8207 /* Create a plain GC for blitting */
8208 mask = GCForeground | GCBackground | GCFunction |
8209 GCPlaneMask | GCGraphicsExposures;
8210 values.foreground = XBlackPixel(xDisplay, xScreen);
8211 values.background = XWhitePixel(xDisplay, xScreen);
8212 values.function = GXcopy;
8213 values.plane_mask = AllPlanes;
8214 values.graphics_exposures = False;
8215 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8217 /* Piece will be copied from an existing context at
8218 the start of each new animation/drag. */
8219 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8221 /* Outline will be a read-only copy of an existing */
8222 anim->outlineGC = None;
8228 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8229 XWindowAttributes info;
8231 if (xpmDone && gameInfo.variant == old) return;
8232 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8233 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8235 InitAnimState(&game, &info);
8236 InitAnimState(&player, &info);
8238 /* For XPM pieces, we need bitmaps to use as masks. */
8240 CreateAnimMasks(info.depth);
8246 static Boolean frameWaiting;
8248 static RETSIGTYPE FrameAlarm (sig)
8251 frameWaiting = False;
8252 /* In case System-V style signals. Needed?? */
8253 signal(SIGALRM, FrameAlarm);
8260 struct itimerval delay;
8262 XSync(xDisplay, False);
8265 frameWaiting = True;
8266 signal(SIGALRM, FrameAlarm);
8267 delay.it_interval.tv_sec =
8268 delay.it_value.tv_sec = time / 1000;
8269 delay.it_interval.tv_usec =
8270 delay.it_value.tv_usec = (time % 1000) * 1000;
8271 setitimer(ITIMER_REAL, &delay, NULL);
8272 while (frameWaiting) pause();
8273 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8274 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8275 setitimer(ITIMER_REAL, &delay, NULL);
8285 XSync(xDisplay, False);
8287 usleep(time * 1000);
8292 /* Convert board position to corner of screen rect and color */
8295 ScreenSquare(column, row, pt, color)
8296 int column; int row; XPoint * pt; int * color;
8299 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8300 pt->y = lineGap + row * (squareSize + lineGap);
8302 pt->x = lineGap + column * (squareSize + lineGap);
8303 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8305 *color = SquareColor(row, column);
8308 /* Convert window coords to square */
8311 BoardSquare(x, y, column, row)
8312 int x; int y; int * column; int * row;
8314 *column = EventToSquare(x, BOARD_WIDTH);
8315 if (flipView && *column >= 0)
8316 *column = BOARD_WIDTH - 1 - *column;
8317 *row = EventToSquare(y, BOARD_HEIGHT);
8318 if (!flipView && *row >= 0)
8319 *row = BOARD_HEIGHT - 1 - *row;
8324 #undef Max /* just in case */
8326 #define Max(a, b) ((a) > (b) ? (a) : (b))
8327 #define Min(a, b) ((a) < (b) ? (a) : (b))
8330 SetRect(rect, x, y, width, height)
8331 XRectangle * rect; int x; int y; int width; int height;
8335 rect->width = width;
8336 rect->height = height;
8339 /* Test if two frames overlap. If they do, return
8340 intersection rect within old and location of
8341 that rect within new. */
8344 Intersect(old, new, size, area, pt)
8345 XPoint * old; XPoint * new;
8346 int size; XRectangle * area; XPoint * pt;
8348 if (old->x > new->x + size || new->x > old->x + size ||
8349 old->y > new->y + size || new->y > old->y + size) {
8352 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8353 size - abs(old->x - new->x), size - abs(old->y - new->y));
8354 pt->x = Max(old->x - new->x, 0);
8355 pt->y = Max(old->y - new->y, 0);
8360 /* For two overlapping frames, return the rect(s)
8361 in the old that do not intersect with the new. */
8364 CalcUpdateRects(old, new, size, update, nUpdates)
8365 XPoint * old; XPoint * new; int size;
8366 XRectangle update[]; int * nUpdates;
8370 /* If old = new (shouldn't happen) then nothing to draw */
8371 if (old->x == new->x && old->y == new->y) {
8375 /* Work out what bits overlap. Since we know the rects
8376 are the same size we don't need a full intersect calc. */
8378 /* Top or bottom edge? */
8379 if (new->y > old->y) {
8380 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8382 } else if (old->y > new->y) {
8383 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8384 size, old->y - new->y);
8387 /* Left or right edge - don't overlap any update calculated above. */
8388 if (new->x > old->x) {
8389 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8390 new->x - old->x, size - abs(new->y - old->y));
8392 } else if (old->x > new->x) {
8393 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8394 old->x - new->x, size - abs(new->y - old->y));
8401 /* Generate a series of frame coords from start->mid->finish.
8402 The movement rate doubles until the half way point is
8403 reached, then halves back down to the final destination,
8404 which gives a nice slow in/out effect. The algorithmn
8405 may seem to generate too many intermediates for short
8406 moves, but remember that the purpose is to attract the
8407 viewers attention to the piece about to be moved and
8408 then to where it ends up. Too few frames would be less
8412 Tween(start, mid, finish, factor, frames, nFrames)
8413 XPoint * start; XPoint * mid;
8414 XPoint * finish; int factor;
8415 XPoint frames[]; int * nFrames;
8417 int fraction, n, count;
8421 /* Slow in, stepping 1/16th, then 1/8th, ... */
8423 for (n = 0; n < factor; n++)
8425 for (n = 0; n < factor; n++) {
8426 frames[count].x = start->x + (mid->x - start->x) / fraction;
8427 frames[count].y = start->y + (mid->y - start->y) / fraction;
8429 fraction = fraction / 2;
8433 frames[count] = *mid;
8436 /* Slow out, stepping 1/2, then 1/4, ... */
8438 for (n = 0; n < factor; n++) {
8439 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8440 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8442 fraction = fraction * 2;
8447 /* Draw a piece on the screen without disturbing what's there */
8450 SelectGCMask(piece, clip, outline, mask)
8451 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8455 /* Bitmap for piece being moved. */
8456 if (appData.monoMode) {
8457 *mask = *pieceToSolid(piece);
8458 } else if (useImages) {
8460 *mask = xpmMask[piece];
8462 *mask = ximMaskPm[piece];
8465 *mask = *pieceToSolid(piece);
8468 /* GC for piece being moved. Square color doesn't matter, but
8469 since it gets modified we make a copy of the original. */
8471 if (appData.monoMode)
8476 if (appData.monoMode)
8481 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8483 /* Outline only used in mono mode and is not modified */
8485 *outline = bwPieceGC;
8487 *outline = wbPieceGC;
8491 OverlayPiece(piece, clip, outline, dest)
8492 ChessSquare piece; GC clip; GC outline; Drawable dest;
8497 /* Draw solid rectangle which will be clipped to shape of piece */
8498 XFillRectangle(xDisplay, dest, clip,
8499 0, 0, squareSize, squareSize);
8500 if (appData.monoMode)
8501 /* Also draw outline in contrasting color for black
8502 on black / white on white cases */
8503 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8504 0, 0, squareSize, squareSize, 0, 0, 1);
8506 /* Copy the piece */
8511 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8513 0, 0, squareSize, squareSize,
8518 /* Animate the movement of a single piece */
8521 BeginAnimation(anim, piece, startColor, start)
8529 /* The old buffer is initialised with the start square (empty) */
8530 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8531 anim->prevFrame = *start;
8533 /* The piece will be drawn using its own bitmap as a matte */
8534 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8535 XSetClipMask(xDisplay, anim->pieceGC, mask);
8539 AnimationFrame(anim, frame, piece)
8544 XRectangle updates[4];
8549 /* Save what we are about to draw into the new buffer */
8550 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8551 frame->x, frame->y, squareSize, squareSize,
8554 /* Erase bits of the previous frame */
8555 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8556 /* Where the new frame overlapped the previous,
8557 the contents in newBuf are wrong. */
8558 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8559 overlap.x, overlap.y,
8560 overlap.width, overlap.height,
8562 /* Repaint the areas in the old that don't overlap new */
8563 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8564 for (i = 0; i < count; i++)
8565 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8566 updates[i].x - anim->prevFrame.x,
8567 updates[i].y - anim->prevFrame.y,
8568 updates[i].width, updates[i].height,
8569 updates[i].x, updates[i].y);
8571 /* Easy when no overlap */
8572 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8573 0, 0, squareSize, squareSize,
8574 anim->prevFrame.x, anim->prevFrame.y);
8577 /* Save this frame for next time round */
8578 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8579 0, 0, squareSize, squareSize,
8581 anim->prevFrame = *frame;
8583 /* Draw piece over original screen contents, not current,
8584 and copy entire rect. Wipes out overlapping piece images. */
8585 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8586 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8587 0, 0, squareSize, squareSize,
8588 frame->x, frame->y);
8592 EndAnimation (anim, finish)
8596 XRectangle updates[4];
8601 /* The main code will redraw the final square, so we
8602 only need to erase the bits that don't overlap. */
8603 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8604 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8605 for (i = 0; i < count; i++)
8606 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8607 updates[i].x - anim->prevFrame.x,
8608 updates[i].y - anim->prevFrame.y,
8609 updates[i].width, updates[i].height,
8610 updates[i].x, updates[i].y);
8612 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8613 0, 0, squareSize, squareSize,
8614 anim->prevFrame.x, anim->prevFrame.y);
8619 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8621 ChessSquare piece; int startColor;
8622 XPoint * start; XPoint * finish;
8623 XPoint frames[]; int nFrames;
8627 BeginAnimation(anim, piece, startColor, start);
8628 for (n = 0; n < nFrames; n++) {
8629 AnimationFrame(anim, &(frames[n]), piece);
8630 FrameDelay(appData.animSpeed);
8632 EndAnimation(anim, finish);
8635 /* Main control logic for deciding what to animate and how */
8638 AnimateMove(board, fromX, fromY, toX, toY)
8647 XPoint start, finish, mid;
8648 XPoint frames[kFactor * 2 + 1];
8649 int nFrames, startColor, endColor;
8651 /* Are we animating? */
8652 if (!appData.animate || appData.blindfold)
8655 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8656 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8657 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8659 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8660 piece = board[fromY][fromX];
8661 if (piece >= EmptySquare) return;
8666 hop = (piece == WhiteKnight || piece == BlackKnight);
8669 if (appData.debugMode) {
8670 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8671 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8672 piece, fromX, fromY, toX, toY); }
8674 ScreenSquare(fromX, fromY, &start, &startColor);
8675 ScreenSquare(toX, toY, &finish, &endColor);
8678 /* Knight: make diagonal movement then straight */
8679 if (abs(toY - fromY) < abs(toX - fromX)) {
8680 mid.x = start.x + (finish.x - start.x) / 2;
8684 mid.y = start.y + (finish.y - start.y) / 2;
8687 mid.x = start.x + (finish.x - start.x) / 2;
8688 mid.y = start.y + (finish.y - start.y) / 2;
8691 /* Don't use as many frames for very short moves */
8692 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8693 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8695 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8696 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8698 /* Be sure end square is redrawn */
8699 damage[toY][toX] = True;
8703 DragPieceBegin(x, y)
8706 int boardX, boardY, color;
8709 /* Are we animating? */
8710 if (!appData.animateDragging || appData.blindfold)
8713 /* Figure out which square we start in and the
8714 mouse position relative to top left corner. */
8715 BoardSquare(x, y, &boardX, &boardY);
8716 player.startBoardX = boardX;
8717 player.startBoardY = boardY;
8718 ScreenSquare(boardX, boardY, &corner, &color);
8719 player.startSquare = corner;
8720 player.startColor = color;
8721 /* As soon as we start dragging, the piece will jump slightly to
8722 be centered over the mouse pointer. */
8723 player.mouseDelta.x = squareSize/2;
8724 player.mouseDelta.y = squareSize/2;
8725 /* Initialise animation */
8726 player.dragPiece = PieceForSquare(boardX, boardY);
8728 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8729 player.dragActive = True;
8730 BeginAnimation(&player, player.dragPiece, color, &corner);
8731 /* Mark this square as needing to be redrawn. Note that
8732 we don't remove the piece though, since logically (ie
8733 as seen by opponent) the move hasn't been made yet. */
8734 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8735 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8736 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8737 corner.x, corner.y, squareSize, squareSize,
8738 0, 0); // [HGM] zh: unstack in stead of grab
8739 damage[boardY][boardX] = True;
8741 player.dragActive = False;
8751 /* Are we animating? */
8752 if (!appData.animateDragging || appData.blindfold)
8756 if (! player.dragActive)
8758 /* Move piece, maintaining same relative position
8759 of mouse within square */
8760 corner.x = x - player.mouseDelta.x;
8761 corner.y = y - player.mouseDelta.y;
8762 AnimationFrame(&player, &corner, player.dragPiece);
8764 if (appData.highlightDragging) {
8766 BoardSquare(x, y, &boardX, &boardY);
8767 SetHighlights(fromX, fromY, boardX, boardY);
8776 int boardX, boardY, color;
8779 /* Are we animating? */
8780 if (!appData.animateDragging || appData.blindfold)
8784 if (! player.dragActive)
8786 /* Last frame in sequence is square piece is
8787 placed on, which may not match mouse exactly. */
8788 BoardSquare(x, y, &boardX, &boardY);
8789 ScreenSquare(boardX, boardY, &corner, &color);
8790 EndAnimation(&player, &corner);
8792 /* Be sure end square is redrawn */
8793 damage[boardY][boardX] = True;
8795 /* This prevents weird things happening with fast successive
8796 clicks which on my Sun at least can cause motion events
8797 without corresponding press/release. */
8798 player.dragActive = False;
8801 /* Handle expose event while piece being dragged */
8806 if (!player.dragActive || appData.blindfold)
8809 /* What we're doing: logically, the move hasn't been made yet,
8810 so the piece is still in it's original square. But visually
8811 it's being dragged around the board. So we erase the square
8812 that the piece is on and draw it at the last known drag point. */
8813 BlankSquare(player.startSquare.x, player.startSquare.y,
8814 player.startColor, EmptySquare, xBoardWindow);
8815 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8816 damage[player.startBoardY][player.startBoardX] = TRUE;
8819 #include <sys/ioctl.h>
8820 int get_term_width()
8822 int fd, default_width;
8825 default_width = 79; // this is FICS default anyway...
8827 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8829 if (!ioctl(fd, TIOCGSIZE, &win))
8830 default_width = win.ts_cols;
8831 #elif defined(TIOCGWINSZ)
8833 if (!ioctl(fd, TIOCGWINSZ, &win))
8834 default_width = win.ws_col;
8836 return default_width;
8839 void update_ics_width()
8841 static int old_width = 0;
8842 int new_width = get_term_width();
8844 if (old_width != new_width)
8845 ics_printf("set width %d\n", new_width);
8846 old_width = new_width;
8849 void NotifyFrontendLogin()