2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
192 #include "frontend.h"
194 #include "backendz.h"
198 #include "xgamelist.h"
199 #include "xhistory.h"
200 #include "xedittags.h"
203 // must be moved to xengineoutput.h
205 void EngineOutputProc P((Widget w, XEvent *event,
206 String *prms, Cardinal *nprms));
207 void EvalGraphProc P((Widget w, XEvent *event,
208 String *prms, Cardinal *nprms));
215 #define usleep(t) _sleep2(((t)+500)/1000)
219 # define _(s) gettext (s)
220 # define N_(s) gettext_noop (s)
236 int main P((int argc, char **argv));
237 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
238 char *init_path, char *mode, int (*show_entry)(), char **name_return));
239 RETSIGTYPE CmailSigHandler P((int sig));
240 RETSIGTYPE IntSigHandler P((int sig));
241 RETSIGTYPE TermSizeSigHandler P((int sig));
242 void CreateGCs P((void));
243 void CreateXIMPieces P((void));
244 void CreateXPMPieces P((void));
245 void CreatePieces P((void));
246 void CreatePieceMenus P((void));
247 Widget CreateMenuBar P((Menu *mb));
248 Widget CreateButtonBar P ((MenuItem *mi));
249 char *FindFont P((char *pattern, int targetPxlSize));
250 void PieceMenuPopup P((Widget w, XEvent *event,
251 String *params, Cardinal *num_params));
252 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
253 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
254 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
255 u_int wreq, u_int hreq));
256 void CreateGrid P((void));
257 int EventToSquare P((int x, int limit));
258 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
259 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
260 void HandleUserMove P((Widget w, XEvent *event,
261 String *prms, Cardinal *nprms));
262 void AnimateUserMove P((Widget w, XEvent * event,
263 String * params, Cardinal * nParams));
264 void HandlePV P((Widget w, XEvent * event,
265 String * params, Cardinal * nParams));
266 void SelectPV P((Widget w, XEvent * event,
267 String * params, Cardinal * nParams));
268 void StopPV P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void WhiteClock P((Widget w, XEvent *event,
271 String *prms, Cardinal *nprms));
272 void BlackClock P((Widget w, XEvent *event,
273 String *prms, Cardinal *nprms));
274 void DrawPositionProc P((Widget w, XEvent *event,
275 String *prms, Cardinal *nprms));
276 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
278 void CommentClick P((Widget w, XEvent * event,
279 String * params, Cardinal * nParams));
280 void CommentPopUp P((char *title, char *label));
281 void CommentPopDown P((void));
282 void CommentCallback P((Widget w, XtPointer client_data,
283 XtPointer call_data));
284 void ICSInputBoxPopUp P((void));
285 void ICSInputBoxPopDown P((void));
286 void FileNamePopUp P((char *label, char *def,
287 FileProc proc, char *openMode));
288 void FileNamePopDown P((void));
289 void FileNameCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void FileNameAction P((Widget w, XEvent *event,
292 String *prms, Cardinal *nprms));
293 void AskQuestionReplyAction P((Widget w, XEvent *event,
294 String *prms, Cardinal *nprms));
295 void AskQuestionProc P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionPopDown P((void));
298 void PromotionPopDown P((void));
299 void PromotionCallback P((Widget w, XtPointer client_data,
300 XtPointer call_data));
301 void EditCommentPopDown P((void));
302 void EditCommentCallback P((Widget w, XtPointer client_data,
303 XtPointer call_data));
304 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
305 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
306 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
307 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
309 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
311 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
313 void LoadPositionProc P((Widget w, XEvent *event,
314 String *prms, Cardinal *nprms));
315 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
317 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
319 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
321 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
323 void PastePositionProc P((Widget w, XEvent *event, String *prms,
325 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void SavePositionProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
333 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
337 void MachineWhiteProc P((Widget w, XEvent *event,
338 String *prms, Cardinal *nprms));
339 void AnalyzeModeProc P((Widget w, XEvent *event,
340 String *prms, Cardinal *nprms));
341 void AnalyzeFileProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
345 void IcsClientProc P((Widget w, XEvent *event, String *prms,
347 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void EditPositionProc P((Widget w, XEvent *event,
349 String *prms, Cardinal *nprms));
350 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void EditCommentProc P((Widget w, XEvent *event,
352 String *prms, Cardinal *nprms));
353 void IcsInputBoxProc P((Widget w, XEvent *event,
354 String *prms, Cardinal *nprms));
355 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void StopObservingProc P((Widget w, XEvent *event, String *prms,
371 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
373 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
382 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
384 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
387 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
389 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
391 void AutocommProc P((Widget w, XEvent *event, String *prms,
393 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void AutobsProc P((Widget w, XEvent *event, String *prms,
397 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
402 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
405 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
407 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
409 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
413 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
415 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
417 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
419 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
421 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
425 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
427 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
429 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
431 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void DisplayMove P((int moveNumber));
443 void DisplayTitle P((char *title));
444 void ICSInitScript P((void));
445 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
446 void ErrorPopUp P((char *title, char *text, int modal));
447 void ErrorPopDown P((void));
448 static char *ExpandPathName P((char *path));
449 static void CreateAnimVars P((void));
450 static void DragPieceMove P((int x, int y));
451 static void DrawDragPiece P((void));
452 char *ModeToWidgetName P((GameMode mode));
453 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void GameListOptionsPopDown P(());
462 void ShufflePopDown P(());
463 void EnginePopDown P(());
464 void UciPopDown P(());
465 void TimeControlPopDown P(());
466 void NewVariantPopDown P(());
467 void SettingsPopDown P(());
468 void update_ics_width P(());
469 int get_term_width P(());
470 int CopyMemoProc P(());
472 * XBoard depends on Xt R4 or higher
474 int xtVersion = XtSpecificationRelease;
479 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
480 jailSquareColor, highlightSquareColor, premoveHighlightColor;
481 Pixel lowTimeWarningColor;
482 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
483 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
484 wjPieceGC, bjPieceGC, prelineGC, countGC;
485 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
486 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
487 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
488 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
489 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
490 ICSInputShell, fileNameShell, askQuestionShell;
491 Widget historyShell, evalGraphShell, gameListShell;
492 int hOffset; // [HGM] dual
493 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
494 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
495 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
496 Font clockFontID, coordFontID, countFontID;
497 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
498 XtAppContext appContext;
500 char *oldICSInteractionTitle;
504 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
506 Position commentX = -1, commentY = -1;
507 Dimension commentW, commentH;
508 typedef unsigned int BoardSize;
510 Boolean chessProgram;
512 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
513 int squareSize, smallLayout = 0, tinyLayout = 0,
514 marginW, marginH, // [HGM] for run-time resizing
515 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
516 ICSInputBoxUp = False, askQuestionUp = False,
517 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
518 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
519 Pixel timerForegroundPixel, timerBackgroundPixel;
520 Pixel buttonForegroundPixel, buttonBackgroundPixel;
521 char *chessDir, *programName, *programVersion,
522 *gameCopyFilename, *gamePasteFilename;
523 Boolean alwaysOnTop = False;
524 Boolean saveSettingsOnExit;
525 char *settingsFileName;
526 char *icsTextMenuString;
528 char *firstChessProgramNames;
529 char *secondChessProgramNames;
531 WindowPlacement wpMain;
532 WindowPlacement wpConsole;
533 WindowPlacement wpComment;
534 WindowPlacement wpMoveHistory;
535 WindowPlacement wpEvalGraph;
536 WindowPlacement wpEngineOutput;
537 WindowPlacement wpGameList;
538 WindowPlacement wpTags;
542 Pixmap pieceBitmap[2][(int)BlackPawn];
543 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
544 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
545 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
546 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
547 int useImages, useImageSqs;
548 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
549 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
550 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
551 XImage *ximLightSquare, *ximDarkSquare;
554 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
555 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
557 #define White(piece) ((int)(piece) < (int)BlackPawn)
559 /* Variables for doing smooth animation. This whole thing
560 would be much easier if the board was double-buffered,
561 but that would require a fairly major rewrite. */
566 GC blitGC, pieceGC, outlineGC;
567 XPoint startSquare, prevFrame, mouseDelta;
571 int startBoardX, startBoardY;
574 /* There can be two pieces being animated at once: a player
575 can begin dragging a piece before the remote opponent has moved. */
577 static AnimState game, player;
579 /* Bitmaps for use as masks when drawing XPM pieces.
580 Need one for each black and white piece. */
581 static Pixmap xpmMask[BlackKing + 1];
583 /* This magic number is the number of intermediate frames used
584 in each half of the animation. For short moves it's reduced
585 by 1. The total number of frames will be factor * 2 + 1. */
588 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
590 MenuItem fileMenu[] = {
591 {N_("New Game"), ResetProc},
592 {N_("New Shuffle Game ..."), ShuffleMenuProc},
593 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
594 {"----", NothingProc},
595 {N_("Load Game"), LoadGameProc},
596 {N_("Load Next Game"), LoadNextGameProc},
597 {N_("Load Previous Game"), LoadPrevGameProc},
598 {N_("Reload Same Game"), ReloadGameProc},
599 {N_("Save Game"), SaveGameProc},
600 {"----", NothingProc},
601 {N_("Copy Game"), CopyGameProc},
602 {N_("Paste Game"), PasteGameProc},
603 {"----", NothingProc},
604 {N_("Load Position"), LoadPositionProc},
605 {N_("Load Next Position"), LoadNextPositionProc},
606 {N_("Load Previous Position"), LoadPrevPositionProc},
607 {N_("Reload Same Position"), ReloadPositionProc},
608 {N_("Save Position"), SavePositionProc},
609 {"----", NothingProc},
610 {N_("Copy Position"), CopyPositionProc},
611 {N_("Paste Position"), PastePositionProc},
612 {"----", NothingProc},
613 {N_("Mail Move"), MailMoveProc},
614 {N_("Reload CMail Message"), ReloadCmailMsgProc},
615 {"----", NothingProc},
616 {N_("Exit"), QuitProc},
620 MenuItem modeMenu[] = {
621 {N_("Machine White"), MachineWhiteProc},
622 {N_("Machine Black"), MachineBlackProc},
623 {N_("Two Machines"), TwoMachinesProc},
624 {N_("Analysis Mode"), AnalyzeModeProc},
625 {N_("Analyze File"), AnalyzeFileProc },
626 {N_("ICS Client"), IcsClientProc},
627 {N_("Edit Game"), EditGameProc},
628 {N_("Edit Position"), EditPositionProc},
629 {N_("Training"), TrainingProc},
630 {"----", NothingProc},
631 {N_("Show Engine Output"), EngineOutputProc},
632 {N_("Show Evaluation Graph"), EvalGraphProc},
633 {N_("Show Game List"), ShowGameListProc},
634 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
635 {"----", NothingProc},
636 {N_("Edit Tags"), EditTagsProc},
637 {N_("Edit Comment"), EditCommentProc},
638 {N_("ICS Input Box"), IcsInputBoxProc},
639 {N_("Pause"), PauseProc},
643 MenuItem actionMenu[] = {
644 {N_("Accept"), AcceptProc},
645 {N_("Decline"), DeclineProc},
646 {N_("Rematch"), RematchProc},
647 {"----", NothingProc},
648 {N_("Call Flag"), CallFlagProc},
649 {N_("Draw"), DrawProc},
650 {N_("Adjourn"), AdjournProc},
651 {N_("Abort"), AbortProc},
652 {N_("Resign"), ResignProc},
653 {"----", NothingProc},
654 {N_("Stop Observing"), StopObservingProc},
655 {N_("Stop Examining"), StopExaminingProc},
656 {N_("Upload to Examine"), UploadProc},
657 {"----", NothingProc},
658 {N_("Adjudicate to White"), AdjuWhiteProc},
659 {N_("Adjudicate to Black"), AdjuBlackProc},
660 {N_("Adjudicate Draw"), AdjuDrawProc},
664 MenuItem stepMenu[] = {
665 {N_("Backward"), BackwardProc},
666 {N_("Forward"), ForwardProc},
667 {N_("Back to Start"), ToStartProc},
668 {N_("Forward to End"), ToEndProc},
669 {N_("Revert"), RevertProc},
670 {N_("Annotate"), AnnotateProc},
671 {N_("Truncate Game"), TruncateGameProc},
672 {"----", NothingProc},
673 {N_("Move Now"), MoveNowProc},
674 {N_("Retract Move"), RetractMoveProc},
678 MenuItem optionsMenu[] = {
679 {N_("Flip View"), FlipViewProc},
680 {"----", NothingProc},
681 {N_("Adjudications ..."), EngineMenuProc},
682 {N_("General Settings ..."), UciMenuProc},
683 {N_("Engine #1 Settings ..."), FirstSettingsProc},
684 {N_("Engine #2 Settings ..."), SecondSettingsProc},
685 {N_("Time Control ..."), TimeControlProc},
686 {N_("Game List ..."), GameListOptionsPopUp},
687 {"----", NothingProc},
688 {N_("Always Queen"), AlwaysQueenProc},
689 {N_("Animate Dragging"), AnimateDraggingProc},
690 {N_("Animate Moving"), AnimateMovingProc},
691 {N_("Auto Comment"), AutocommProc},
692 {N_("Auto Flag"), AutoflagProc},
693 {N_("Auto Flip View"), AutoflipProc},
694 {N_("Auto Observe"), AutobsProc},
695 {N_("Auto Raise Board"), AutoraiseProc},
696 {N_("Auto Save"), AutosaveProc},
697 {N_("Blindfold"), BlindfoldProc},
698 {N_("Flash Moves"), FlashMovesProc},
699 {N_("Get Move List"), GetMoveListProc},
701 {N_("Highlight Dragging"), HighlightDraggingProc},
703 {N_("Highlight Last Move"), HighlightLastMoveProc},
704 {N_("Move Sound"), MoveSoundProc},
705 {N_("ICS Alarm"), IcsAlarmProc},
706 {N_("Old Save Style"), OldSaveStyleProc},
707 {N_("Periodic Updates"), PeriodicUpdatesProc},
708 {N_("Ponder Next Move"), PonderNextMoveProc},
709 {N_("Popup Exit Message"), PopupExitMessageProc},
710 {N_("Popup Move Errors"), PopupMoveErrorsProc},
711 {N_("Premove"), PremoveProc},
712 {N_("Quiet Play"), QuietPlayProc},
713 {N_("Show Coords"), ShowCoordsProc},
714 {N_("Hide Thinking"), HideThinkingProc},
715 {N_("Test Legality"), TestLegalityProc},
716 {"----", NothingProc},
717 {N_("Save Settings Now"), SaveSettingsProc},
718 {N_("Save Settings on Exit"), SaveOnExitProc},
722 MenuItem helpMenu[] = {
723 {N_("Info XBoard"), InfoProc},
724 {N_("Man XBoard"), ManProc},
725 {"----", NothingProc},
726 {N_("Hint"), HintProc},
727 {N_("Book"), BookProc},
728 {"----", NothingProc},
729 {N_("About XBoard"), AboutProc},
734 {N_("File"), fileMenu},
735 {N_("Mode"), modeMenu},
736 {N_("Action"), actionMenu},
737 {N_("Step"), stepMenu},
738 {N_("Options"), optionsMenu},
739 {N_("Help"), helpMenu},
743 #define PAUSE_BUTTON N_("P")
744 MenuItem buttonBar[] = {
747 {PAUSE_BUTTON, PauseProc},
753 #define PIECE_MENU_SIZE 18
754 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
755 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
756 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
757 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
758 N_("Empty square"), N_("Clear board") },
759 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
760 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
761 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
762 N_("Empty square"), N_("Clear board") }
764 /* must be in same order as PieceMenuStrings! */
765 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
766 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
767 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
768 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
769 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
770 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
771 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
772 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
773 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
776 #define DROP_MENU_SIZE 6
777 String dropMenuStrings[DROP_MENU_SIZE] = {
778 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
780 /* must be in same order as PieceMenuStrings! */
781 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
782 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
783 WhiteRook, WhiteQueen
791 DropMenuEnables dmEnables[] = {
809 { XtNborderWidth, 0 },
810 { XtNdefaultDistance, 0 },
814 { XtNborderWidth, 0 },
815 { XtNresizable, (XtArgVal) True },
819 { XtNborderWidth, 0 },
825 { XtNjustify, (XtArgVal) XtJustifyRight },
826 { XtNlabel, (XtArgVal) "..." },
827 { XtNresizable, (XtArgVal) True },
828 { XtNresize, (XtArgVal) False }
831 Arg messageArgs[] = {
832 { XtNjustify, (XtArgVal) XtJustifyLeft },
833 { XtNlabel, (XtArgVal) "..." },
834 { XtNresizable, (XtArgVal) True },
835 { XtNresize, (XtArgVal) False }
839 { XtNborderWidth, 0 },
840 { XtNjustify, (XtArgVal) XtJustifyLeft }
843 XtResource clientResources[] = {
844 { "flashCount", "flashCount", XtRInt, sizeof(int),
845 XtOffset(AppDataPtr, flashCount), XtRImmediate,
846 (XtPointer) FLASH_COUNT },
849 XrmOptionDescRec shellOptions[] = {
850 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
851 { "-flash", "flashCount", XrmoptionNoArg, "3" },
852 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
855 XtActionsRec boardActions[] = {
856 { "DrawPosition", DrawPositionProc },
857 { "HandleUserMove", HandleUserMove },
858 { "AnimateUserMove", AnimateUserMove },
859 { "HandlePV", HandlePV },
860 { "SelectPV", SelectPV },
861 { "StopPV", StopPV },
862 { "FileNameAction", FileNameAction },
863 { "AskQuestionProc", AskQuestionProc },
864 { "AskQuestionReplyAction", AskQuestionReplyAction },
865 { "PieceMenuPopup", PieceMenuPopup },
866 { "WhiteClock", WhiteClock },
867 { "BlackClock", BlackClock },
868 { "Iconify", Iconify },
869 { "ResetProc", ResetProc },
870 { "NewVariantProc", NewVariantProc },
871 { "LoadGameProc", LoadGameProc },
872 { "LoadNextGameProc", LoadNextGameProc },
873 { "LoadPrevGameProc", LoadPrevGameProc },
874 { "LoadSelectedProc", LoadSelectedProc },
875 { "SetFilterProc", SetFilterProc },
876 { "ReloadGameProc", ReloadGameProc },
877 { "LoadPositionProc", LoadPositionProc },
878 { "LoadNextPositionProc", LoadNextPositionProc },
879 { "LoadPrevPositionProc", LoadPrevPositionProc },
880 { "ReloadPositionProc", ReloadPositionProc },
881 { "CopyPositionProc", CopyPositionProc },
882 { "PastePositionProc", PastePositionProc },
883 { "CopyGameProc", CopyGameProc },
884 { "PasteGameProc", PasteGameProc },
885 { "SaveGameProc", SaveGameProc },
886 { "SavePositionProc", SavePositionProc },
887 { "MailMoveProc", MailMoveProc },
888 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
889 { "QuitProc", QuitProc },
890 { "MachineWhiteProc", MachineWhiteProc },
891 { "MachineBlackProc", MachineBlackProc },
892 { "AnalysisModeProc", AnalyzeModeProc },
893 { "AnalyzeFileProc", AnalyzeFileProc },
894 { "TwoMachinesProc", TwoMachinesProc },
895 { "IcsClientProc", IcsClientProc },
896 { "EditGameProc", EditGameProc },
897 { "EditPositionProc", EditPositionProc },
898 { "TrainingProc", EditPositionProc },
899 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
900 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
901 { "ShowGameListProc", ShowGameListProc },
902 { "ShowMoveListProc", HistoryShowProc},
903 { "EditTagsProc", EditCommentProc },
904 { "EditCommentProc", EditCommentProc },
905 { "IcsAlarmProc", IcsAlarmProc },
906 { "IcsInputBoxProc", IcsInputBoxProc },
907 { "PauseProc", PauseProc },
908 { "AcceptProc", AcceptProc },
909 { "DeclineProc", DeclineProc },
910 { "RematchProc", RematchProc },
911 { "CallFlagProc", CallFlagProc },
912 { "DrawProc", DrawProc },
913 { "AdjournProc", AdjournProc },
914 { "AbortProc", AbortProc },
915 { "ResignProc", ResignProc },
916 { "AdjuWhiteProc", AdjuWhiteProc },
917 { "AdjuBlackProc", AdjuBlackProc },
918 { "AdjuDrawProc", AdjuDrawProc },
919 { "EnterKeyProc", EnterKeyProc },
920 { "UpKeyProc", UpKeyProc },
921 { "DownKeyProc", DownKeyProc },
922 { "StopObservingProc", StopObservingProc },
923 { "StopExaminingProc", StopExaminingProc },
924 { "UploadProc", UploadProc },
925 { "BackwardProc", BackwardProc },
926 { "ForwardProc", ForwardProc },
927 { "ToStartProc", ToStartProc },
928 { "ToEndProc", ToEndProc },
929 { "RevertProc", RevertProc },
930 { "AnnotateProc", AnnotateProc },
931 { "TruncateGameProc", TruncateGameProc },
932 { "MoveNowProc", MoveNowProc },
933 { "RetractMoveProc", RetractMoveProc },
934 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
935 { "UciMenuProc", (XtActionProc) UciMenuProc },
936 { "TimeControlProc", (XtActionProc) TimeControlProc },
937 { "AlwaysQueenProc", AlwaysQueenProc },
938 { "AnimateDraggingProc", AnimateDraggingProc },
939 { "AnimateMovingProc", AnimateMovingProc },
940 { "AutoflagProc", AutoflagProc },
941 { "AutoflipProc", AutoflipProc },
942 { "AutobsProc", AutobsProc },
943 { "AutoraiseProc", AutoraiseProc },
944 { "AutosaveProc", AutosaveProc },
945 { "BlindfoldProc", BlindfoldProc },
946 { "FlashMovesProc", FlashMovesProc },
947 { "FlipViewProc", FlipViewProc },
948 { "GetMoveListProc", GetMoveListProc },
950 { "HighlightDraggingProc", HighlightDraggingProc },
952 { "HighlightLastMoveProc", HighlightLastMoveProc },
953 { "IcsAlarmProc", IcsAlarmProc },
954 { "MoveSoundProc", MoveSoundProc },
955 { "OldSaveStyleProc", OldSaveStyleProc },
956 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
957 { "PonderNextMoveProc", PonderNextMoveProc },
958 { "PopupExitMessageProc", PopupExitMessageProc },
959 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
960 { "PremoveProc", PremoveProc },
961 { "QuietPlayProc", QuietPlayProc },
962 { "ShowCoordsProc", ShowCoordsProc },
963 { "ShowThinkingProc", ShowThinkingProc },
964 { "HideThinkingProc", HideThinkingProc },
965 { "TestLegalityProc", TestLegalityProc },
966 { "SaveSettingsProc", SaveSettingsProc },
967 { "SaveOnExitProc", SaveOnExitProc },
968 { "InfoProc", InfoProc },
969 { "ManProc", ManProc },
970 { "HintProc", HintProc },
971 { "BookProc", BookProc },
972 { "AboutGameProc", AboutGameProc },
973 { "AboutProc", AboutProc },
974 { "DebugProc", DebugProc },
975 { "NothingProc", NothingProc },
976 { "CommentClick", (XtActionProc) CommentClick },
977 { "CommentPopDown", (XtActionProc) CommentPopDown },
978 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
979 { "TagsPopDown", (XtActionProc) TagsPopDown },
980 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
981 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
982 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
983 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
984 { "GameListPopDown", (XtActionProc) GameListPopDown },
985 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
986 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
987 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
988 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
989 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
990 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
991 { "EnginePopDown", (XtActionProc) EnginePopDown },
992 { "UciPopDown", (XtActionProc) UciPopDown },
993 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
994 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
995 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
996 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
999 char globalTranslations[] =
1000 ":<Key>F9: ResignProc() \n \
1001 :Ctrl<Key>n: ResetProc() \n \
1002 :Meta<Key>V: NewVariantProc() \n \
1003 :Ctrl<Key>o: LoadGameProc() \n \
1004 :Meta<Key>Next: LoadNextGameProc() \n \
1005 :Meta<Key>Prior: LoadPrevGameProc() \n \
1006 :Ctrl<Key>s: SaveGameProc() \n \
1007 :Ctrl<Key>c: CopyGameProc() \n \
1008 :Ctrl<Key>v: PasteGameProc() \n \
1009 :Ctrl<Key>O: LoadPositionProc() \n \
1010 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1011 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1012 :Ctrl<Key>S: SavePositionProc() \n \
1013 :Ctrl<Key>C: CopyPositionProc() \n \
1014 :Ctrl<Key>V: PastePositionProc() \n \
1015 :Ctrl<Key>q: QuitProc() \n \
1016 :Ctrl<Key>w: MachineWhiteProc() \n \
1017 :Ctrl<Key>b: MachineBlackProc() \n \
1018 :Ctrl<Key>t: TwoMachinesProc() \n \
1019 :Ctrl<Key>a: AnalysisModeProc() \n \
1020 :Ctrl<Key>f: AnalyzeFileProc() \n \
1021 :Ctrl<Key>e: EditGameProc() \n \
1022 :Ctrl<Key>E: EditPositionProc() \n \
1023 :Meta<Key>O: EngineOutputProc() \n \
1024 :Meta<Key>E: EvalGraphProc() \n \
1025 :Meta<Key>G: ShowGameListProc() \n \
1026 :Meta<Key>H: ShowMoveListProc() \n \
1027 :<Key>Pause: PauseProc() \n \
1028 :<Key>F3: AcceptProc() \n \
1029 :<Key>F4: DeclineProc() \n \
1030 :<Key>F12: RematchProc() \n \
1031 :<Key>F5: CallFlagProc() \n \
1032 :<Key>F6: DrawProc() \n \
1033 :<Key>F7: AdjournProc() \n \
1034 :<Key>F8: AbortProc() \n \
1035 :<Key>F10: StopObservingProc() \n \
1036 :<Key>F11: StopExaminingProc() \n \
1037 :Meta Ctrl<Key>F12: DebugProc() \n \
1038 :Meta<Key>End: ToEndProc() \n \
1039 :Meta<Key>Right: ForwardProc() \n \
1040 :Meta<Key>Home: ToStartProc() \n \
1041 :Meta<Key>Left: BackwardProc() \n \
1042 :Ctrl<Key>m: MoveNowProc() \n \
1043 :Ctrl<Key>x: RetractMoveProc() \n \
1044 :Meta<Key>J: EngineMenuProc() \n \
1045 :Meta<Key>U: UciMenuProc() \n \
1046 :Meta<Key>T: TimeControlProc() \n \
1047 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1048 :Ctrl<Key>F: AutoflagProc() \n \
1049 :Ctrl<Key>A: AnimateMovingProc() \n \
1050 :Ctrl<Key>P: PonderNextMoveProc() \n \
1051 :Ctrl<Key>L: TestLegalityProc() \n \
1052 :Ctrl<Key>H: HideThinkingProc() \n \
1053 :<Key>-: Iconify() \n \
1054 :<Key>F1: ManProc() \n \
1055 :<Key>F2: FlipViewProc() \n \
1056 <KeyDown>.: BackwardProc() \n \
1057 <KeyUp>.: ForwardProc() \n \
1058 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1059 \"Send to chess program:\",,1) \n \
1060 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1061 \"Send to second chess program:\",,2) \n";
1063 char boardTranslations[] =
1064 "<Btn1Down>: HandleUserMove() \n \
1065 <Btn1Up>: HandleUserMove() \n \
1066 <Btn1Motion>: AnimateUserMove() \n \
1067 <Btn3Motion>: HandlePV() \n \
1068 <Btn3Up>: PieceMenuPopup(menuB) \n \
1069 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1070 PieceMenuPopup(menuB) \n \
1071 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1072 PieceMenuPopup(menuW) \n \
1073 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1074 PieceMenuPopup(menuW) \n \
1075 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1076 PieceMenuPopup(menuB) \n";
1078 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1079 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1081 char ICSInputTranslations[] =
1082 "<Key>Up: UpKeyProc() \n "
1083 "<Key>Down: DownKeyProc() \n "
1084 "<Key>Return: EnterKeyProc() \n";
1086 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1087 // as the widget is destroyed before the up-click can call extend-end
1088 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1090 String xboardResources[] = {
1091 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1092 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1093 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1098 /* Max possible square size */
1099 #define MAXSQSIZE 256
1101 static int xpm_avail[MAXSQSIZE];
1103 #ifdef HAVE_DIR_STRUCT
1105 /* Extract piece size from filename */
1107 xpm_getsize(name, len, ext)
1118 if ((p=strchr(name, '.')) == NULL ||
1119 StrCaseCmp(p+1, ext) != 0)
1125 while (*p && isdigit(*p))
1132 /* Setup xpm_avail */
1134 xpm_getavail(dirname, ext)
1142 for (i=0; i<MAXSQSIZE; ++i)
1145 if (appData.debugMode)
1146 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1148 dir = opendir(dirname);
1151 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1152 programName, dirname);
1156 while ((ent=readdir(dir)) != NULL) {
1157 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1158 if (i > 0 && i < MAXSQSIZE)
1168 xpm_print_avail(fp, ext)
1174 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1175 for (i=1; i<MAXSQSIZE; ++i) {
1181 /* Return XPM piecesize closest to size */
1183 xpm_closest_to(dirname, size, ext)
1189 int sm_diff = MAXSQSIZE;
1193 xpm_getavail(dirname, ext);
1195 if (appData.debugMode)
1196 xpm_print_avail(stderr, ext);
1198 for (i=1; i<MAXSQSIZE; ++i) {
1201 diff = (diff<0) ? -diff : diff;
1202 if (diff < sm_diff) {
1210 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1216 #else /* !HAVE_DIR_STRUCT */
1217 /* If we are on a system without a DIR struct, we can't
1218 read the directory, so we can't collect a list of
1219 filenames, etc., so we can't do any size-fitting. */
1221 xpm_closest_to(dirname, size, ext)
1226 fprintf(stderr, _("\
1227 Warning: No DIR structure found on this system --\n\
1228 Unable to autosize for XPM/XIM pieces.\n\
1229 Please report this error to frankm@hiwaay.net.\n\
1230 Include system type & operating system in message.\n"));
1233 #endif /* HAVE_DIR_STRUCT */
1235 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1236 "magenta", "cyan", "white" };
1240 TextColors textColors[(int)NColorClasses];
1242 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1244 parse_color(str, which)
1248 char *p, buf[100], *d;
1251 if (strlen(str) > 99) /* watch bounds on buf */
1256 for (i=0; i<which; ++i) {
1263 /* Could be looking at something like:
1265 .. in which case we want to stop on a comma also */
1266 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1270 return -1; /* Use default for empty field */
1273 if (which == 2 || isdigit(*p))
1276 while (*p && isalpha(*p))
1281 for (i=0; i<8; ++i) {
1282 if (!StrCaseCmp(buf, cnames[i]))
1283 return which? (i+40) : (i+30);
1285 if (!StrCaseCmp(buf, "default")) return -1;
1287 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1292 parse_cpair(cc, str)
1296 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1297 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1302 /* bg and attr are optional */
1303 textColors[(int)cc].bg = parse_color(str, 1);
1304 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1305 textColors[(int)cc].attr = 0;
1311 /* Arrange to catch delete-window events */
1312 Atom wm_delete_window;
1314 CatchDeleteWindow(Widget w, String procname)
1317 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1318 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1319 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1326 XtSetArg(args[0], XtNiconic, False);
1327 XtSetValues(shellWidget, args, 1);
1329 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1332 //---------------------------------------------------------------------------------------------------------
1333 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1336 #define CW_USEDEFAULT (1<<31)
1337 #define ICS_TEXT_MENU_SIZE 90
1338 #define DEBUG_FILE "xboard.debug"
1339 #define SetCurrentDirectory chdir
1340 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1344 // these two must some day move to frontend.h, when they are implemented
1345 Boolean GameListIsUp();
1347 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1350 // front-end part of option handling
1352 // [HGM] This platform-dependent table provides the location for storing the color info
1353 extern char *crWhite, * crBlack;
1357 &appData.whitePieceColor,
1358 &appData.blackPieceColor,
1359 &appData.lightSquareColor,
1360 &appData.darkSquareColor,
1361 &appData.highlightSquareColor,
1362 &appData.premoveHighlightColor,
1363 &appData.lowTimeWarningColor,
1374 // [HGM] font: keep a font for each square size, even non-stndard ones
1375 #define NUM_SIZES 18
1376 #define MAX_SIZE 130
1377 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1378 char *fontTable[NUM_FONTS][MAX_SIZE];
1381 ParseFont(char *name, int number)
1382 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1384 if(sscanf(name, "size%d:", &size)) {
1385 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1386 // defer processing it until we know if it matches our board size
1387 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1388 fontTable[number][size] = strdup(strchr(name, ':')+1);
1389 fontValid[number][size] = True;
1394 case 0: // CLOCK_FONT
1395 appData.clockFont = strdup(name);
1397 case 1: // MESSAGE_FONT
1398 appData.font = strdup(name);
1400 case 2: // COORD_FONT
1401 appData.coordFont = strdup(name);
1406 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1411 { // only 2 fonts currently
1412 appData.clockFont = CLOCK_FONT_NAME;
1413 appData.coordFont = COORD_FONT_NAME;
1414 appData.font = DEFAULT_FONT_NAME;
1419 { // no-op, until we identify the code for this already in XBoard and move it here
1423 ParseColor(int n, char *name)
1424 { // in XBoard, just copy the color-name string
1425 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1429 ParseTextAttribs(ColorClass cc, char *s)
1431 (&appData.colorShout)[cc] = strdup(s);
1435 ParseBoardSize(void *addr, char *name)
1437 appData.boardSize = strdup(name);
1442 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1446 SetCommPortDefaults()
1447 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1450 // [HGM] args: these three cases taken out to stay in front-end
1452 SaveFontArg(FILE *f, ArgDescriptor *ad)
1455 int i, n = (int)ad->argLoc;
1457 case 0: // CLOCK_FONT
1458 name = appData.clockFont;
1460 case 1: // MESSAGE_FONT
1461 name = appData.font;
1463 case 2: // COORD_FONT
1464 name = appData.coordFont;
1469 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1470 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1471 fontTable[n][squareSize] = strdup(name);
1472 fontValid[n][squareSize] = True;
1475 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1476 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1481 { // nothing to do, as the sounds are at all times represented by their text-string names already
1485 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1486 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1487 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1491 SaveColor(FILE *f, ArgDescriptor *ad)
1492 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1493 if(colorVariable[(int)ad->argLoc])
1494 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1498 SaveBoardSize(FILE *f, char *name, void *addr)
1499 { // wrapper to shield back-end from BoardSize & sizeInfo
1500 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1504 ParseCommPortSettings(char *s)
1505 { // no such option in XBoard (yet)
1508 extern Widget engineOutputShell;
1509 extern Widget tagsShell, editTagsShell;
1511 GetActualPlacement(Widget wg, WindowPlacement *wp)
1521 XtSetArg(args[i], XtNx, &x); i++;
1522 XtSetArg(args[i], XtNy, &y); i++;
1523 XtSetArg(args[i], XtNwidth, &w); i++;
1524 XtSetArg(args[i], XtNheight, &h); i++;
1525 XtGetValues(wg, args, i);
1534 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1535 // In XBoard this will have to wait until awareness of window parameters is implemented
1536 GetActualPlacement(shellWidget, &wpMain);
1537 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1538 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1539 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1540 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1541 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1542 else GetActualPlacement(editShell, &wpComment);
1543 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1544 else GetActualPlacement(editTagsShell, &wpTags);
1548 PrintCommPortSettings(FILE *f, char *name)
1549 { // This option does not exist in XBoard
1553 MySearchPath(char *installDir, char *name, char *fullname)
1554 { // just append installDir and name. Perhaps ExpandPath should be used here?
1555 name = ExpandPathName(name);
1556 if(name && name[0] == '/')
1557 safeStrCpy(fullname, name, MSG_SIZ );
1559 sprintf(fullname, "%s%c%s", installDir, '/', name);
1565 MyGetFullPathName(char *name, char *fullname)
1566 { // should use ExpandPath?
1567 name = ExpandPathName(name);
1568 safeStrCpy(fullname, name, MSG_SIZ );
1573 EnsureOnScreen(int *x, int *y, int minX, int minY)
1580 { // [HGM] args: allows testing if main window is realized from back-end
1581 return xBoardWindow != 0;
1585 PopUpStartupDialog()
1586 { // start menu not implemented in XBoard
1589 ConvertToLine(int argc, char **argv)
1591 static char line[128*1024], buf[1024];
1595 for(i=1; i<argc; i++) {
1596 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1597 && argv[i][0] != '{' )
1598 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1600 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1603 line[strlen(line)-1] = NULLCHAR;
1607 //--------------------------------------------------------------------------------------------
1609 extern Boolean twoBoards, partnerUp;
1612 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1614 #define BoardSize int
1615 void InitDrawingSizes(BoardSize boardSize, int flags)
1616 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1617 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1619 XtGeometryResult gres;
1622 if(!formWidget) return;
1625 * Enable shell resizing.
1627 shellArgs[0].value = (XtArgVal) &w;
1628 shellArgs[1].value = (XtArgVal) &h;
1629 XtGetValues(shellWidget, shellArgs, 2);
1631 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1632 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1633 XtSetValues(shellWidget, &shellArgs[2], 4);
1635 XtSetArg(args[0], XtNdefaultDistance, &sep);
1636 XtGetValues(formWidget, args, 1);
1638 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1639 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1641 hOffset = boardWidth + 10;
1642 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1643 secondSegments[i] = gridSegments[i];
1644 secondSegments[i].x1 += hOffset;
1645 secondSegments[i].x2 += hOffset;
1648 XtSetArg(args[0], XtNwidth, boardWidth);
1649 XtSetArg(args[1], XtNheight, boardHeight);
1650 XtSetValues(boardWidget, args, 2);
1652 timerWidth = (boardWidth - sep) / 2;
1653 XtSetArg(args[0], XtNwidth, timerWidth);
1654 XtSetValues(whiteTimerWidget, args, 1);
1655 XtSetValues(blackTimerWidget, args, 1);
1657 XawFormDoLayout(formWidget, False);
1659 if (appData.titleInWindow) {
1661 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1662 XtSetArg(args[i], XtNheight, &h); i++;
1663 XtGetValues(titleWidget, args, i);
1665 w = boardWidth - 2*bor;
1667 XtSetArg(args[0], XtNwidth, &w);
1668 XtGetValues(menuBarWidget, args, 1);
1669 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1672 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1673 if (gres != XtGeometryYes && appData.debugMode) {
1675 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1676 programName, gres, w, h, wr, hr);
1680 XawFormDoLayout(formWidget, True);
1683 * Inhibit shell resizing.
1685 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1686 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1687 shellArgs[4].value = shellArgs[2].value = w;
1688 shellArgs[5].value = shellArgs[3].value = h;
1689 XtSetValues(shellWidget, &shellArgs[0], 6);
1691 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1694 for(i=0; i<4; i++) {
1696 for(p=0; p<=(int)WhiteKing; p++)
1697 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1698 if(gameInfo.variant == VariantShogi) {
1699 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1700 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1701 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1702 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1703 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1706 if(gameInfo.variant == VariantGothic) {
1707 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1711 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1712 for(p=0; p<=(int)WhiteKing; p++)
1713 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1714 if(gameInfo.variant == VariantShogi) {
1715 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1716 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1717 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1718 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1719 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1722 if(gameInfo.variant == VariantGothic) {
1723 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1729 for(i=0; i<2; i++) {
1731 for(p=0; p<=(int)WhiteKing; p++)
1732 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1733 if(gameInfo.variant == VariantShogi) {
1734 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1735 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1736 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1737 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1738 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1741 if(gameInfo.variant == VariantGothic) {
1742 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1758 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1759 XSetWindowAttributes window_attributes;
1761 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1762 XrmValue vFrom, vTo;
1763 XtGeometryResult gres;
1766 int forceMono = False;
1768 srandom(time(0)); // [HGM] book: make random truly random
1770 setbuf(stdout, NULL);
1771 setbuf(stderr, NULL);
1774 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1775 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1779 programName = strrchr(argv[0], '/');
1780 if (programName == NULL)
1781 programName = argv[0];
1786 XtSetLanguageProc(NULL, NULL, NULL);
1787 bindtextdomain(PACKAGE, LOCALEDIR);
1788 textdomain(PACKAGE);
1792 XtAppInitialize(&appContext, "XBoard", shellOptions,
1793 XtNumber(shellOptions),
1794 &argc, argv, xboardResources, NULL, 0);
1795 appData.boardSize = "";
1796 InitAppData(ConvertToLine(argc, argv));
1798 if (p == NULL) p = "/tmp";
1799 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1800 gameCopyFilename = (char*) malloc(i);
1801 gamePasteFilename = (char*) malloc(i);
1802 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1803 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1805 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1806 clientResources, XtNumber(clientResources),
1809 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1810 static char buf[MSG_SIZ];
1811 EscapeExpand(buf, appData.initString);
1812 appData.initString = strdup(buf);
1813 EscapeExpand(buf, appData.secondInitString);
1814 appData.secondInitString = strdup(buf);
1815 EscapeExpand(buf, appData.firstComputerString);
1816 appData.firstComputerString = strdup(buf);
1817 EscapeExpand(buf, appData.secondComputerString);
1818 appData.secondComputerString = strdup(buf);
1821 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1824 if (chdir(chessDir) != 0) {
1825 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1831 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1832 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1833 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1834 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1837 setbuf(debugFP, NULL);
1840 /* [HGM,HR] make sure board size is acceptable */
1841 if(appData.NrFiles > BOARD_FILES ||
1842 appData.NrRanks > BOARD_RANKS )
1843 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1846 /* This feature does not work; animation needs a rewrite */
1847 appData.highlightDragging = FALSE;
1851 xDisplay = XtDisplay(shellWidget);
1852 xScreen = DefaultScreen(xDisplay);
1853 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1855 gameInfo.variant = StringToVariant(appData.variant);
1856 InitPosition(FALSE);
1859 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1861 if (isdigit(appData.boardSize[0])) {
1862 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1863 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1864 &fontPxlSize, &smallLayout, &tinyLayout);
1866 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1867 programName, appData.boardSize);
1871 /* Find some defaults; use the nearest known size */
1872 SizeDefaults *szd, *nearest;
1873 int distance = 99999;
1874 nearest = szd = sizeDefaults;
1875 while (szd->name != NULL) {
1876 if (abs(szd->squareSize - squareSize) < distance) {
1878 distance = abs(szd->squareSize - squareSize);
1879 if (distance == 0) break;
1883 if (i < 2) lineGap = nearest->lineGap;
1884 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1885 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1886 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1887 if (i < 6) smallLayout = nearest->smallLayout;
1888 if (i < 7) tinyLayout = nearest->tinyLayout;
1891 SizeDefaults *szd = sizeDefaults;
1892 if (*appData.boardSize == NULLCHAR) {
1893 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1894 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1897 if (szd->name == NULL) szd--;
1898 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1900 while (szd->name != NULL &&
1901 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1902 if (szd->name == NULL) {
1903 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1904 programName, appData.boardSize);
1908 squareSize = szd->squareSize;
1909 lineGap = szd->lineGap;
1910 clockFontPxlSize = szd->clockFontPxlSize;
1911 coordFontPxlSize = szd->coordFontPxlSize;
1912 fontPxlSize = szd->fontPxlSize;
1913 smallLayout = szd->smallLayout;
1914 tinyLayout = szd->tinyLayout;
1915 // [HGM] font: use defaults from settings file if available and not overruled
1917 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1918 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1919 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1920 appData.font = fontTable[MESSAGE_FONT][squareSize];
1921 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1922 appData.coordFont = fontTable[COORD_FONT][squareSize];
1924 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1925 if (strlen(appData.pixmapDirectory) > 0) {
1926 p = ExpandPathName(appData.pixmapDirectory);
1928 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1929 appData.pixmapDirectory);
1932 if (appData.debugMode) {
1933 fprintf(stderr, _("\
1934 XBoard square size (hint): %d\n\
1935 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1937 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1938 if (appData.debugMode) {
1939 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1943 /* [HR] height treated separately (hacked) */
1944 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1945 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1946 if (appData.showJail == 1) {
1947 /* Jail on top and bottom */
1948 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1949 XtSetArg(boardArgs[2], XtNheight,
1950 boardHeight + 2*(lineGap + squareSize));
1951 } else if (appData.showJail == 2) {
1953 XtSetArg(boardArgs[1], XtNwidth,
1954 boardWidth + 2*(lineGap + squareSize));
1955 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1958 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1959 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1963 * Determine what fonts to use.
1965 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1966 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1967 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1968 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1969 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1970 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1971 appData.font = FindFont(appData.font, fontPxlSize);
1972 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1973 countFontStruct = XQueryFont(xDisplay, countFontID);
1974 // appData.font = FindFont(appData.font, fontPxlSize);
1976 xdb = XtDatabase(xDisplay);
1977 XrmPutStringResource(&xdb, "*font", appData.font);
1980 * Detect if there are not enough colors available and adapt.
1982 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1983 appData.monoMode = True;
1986 if (!appData.monoMode) {
1987 vFrom.addr = (caddr_t) appData.lightSquareColor;
1988 vFrom.size = strlen(appData.lightSquareColor);
1989 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1990 if (vTo.addr == NULL) {
1991 appData.monoMode = True;
1994 lightSquareColor = *(Pixel *) vTo.addr;
1997 if (!appData.monoMode) {
1998 vFrom.addr = (caddr_t) appData.darkSquareColor;
1999 vFrom.size = strlen(appData.darkSquareColor);
2000 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2001 if (vTo.addr == NULL) {
2002 appData.monoMode = True;
2005 darkSquareColor = *(Pixel *) vTo.addr;
2008 if (!appData.monoMode) {
2009 vFrom.addr = (caddr_t) appData.whitePieceColor;
2010 vFrom.size = strlen(appData.whitePieceColor);
2011 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2012 if (vTo.addr == NULL) {
2013 appData.monoMode = True;
2016 whitePieceColor = *(Pixel *) vTo.addr;
2019 if (!appData.monoMode) {
2020 vFrom.addr = (caddr_t) appData.blackPieceColor;
2021 vFrom.size = strlen(appData.blackPieceColor);
2022 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2023 if (vTo.addr == NULL) {
2024 appData.monoMode = True;
2027 blackPieceColor = *(Pixel *) vTo.addr;
2031 if (!appData.monoMode) {
2032 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2033 vFrom.size = strlen(appData.highlightSquareColor);
2034 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2035 if (vTo.addr == NULL) {
2036 appData.monoMode = True;
2039 highlightSquareColor = *(Pixel *) vTo.addr;
2043 if (!appData.monoMode) {
2044 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2045 vFrom.size = strlen(appData.premoveHighlightColor);
2046 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2047 if (vTo.addr == NULL) {
2048 appData.monoMode = True;
2051 premoveHighlightColor = *(Pixel *) vTo.addr;
2056 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2059 if (appData.bitmapDirectory == NULL ||
2060 appData.bitmapDirectory[0] == NULLCHAR)
2061 appData.bitmapDirectory = DEF_BITMAP_DIR;
2064 if (appData.lowTimeWarning && !appData.monoMode) {
2065 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2066 vFrom.size = strlen(appData.lowTimeWarningColor);
2067 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2068 if (vTo.addr == NULL)
2069 appData.monoMode = True;
2071 lowTimeWarningColor = *(Pixel *) vTo.addr;
2074 if (appData.monoMode && appData.debugMode) {
2075 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2076 (unsigned long) XWhitePixel(xDisplay, xScreen),
2077 (unsigned long) XBlackPixel(xDisplay, xScreen));
2080 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2081 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2082 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2083 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2084 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2085 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2086 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2087 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2088 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2089 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2091 if (appData.colorize) {
2093 _("%s: can't parse color names; disabling colorization\n"),
2096 appData.colorize = FALSE;
2098 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2099 textColors[ColorNone].attr = 0;
2101 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2107 layoutName = "tinyLayout";
2108 } else if (smallLayout) {
2109 layoutName = "smallLayout";
2111 layoutName = "normalLayout";
2113 /* Outer layoutWidget is there only to provide a name for use in
2114 resources that depend on the layout style */
2116 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2117 layoutArgs, XtNumber(layoutArgs));
2119 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2120 formArgs, XtNumber(formArgs));
2121 XtSetArg(args[0], XtNdefaultDistance, &sep);
2122 XtGetValues(formWidget, args, 1);
2125 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2126 XtSetArg(args[0], XtNtop, XtChainTop);
2127 XtSetArg(args[1], XtNbottom, XtChainTop);
2128 XtSetArg(args[2], XtNright, XtChainLeft);
2129 XtSetValues(menuBarWidget, args, 3);
2131 widgetList[j++] = whiteTimerWidget =
2132 XtCreateWidget("whiteTime", labelWidgetClass,
2133 formWidget, timerArgs, XtNumber(timerArgs));
2134 XtSetArg(args[0], XtNfont, clockFontStruct);
2135 XtSetArg(args[1], XtNtop, XtChainTop);
2136 XtSetArg(args[2], XtNbottom, XtChainTop);
2137 XtSetValues(whiteTimerWidget, args, 3);
2139 widgetList[j++] = blackTimerWidget =
2140 XtCreateWidget("blackTime", labelWidgetClass,
2141 formWidget, timerArgs, XtNumber(timerArgs));
2142 XtSetArg(args[0], XtNfont, clockFontStruct);
2143 XtSetArg(args[1], XtNtop, XtChainTop);
2144 XtSetArg(args[2], XtNbottom, XtChainTop);
2145 XtSetValues(blackTimerWidget, args, 3);
2147 if (appData.titleInWindow) {
2148 widgetList[j++] = titleWidget =
2149 XtCreateWidget("title", labelWidgetClass, formWidget,
2150 titleArgs, XtNumber(titleArgs));
2151 XtSetArg(args[0], XtNtop, XtChainTop);
2152 XtSetArg(args[1], XtNbottom, XtChainTop);
2153 XtSetValues(titleWidget, args, 2);
2156 if (appData.showButtonBar) {
2157 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2158 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2159 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2160 XtSetArg(args[2], XtNtop, XtChainTop);
2161 XtSetArg(args[3], XtNbottom, XtChainTop);
2162 XtSetValues(buttonBarWidget, args, 4);
2165 widgetList[j++] = messageWidget =
2166 XtCreateWidget("message", labelWidgetClass, formWidget,
2167 messageArgs, XtNumber(messageArgs));
2168 XtSetArg(args[0], XtNtop, XtChainTop);
2169 XtSetArg(args[1], XtNbottom, XtChainTop);
2170 XtSetValues(messageWidget, args, 2);
2172 widgetList[j++] = boardWidget =
2173 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2174 XtNumber(boardArgs));
2176 XtManageChildren(widgetList, j);
2178 timerWidth = (boardWidth - sep) / 2;
2179 XtSetArg(args[0], XtNwidth, timerWidth);
2180 XtSetValues(whiteTimerWidget, args, 1);
2181 XtSetValues(blackTimerWidget, args, 1);
2183 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2184 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2185 XtGetValues(whiteTimerWidget, args, 2);
2187 if (appData.showButtonBar) {
2188 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2189 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2190 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2194 * formWidget uses these constraints but they are stored
2198 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2199 XtSetValues(menuBarWidget, args, i);
2200 if (appData.titleInWindow) {
2203 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2204 XtSetValues(whiteTimerWidget, args, i);
2206 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2207 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2208 XtSetValues(blackTimerWidget, args, i);
2210 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2211 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2212 XtSetValues(titleWidget, args, i);
2214 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2215 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2216 XtSetValues(messageWidget, args, i);
2217 if (appData.showButtonBar) {
2219 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2220 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2221 XtSetValues(buttonBarWidget, args, i);
2225 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2226 XtSetValues(whiteTimerWidget, args, i);
2228 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2229 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2230 XtSetValues(blackTimerWidget, args, i);
2232 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2233 XtSetValues(titleWidget, args, i);
2235 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2236 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2237 XtSetValues(messageWidget, args, i);
2238 if (appData.showButtonBar) {
2240 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2241 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2242 XtSetValues(buttonBarWidget, args, i);
2247 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2248 XtSetValues(whiteTimerWidget, args, i);
2250 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2251 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2252 XtSetValues(blackTimerWidget, args, i);
2254 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2255 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2256 XtSetValues(messageWidget, args, i);
2257 if (appData.showButtonBar) {
2259 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2260 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2261 XtSetValues(buttonBarWidget, args, i);
2265 XtSetArg(args[0], XtNfromVert, messageWidget);
2266 XtSetArg(args[1], XtNtop, XtChainTop);
2267 XtSetArg(args[2], XtNbottom, XtChainBottom);
2268 XtSetArg(args[3], XtNleft, XtChainLeft);
2269 XtSetArg(args[4], XtNright, XtChainRight);
2270 XtSetValues(boardWidget, args, 5);
2272 XtRealizeWidget(shellWidget);
2275 XtSetArg(args[0], XtNx, wpMain.x);
2276 XtSetArg(args[1], XtNy, wpMain.y);
2277 XtSetValues(shellWidget, args, 2);
2281 * Correct the width of the message and title widgets.
2282 * It is not known why some systems need the extra fudge term.
2283 * The value "2" is probably larger than needed.
2285 XawFormDoLayout(formWidget, False);
2287 #define WIDTH_FUDGE 2
2289 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2290 XtSetArg(args[i], XtNheight, &h); i++;
2291 XtGetValues(messageWidget, args, i);
2292 if (appData.showButtonBar) {
2294 XtSetArg(args[i], XtNwidth, &w); i++;
2295 XtGetValues(buttonBarWidget, args, i);
2296 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2298 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2301 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2302 if (gres != XtGeometryYes && appData.debugMode) {
2303 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2304 programName, gres, w, h, wr, hr);
2307 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2308 /* The size used for the child widget in layout lags one resize behind
2309 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2311 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2312 if (gres != XtGeometryYes && appData.debugMode) {
2313 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2314 programName, gres, w, h, wr, hr);
2317 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2318 XtSetArg(args[1], XtNright, XtChainRight);
2319 XtSetValues(messageWidget, args, 2);
2321 if (appData.titleInWindow) {
2323 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2324 XtSetArg(args[i], XtNheight, &h); i++;
2325 XtGetValues(titleWidget, args, i);
2327 w = boardWidth - 2*bor;
2329 XtSetArg(args[0], XtNwidth, &w);
2330 XtGetValues(menuBarWidget, args, 1);
2331 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2334 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2335 if (gres != XtGeometryYes && appData.debugMode) {
2337 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2338 programName, gres, w, h, wr, hr);
2341 XawFormDoLayout(formWidget, True);
2343 xBoardWindow = XtWindow(boardWidget);
2345 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2346 // not need to go into InitDrawingSizes().
2350 * Create X checkmark bitmap and initialize option menu checks.
2352 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2353 checkmark_bits, checkmark_width, checkmark_height);
2354 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2355 if (appData.alwaysPromoteToQueen) {
2356 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2359 if (appData.animateDragging) {
2360 XtSetValues(XtNameToWidget(menuBarWidget,
2361 "menuOptions.Animate Dragging"),
2364 if (appData.animate) {
2365 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2368 if (appData.autoComment) {
2369 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2372 if (appData.autoCallFlag) {
2373 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2376 if (appData.autoFlipView) {
2377 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2380 if (appData.autoObserve) {
2381 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2384 if (appData.autoRaiseBoard) {
2385 XtSetValues(XtNameToWidget(menuBarWidget,
2386 "menuOptions.Auto Raise Board"), args, 1);
2388 if (appData.autoSaveGames) {
2389 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2392 if (appData.saveGameFile[0] != NULLCHAR) {
2393 /* Can't turn this off from menu */
2394 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2396 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2400 if (appData.blindfold) {
2401 XtSetValues(XtNameToWidget(menuBarWidget,
2402 "menuOptions.Blindfold"), args, 1);
2404 if (appData.flashCount > 0) {
2405 XtSetValues(XtNameToWidget(menuBarWidget,
2406 "menuOptions.Flash Moves"),
2409 if (appData.getMoveList) {
2410 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2414 if (appData.highlightDragging) {
2415 XtSetValues(XtNameToWidget(menuBarWidget,
2416 "menuOptions.Highlight Dragging"),
2420 if (appData.highlightLastMove) {
2421 XtSetValues(XtNameToWidget(menuBarWidget,
2422 "menuOptions.Highlight Last Move"),
2425 if (appData.icsAlarm) {
2426 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2429 if (appData.ringBellAfterMoves) {
2430 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2433 if (appData.oldSaveStyle) {
2434 XtSetValues(XtNameToWidget(menuBarWidget,
2435 "menuOptions.Old Save Style"), args, 1);
2437 if (appData.periodicUpdates) {
2438 XtSetValues(XtNameToWidget(menuBarWidget,
2439 "menuOptions.Periodic Updates"), args, 1);
2441 if (appData.ponderNextMove) {
2442 XtSetValues(XtNameToWidget(menuBarWidget,
2443 "menuOptions.Ponder Next Move"), args, 1);
2445 if (appData.popupExitMessage) {
2446 XtSetValues(XtNameToWidget(menuBarWidget,
2447 "menuOptions.Popup Exit Message"), args, 1);
2449 if (appData.popupMoveErrors) {
2450 XtSetValues(XtNameToWidget(menuBarWidget,
2451 "menuOptions.Popup Move Errors"), args, 1);
2453 if (appData.premove) {
2454 XtSetValues(XtNameToWidget(menuBarWidget,
2455 "menuOptions.Premove"), args, 1);
2457 if (appData.quietPlay) {
2458 XtSetValues(XtNameToWidget(menuBarWidget,
2459 "menuOptions.Quiet Play"), args, 1);
2461 if (appData.showCoords) {
2462 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2465 if (appData.hideThinkingFromHuman) {
2466 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2469 if (appData.testLegality) {
2470 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2473 if (saveSettingsOnExit) {
2474 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2481 ReadBitmap(&wIconPixmap, "icon_white.bm",
2482 icon_white_bits, icon_white_width, icon_white_height);
2483 ReadBitmap(&bIconPixmap, "icon_black.bm",
2484 icon_black_bits, icon_black_width, icon_black_height);
2485 iconPixmap = wIconPixmap;
2487 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2488 XtSetValues(shellWidget, args, i);
2491 * Create a cursor for the board widget.
2493 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2494 XChangeWindowAttributes(xDisplay, xBoardWindow,
2495 CWCursor, &window_attributes);
2498 * Inhibit shell resizing.
2500 shellArgs[0].value = (XtArgVal) &w;
2501 shellArgs[1].value = (XtArgVal) &h;
2502 XtGetValues(shellWidget, shellArgs, 2);
2503 shellArgs[4].value = shellArgs[2].value = w;
2504 shellArgs[5].value = shellArgs[3].value = h;
2505 XtSetValues(shellWidget, &shellArgs[2], 4);
2506 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2507 marginH = h - boardHeight;
2509 CatchDeleteWindow(shellWidget, "QuitProc");
2514 if (appData.bitmapDirectory[0] != NULLCHAR) {
2521 /* Create regular pieces */
2522 if (!useImages) CreatePieces();
2527 if (appData.animate || appData.animateDragging)
2530 XtAugmentTranslations(formWidget,
2531 XtParseTranslationTable(globalTranslations));
2532 XtAugmentTranslations(boardWidget,
2533 XtParseTranslationTable(boardTranslations));
2534 XtAugmentTranslations(whiteTimerWidget,
2535 XtParseTranslationTable(whiteTranslations));
2536 XtAugmentTranslations(blackTimerWidget,
2537 XtParseTranslationTable(blackTranslations));
2539 /* Why is the following needed on some versions of X instead
2540 * of a translation? */
2541 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2542 (XtEventHandler) EventProc, NULL);
2545 /* [AS] Restore layout */
2546 if( wpMoveHistory.visible ) {
2550 if( wpEvalGraph.visible )
2555 if( wpEngineOutput.visible ) {
2556 EngineOutputPopUp();
2561 if (errorExitStatus == -1) {
2562 if (appData.icsActive) {
2563 /* We now wait until we see "login:" from the ICS before
2564 sending the logon script (problems with timestamp otherwise) */
2565 /*ICSInitScript();*/
2566 if (appData.icsInputBox) ICSInputBoxPopUp();
2570 signal(SIGWINCH, TermSizeSigHandler);
2572 signal(SIGINT, IntSigHandler);
2573 signal(SIGTERM, IntSigHandler);
2574 if (*appData.cmailGameName != NULLCHAR) {
2575 signal(SIGUSR1, CmailSigHandler);
2578 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2580 XtSetKeyboardFocus(shellWidget, formWidget);
2582 XtAppMainLoop(appContext);
2583 if (appData.debugMode) fclose(debugFP); // [DM] debug
2590 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2591 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2593 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2594 unlink(gameCopyFilename);
2595 unlink(gamePasteFilename);
2598 RETSIGTYPE TermSizeSigHandler(int sig)
2611 CmailSigHandler(sig)
2617 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2619 /* Activate call-back function CmailSigHandlerCallBack() */
2620 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2622 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2626 CmailSigHandlerCallBack(isr, closure, message, count, error)
2634 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2636 /**** end signal code ****/
2646 f = fopen(appData.icsLogon, "r");
2650 safeStrCpy(buf, p, sizeof(buf)/sizeof(buf[0]) );
2652 strcat(buf, appData.icsLogon);
2653 f = fopen(buf, "r");
2657 ProcessICSInitScript(f);
2664 EditCommentPopDown();
2679 if (!menuBarWidget) return;
2680 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2682 DisplayError("menuStep.Revert", 0);
2684 XtSetSensitive(w, !grey);
2686 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2688 DisplayError("menuStep.Annotate", 0);
2690 XtSetSensitive(w, !grey);
2695 SetMenuEnables(enab)
2699 if (!menuBarWidget) return;
2700 while (enab->name != NULL) {
2701 w = XtNameToWidget(menuBarWidget, enab->name);
2703 DisplayError(enab->name, 0);
2705 XtSetSensitive(w, enab->value);
2711 Enables icsEnables[] = {
2712 { "menuFile.Mail Move", False },
2713 { "menuFile.Reload CMail Message", False },
2714 { "menuMode.Machine Black", False },
2715 { "menuMode.Machine White", False },
2716 { "menuMode.Analysis Mode", False },
2717 { "menuMode.Analyze File", False },
2718 { "menuMode.Two Machines", False },
2720 { "menuHelp.Hint", False },
2721 { "menuHelp.Book", False },
2722 { "menuStep.Move Now", False },
2723 { "menuOptions.Periodic Updates", False },
2724 { "menuOptions.Hide Thinking", False },
2725 { "menuOptions.Ponder Next Move", False },
2727 { "menuStep.Annotate", False },
2731 Enables ncpEnables[] = {
2732 { "menuFile.Mail Move", False },
2733 { "menuFile.Reload CMail Message", False },
2734 { "menuMode.Machine White", False },
2735 { "menuMode.Machine Black", False },
2736 { "menuMode.Analysis Mode", False },
2737 { "menuMode.Analyze File", False },
2738 { "menuMode.Two Machines", False },
2739 { "menuMode.ICS Client", False },
2740 { "menuMode.ICS Input Box", False },
2741 { "Action", False },
2742 { "menuStep.Revert", False },
2743 { "menuStep.Annotate", False },
2744 { "menuStep.Move Now", False },
2745 { "menuStep.Retract Move", False },
2746 { "menuOptions.Auto Comment", False },
2747 { "menuOptions.Auto Flag", False },
2748 { "menuOptions.Auto Flip View", False },
2749 { "menuOptions.Auto Observe", False },
2750 { "menuOptions.Auto Raise Board", False },
2751 { "menuOptions.Get Move List", False },
2752 { "menuOptions.ICS Alarm", False },
2753 { "menuOptions.Move Sound", False },
2754 { "menuOptions.Quiet Play", False },
2755 { "menuOptions.Hide Thinking", False },
2756 { "menuOptions.Periodic Updates", False },
2757 { "menuOptions.Ponder Next Move", False },
2758 { "menuHelp.Hint", False },
2759 { "menuHelp.Book", False },
2763 Enables gnuEnables[] = {
2764 { "menuMode.ICS Client", False },
2765 { "menuMode.ICS Input Box", False },
2766 { "menuAction.Accept", False },
2767 { "menuAction.Decline", False },
2768 { "menuAction.Rematch", False },
2769 { "menuAction.Adjourn", False },
2770 { "menuAction.Stop Examining", False },
2771 { "menuAction.Stop Observing", False },
2772 { "menuAction.Upload to Examine", False },
2773 { "menuStep.Revert", False },
2774 { "menuStep.Annotate", False },
2775 { "menuOptions.Auto Comment", False },
2776 { "menuOptions.Auto Observe", False },
2777 { "menuOptions.Auto Raise Board", False },
2778 { "menuOptions.Get Move List", False },
2779 { "menuOptions.Premove", False },
2780 { "menuOptions.Quiet Play", False },
2782 /* The next two options rely on SetCmailMode being called *after* */
2783 /* SetGNUMode so that when GNU is being used to give hints these */
2784 /* menu options are still available */
2786 { "menuFile.Mail Move", False },
2787 { "menuFile.Reload CMail Message", False },
2791 Enables cmailEnables[] = {
2793 { "menuAction.Call Flag", False },
2794 { "menuAction.Draw", True },
2795 { "menuAction.Adjourn", False },
2796 { "menuAction.Abort", False },
2797 { "menuAction.Stop Observing", False },
2798 { "menuAction.Stop Examining", False },
2799 { "menuFile.Mail Move", True },
2800 { "menuFile.Reload CMail Message", True },
2804 Enables trainingOnEnables[] = {
2805 { "menuMode.Edit Comment", False },
2806 { "menuMode.Pause", False },
2807 { "menuStep.Forward", False },
2808 { "menuStep.Backward", False },
2809 { "menuStep.Forward to End", False },
2810 { "menuStep.Back to Start", False },
2811 { "menuStep.Move Now", False },
2812 { "menuStep.Truncate Game", False },
2816 Enables trainingOffEnables[] = {
2817 { "menuMode.Edit Comment", True },
2818 { "menuMode.Pause", True },
2819 { "menuStep.Forward", True },
2820 { "menuStep.Backward", True },
2821 { "menuStep.Forward to End", True },
2822 { "menuStep.Back to Start", True },
2823 { "menuStep.Move Now", True },
2824 { "menuStep.Truncate Game", True },
2828 Enables machineThinkingEnables[] = {
2829 { "menuFile.Load Game", False },
2830 { "menuFile.Load Next Game", False },
2831 { "menuFile.Load Previous Game", False },
2832 { "menuFile.Reload Same Game", False },
2833 { "menuFile.Paste Game", False },
2834 { "menuFile.Load Position", False },
2835 { "menuFile.Load Next Position", False },
2836 { "menuFile.Load Previous Position", False },
2837 { "menuFile.Reload Same Position", False },
2838 { "menuFile.Paste Position", False },
2839 { "menuMode.Machine White", False },
2840 { "menuMode.Machine Black", False },
2841 { "menuMode.Two Machines", False },
2842 { "menuStep.Retract Move", False },
2846 Enables userThinkingEnables[] = {
2847 { "menuFile.Load Game", True },
2848 { "menuFile.Load Next Game", True },
2849 { "menuFile.Load Previous Game", True },
2850 { "menuFile.Reload Same Game", True },
2851 { "menuFile.Paste Game", True },
2852 { "menuFile.Load Position", True },
2853 { "menuFile.Load Next Position", True },
2854 { "menuFile.Load Previous Position", True },
2855 { "menuFile.Reload Same Position", True },
2856 { "menuFile.Paste Position", True },
2857 { "menuMode.Machine White", True },
2858 { "menuMode.Machine Black", True },
2859 { "menuMode.Two Machines", True },
2860 { "menuStep.Retract Move", True },
2866 SetMenuEnables(icsEnables);
2869 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2870 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2877 SetMenuEnables(ncpEnables);
2883 SetMenuEnables(gnuEnables);
2889 SetMenuEnables(cmailEnables);
2895 SetMenuEnables(trainingOnEnables);
2896 if (appData.showButtonBar) {
2897 XtSetSensitive(buttonBarWidget, False);
2903 SetTrainingModeOff()
2905 SetMenuEnables(trainingOffEnables);
2906 if (appData.showButtonBar) {
2907 XtSetSensitive(buttonBarWidget, True);
2912 SetUserThinkingEnables()
2914 if (appData.noChessProgram) return;
2915 SetMenuEnables(userThinkingEnables);
2919 SetMachineThinkingEnables()
2921 if (appData.noChessProgram) return;
2922 SetMenuEnables(machineThinkingEnables);
2924 case MachinePlaysBlack:
2925 case MachinePlaysWhite:
2926 case TwoMachinesPlay:
2927 XtSetSensitive(XtNameToWidget(menuBarWidget,
2928 ModeToWidgetName(gameMode)), True);
2935 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2936 #define HISTORY_SIZE 64
\r
2937 static char *history[HISTORY_SIZE];
\r
2938 int histIn = 0, histP = 0;
\r
2941 SaveInHistory(char *cmd)
\r
2943 if (history[histIn] != NULL) {
\r
2944 free(history[histIn]);
\r
2945 history[histIn] = NULL;
\r
2947 if (*cmd == NULLCHAR) return;
\r
2948 history[histIn] = StrSave(cmd);
\r
2949 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2950 if (history[histIn] != NULL) {
\r
2951 free(history[histIn]);
\r
2952 history[histIn] = NULL;
\r
2958 PrevInHistory(char *cmd)
\r
2961 if (histP == histIn) {
\r
2962 if (history[histIn] != NULL) free(history[histIn]);
\r
2963 history[histIn] = StrSave(cmd);
\r
2965 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2966 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2968 return history[histP];
\r
2974 if (histP == histIn) return NULL;
\r
2975 histP = (histP + 1) % HISTORY_SIZE;
\r
2976 return history[histP];
\r
2978 // end of borrowed code
\r
2980 #define Abs(n) ((n)<0 ? -(n) : (n))
2983 * Find a font that matches "pattern" that is as close as
2984 * possible to the targetPxlSize. Prefer fonts that are k
2985 * pixels smaller to fonts that are k pixels larger. The
2986 * pattern must be in the X Consortium standard format,
2987 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2988 * The return value should be freed with XtFree when no
2992 FindFont(pattern, targetPxlSize)
2996 char **fonts, *p, *best, *scalable, *scalableTail;
2997 int i, j, nfonts, minerr, err, pxlSize;
3000 char **missing_list;
3002 char *def_string, *base_fnt_lst, strInt[3];
3004 XFontStruct **fnt_list;
3006 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3007 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3008 p = strstr(pattern, "--");
3009 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3010 strcat(base_fnt_lst, strInt);
3011 strcat(base_fnt_lst, strchr(p + 2, '-'));
3013 if ((fntSet = XCreateFontSet(xDisplay,
3017 &def_string)) == NULL) {
3019 fprintf(stderr, _("Unable to create font set.\n"));
3023 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3025 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3027 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3028 programName, pattern);
3036 for (i=0; i<nfonts; i++) {
3039 if (*p != '-') continue;
3041 if (*p == NULLCHAR) break;
3042 if (*p++ == '-') j++;
3044 if (j < 7) continue;
3047 scalable = fonts[i];
3050 err = pxlSize - targetPxlSize;
3051 if (Abs(err) < Abs(minerr) ||
3052 (minerr > 0 && err < 0 && -err == minerr)) {
3058 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3059 /* If the error is too big and there is a scalable font,
3060 use the scalable font. */
3061 int headlen = scalableTail - scalable;
3062 p = (char *) XtMalloc(strlen(scalable) + 10);
3063 while (isdigit(*scalableTail)) scalableTail++;
3064 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3066 p = (char *) XtMalloc(strlen(best) + 2);
3067 safeStrCpy(p, best, strlen(best)+1 );
3069 if (appData.debugMode) {
3070 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3071 pattern, targetPxlSize, p);
3074 if (missing_count > 0)
3075 XFreeStringList(missing_list);
3076 XFreeFontSet(xDisplay, fntSet);
3078 XFreeFontNames(fonts);
3085 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3086 | GCBackground | GCFunction | GCPlaneMask;
3087 XGCValues gc_values;
3090 gc_values.plane_mask = AllPlanes;
3091 gc_values.line_width = lineGap;
3092 gc_values.line_style = LineSolid;
3093 gc_values.function = GXcopy;
3095 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3096 gc_values.background = XBlackPixel(xDisplay, xScreen);
3097 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3099 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3100 gc_values.background = XWhitePixel(xDisplay, xScreen);
3101 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3102 XSetFont(xDisplay, coordGC, coordFontID);
3104 // [HGM] make font for holdings counts (white on black0
3105 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3106 gc_values.background = XBlackPixel(xDisplay, xScreen);
3107 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3108 XSetFont(xDisplay, countGC, countFontID);
3110 if (appData.monoMode) {
3111 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3112 gc_values.background = XWhitePixel(xDisplay, xScreen);
3113 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3115 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3116 gc_values.background = XBlackPixel(xDisplay, xScreen);
3117 lightSquareGC = wbPieceGC
3118 = XtGetGC(shellWidget, value_mask, &gc_values);
3120 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3121 gc_values.background = XWhitePixel(xDisplay, xScreen);
3122 darkSquareGC = bwPieceGC
3123 = XtGetGC(shellWidget, value_mask, &gc_values);
3125 if (DefaultDepth(xDisplay, xScreen) == 1) {
3126 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3127 gc_values.function = GXcopyInverted;
3128 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3129 gc_values.function = GXcopy;
3130 if (XBlackPixel(xDisplay, xScreen) == 1) {
3131 bwPieceGC = darkSquareGC;
3132 wbPieceGC = copyInvertedGC;
3134 bwPieceGC = copyInvertedGC;
3135 wbPieceGC = lightSquareGC;
3139 gc_values.foreground = highlightSquareColor;
3140 gc_values.background = highlightSquareColor;
3141 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3143 gc_values.foreground = premoveHighlightColor;
3144 gc_values.background = premoveHighlightColor;
3145 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3147 gc_values.foreground = lightSquareColor;
3148 gc_values.background = darkSquareColor;
3149 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3151 gc_values.foreground = darkSquareColor;
3152 gc_values.background = lightSquareColor;
3153 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3155 gc_values.foreground = jailSquareColor;
3156 gc_values.background = jailSquareColor;
3157 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3159 gc_values.foreground = whitePieceColor;
3160 gc_values.background = darkSquareColor;
3161 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3163 gc_values.foreground = whitePieceColor;
3164 gc_values.background = lightSquareColor;
3165 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3167 gc_values.foreground = whitePieceColor;
3168 gc_values.background = jailSquareColor;
3169 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3171 gc_values.foreground = blackPieceColor;
3172 gc_values.background = darkSquareColor;
3173 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3175 gc_values.foreground = blackPieceColor;
3176 gc_values.background = lightSquareColor;
3177 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3179 gc_values.foreground = blackPieceColor;
3180 gc_values.background = jailSquareColor;
3181 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3185 void loadXIM(xim, xmask, filename, dest, mask)
3198 fp = fopen(filename, "rb");
3200 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3207 for (y=0; y<h; ++y) {
3208 for (x=0; x<h; ++x) {
3213 XPutPixel(xim, x, y, blackPieceColor);
3215 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3218 XPutPixel(xim, x, y, darkSquareColor);
3220 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3223 XPutPixel(xim, x, y, whitePieceColor);
3225 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3228 XPutPixel(xim, x, y, lightSquareColor);
3230 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3236 /* create Pixmap of piece */
3237 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3239 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3242 /* create Pixmap of clipmask
3243 Note: We assume the white/black pieces have the same
3244 outline, so we make only 6 masks. This is okay
3245 since the XPM clipmask routines do the same. */
3247 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3249 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3252 /* now create the 1-bit version */
3253 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3256 values.foreground = 1;
3257 values.background = 0;
3259 /* Don't use XtGetGC, not read only */
3260 maskGC = XCreateGC(xDisplay, *mask,
3261 GCForeground | GCBackground, &values);
3262 XCopyPlane(xDisplay, temp, *mask, maskGC,
3263 0, 0, squareSize, squareSize, 0, 0, 1);
3264 XFreePixmap(xDisplay, temp);
3269 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3271 void CreateXIMPieces()
3276 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3281 /* The XSynchronize calls were copied from CreatePieces.
3282 Not sure if needed, but can't hurt */
3283 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3286 /* temp needed by loadXIM() */
3287 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3288 0, 0, ss, ss, AllPlanes, XYPixmap);
3290 if (strlen(appData.pixmapDirectory) == 0) {
3294 if (appData.monoMode) {
3295 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3299 fprintf(stderr, _("\nLoading XIMs...\n"));
3301 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3302 fprintf(stderr, "%d", piece+1);
3303 for (kind=0; kind<4; kind++) {
3304 fprintf(stderr, ".");
3305 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3306 ExpandPathName(appData.pixmapDirectory),
3307 piece <= (int) WhiteKing ? "" : "w",
3308 pieceBitmapNames[piece],
3310 ximPieceBitmap[kind][piece] =
3311 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3312 0, 0, ss, ss, AllPlanes, XYPixmap);
3313 if (appData.debugMode)
3314 fprintf(stderr, _("(File:%s:) "), buf);
3315 loadXIM(ximPieceBitmap[kind][piece],
3317 &(xpmPieceBitmap2[kind][piece]),
3318 &(ximMaskPm2[piece]));
3319 if(piece <= (int)WhiteKing)
3320 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3322 fprintf(stderr," ");
3324 /* Load light and dark squares */
3325 /* If the LSQ and DSQ pieces don't exist, we will
3326 draw them with solid squares. */
3327 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3328 if (access(buf, 0) != 0) {
3332 fprintf(stderr, _("light square "));
3334 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3335 0, 0, ss, ss, AllPlanes, XYPixmap);
3336 if (appData.debugMode)
3337 fprintf(stderr, _("(File:%s:) "), buf);
3339 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3340 fprintf(stderr, _("dark square "));
3341 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3342 ExpandPathName(appData.pixmapDirectory), ss);
3343 if (appData.debugMode)
3344 fprintf(stderr, _("(File:%s:) "), buf);
3346 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3347 0, 0, ss, ss, AllPlanes, XYPixmap);
3348 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3349 xpmJailSquare = xpmLightSquare;
3351 fprintf(stderr, _("Done.\n"));
3353 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3357 void CreateXPMPieces()
3361 u_int ss = squareSize;
3363 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3364 XpmColorSymbol symbols[4];
3366 /* The XSynchronize calls were copied from CreatePieces.
3367 Not sure if needed, but can't hurt */
3368 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3370 /* Setup translations so piece colors match square colors */
3371 symbols[0].name = "light_piece";
3372 symbols[0].value = appData.whitePieceColor;
3373 symbols[1].name = "dark_piece";
3374 symbols[1].value = appData.blackPieceColor;
3375 symbols[2].name = "light_square";
3376 symbols[2].value = appData.lightSquareColor;
3377 symbols[3].name = "dark_square";
3378 symbols[3].value = appData.darkSquareColor;
3380 attr.valuemask = XpmColorSymbols;
3381 attr.colorsymbols = symbols;
3382 attr.numsymbols = 4;
3384 if (appData.monoMode) {
3385 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3389 if (strlen(appData.pixmapDirectory) == 0) {
3390 XpmPieces* pieces = builtInXpms;
3393 while (pieces->size != squareSize && pieces->size) pieces++;
3394 if (!pieces->size) {
3395 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3398 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3399 for (kind=0; kind<4; kind++) {
3401 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3402 pieces->xpm[piece][kind],
3403 &(xpmPieceBitmap2[kind][piece]),
3404 NULL, &attr)) != 0) {
3405 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3409 if(piece <= (int) WhiteKing)
3410 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3414 xpmJailSquare = xpmLightSquare;
3418 fprintf(stderr, _("\nLoading XPMs...\n"));
3421 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3422 fprintf(stderr, "%d ", piece+1);
3423 for (kind=0; kind<4; kind++) {
3424 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3425 ExpandPathName(appData.pixmapDirectory),
3426 piece > (int) WhiteKing ? "w" : "",
3427 pieceBitmapNames[piece],
3429 if (appData.debugMode) {
3430 fprintf(stderr, _("(File:%s:) "), buf);
3432 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3433 &(xpmPieceBitmap2[kind][piece]),
3434 NULL, &attr)) != 0) {
3435 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3436 // [HGM] missing: read of unorthodox piece failed; substitute King.
3437 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3438 ExpandPathName(appData.pixmapDirectory),
3440 if (appData.debugMode) {
3441 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3443 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3444 &(xpmPieceBitmap2[kind][piece]),
3448 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3453 if(piece <= (int) WhiteKing)
3454 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3457 /* Load light and dark squares */
3458 /* If the LSQ and DSQ pieces don't exist, we will
3459 draw them with solid squares. */
3460 fprintf(stderr, _("light square "));
3461 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3462 if (access(buf, 0) != 0) {
3466 if (appData.debugMode)
3467 fprintf(stderr, _("(File:%s:) "), buf);
3469 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3470 &xpmLightSquare, NULL, &attr)) != 0) {
3471 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3474 fprintf(stderr, _("dark square "));
3475 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3476 ExpandPathName(appData.pixmapDirectory), ss);
3477 if (appData.debugMode) {
3478 fprintf(stderr, _("(File:%s:) "), buf);
3480 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3481 &xpmDarkSquare, NULL, &attr)) != 0) {
3482 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3486 xpmJailSquare = xpmLightSquare;
3487 fprintf(stderr, _("Done.\n"));
3489 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3492 #endif /* HAVE_LIBXPM */
3495 /* No built-in bitmaps */
3500 u_int ss = squareSize;
3502 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3505 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3506 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3507 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3508 pieceBitmapNames[piece],
3509 ss, kind == SOLID ? 's' : 'o');
3510 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3511 if(piece <= (int)WhiteKing)
3512 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3516 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3520 /* With built-in bitmaps */
3523 BuiltInBits* bib = builtInBits;
3526 u_int ss = squareSize;
3528 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3531 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3533 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3534 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3535 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3536 pieceBitmapNames[piece],
3537 ss, kind == SOLID ? 's' : 'o');
3538 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3539 bib->bits[kind][piece], ss, ss);
3540 if(piece <= (int)WhiteKing)
3541 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3545 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3550 void ReadBitmap(pm, name, bits, wreq, hreq)
3553 unsigned char bits[];
3559 char msg[MSG_SIZ], fullname[MSG_SIZ];
3561 if (*appData.bitmapDirectory != NULLCHAR) {
3562 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3563 strcat(fullname, "/");
3564 strcat(fullname, name);
3565 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3566 &w, &h, pm, &x_hot, &y_hot);
3567 fprintf(stderr, "load %s\n", name);
3568 if (errcode != BitmapSuccess) {
3570 case BitmapOpenFailed:
3571 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3573 case BitmapFileInvalid:
3574 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3576 case BitmapNoMemory:
3577 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3581 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3585 fprintf(stderr, _("%s: %s...using built-in\n"),
3587 } else if (w != wreq || h != hreq) {
3589 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3590 programName, fullname, w, h, wreq, hreq);
3596 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3605 if (lineGap == 0) return;
3607 /* [HR] Split this into 2 loops for non-square boards. */
3609 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3610 gridSegments[i].x1 = 0;
3611 gridSegments[i].x2 =
3612 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3613 gridSegments[i].y1 = gridSegments[i].y2
3614 = lineGap / 2 + (i * (squareSize + lineGap));
3617 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3618 gridSegments[j + i].y1 = 0;
3619 gridSegments[j + i].y2 =
3620 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3621 gridSegments[j + i].x1 = gridSegments[j + i].x2
3622 = lineGap / 2 + (j * (squareSize + lineGap));
3626 static void MenuBarSelect(w, addr, index)
3631 XtActionProc proc = (XtActionProc) addr;
3633 (proc)(NULL, NULL, NULL, NULL);
3636 void CreateMenuBarPopup(parent, name, mb)
3646 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3649 XtSetArg(args[j], XtNleftMargin, 20); j++;
3650 XtSetArg(args[j], XtNrightMargin, 20); j++;
3652 while (mi->string != NULL) {
3653 if (strcmp(mi->string, "----") == 0) {
3654 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3657 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3658 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3660 XtAddCallback(entry, XtNcallback,
3661 (XtCallbackProc) MenuBarSelect,
3662 (caddr_t) mi->proc);
3668 Widget CreateMenuBar(mb)
3672 Widget anchor, menuBar;
3674 char menuName[MSG_SIZ];
3677 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3678 XtSetArg(args[j], XtNvSpace, 0); j++;
3679 XtSetArg(args[j], XtNborderWidth, 0); j++;
3680 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3681 formWidget, args, j);
3683 while (mb->name != NULL) {
3684 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3685 strcat(menuName, mb->name);
3687 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3690 shortName[0] = _(mb->name)[0];
3691 shortName[1] = NULLCHAR;
3692 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3695 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3698 XtSetArg(args[j], XtNborderWidth, 0); j++;
3699 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3701 CreateMenuBarPopup(menuBar, menuName, mb);
3707 Widget CreateButtonBar(mi)
3711 Widget button, buttonBar;
3715 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3717 XtSetArg(args[j], XtNhSpace, 0); j++;
3719 XtSetArg(args[j], XtNborderWidth, 0); j++;
3720 XtSetArg(args[j], XtNvSpace, 0); j++;
3721 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3722 formWidget, args, j);
3724 while (mi->string != NULL) {
3727 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3728 XtSetArg(args[j], XtNborderWidth, 0); j++;
3730 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3731 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3732 buttonBar, args, j);
3733 XtAddCallback(button, XtNcallback,
3734 (XtCallbackProc) MenuBarSelect,
3735 (caddr_t) mi->proc);
3742 CreatePieceMenu(name, color)
3749 ChessSquare selection;
3751 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3752 boardWidget, args, 0);
3754 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3755 String item = pieceMenuStrings[color][i];
3757 if (strcmp(item, "----") == 0) {
3758 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3761 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3762 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3764 selection = pieceMenuTranslation[color][i];
3765 XtAddCallback(entry, XtNcallback,
3766 (XtCallbackProc) PieceMenuSelect,
3767 (caddr_t) selection);
3768 if (selection == WhitePawn || selection == BlackPawn) {
3769 XtSetArg(args[0], XtNpopupOnEntry, entry);
3770 XtSetValues(menu, args, 1);
3783 ChessSquare selection;
3785 whitePieceMenu = CreatePieceMenu("menuW", 0);
3786 blackPieceMenu = CreatePieceMenu("menuB", 1);
3788 XtRegisterGrabAction(PieceMenuPopup, True,
3789 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3790 GrabModeAsync, GrabModeAsync);
3792 XtSetArg(args[0], XtNlabel, _("Drop"));
3793 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3794 boardWidget, args, 1);
3795 for (i = 0; i < DROP_MENU_SIZE; i++) {
3796 String item = dropMenuStrings[i];
3798 if (strcmp(item, "----") == 0) {
3799 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3802 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3803 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3805 selection = dropMenuTranslation[i];
3806 XtAddCallback(entry, XtNcallback,
3807 (XtCallbackProc) DropMenuSelect,
3808 (caddr_t) selection);
3813 void SetupDropMenu()
3821 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3822 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3823 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3824 dmEnables[i].piece);
3825 XtSetSensitive(entry, p != NULL || !appData.testLegality
3826 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3827 && !appData.icsActive));
3829 while (p && *p++ == dmEnables[i].piece) count++;
3830 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3832 XtSetArg(args[j], XtNlabel, label); j++;
3833 XtSetValues(entry, args, j);
3837 void PieceMenuPopup(w, event, params, num_params)
3841 Cardinal *num_params;
3843 String whichMenu; int menuNr;
3844 if (event->type == ButtonRelease)
3845 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3846 else if (event->type == ButtonPress)
3847 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3849 case 0: whichMenu = params[0]; break;
3850 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3852 case -1: if (errorUp) ErrorPopDown();
3855 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3858 static void PieceMenuSelect(w, piece, junk)
3863 if (pmFromX < 0 || pmFromY < 0) return;
3864 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3867 static void DropMenuSelect(w, piece, junk)
3872 if (pmFromX < 0 || pmFromY < 0) return;
3873 DropMenuEvent(piece, pmFromX, pmFromY);
3876 void WhiteClock(w, event, prms, nprms)
3882 if (gameMode == EditPosition || gameMode == IcsExamining) {
3883 SetWhiteToPlayEvent();
3884 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3889 void BlackClock(w, event, prms, nprms)
3895 if (gameMode == EditPosition || gameMode == IcsExamining) {
3896 SetBlackToPlayEvent();
3897 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3904 * If the user selects on a border boundary, return -1; if off the board,
3905 * return -2. Otherwise map the event coordinate to the square.
3907 int EventToSquare(x, limit)
3915 if ((x % (squareSize + lineGap)) >= squareSize)
3917 x /= (squareSize + lineGap);
3923 static void do_flash_delay(msec)
3929 static void drawHighlight(file, rank, gc)
3935 if (lineGap == 0 || appData.blindfold) return;
3938 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3939 (squareSize + lineGap);
3940 y = lineGap/2 + rank * (squareSize + lineGap);
3942 x = lineGap/2 + file * (squareSize + lineGap);
3943 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3944 (squareSize + lineGap);
3947 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3948 squareSize+lineGap, squareSize+lineGap);
3951 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3952 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3955 SetHighlights(fromX, fromY, toX, toY)
3956 int fromX, fromY, toX, toY;
3958 if (hi1X != fromX || hi1Y != fromY) {
3959 if (hi1X >= 0 && hi1Y >= 0) {
3960 drawHighlight(hi1X, hi1Y, lineGC);
3962 } // [HGM] first erase both, then draw new!
3963 if (hi2X != toX || hi2Y != toY) {
3964 if (hi2X >= 0 && hi2Y >= 0) {
3965 drawHighlight(hi2X, hi2Y, lineGC);
3968 if (hi1X != fromX || hi1Y != fromY) {
3969 if (fromX >= 0 && fromY >= 0) {
3970 drawHighlight(fromX, fromY, highlineGC);
3973 if (hi2X != toX || hi2Y != toY) {
3974 if (toX >= 0 && toY >= 0) {
3975 drawHighlight(toX, toY, highlineGC);
3987 SetHighlights(-1, -1, -1, -1);
3992 SetPremoveHighlights(fromX, fromY, toX, toY)
3993 int fromX, fromY, toX, toY;
3995 if (pm1X != fromX || pm1Y != fromY) {
3996 if (pm1X >= 0 && pm1Y >= 0) {
3997 drawHighlight(pm1X, pm1Y, lineGC);
3999 if (fromX >= 0 && fromY >= 0) {
4000 drawHighlight(fromX, fromY, prelineGC);
4003 if (pm2X != toX || pm2Y != toY) {
4004 if (pm2X >= 0 && pm2Y >= 0) {
4005 drawHighlight(pm2X, pm2Y, lineGC);
4007 if (toX >= 0 && toY >= 0) {
4008 drawHighlight(toX, toY, prelineGC);
4018 ClearPremoveHighlights()
4020 SetPremoveHighlights(-1, -1, -1, -1);
4023 static void BlankSquare(x, y, color, piece, dest)
4028 if (useImages && useImageSqs) {
4032 pm = xpmLightSquare;
4037 case 2: /* neutral */
4042 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4043 squareSize, squareSize, x, y);
4053 case 2: /* neutral */
4058 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4063 I split out the routines to draw a piece so that I could
4064 make a generic flash routine.
4066 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4068 int square_color, x, y;
4071 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4072 switch (square_color) {
4074 case 2: /* neutral */
4076 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4077 ? *pieceToOutline(piece)
4078 : *pieceToSolid(piece),
4079 dest, bwPieceGC, 0, 0,
4080 squareSize, squareSize, x, y);
4083 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4084 ? *pieceToSolid(piece)
4085 : *pieceToOutline(piece),
4086 dest, wbPieceGC, 0, 0,
4087 squareSize, squareSize, x, y);
4092 static void monoDrawPiece(piece, square_color, x, y, dest)
4094 int square_color, x, y;
4097 switch (square_color) {
4099 case 2: /* neutral */
4101 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4102 ? *pieceToOutline(piece)
4103 : *pieceToSolid(piece),
4104 dest, bwPieceGC, 0, 0,
4105 squareSize, squareSize, x, y, 1);
4108 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4109 ? *pieceToSolid(piece)
4110 : *pieceToOutline(piece),
4111 dest, wbPieceGC, 0, 0,
4112 squareSize, squareSize, x, y, 1);
4117 static void colorDrawPiece(piece, square_color, x, y, dest)
4119 int square_color, x, y;
4122 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4123 switch (square_color) {
4125 XCopyPlane(xDisplay, *pieceToSolid(piece),
4126 dest, (int) piece < (int) BlackPawn
4127 ? wlPieceGC : blPieceGC, 0, 0,
4128 squareSize, squareSize, x, y, 1);
4131 XCopyPlane(xDisplay, *pieceToSolid(piece),
4132 dest, (int) piece < (int) BlackPawn
4133 ? wdPieceGC : bdPieceGC, 0, 0,
4134 squareSize, squareSize, x, y, 1);
4136 case 2: /* neutral */
4138 XCopyPlane(xDisplay, *pieceToSolid(piece),
4139 dest, (int) piece < (int) BlackPawn
4140 ? wjPieceGC : bjPieceGC, 0, 0,
4141 squareSize, squareSize, x, y, 1);
4146 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4148 int square_color, x, y;
4153 switch (square_color) {
4155 case 2: /* neutral */
4157 if ((int)piece < (int) BlackPawn) {
4165 if ((int)piece < (int) BlackPawn) {
4173 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4174 dest, wlPieceGC, 0, 0,
4175 squareSize, squareSize, x, y);
4178 typedef void (*DrawFunc)();
4180 DrawFunc ChooseDrawFunc()
4182 if (appData.monoMode) {
4183 if (DefaultDepth(xDisplay, xScreen) == 1) {
4184 return monoDrawPiece_1bit;
4186 return monoDrawPiece;
4190 return colorDrawPieceImage;
4192 return colorDrawPiece;
4196 /* [HR] determine square color depending on chess variant. */
4197 static int SquareColor(row, column)
4202 if (gameInfo.variant == VariantXiangqi) {
4203 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4205 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4207 } else if (row <= 4) {
4213 square_color = ((column + row) % 2) == 1;
4216 /* [hgm] holdings: next line makes all holdings squares light */
4217 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4219 return square_color;
4222 void DrawSquare(row, column, piece, do_flash)
4223 int row, column, do_flash;
4226 int square_color, x, y, direction, font_ascent, font_descent;
4229 XCharStruct overall;
4233 /* Calculate delay in milliseconds (2-delays per complete flash) */
4234 flash_delay = 500 / appData.flashRate;
4237 x = lineGap + ((BOARD_WIDTH-1)-column) *
4238 (squareSize + lineGap);
4239 y = lineGap + row * (squareSize + lineGap);
4241 x = lineGap + column * (squareSize + lineGap);
4242 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4243 (squareSize + lineGap);
4246 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4248 square_color = SquareColor(row, column);
4250 if ( // [HGM] holdings: blank out area between board and holdings
4251 column == BOARD_LEFT-1 || column == BOARD_RGHT
4252 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4253 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4254 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4256 // [HGM] print piece counts next to holdings
4257 string[1] = NULLCHAR;
4258 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4259 string[0] = '0' + piece;
4260 XTextExtents(countFontStruct, string, 1, &direction,
4261 &font_ascent, &font_descent, &overall);
4262 if (appData.monoMode) {
4263 XDrawImageString(xDisplay, xBoardWindow, countGC,
4264 x + squareSize - overall.width - 2,
4265 y + font_ascent + 1, string, 1);
4267 XDrawString(xDisplay, xBoardWindow, countGC,
4268 x + squareSize - overall.width - 2,
4269 y + font_ascent + 1, string, 1);
4272 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4273 string[0] = '0' + piece;
4274 XTextExtents(countFontStruct, string, 1, &direction,
4275 &font_ascent, &font_descent, &overall);
4276 if (appData.monoMode) {
4277 XDrawImageString(xDisplay, xBoardWindow, countGC,
4278 x + 2, y + font_ascent + 1, string, 1);
4280 XDrawString(xDisplay, xBoardWindow, countGC,
4281 x + 2, y + font_ascent + 1, string, 1);
4285 if (piece == EmptySquare || appData.blindfold) {
4286 BlankSquare(x, y, square_color, piece, xBoardWindow);
4288 drawfunc = ChooseDrawFunc();
4289 if (do_flash && appData.flashCount > 0) {
4290 for (i=0; i<appData.flashCount; ++i) {
4292 drawfunc(piece, square_color, x, y, xBoardWindow);
4293 XSync(xDisplay, False);
4294 do_flash_delay(flash_delay);
4296 BlankSquare(x, y, square_color, piece, xBoardWindow);
4297 XSync(xDisplay, False);
4298 do_flash_delay(flash_delay);
4301 drawfunc(piece, square_color, x, y, xBoardWindow);
4305 string[1] = NULLCHAR;
4306 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4307 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4308 string[0] = 'a' + column - BOARD_LEFT;
4309 XTextExtents(coordFontStruct, string, 1, &direction,
4310 &font_ascent, &font_descent, &overall);
4311 if (appData.monoMode) {
4312 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4313 x + squareSize - overall.width - 2,
4314 y + squareSize - font_descent - 1, string, 1);
4316 XDrawString(xDisplay, xBoardWindow, coordGC,
4317 x + squareSize - overall.width - 2,
4318 y + squareSize - font_descent - 1, string, 1);
4321 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4322 string[0] = ONE + row;
4323 XTextExtents(coordFontStruct, string, 1, &direction,
4324 &font_ascent, &font_descent, &overall);
4325 if (appData.monoMode) {
4326 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4327 x + 2, y + font_ascent + 1, string, 1);
4329 XDrawString(xDisplay, xBoardWindow, coordGC,
4330 x + 2, y + font_ascent + 1, string, 1);
4333 if(!partnerUp && marker[row][column]) {
4334 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4335 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4340 /* Why is this needed on some versions of X? */
4341 void EventProc(widget, unused, event)
4346 if (!XtIsRealized(widget))
4349 switch (event->type) {
4351 if (event->xexpose.count > 0) return; /* no clipping is done */
4352 XDrawPosition(widget, True, NULL);
4353 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4354 flipView = !flipView; partnerUp = !partnerUp;
4355 XDrawPosition(widget, True, NULL);
4356 flipView = !flipView; partnerUp = !partnerUp;
4360 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4367 void DrawPosition(fullRedraw, board)
4368 /*Boolean*/int fullRedraw;
4371 XDrawPosition(boardWidget, fullRedraw, board);
4374 /* Returns 1 if there are "too many" differences between b1 and b2
4375 (i.e. more than 1 move was made) */
4376 static int too_many_diffs(b1, b2)
4382 for (i=0; i<BOARD_HEIGHT; ++i) {
4383 for (j=0; j<BOARD_WIDTH; ++j) {
4384 if (b1[i][j] != b2[i][j]) {
4385 if (++c > 4) /* Castling causes 4 diffs */
4394 /* Matrix describing castling maneuvers */
4395 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4396 static int castling_matrix[4][5] = {
4397 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4398 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4399 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4400 { 7, 7, 4, 5, 6 } /* 0-0, black */
4403 /* Checks whether castling occurred. If it did, *rrow and *rcol
4404 are set to the destination (row,col) of the rook that moved.
4406 Returns 1 if castling occurred, 0 if not.
4408 Note: Only handles a max of 1 castling move, so be sure
4409 to call too_many_diffs() first.
4411 static int check_castle_draw(newb, oldb, rrow, rcol)
4418 /* For each type of castling... */
4419 for (i=0; i<4; ++i) {
4420 r = castling_matrix[i];
4422 /* Check the 4 squares involved in the castling move */
4424 for (j=1; j<=4; ++j) {
4425 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4432 /* All 4 changed, so it must be a castling move */
4441 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4442 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4444 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4447 void DrawSeekBackground( int left, int top, int right, int bottom )
4449 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4452 void DrawSeekText(char *buf, int x, int y)
4454 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4457 void DrawSeekDot(int x, int y, int colorNr)
4459 int square = colorNr & 0x80;
4462 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4464 XFillRectangle(xDisplay, xBoardWindow, color,
4465 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4467 XFillArc(xDisplay, xBoardWindow, color,
4468 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4471 static int damage[2][BOARD_RANKS][BOARD_FILES];
4474 * event handler for redrawing the board
4476 void XDrawPosition(w, repaint, board)
4478 /*Boolean*/int repaint;
4482 static int lastFlipView = 0;
4483 static int lastBoardValid[2] = {0, 0};
4484 static Board lastBoard[2];
4487 int nr = twoBoards*partnerUp;
4489 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4491 if (board == NULL) {
4492 if (!lastBoardValid) return;
4493 board = lastBoard[nr];
4495 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4496 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4497 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4502 * It would be simpler to clear the window with XClearWindow()
4503 * but this causes a very distracting flicker.
4506 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4508 /* If too much changes (begin observing new game, etc.), don't
4510 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4512 /* Special check for castling so we don't flash both the king
4513 and the rook (just flash the king). */
4515 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4516 /* Draw rook with NO flashing. King will be drawn flashing later */
4517 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4518 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4522 /* First pass -- Draw (newly) empty squares and repair damage.
4523 This prevents you from having a piece show up twice while it
4524 is flashing on its new square */
4525 for (i = 0; i < BOARD_HEIGHT; i++)
4526 for (j = 0; j < BOARD_WIDTH; j++)
4527 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4528 || damage[nr][i][j]) {
4529 DrawSquare(i, j, board[i][j], 0);
4530 damage[nr][i][j] = False;
4533 /* Second pass -- Draw piece(s) in new position and flash them */
4534 for (i = 0; i < BOARD_HEIGHT; i++)
4535 for (j = 0; j < BOARD_WIDTH; j++)
4536 if (board[i][j] != lastBoard[nr][i][j]) {
4537 DrawSquare(i, j, board[i][j], do_flash);
4541 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4542 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4543 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4545 for (i = 0; i < BOARD_HEIGHT; i++)
4546 for (j = 0; j < BOARD_WIDTH; j++) {
4547 DrawSquare(i, j, board[i][j], 0);
4548 damage[nr][i][j] = False;
4552 CopyBoard(lastBoard[nr], board);
4553 lastBoardValid[nr] = 1;
4554 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4555 lastFlipView = flipView;
4557 /* Draw highlights */
4558 if (pm1X >= 0 && pm1Y >= 0) {
4559 drawHighlight(pm1X, pm1Y, prelineGC);
4561 if (pm2X >= 0 && pm2Y >= 0) {
4562 drawHighlight(pm2X, pm2Y, prelineGC);
4564 if (hi1X >= 0 && hi1Y >= 0) {
4565 drawHighlight(hi1X, hi1Y, highlineGC);
4567 if (hi2X >= 0 && hi2Y >= 0) {
4568 drawHighlight(hi2X, hi2Y, highlineGC);
4571 /* If piece being dragged around board, must redraw that too */
4574 XSync(xDisplay, False);
4579 * event handler for redrawing the board
4581 void DrawPositionProc(w, event, prms, nprms)
4587 XDrawPosition(w, True, NULL);
4592 * event handler for parsing user moves
4594 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4595 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4596 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4597 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4598 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4599 // and at the end FinishMove() to perform the move after optional promotion popups.
4600 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4601 void HandleUserMove(w, event, prms, nprms)
4607 if (w != boardWidget || errorExitStatus != -1) return;
4610 if (event->type == ButtonPress) {
4611 XtPopdown(promotionShell);
4612 XtDestroyWidget(promotionShell);
4613 promotionUp = False;
4621 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4622 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4623 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4626 void AnimateUserMove (Widget w, XEvent * event,
4627 String * params, Cardinal * nParams)
4629 DragPieceMove(event->xmotion.x, event->xmotion.y);
4632 void HandlePV (Widget w, XEvent * event,
4633 String * params, Cardinal * nParams)
4634 { // [HGM] pv: walk PV
4635 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4638 Widget CommentCreate(name, text, mutable, callback, lines)
4640 int /*Boolean*/ mutable;
4641 XtCallbackProc callback;
4645 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4650 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4651 XtGetValues(boardWidget, args, j);
4654 XtSetArg(args[j], XtNresizable, True); j++;
4657 XtCreatePopupShell(name, topLevelShellWidgetClass,
4658 shellWidget, args, j);
4661 XtCreatePopupShell(name, transientShellWidgetClass,
4662 shellWidget, args, j);
4665 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4666 layoutArgs, XtNumber(layoutArgs));
4668 XtCreateManagedWidget("form", formWidgetClass, layout,
4669 formArgs, XtNumber(formArgs));
4673 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4674 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4676 XtSetArg(args[j], XtNstring, text); j++;
4677 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4678 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4679 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4680 XtSetArg(args[j], XtNright, XtChainRight); j++;
4681 XtSetArg(args[j], XtNresizable, True); j++;
4682 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4683 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4684 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4685 XtSetArg(args[j], XtNautoFill, True); j++;
4686 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4688 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4689 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4693 XtSetArg(args[j], XtNfromVert, edit); j++;
4694 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4695 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4696 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4697 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4699 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4700 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4703 XtSetArg(args[j], XtNfromVert, edit); j++;
4704 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4705 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4706 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4707 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4708 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4710 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4711 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4714 XtSetArg(args[j], XtNfromVert, edit); j++;
4715 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4716 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4717 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4718 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4719 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4721 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4722 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4725 XtSetArg(args[j], XtNfromVert, edit); j++;
4726 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4727 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4728 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4729 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4731 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4732 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4735 XtSetArg(args[j], XtNfromVert, edit); j++;
4736 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4737 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4738 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4739 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4740 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4742 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4743 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4746 XtRealizeWidget(shell);
4748 if (commentX == -1) {
4751 Dimension pw_height;
4752 Dimension ew_height;
4755 XtSetArg(args[j], XtNheight, &ew_height); j++;
4756 XtGetValues(edit, args, j);
4759 XtSetArg(args[j], XtNheight, &pw_height); j++;
4760 XtGetValues(shell, args, j);
4761 commentH = pw_height + (lines - 1) * ew_height;
4762 commentW = bw_width - 16;
4764 XSync(xDisplay, False);
4766 /* This code seems to tickle an X bug if it is executed too soon
4767 after xboard starts up. The coordinates get transformed as if
4768 the main window was positioned at (0, 0).
4770 XtTranslateCoords(shellWidget,
4771 (bw_width - commentW) / 2, 0 - commentH / 2,
4772 &commentX, &commentY);
4774 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4775 RootWindowOfScreen(XtScreen(shellWidget)),
4776 (bw_width - commentW) / 2, 0 - commentH / 2,
4781 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4784 if(wpComment.width > 0) {
4785 commentX = wpComment.x;
4786 commentY = wpComment.y;
4787 commentW = wpComment.width;
4788 commentH = wpComment.height;
4792 XtSetArg(args[j], XtNheight, commentH); j++;
4793 XtSetArg(args[j], XtNwidth, commentW); j++;
4794 XtSetArg(args[j], XtNx, commentX); j++;
4795 XtSetArg(args[j], XtNy, commentY); j++;
4796 XtSetValues(shell, args, j);
4797 XtSetKeyboardFocus(shell, edit);
4802 /* Used for analysis window and ICS input window */
4803 Widget MiscCreate(name, text, mutable, callback, lines)
4805 int /*Boolean*/ mutable;
4806 XtCallbackProc callback;
4810 Widget shell, layout, form, edit;
4812 Dimension bw_width, pw_height, ew_height, w, h;
4818 XtSetArg(args[j], XtNresizable, True); j++;
4821 XtCreatePopupShell(name, topLevelShellWidgetClass,
4822 shellWidget, args, j);
4825 XtCreatePopupShell(name, transientShellWidgetClass,
4826 shellWidget, args, j);
4829 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4830 layoutArgs, XtNumber(layoutArgs));
4832 XtCreateManagedWidget("form", formWidgetClass, layout,
4833 formArgs, XtNumber(formArgs));
4837 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4838 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4840 XtSetArg(args[j], XtNstring, text); j++;
4841 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4842 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4843 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4844 XtSetArg(args[j], XtNright, XtChainRight); j++;
4845 XtSetArg(args[j], XtNresizable, True); j++;
4846 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4847 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4848 XtSetArg(args[j], XtNautoFill, True); j++;
4849 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4851 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4853 XtRealizeWidget(shell);
4856 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4857 XtGetValues(boardWidget, args, j);
4860 XtSetArg(args[j], XtNheight, &ew_height); j++;
4861 XtGetValues(edit, args, j);
4864 XtSetArg(args[j], XtNheight, &pw_height); j++;
4865 XtGetValues(shell, args, j);
4866 h = pw_height + (lines - 1) * ew_height;
4869 XSync(xDisplay, False);
4871 /* This code seems to tickle an X bug if it is executed too soon
4872 after xboard starts up. The coordinates get transformed as if
4873 the main window was positioned at (0, 0).
4875 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4877 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4878 RootWindowOfScreen(XtScreen(shellWidget)),
4879 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4883 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4886 XtSetArg(args[j], XtNheight, h); j++;
4887 XtSetArg(args[j], XtNwidth, w); j++;
4888 XtSetArg(args[j], XtNx, x); j++;
4889 XtSetArg(args[j], XtNy, y); j++;
4890 XtSetValues(shell, args, j);
4896 static int savedIndex; /* gross that this is global */
4898 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4901 XawTextPosition index, dummy;
4904 XawTextGetSelectionPos(w, &index, &dummy);
4905 XtSetArg(arg, XtNstring, &val);
4906 XtGetValues(w, &arg, 1);
4907 ReplaceComment(savedIndex, val);
4908 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4909 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4912 void EditCommentPopUp(index, title, text)
4921 if (text == NULL) text = "";
4923 if (editShell == NULL) {
4925 CommentCreate(title, text, True, EditCommentCallback, 4);
4926 XtRealizeWidget(editShell);
4927 CatchDeleteWindow(editShell, "EditCommentPopDown");
4929 edit = XtNameToWidget(editShell, "*form.text");
4931 XtSetArg(args[j], XtNstring, text); j++;
4932 XtSetValues(edit, args, j);
4934 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4935 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4936 XtSetValues(editShell, args, j);
4939 XtPopup(editShell, XtGrabNone);
4943 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4944 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4948 void EditCommentCallback(w, client_data, call_data)
4950 XtPointer client_data, call_data;
4958 XtSetArg(args[j], XtNlabel, &name); j++;
4959 XtGetValues(w, args, j);
4961 if (strcmp(name, _("ok")) == 0) {
4962 edit = XtNameToWidget(editShell, "*form.text");
4964 XtSetArg(args[j], XtNstring, &val); j++;
4965 XtGetValues(edit, args, j);
4966 ReplaceComment(savedIndex, val);
4967 EditCommentPopDown();
4968 } else if (strcmp(name, _("cancel")) == 0) {
4969 EditCommentPopDown();
4970 } else if (strcmp(name, _("clear")) == 0) {
4971 edit = XtNameToWidget(editShell, "*form.text");
4972 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4973 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4977 void EditCommentPopDown()
4982 if (!editUp) return;
4984 XtSetArg(args[j], XtNx, &commentX); j++;
4985 XtSetArg(args[j], XtNy, &commentY); j++;
4986 XtSetArg(args[j], XtNheight, &commentH); j++;
4987 XtSetArg(args[j], XtNwidth, &commentW); j++;
4988 XtGetValues(editShell, args, j);
4989 XtPopdown(editShell);
4992 XtSetArg(args[j], XtNleftBitmap, None); j++;
4993 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4997 void ICSInputBoxPopUp()
5002 char *title = _("ICS Input");
5005 if (ICSInputShell == NULL) {
5006 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5007 tr = XtParseTranslationTable(ICSInputTranslations);
5008 edit = XtNameToWidget(ICSInputShell, "*form.text");
5009 XtOverrideTranslations(edit, tr);
5010 XtRealizeWidget(ICSInputShell);
5011 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5014 edit = XtNameToWidget(ICSInputShell, "*form.text");
5016 XtSetArg(args[j], XtNstring, ""); j++;
5017 XtSetValues(edit, args, j);
5019 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5020 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5021 XtSetValues(ICSInputShell, args, j);
5024 XtPopup(ICSInputShell, XtGrabNone);
5025 XtSetKeyboardFocus(ICSInputShell, edit);
5027 ICSInputBoxUp = True;
5029 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5030 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5034 void ICSInputSendText()
5041 edit = XtNameToWidget(ICSInputShell, "*form.text");
5043 XtSetArg(args[j], XtNstring, &val); j++;
5044 XtGetValues(edit, args, j);
5046 SendMultiLineToICS(val);
5047 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5048 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5051 void ICSInputBoxPopDown()
5056 if (!ICSInputBoxUp) return;
5058 XtPopdown(ICSInputShell);
5059 ICSInputBoxUp = False;
5061 XtSetArg(args[j], XtNleftBitmap, None); j++;
5062 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5066 void CommentPopUp(title, text)
5073 savedIndex = currentMove; // [HGM] vari
5074 if (commentShell == NULL) {
5076 CommentCreate(title, text, False, CommentCallback, 4);
5077 XtRealizeWidget(commentShell);
5078 CatchDeleteWindow(commentShell, "CommentPopDown");
5080 edit = XtNameToWidget(commentShell, "*form.text");
5082 XtSetArg(args[j], XtNstring, text); j++;
5083 XtSetValues(edit, args, j);
5085 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5086 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5087 XtSetValues(commentShell, args, j);
5090 XtPopup(commentShell, XtGrabNone);
5091 XSync(xDisplay, False);
5096 void CommentCallback(w, client_data, call_data)
5098 XtPointer client_data, call_data;
5105 XtSetArg(args[j], XtNlabel, &name); j++;
5106 XtGetValues(w, args, j);
5108 if (strcmp(name, _("close")) == 0) {
5110 } else if (strcmp(name, _("edit")) == 0) {
5117 void CommentPopDown()
5122 if (!commentUp) return;
5124 XtSetArg(args[j], XtNx, &commentX); j++;
5125 XtSetArg(args[j], XtNy, &commentY); j++;
5126 XtSetArg(args[j], XtNwidth, &commentW); j++;
5127 XtSetArg(args[j], XtNheight, &commentH); j++;
5128 XtGetValues(commentShell, args, j);
5129 XtPopdown(commentShell);
5130 XSync(xDisplay, False);
5134 void FileNamePopUp(label, def, proc, openMode)
5140 fileProc = proc; /* I can't see a way not */
5141 fileOpenMode = openMode; /* to use globals here */
5142 { // [HGM] use file-selector dialog stolen from Ghostview
5144 int index; // this is not supported yet
5146 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5147 def, openMode, NULL, &name))
5148 (void) (*fileProc)(f, index=0, name);
5152 void FileNamePopDown()
5154 if (!filenameUp) return;
5155 XtPopdown(fileNameShell);
5156 XtDestroyWidget(fileNameShell);
5161 void FileNameCallback(w, client_data, call_data)
5163 XtPointer client_data, call_data;
5168 XtSetArg(args[0], XtNlabel, &name);
5169 XtGetValues(w, args, 1);
5171 if (strcmp(name, _("cancel")) == 0) {
5176 FileNameAction(w, NULL, NULL, NULL);
5179 void FileNameAction(w, event, prms, nprms)
5191 name = XawDialogGetValueString(w = XtParent(w));
5193 if ((name != NULL) && (*name != NULLCHAR)) {
5194 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5195 XtPopdown(w = XtParent(XtParent(w)));
5199 p = strrchr(buf, ' ');
5206 fullname = ExpandPathName(buf);
5208 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5211 f = fopen(fullname, fileOpenMode);
5213 DisplayError(_("Failed to open file"), errno);
5215 (void) (*fileProc)(f, index, buf);
5222 XtPopdown(w = XtParent(XtParent(w)));
5228 void PromotionPopUp()
5231 Widget dialog, layout;
5233 Dimension bw_width, pw_width;
5237 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5238 XtGetValues(boardWidget, args, j);
5241 XtSetArg(args[j], XtNresizable, True); j++;
5242 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5244 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5245 shellWidget, args, j);
5247 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5248 layoutArgs, XtNumber(layoutArgs));
5251 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5252 XtSetArg(args[j], XtNborderWidth, 0); j++;
5253 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5256 if(gameInfo.variant != VariantShogi) {
5257 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5258 (XtPointer) dialog);
5259 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5260 (XtPointer) dialog);
5261 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5262 (XtPointer) dialog);
5263 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5264 (XtPointer) dialog);
5265 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5266 gameInfo.variant == VariantGiveaway) {
5267 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5268 (XtPointer) dialog);
5270 if(gameInfo.variant == VariantCapablanca ||
5271 gameInfo.variant == VariantGothic ||
5272 gameInfo.variant == VariantCapaRandom) {
5273 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5274 (XtPointer) dialog);
5275 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5276 (XtPointer) dialog);
5278 } else // [HGM] shogi
5280 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5281 (XtPointer) dialog);
5282 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5283 (XtPointer) dialog);
5285 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5286 (XtPointer) dialog);
5288 XtRealizeWidget(promotionShell);
5289 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5292 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5293 XtGetValues(promotionShell, args, j);
5295 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5296 lineGap + squareSize/3 +
5297 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5298 0 : 6*(squareSize + lineGap)), &x, &y);
5301 XtSetArg(args[j], XtNx, x); j++;
5302 XtSetArg(args[j], XtNy, y); j++;
5303 XtSetValues(promotionShell, args, j);
5305 XtPopup(promotionShell, XtGrabNone);
5310 void PromotionPopDown()
5312 if (!promotionUp) return;
5313 XtPopdown(promotionShell);
5314 XtDestroyWidget(promotionShell);
5315 promotionUp = False;
5318 void PromotionCallback(w, client_data, call_data)
5320 XtPointer client_data, call_data;
5326 XtSetArg(args[0], XtNlabel, &name);
5327 XtGetValues(w, args, 1);
5331 if (fromX == -1) return;
5333 if (strcmp(name, _("cancel")) == 0) {
5337 } else if (strcmp(name, _("Knight")) == 0) {
5339 } else if (strcmp(name, _("Promote")) == 0) {
5341 } else if (strcmp(name, _("Defer")) == 0) {
5344 promoChar = ToLower(name[0]);
5347 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5349 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5350 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5355 void ErrorCallback(w, client_data, call_data)
5357 XtPointer client_data, call_data;
5360 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5362 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5368 if (!errorUp) return;
5370 XtPopdown(errorShell);
5371 XtDestroyWidget(errorShell);
5372 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5375 void ErrorPopUp(title, label, modal)
5376 char *title, *label;
5380 Widget dialog, layout;
5384 Dimension bw_width, pw_width;
5385 Dimension pw_height;
5389 XtSetArg(args[i], XtNresizable, True); i++;
5390 XtSetArg(args[i], XtNtitle, title); i++;
5392 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5393 shellWidget, args, i);
5395 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5396 layoutArgs, XtNumber(layoutArgs));
5399 XtSetArg(args[i], XtNlabel, label); i++;
5400 XtSetArg(args[i], XtNborderWidth, 0); i++;
5401 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5404 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5406 XtRealizeWidget(errorShell);
5407 CatchDeleteWindow(errorShell, "ErrorPopDown");
5410 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5411 XtGetValues(boardWidget, args, i);
5413 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5414 XtSetArg(args[i], XtNheight, &pw_height); i++;
5415 XtGetValues(errorShell, args, i);
5418 /* This code seems to tickle an X bug if it is executed too soon
5419 after xboard starts up. The coordinates get transformed as if
5420 the main window was positioned at (0, 0).
5422 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5423 0 - pw_height + squareSize / 3, &x, &y);
5425 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5426 RootWindowOfScreen(XtScreen(boardWidget)),
5427 (bw_width - pw_width) / 2,
5428 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5432 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5435 XtSetArg(args[i], XtNx, x); i++;
5436 XtSetArg(args[i], XtNy, y); i++;
5437 XtSetValues(errorShell, args, i);
5440 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5443 /* Disable all user input other than deleting the window */
5444 static int frozen = 0;
5448 /* Grab by a widget that doesn't accept input */
5449 XtAddGrab(messageWidget, TRUE, FALSE);
5453 /* Undo a FreezeUI */
5456 if (!frozen) return;
5457 XtRemoveGrab(messageWidget);
5461 char *ModeToWidgetName(mode)
5465 case BeginningOfGame:
5466 if (appData.icsActive)
5467 return "menuMode.ICS Client";
5468 else if (appData.noChessProgram ||
5469 *appData.cmailGameName != NULLCHAR)
5470 return "menuMode.Edit Game";
5472 return "menuMode.Machine Black";
5473 case MachinePlaysBlack:
5474 return "menuMode.Machine Black";
5475 case MachinePlaysWhite:
5476 return "menuMode.Machine White";
5478 return "menuMode.Analysis Mode";
5480 return "menuMode.Analyze File";
5481 case TwoMachinesPlay:
5482 return "menuMode.Two Machines";
5484 return "menuMode.Edit Game";
5485 case PlayFromGameFile:
5486 return "menuFile.Load Game";
5488 return "menuMode.Edit Position";
5490 return "menuMode.Training";
5491 case IcsPlayingWhite:
5492 case IcsPlayingBlack:
5496 return "menuMode.ICS Client";
5503 void ModeHighlight()
5506 static int oldPausing = FALSE;
5507 static GameMode oldmode = (GameMode) -1;
5510 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5512 if (pausing != oldPausing) {
5513 oldPausing = pausing;
5515 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5517 XtSetArg(args[0], XtNleftBitmap, None);
5519 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5522 if (appData.showButtonBar) {
5523 /* Always toggle, don't set. Previous code messes up when
5524 invoked while the button is pressed, as releasing it
5525 toggles the state again. */
5528 XtSetArg(args[0], XtNbackground, &oldbg);
5529 XtSetArg(args[1], XtNforeground, &oldfg);
5530 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5532 XtSetArg(args[0], XtNbackground, oldfg);
5533 XtSetArg(args[1], XtNforeground, oldbg);
5535 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5539 wname = ModeToWidgetName(oldmode);
5540 if (wname != NULL) {
5541 XtSetArg(args[0], XtNleftBitmap, None);
5542 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5544 wname = ModeToWidgetName(gameMode);
5545 if (wname != NULL) {
5546 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5547 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5551 /* Maybe all the enables should be handled here, not just this one */
5552 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5553 gameMode == Training || gameMode == PlayFromGameFile);
5558 * Button/menu procedures
5560 void ResetProc(w, event, prms, nprms)
5569 int LoadGamePopUp(f, gameNumber, title)
5574 cmailMsgLoaded = FALSE;
5575 if (gameNumber == 0) {
5576 int error = GameListBuild(f);
5578 DisplayError(_("Cannot build game list"), error);
5579 } else if (!ListEmpty(&gameList) &&
5580 ((ListGame *) gameList.tailPred)->number > 1) {
5581 GameListPopUp(f, title);
5587 return LoadGame(f, gameNumber, title, FALSE);
5590 void LoadGameProc(w, event, prms, nprms)
5596 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5599 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5602 void LoadNextGameProc(w, event, prms, nprms)
5611 void LoadPrevGameProc(w, event, prms, nprms)
5620 void ReloadGameProc(w, event, prms, nprms)
5629 void LoadNextPositionProc(w, event, prms, nprms)
5638 void LoadPrevPositionProc(w, event, prms, nprms)
5647 void ReloadPositionProc(w, event, prms, nprms)
5656 void LoadPositionProc(w, event, prms, nprms)
5662 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5665 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5668 void SaveGameProc(w, event, prms, nprms)
5674 FileNamePopUp(_("Save game file name?"),
5675 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5679 void SavePositionProc(w, event, prms, nprms)
5685 FileNamePopUp(_("Save position file name?"),
5686 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5690 void ReloadCmailMsgProc(w, event, prms, nprms)
5696 ReloadCmailMsgEvent(FALSE);
5699 void MailMoveProc(w, event, prms, nprms)
5708 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5709 char *selected_fen_position=NULL;
5712 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5713 Atom *type_return, XtPointer *value_return,
5714 unsigned long *length_return, int *format_return)
5716 char *selection_tmp;
5718 if (!selected_fen_position) return False; /* should never happen */
5719 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5720 /* note: since no XtSelectionDoneProc was registered, Xt will
5721 * automatically call XtFree on the value returned. So have to
5722 * make a copy of it allocated with XtMalloc */
5723 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5724 safeStrCpy(selection_tmp, selected_fen_position, sizeof(selection_tmp)/sizeof(selection_tmp[0]) );
5726 *value_return=selection_tmp;
5727 *length_return=strlen(selection_tmp);
5728 *type_return=*target;
5729 *format_return = 8; /* bits per byte */
5731 } else if (*target == XA_TARGETS(xDisplay)) {
5732 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5733 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5734 targets_tmp[1] = XA_STRING;
5735 *value_return = targets_tmp;
5736 *type_return = XA_ATOM;
5738 *format_return = 8 * sizeof(Atom);
5739 if (*format_return > 32) {
5740 *length_return *= *format_return / 32;
5741 *format_return = 32;
5749 /* note: when called from menu all parameters are NULL, so no clue what the
5750 * Widget which was clicked on was, or what the click event was
5752 void CopyPositionProc(w, event, prms, nprms)
5759 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5760 * have a notion of a position that is selected but not copied.
5761 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5763 if(gameMode == EditPosition) EditPositionDone(TRUE);
5764 if (selected_fen_position) free(selected_fen_position);
5765 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5766 if (!selected_fen_position) return;
5767 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5769 SendPositionSelection,
5770 NULL/* lose_ownership_proc */ ,
5771 NULL/* transfer_done_proc */);
5772 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5774 SendPositionSelection,
5775 NULL/* lose_ownership_proc */ ,
5776 NULL/* transfer_done_proc */);
5779 /* function called when the data to Paste is ready */
5781 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5782 Atom *type, XtPointer value, unsigned long *len, int *format)
5785 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5786 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5787 EditPositionPasteFEN(fenstr);
5791 /* called when Paste Position button is pressed,
5792 * all parameters will be NULL */
5793 void PastePositionProc(w, event, prms, nprms)
5799 XtGetSelectionValue(menuBarWidget,
5800 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5801 /* (XtSelectionCallbackProc) */ PastePositionCB,
5802 NULL, /* client_data passed to PastePositionCB */
5804 /* better to use the time field from the event that triggered the
5805 * call to this function, but that isn't trivial to get
5813 SendGameSelection(Widget w, Atom *selection, Atom *target,
5814 Atom *type_return, XtPointer *value_return,
5815 unsigned long *length_return, int *format_return)
5817 char *selection_tmp;
5819 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5820 FILE* f = fopen(gameCopyFilename, "r");
5823 if (f == NULL) return False;
5827 selection_tmp = XtMalloc(len + 1);
5828 count = fread(selection_tmp, 1, len, f);
5830 XtFree(selection_tmp);
5833 selection_tmp[len] = NULLCHAR;
5834 *value_return = selection_tmp;
5835 *length_return = len;
5836 *type_return = *target;
5837 *format_return = 8; /* bits per byte */
5839 } else if (*target == XA_TARGETS(xDisplay)) {
5840 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5841 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5842 targets_tmp[1] = XA_STRING;
5843 *value_return = targets_tmp;
5844 *type_return = XA_ATOM;
5846 *format_return = 8 * sizeof(Atom);
5847 if (*format_return > 32) {
5848 *length_return *= *format_return / 32;
5849 *format_return = 32;
5857 /* note: when called from menu all parameters are NULL, so no clue what the
5858 * Widget which was clicked on was, or what the click event was
5860 void CopyGameProc(w, event, prms, nprms)
5868 ret = SaveGameToFile(gameCopyFilename, FALSE);
5872 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5873 * have a notion of a game that is selected but not copied.
5874 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5876 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5879 NULL/* lose_ownership_proc */ ,
5880 NULL/* transfer_done_proc */);
5881 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5884 NULL/* lose_ownership_proc */ ,
5885 NULL/* transfer_done_proc */);
5888 /* function called when the data to Paste is ready */
5890 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5891 Atom *type, XtPointer value, unsigned long *len, int *format)
5894 if (value == NULL || *len == 0) {
5895 return; /* nothing had been selected to copy */
5897 f = fopen(gamePasteFilename, "w");
5899 DisplayError(_("Can't open temp file"), errno);
5902 fwrite(value, 1, *len, f);
5905 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5908 /* called when Paste Game button is pressed,
5909 * all parameters will be NULL */
5910 void PasteGameProc(w, event, prms, nprms)
5916 XtGetSelectionValue(menuBarWidget,
5917 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5918 /* (XtSelectionCallbackProc) */ PasteGameCB,
5919 NULL, /* client_data passed to PasteGameCB */
5921 /* better to use the time field from the event that triggered the
5922 * call to this function, but that isn't trivial to get
5932 SaveGameProc(NULL, NULL, NULL, NULL);
5936 void QuitProc(w, event, prms, nprms)
5945 void PauseProc(w, event, prms, nprms)
5955 void MachineBlackProc(w, event, prms, nprms)
5961 MachineBlackEvent();
5964 void MachineWhiteProc(w, event, prms, nprms)
5970 MachineWhiteEvent();
5973 void AnalyzeModeProc(w, event, prms, nprms)
5981 if (!first.analysisSupport) {
5982 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5983 DisplayError(buf, 0);
5986 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5987 if (appData.icsActive) {
5988 if (gameMode != IcsObserving) {
5989 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5990 DisplayError(buf, 0);
5992 if (appData.icsEngineAnalyze) {
5993 if (appData.debugMode)
5994 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6000 /* if enable, use want disable icsEngineAnalyze */
6001 if (appData.icsEngineAnalyze) {
6006 appData.icsEngineAnalyze = TRUE;
6007 if (appData.debugMode)
6008 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6010 if (!appData.showThinking)
6011 ShowThinkingProc(w,event,prms,nprms);
6016 void AnalyzeFileProc(w, event, prms, nprms)
6022 if (!first.analysisSupport) {
6024 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6025 DisplayError(buf, 0);
6030 if (!appData.showThinking)
6031 ShowThinkingProc(w,event,prms,nprms);
6034 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6035 AnalysisPeriodicEvent(1);
6038 void TwoMachinesProc(w, event, prms, nprms)
6047 void IcsClientProc(w, event, prms, nprms)
6056 void EditGameProc(w, event, prms, nprms)
6065 void EditPositionProc(w, event, prms, nprms)
6071 EditPositionEvent();
6074 void TrainingProc(w, event, prms, nprms)
6083 void EditCommentProc(w, event, prms, nprms)
6090 EditCommentPopDown();
6096 void IcsInputBoxProc(w, event, prms, nprms)
6102 if (ICSInputBoxUp) {
6103 ICSInputBoxPopDown();
6109 void AcceptProc(w, event, prms, nprms)
6118 void DeclineProc(w, event, prms, nprms)
6127 void RematchProc(w, event, prms, nprms)
6136 void CallFlagProc(w, event, prms, nprms)
6145 void DrawProc(w, event, prms, nprms)
6154 void AbortProc(w, event, prms, nprms)
6163 void AdjournProc(w, event, prms, nprms)
6172 void ResignProc(w, event, prms, nprms)
6181 void AdjuWhiteProc(w, event, prms, nprms)
6187 UserAdjudicationEvent(+1);
6190 void AdjuBlackProc(w, event, prms, nprms)
6196 UserAdjudicationEvent(-1);
6199 void AdjuDrawProc(w, event, prms, nprms)
6205 UserAdjudicationEvent(0);
6208 void EnterKeyProc(w, event, prms, nprms)
6214 if (ICSInputBoxUp == True)
6218 void UpKeyProc(w, event, prms, nprms)
6223 { // [HGM] input: let up-arrow recall previous line from history
6230 if (!ICSInputBoxUp) return;
6231 edit = XtNameToWidget(ICSInputShell, "*form.text");
6233 XtSetArg(args[j], XtNstring, &val); j++;
6234 XtGetValues(edit, args, j);
6235 val = PrevInHistory(val);
6236 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6237 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6239 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6240 XawTextReplace(edit, 0, 0, &t);
6241 XawTextSetInsertionPoint(edit, 9999);
6245 void DownKeyProc(w, event, prms, nprms)
6250 { // [HGM] input: let down-arrow recall next line from history
6255 if (!ICSInputBoxUp) return;
6256 edit = XtNameToWidget(ICSInputShell, "*form.text");
6257 val = NextInHistory();
6258 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6259 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6261 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6262 XawTextReplace(edit, 0, 0, &t);
6263 XawTextSetInsertionPoint(edit, 9999);
6267 void StopObservingProc(w, event, prms, nprms)
6273 StopObservingEvent();
6276 void StopExaminingProc(w, event, prms, nprms)
6282 StopExaminingEvent();
6285 void UploadProc(w, event, prms, nprms)
6295 void ForwardProc(w, event, prms, nprms)
6305 void BackwardProc(w, event, prms, nprms)
6314 void ToStartProc(w, event, prms, nprms)
6323 void ToEndProc(w, event, prms, nprms)
6332 void RevertProc(w, event, prms, nprms)
6341 void AnnotateProc(w, event, prms, nprms)
6350 void TruncateGameProc(w, event, prms, nprms)
6356 TruncateGameEvent();
6358 void RetractMoveProc(w, event, prms, nprms)
6367 void MoveNowProc(w, event, prms, nprms)
6377 void AlwaysQueenProc(w, event, prms, nprms)
6385 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6387 if (appData.alwaysPromoteToQueen) {
6388 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6390 XtSetArg(args[0], XtNleftBitmap, None);
6392 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6396 void AnimateDraggingProc(w, event, prms, nprms)
6404 appData.animateDragging = !appData.animateDragging;
6406 if (appData.animateDragging) {
6407 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6410 XtSetArg(args[0], XtNleftBitmap, None);
6412 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6416 void AnimateMovingProc(w, event, prms, nprms)
6424 appData.animate = !appData.animate;
6426 if (appData.animate) {
6427 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6430 XtSetArg(args[0], XtNleftBitmap, None);
6432 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6436 void AutocommProc(w, event, prms, nprms)
6444 appData.autoComment = !appData.autoComment;
6446 if (appData.autoComment) {
6447 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6449 XtSetArg(args[0], XtNleftBitmap, None);
6451 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6456 void AutoflagProc(w, event, prms, nprms)
6464 appData.autoCallFlag = !appData.autoCallFlag;
6466 if (appData.autoCallFlag) {
6467 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6469 XtSetArg(args[0], XtNleftBitmap, None);
6471 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6475 void AutoflipProc(w, event, prms, nprms)
6483 appData.autoFlipView = !appData.autoFlipView;
6485 if (appData.autoFlipView) {
6486 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6488 XtSetArg(args[0], XtNleftBitmap, None);
6490 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6494 void AutobsProc(w, event, prms, nprms)
6502 appData.autoObserve = !appData.autoObserve;
6504 if (appData.autoObserve) {
6505 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6507 XtSetArg(args[0], XtNleftBitmap, None);
6509 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6513 void AutoraiseProc(w, event, prms, nprms)
6521 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6523 if (appData.autoRaiseBoard) {
6524 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6526 XtSetArg(args[0], XtNleftBitmap, None);
6528 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6532 void AutosaveProc(w, event, prms, nprms)
6540 appData.autoSaveGames = !appData.autoSaveGames;
6542 if (appData.autoSaveGames) {
6543 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6545 XtSetArg(args[0], XtNleftBitmap, None);
6547 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6551 void BlindfoldProc(w, event, prms, nprms)
6559 appData.blindfold = !appData.blindfold;
6561 if (appData.blindfold) {
6562 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6564 XtSetArg(args[0], XtNleftBitmap, None);
6566 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6569 DrawPosition(True, NULL);
6572 void TestLegalityProc(w, event, prms, nprms)
6580 appData.testLegality = !appData.testLegality;
6582 if (appData.testLegality) {
6583 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6585 XtSetArg(args[0], XtNleftBitmap, None);
6587 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6592 void FlashMovesProc(w, event, prms, nprms)
6600 if (appData.flashCount == 0) {
6601 appData.flashCount = 3;
6603 appData.flashCount = -appData.flashCount;
6606 if (appData.flashCount > 0) {
6607 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6609 XtSetArg(args[0], XtNleftBitmap, None);
6611 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6615 void FlipViewProc(w, event, prms, nprms)
6621 flipView = !flipView;
6622 DrawPosition(True, NULL);
6625 void GetMoveListProc(w, event, prms, nprms)
6633 appData.getMoveList = !appData.getMoveList;
6635 if (appData.getMoveList) {
6636 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6639 XtSetArg(args[0], XtNleftBitmap, None);
6641 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6646 void HighlightDraggingProc(w, event, prms, nprms)
6654 appData.highlightDragging = !appData.highlightDragging;
6656 if (appData.highlightDragging) {
6657 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6659 XtSetArg(args[0], XtNleftBitmap, None);
6661 XtSetValues(XtNameToWidget(menuBarWidget,
6662 "menuOptions.Highlight Dragging"), args, 1);
6666 void HighlightLastMoveProc(w, event, prms, nprms)
6674 appData.highlightLastMove = !appData.highlightLastMove;
6676 if (appData.highlightLastMove) {
6677 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6679 XtSetArg(args[0], XtNleftBitmap, None);
6681 XtSetValues(XtNameToWidget(menuBarWidget,
6682 "menuOptions.Highlight Last Move"), args, 1);
6685 void IcsAlarmProc(w, event, prms, nprms)
6693 appData.icsAlarm = !appData.icsAlarm;
6695 if (appData.icsAlarm) {
6696 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6698 XtSetArg(args[0], XtNleftBitmap, None);
6700 XtSetValues(XtNameToWidget(menuBarWidget,
6701 "menuOptions.ICS Alarm"), args, 1);
6704 void MoveSoundProc(w, event, prms, nprms)
6712 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6714 if (appData.ringBellAfterMoves) {
6715 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6717 XtSetArg(args[0], XtNleftBitmap, None);
6719 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6724 void OldSaveStyleProc(w, event, prms, nprms)
6732 appData.oldSaveStyle = !appData.oldSaveStyle;
6734 if (appData.oldSaveStyle) {
6735 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6737 XtSetArg(args[0], XtNleftBitmap, None);
6739 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6743 void PeriodicUpdatesProc(w, event, prms, nprms)
6751 PeriodicUpdatesEvent(!appData.periodicUpdates);
6753 if (appData.periodicUpdates) {
6754 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6756 XtSetArg(args[0], XtNleftBitmap, None);
6758 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6762 void PonderNextMoveProc(w, event, prms, nprms)
6770 PonderNextMoveEvent(!appData.ponderNextMove);
6772 if (appData.ponderNextMove) {
6773 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6775 XtSetArg(args[0], XtNleftBitmap, None);
6777 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6781 void PopupExitMessageProc(w, event, prms, nprms)
6789 appData.popupExitMessage = !appData.popupExitMessage;
6791 if (appData.popupExitMessage) {
6792 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6794 XtSetArg(args[0], XtNleftBitmap, None);
6796 XtSetValues(XtNameToWidget(menuBarWidget,
6797 "menuOptions.Popup Exit Message"), args, 1);
6800 void PopupMoveErrorsProc(w, event, prms, nprms)
6808 appData.popupMoveErrors = !appData.popupMoveErrors;
6810 if (appData.popupMoveErrors) {
6811 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6813 XtSetArg(args[0], XtNleftBitmap, None);
6815 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6819 void PremoveProc(w, event, prms, nprms)
6827 appData.premove = !appData.premove;
6829 if (appData.premove) {
6830 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6832 XtSetArg(args[0], XtNleftBitmap, None);
6834 XtSetValues(XtNameToWidget(menuBarWidget,
6835 "menuOptions.Premove"), args, 1);
6838 void QuietPlayProc(w, event, prms, nprms)
6846 appData.quietPlay = !appData.quietPlay;
6848 if (appData.quietPlay) {
6849 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6851 XtSetArg(args[0], XtNleftBitmap, None);
6853 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6857 void ShowCoordsProc(w, event, prms, nprms)
6865 appData.showCoords = !appData.showCoords;
6867 if (appData.showCoords) {
6868 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6870 XtSetArg(args[0], XtNleftBitmap, None);
6872 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6875 DrawPosition(True, NULL);
6878 void ShowThinkingProc(w, event, prms, nprms)
6884 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6885 ShowThinkingEvent();
6888 void HideThinkingProc(w, event, prms, nprms)
6896 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6897 ShowThinkingEvent();
6899 if (appData.hideThinkingFromHuman) {
6900 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6902 XtSetArg(args[0], XtNleftBitmap, None);
6904 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6908 void SaveOnExitProc(w, event, prms, nprms)
6916 saveSettingsOnExit = !saveSettingsOnExit;
6918 if (saveSettingsOnExit) {
6919 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6921 XtSetArg(args[0], XtNleftBitmap, None);
6923 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6927 void SaveSettingsProc(w, event, prms, nprms)
6933 SaveSettings(settingsFileName);
6936 void InfoProc(w, event, prms, nprms)
6943 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6948 void ManProc(w, event, prms, nprms)
6956 if (nprms && *nprms > 0)
6960 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6964 void HintProc(w, event, prms, nprms)
6973 void BookProc(w, event, prms, nprms)
6982 void AboutProc(w, event, prms, nprms)
6990 char *zippy = " (with Zippy code)";
6994 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6995 programVersion, zippy,
6996 "Copyright 1991 Digital Equipment Corporation",
6997 "Enhancements Copyright 1992-2009 Free Software Foundation",
6998 "Enhancements Copyright 2005 Alessandro Scotti",
6999 PACKAGE, " is free software and carries NO WARRANTY;",
7000 "see the file COPYING for more information.");
7001 ErrorPopUp(_("About XBoard"), buf, FALSE);
7004 void DebugProc(w, event, prms, nprms)
7010 appData.debugMode = !appData.debugMode;
7013 void AboutGameProc(w, event, prms, nprms)
7022 void NothingProc(w, event, prms, nprms)
7031 void Iconify(w, event, prms, nprms)
7040 XtSetArg(args[0], XtNiconic, True);
7041 XtSetValues(shellWidget, args, 1);
7044 void DisplayMessage(message, extMessage)
7045 char *message, *extMessage;
7047 /* display a message in the message widget */
7056 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7061 message = extMessage;
7065 /* need to test if messageWidget already exists, since this function
7066 can also be called during the startup, if for example a Xresource
7067 is not set up correctly */
7070 XtSetArg(arg, XtNlabel, message);
7071 XtSetValues(messageWidget, &arg, 1);
7077 void DisplayTitle(text)
7082 char title[MSG_SIZ];
7085 if (text == NULL) text = "";
7087 if (appData.titleInWindow) {
7089 XtSetArg(args[i], XtNlabel, text); i++;
7090 XtSetValues(titleWidget, args, i);
7093 if (*text != NULLCHAR) {
7094 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7095 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7096 } else if (appData.icsActive) {
7097 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7098 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7099 } else if (appData.cmailGameName[0] != NULLCHAR) {
7100 snprintf(icon, sizeof(icon), "%s", "CMail");
7101 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7103 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7104 } else if (gameInfo.variant == VariantGothic) {
7105 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7106 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7109 } else if (gameInfo.variant == VariantFalcon) {
7110 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7111 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7113 } else if (appData.noChessProgram) {
7114 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7115 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7117 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7118 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7121 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7122 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7123 XtSetValues(shellWidget, args, i);
7128 DisplayError(message, error)
7135 if (appData.debugMode || appData.matchMode) {
7136 fprintf(stderr, "%s: %s\n", programName, message);
7139 if (appData.debugMode || appData.matchMode) {
7140 fprintf(stderr, "%s: %s: %s\n",
7141 programName, message, strerror(error));
7143 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7146 ErrorPopUp(_("Error"), message, FALSE);
7150 void DisplayMoveError(message)
7155 DrawPosition(FALSE, NULL);
7156 if (appData.debugMode || appData.matchMode) {
7157 fprintf(stderr, "%s: %s\n", programName, message);
7159 if (appData.popupMoveErrors) {
7160 ErrorPopUp(_("Error"), message, FALSE);
7162 DisplayMessage(message, "");
7167 void DisplayFatalError(message, error, status)
7173 errorExitStatus = status;
7175 fprintf(stderr, "%s: %s\n", programName, message);
7177 fprintf(stderr, "%s: %s: %s\n",
7178 programName, message, strerror(error));
7179 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7182 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7183 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7189 void DisplayInformation(message)
7193 ErrorPopUp(_("Information"), message, TRUE);
7196 void DisplayNote(message)
7200 ErrorPopUp(_("Note"), message, FALSE);
7204 NullXErrorCheck(dpy, error_event)
7206 XErrorEvent *error_event;
7211 void DisplayIcsInteractionTitle(message)
7214 if (oldICSInteractionTitle == NULL) {
7215 /* Magic to find the old window title, adapted from vim */
7216 char *wina = getenv("WINDOWID");
7218 Window win = (Window) atoi(wina);
7219 Window root, parent, *children;
7220 unsigned int nchildren;
7221 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7223 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7224 if (!XQueryTree(xDisplay, win, &root, &parent,
7225 &children, &nchildren)) break;
7226 if (children) XFree((void *)children);
7227 if (parent == root || parent == 0) break;
7230 XSetErrorHandler(oldHandler);
7232 if (oldICSInteractionTitle == NULL) {
7233 oldICSInteractionTitle = "xterm";
7236 printf("\033]0;%s\007", message);
7240 char pendingReplyPrefix[MSG_SIZ];
7241 ProcRef pendingReplyPR;
7243 void AskQuestionProc(w, event, prms, nprms)
7250 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7254 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7257 void AskQuestionPopDown()
7259 if (!askQuestionUp) return;
7260 XtPopdown(askQuestionShell);
7261 XtDestroyWidget(askQuestionShell);
7262 askQuestionUp = False;
7265 void AskQuestionReplyAction(w, event, prms, nprms)
7275 reply = XawDialogGetValueString(w = XtParent(w));
7276 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7277 if (*buf) strcat(buf, " ");
7280 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7281 AskQuestionPopDown();
7283 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7286 void AskQuestionCallback(w, client_data, call_data)
7288 XtPointer client_data, call_data;
7293 XtSetArg(args[0], XtNlabel, &name);
7294 XtGetValues(w, args, 1);
7296 if (strcmp(name, _("cancel")) == 0) {
7297 AskQuestionPopDown();
7299 AskQuestionReplyAction(w, NULL, NULL, NULL);
7303 void AskQuestion(title, question, replyPrefix, pr)
7304 char *title, *question, *replyPrefix;
7308 Widget popup, layout, dialog, edit;
7314 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7315 pendingReplyPR = pr;
7318 XtSetArg(args[i], XtNresizable, True); i++;
7319 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7320 askQuestionShell = popup =
7321 XtCreatePopupShell(title, transientShellWidgetClass,
7322 shellWidget, args, i);
7325 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7326 layoutArgs, XtNumber(layoutArgs));
7329 XtSetArg(args[i], XtNlabel, question); i++;
7330 XtSetArg(args[i], XtNvalue, ""); i++;
7331 XtSetArg(args[i], XtNborderWidth, 0); i++;
7332 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7335 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7336 (XtPointer) dialog);
7337 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7338 (XtPointer) dialog);
7340 XtRealizeWidget(popup);
7341 CatchDeleteWindow(popup, "AskQuestionPopDown");
7343 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7344 &x, &y, &win_x, &win_y, &mask);
7346 XtSetArg(args[0], XtNx, x - 10);
7347 XtSetArg(args[1], XtNy, y - 30);
7348 XtSetValues(popup, args, 2);
7350 XtPopup(popup, XtGrabExclusive);
7351 askQuestionUp = True;
7353 edit = XtNameToWidget(dialog, "*value");
7354 XtSetKeyboardFocus(popup, edit);
7362 if (*name == NULLCHAR) {
7364 } else if (strcmp(name, "$") == 0) {
7365 putc(BELLCHAR, stderr);
7368 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7376 PlaySound(appData.soundMove);
7382 PlaySound(appData.soundIcsWin);
7388 PlaySound(appData.soundIcsLoss);
7394 PlaySound(appData.soundIcsDraw);
7398 PlayIcsUnfinishedSound()
7400 PlaySound(appData.soundIcsUnfinished);
7406 PlaySound(appData.soundIcsAlarm);
7412 system("stty echo");
7418 system("stty -echo");
7422 Colorize(cc, continuation)
7427 int count, outCount, error;
7429 if (textColors[(int)cc].bg > 0) {
7430 if (textColors[(int)cc].fg > 0) {
7431 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7432 textColors[(int)cc].fg, textColors[(int)cc].bg);
7434 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7435 textColors[(int)cc].bg);
7438 if (textColors[(int)cc].fg > 0) {
7439 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7440 textColors[(int)cc].fg);
7442 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7445 count = strlen(buf);
7446 outCount = OutputToProcess(NoProc, buf, count, &error);
7447 if (outCount < count) {
7448 DisplayFatalError(_("Error writing to display"), error, 1);
7451 if (continuation) return;
7454 PlaySound(appData.soundShout);
7457 PlaySound(appData.soundSShout);
7460 PlaySound(appData.soundChannel1);
7463 PlaySound(appData.soundChannel);
7466 PlaySound(appData.soundKibitz);
7469 PlaySound(appData.soundTell);
7471 case ColorChallenge:
7472 PlaySound(appData.soundChallenge);
7475 PlaySound(appData.soundRequest);
7478 PlaySound(appData.soundSeek);
7489 return getpwuid(getuid())->pw_name;
7493 ExpandPathName(path)
7496 static char static_buf[4*MSG_SIZ];
7497 char *d, *s, buf[4*MSG_SIZ];
7503 while (*s && isspace(*s))
7512 if (*(s+1) == '/') {
7513 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7517 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7518 *strchr(buf, '/') = 0;
7519 pwd = getpwnam(buf);
7522 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7526 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7527 strcat(d, strchr(s+1, '/'));
7531 safeStrCpy(d, s, 4*MSG_SIZ );
7538 static char host_name[MSG_SIZ];
7540 #if HAVE_GETHOSTNAME
7541 gethostname(host_name, MSG_SIZ);
7543 #else /* not HAVE_GETHOSTNAME */
7544 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7545 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7547 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7549 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7550 #endif /* not HAVE_GETHOSTNAME */
7553 XtIntervalId delayedEventTimerXID = 0;
7554 DelayedEventCallback delayedEventCallback = 0;
7559 delayedEventTimerXID = 0;
7560 delayedEventCallback();
7564 ScheduleDelayedEvent(cb, millisec)
7565 DelayedEventCallback cb; long millisec;
7567 if(delayedEventTimerXID && delayedEventCallback == cb)
7568 // [HGM] alive: replace, rather than add or flush identical event
7569 XtRemoveTimeOut(delayedEventTimerXID);
7570 delayedEventCallback = cb;
7571 delayedEventTimerXID =
7572 XtAppAddTimeOut(appContext, millisec,
7573 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7576 DelayedEventCallback
7579 if (delayedEventTimerXID) {
7580 return delayedEventCallback;
7587 CancelDelayedEvent()
7589 if (delayedEventTimerXID) {
7590 XtRemoveTimeOut(delayedEventTimerXID);
7591 delayedEventTimerXID = 0;
7595 XtIntervalId loadGameTimerXID = 0;
7597 int LoadGameTimerRunning()
7599 return loadGameTimerXID != 0;
7602 int StopLoadGameTimer()
7604 if (loadGameTimerXID != 0) {
7605 XtRemoveTimeOut(loadGameTimerXID);
7606 loadGameTimerXID = 0;
7614 LoadGameTimerCallback(arg, id)
7618 loadGameTimerXID = 0;
7623 StartLoadGameTimer(millisec)
7627 XtAppAddTimeOut(appContext, millisec,
7628 (XtTimerCallbackProc) LoadGameTimerCallback,
7632 XtIntervalId analysisClockXID = 0;
7635 AnalysisClockCallback(arg, id)
7639 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7640 || appData.icsEngineAnalyze) { // [DM]
7641 AnalysisPeriodicEvent(0);
7642 StartAnalysisClock();
7647 StartAnalysisClock()
7650 XtAppAddTimeOut(appContext, 2000,
7651 (XtTimerCallbackProc) AnalysisClockCallback,
7655 XtIntervalId clockTimerXID = 0;
7657 int ClockTimerRunning()
7659 return clockTimerXID != 0;
7662 int StopClockTimer()
7664 if (clockTimerXID != 0) {
7665 XtRemoveTimeOut(clockTimerXID);
7674 ClockTimerCallback(arg, id)
7683 StartClockTimer(millisec)
7687 XtAppAddTimeOut(appContext, millisec,
7688 (XtTimerCallbackProc) ClockTimerCallback,
7693 DisplayTimerLabel(w, color, timer, highlight)
7702 /* check for low time warning */
7703 Pixel foregroundOrWarningColor = timerForegroundPixel;
7706 appData.lowTimeWarning &&
7707 (timer / 1000) < appData.icsAlarmTime)
7708 foregroundOrWarningColor = lowTimeWarningColor;
7710 if (appData.clockMode) {
7711 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7712 XtSetArg(args[0], XtNlabel, buf);
7714 snprintf(buf, MSG_SIZ, "%s ", color);
7715 XtSetArg(args[0], XtNlabel, buf);
7720 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7721 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7723 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7724 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7727 XtSetValues(w, args, 3);
7731 DisplayWhiteClock(timeRemaining, highlight)
7737 if(appData.noGUI) return;
7738 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7739 if (highlight && iconPixmap == bIconPixmap) {
7740 iconPixmap = wIconPixmap;
7741 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7742 XtSetValues(shellWidget, args, 1);
7747 DisplayBlackClock(timeRemaining, highlight)
7753 if(appData.noGUI) return;
7754 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7755 if (highlight && iconPixmap == wIconPixmap) {
7756 iconPixmap = bIconPixmap;
7757 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7758 XtSetValues(shellWidget, args, 1);
7776 int StartChildProcess(cmdLine, dir, pr)
7783 int to_prog[2], from_prog[2];
7787 if (appData.debugMode) {
7788 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7791 /* We do NOT feed the cmdLine to the shell; we just
7792 parse it into blank-separated arguments in the
7793 most simple-minded way possible.
7796 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7799 while(*p == ' ') p++;
7801 if(*p == '"' || *p == '\'')
7802 p = strchr(++argv[i-1], *p);
7803 else p = strchr(p, ' ');
7804 if (p == NULL) break;
7809 SetUpChildIO(to_prog, from_prog);
7811 if ((pid = fork()) == 0) {
7813 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7814 close(to_prog[1]); // first close the unused pipe ends
7815 close(from_prog[0]);
7816 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7817 dup2(from_prog[1], 1);
7818 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7819 close(from_prog[1]); // and closing again loses one of the pipes!
7820 if(fileno(stderr) >= 2) // better safe than sorry...
7821 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7823 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7828 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7830 execvp(argv[0], argv);
7832 /* If we get here, exec failed */
7837 /* Parent process */
7839 close(from_prog[1]);
7841 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7844 cp->fdFrom = from_prog[0];
7845 cp->fdTo = to_prog[1];
7850 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7851 static RETSIGTYPE AlarmCallBack(int n)
7857 DestroyChildProcess(pr, signalType)
7861 ChildProc *cp = (ChildProc *) pr;
7863 if (cp->kind != CPReal) return;
7865 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7866 signal(SIGALRM, AlarmCallBack);
7868 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7869 kill(cp->pid, SIGKILL); // kill it forcefully
7870 wait((int *) 0); // and wait again
7874 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7876 /* Process is exiting either because of the kill or because of
7877 a quit command sent by the backend; either way, wait for it to die.
7886 InterruptChildProcess(pr)
7889 ChildProc *cp = (ChildProc *) pr;
7891 if (cp->kind != CPReal) return;
7892 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7895 int OpenTelnet(host, port, pr)
7900 char cmdLine[MSG_SIZ];
7902 if (port[0] == NULLCHAR) {
7903 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7905 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7907 return StartChildProcess(cmdLine, "", pr);
7910 int OpenTCP(host, port, pr)
7916 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7917 #else /* !OMIT_SOCKETS */
7919 struct sockaddr_in sa;
7921 unsigned short uport;
7924 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7928 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7929 sa.sin_family = AF_INET;
7930 sa.sin_addr.s_addr = INADDR_ANY;
7931 uport = (unsigned short) 0;
7932 sa.sin_port = htons(uport);
7933 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7937 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7938 if (!(hp = gethostbyname(host))) {
7940 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7941 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7942 hp->h_addrtype = AF_INET;
7944 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7945 hp->h_addr_list[0] = (char *) malloc(4);
7946 hp->h_addr_list[0][0] = b0;
7947 hp->h_addr_list[0][1] = b1;
7948 hp->h_addr_list[0][2] = b2;
7949 hp->h_addr_list[0][3] = b3;
7954 sa.sin_family = hp->h_addrtype;
7955 uport = (unsigned short) atoi(port);
7956 sa.sin_port = htons(uport);
7957 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7959 if (connect(s, (struct sockaddr *) &sa,
7960 sizeof(struct sockaddr_in)) < 0) {
7964 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7971 #endif /* !OMIT_SOCKETS */
7976 int OpenCommPort(name, pr)
7983 fd = open(name, 2, 0);
7984 if (fd < 0) return errno;
7986 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7996 int OpenLoopback(pr)
8002 SetUpChildIO(to, from);
8004 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8007 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8014 int OpenRcmd(host, user, cmd, pr)
8015 char *host, *user, *cmd;
8018 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8022 #define INPUT_SOURCE_BUF_SIZE 8192
8031 char buf[INPUT_SOURCE_BUF_SIZE];
8036 DoInputCallback(closure, source, xid)
8041 InputSource *is = (InputSource *) closure;
8046 if (is->lineByLine) {
8047 count = read(is->fd, is->unused,
8048 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8050 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8053 is->unused += count;
8055 while (p < is->unused) {
8056 q = memchr(p, '\n', is->unused - p);
8057 if (q == NULL) break;
8059 (is->func)(is, is->closure, p, q - p, 0);
8063 while (p < is->unused) {
8068 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8073 (is->func)(is, is->closure, is->buf, count, error);
8077 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8084 ChildProc *cp = (ChildProc *) pr;
8086 is = (InputSource *) calloc(1, sizeof(InputSource));
8087 is->lineByLine = lineByLine;
8091 is->fd = fileno(stdin);
8093 is->kind = cp->kind;
8094 is->fd = cp->fdFrom;
8097 is->unused = is->buf;
8100 is->xid = XtAppAddInput(appContext, is->fd,
8101 (XtPointer) (XtInputReadMask),
8102 (XtInputCallbackProc) DoInputCallback,
8104 is->closure = closure;
8105 return (InputSourceRef) is;
8109 RemoveInputSource(isr)
8112 InputSource *is = (InputSource *) isr;
8114 if (is->xid == 0) return;
8115 XtRemoveInput(is->xid);
8119 int OutputToProcess(pr, message, count, outError)
8125 static int line = 0;
8126 ChildProc *cp = (ChildProc *) pr;
8131 if (appData.noJoin || !appData.useInternalWrap)
8132 outCount = fwrite(message, 1, count, stdout);
8135 int width = get_term_width();
8136 int len = wrap(NULL, message, count, width, &line);
8137 char *msg = malloc(len);
8141 outCount = fwrite(message, 1, count, stdout);
8144 dbgchk = wrap(msg, message, count, width, &line);
8145 if (dbgchk != len && appData.debugMode)
8146 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8147 outCount = fwrite(msg, 1, dbgchk, stdout);
8153 outCount = write(cp->fdTo, message, count);
8163 /* Output message to process, with "ms" milliseconds of delay
8164 between each character. This is needed when sending the logon
8165 script to ICC, which for some reason doesn't like the
8166 instantaneous send. */
8167 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8174 ChildProc *cp = (ChildProc *) pr;
8179 r = write(cp->fdTo, message++, 1);
8192 /**** Animation code by Hugh Fisher, DCS, ANU.
8194 Known problem: if a window overlapping the board is
8195 moved away while a piece is being animated underneath,
8196 the newly exposed area won't be updated properly.
8197 I can live with this.
8199 Known problem: if you look carefully at the animation
8200 of pieces in mono mode, they are being drawn as solid
8201 shapes without interior detail while moving. Fixing
8202 this would be a major complication for minimal return.
8205 /* Masks for XPM pieces. Black and white pieces can have
8206 different shapes, but in the interest of retaining my
8207 sanity pieces must have the same outline on both light
8208 and dark squares, and all pieces must use the same
8209 background square colors/images. */
8211 static int xpmDone = 0;
8214 CreateAnimMasks (pieceDepth)
8221 unsigned long plane;
8224 /* Need a bitmap just to get a GC with right depth */
8225 buf = XCreatePixmap(xDisplay, xBoardWindow,
8227 values.foreground = 1;
8228 values.background = 0;
8229 /* Don't use XtGetGC, not read only */
8230 maskGC = XCreateGC(xDisplay, buf,
8231 GCForeground | GCBackground, &values);
8232 XFreePixmap(xDisplay, buf);
8234 buf = XCreatePixmap(xDisplay, xBoardWindow,
8235 squareSize, squareSize, pieceDepth);
8236 values.foreground = XBlackPixel(xDisplay, xScreen);
8237 values.background = XWhitePixel(xDisplay, xScreen);
8238 bufGC = XCreateGC(xDisplay, buf,
8239 GCForeground | GCBackground, &values);
8241 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8242 /* Begin with empty mask */
8243 if(!xpmDone) // [HGM] pieces: keep using existing
8244 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8245 squareSize, squareSize, 1);
8246 XSetFunction(xDisplay, maskGC, GXclear);
8247 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8248 0, 0, squareSize, squareSize);
8250 /* Take a copy of the piece */
8255 XSetFunction(xDisplay, bufGC, GXcopy);
8256 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8258 0, 0, squareSize, squareSize, 0, 0);
8260 /* XOR the background (light) over the piece */
8261 XSetFunction(xDisplay, bufGC, GXxor);
8263 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8264 0, 0, squareSize, squareSize, 0, 0);
8266 XSetForeground(xDisplay, bufGC, lightSquareColor);
8267 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8270 /* We now have an inverted piece image with the background
8271 erased. Construct mask by just selecting all the non-zero
8272 pixels - no need to reconstruct the original image. */
8273 XSetFunction(xDisplay, maskGC, GXor);
8275 /* Might be quicker to download an XImage and create bitmap
8276 data from it rather than this N copies per piece, but it
8277 only takes a fraction of a second and there is a much
8278 longer delay for loading the pieces. */
8279 for (n = 0; n < pieceDepth; n ++) {
8280 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8281 0, 0, squareSize, squareSize,
8287 XFreePixmap(xDisplay, buf);
8288 XFreeGC(xDisplay, bufGC);
8289 XFreeGC(xDisplay, maskGC);
8293 InitAnimState (anim, info)
8295 XWindowAttributes * info;
8300 /* Each buffer is square size, same depth as window */
8301 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8302 squareSize, squareSize, info->depth);
8303 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8304 squareSize, squareSize, info->depth);
8306 /* Create a plain GC for blitting */
8307 mask = GCForeground | GCBackground | GCFunction |
8308 GCPlaneMask | GCGraphicsExposures;
8309 values.foreground = XBlackPixel(xDisplay, xScreen);
8310 values.background = XWhitePixel(xDisplay, xScreen);
8311 values.function = GXcopy;
8312 values.plane_mask = AllPlanes;
8313 values.graphics_exposures = False;
8314 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8316 /* Piece will be copied from an existing context at
8317 the start of each new animation/drag. */
8318 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8320 /* Outline will be a read-only copy of an existing */
8321 anim->outlineGC = None;
8327 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8328 XWindowAttributes info;
8330 if (xpmDone && gameInfo.variant == old) return;
8331 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8332 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8334 InitAnimState(&game, &info);
8335 InitAnimState(&player, &info);
8337 /* For XPM pieces, we need bitmaps to use as masks. */
8339 CreateAnimMasks(info.depth);
8345 static Boolean frameWaiting;
8347 static RETSIGTYPE FrameAlarm (sig)
8350 frameWaiting = False;
8351 /* In case System-V style signals. Needed?? */
8352 signal(SIGALRM, FrameAlarm);
8359 struct itimerval delay;
8361 XSync(xDisplay, False);
8364 frameWaiting = True;
8365 signal(SIGALRM, FrameAlarm);
8366 delay.it_interval.tv_sec =
8367 delay.it_value.tv_sec = time / 1000;
8368 delay.it_interval.tv_usec =
8369 delay.it_value.tv_usec = (time % 1000) * 1000;
8370 setitimer(ITIMER_REAL, &delay, NULL);
8371 while (frameWaiting) pause();
8372 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8373 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8374 setitimer(ITIMER_REAL, &delay, NULL);
8384 XSync(xDisplay, False);
8386 usleep(time * 1000);
8391 /* Convert board position to corner of screen rect and color */
8394 ScreenSquare(column, row, pt, color)
8395 int column; int row; XPoint * pt; int * color;
8398 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8399 pt->y = lineGap + row * (squareSize + lineGap);
8401 pt->x = lineGap + column * (squareSize + lineGap);
8402 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8404 *color = SquareColor(row, column);
8407 /* Convert window coords to square */
8410 BoardSquare(x, y, column, row)
8411 int x; int y; int * column; int * row;
8413 *column = EventToSquare(x, BOARD_WIDTH);
8414 if (flipView && *column >= 0)
8415 *column = BOARD_WIDTH - 1 - *column;
8416 *row = EventToSquare(y, BOARD_HEIGHT);
8417 if (!flipView && *row >= 0)
8418 *row = BOARD_HEIGHT - 1 - *row;
8423 #undef Max /* just in case */
8425 #define Max(a, b) ((a) > (b) ? (a) : (b))
8426 #define Min(a, b) ((a) < (b) ? (a) : (b))
8429 SetRect(rect, x, y, width, height)
8430 XRectangle * rect; int x; int y; int width; int height;
8434 rect->width = width;
8435 rect->height = height;
8438 /* Test if two frames overlap. If they do, return
8439 intersection rect within old and location of
8440 that rect within new. */
8443 Intersect(old, new, size, area, pt)
8444 XPoint * old; XPoint * new;
8445 int size; XRectangle * area; XPoint * pt;
8447 if (old->x > new->x + size || new->x > old->x + size ||
8448 old->y > new->y + size || new->y > old->y + size) {
8451 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8452 size - abs(old->x - new->x), size - abs(old->y - new->y));
8453 pt->x = Max(old->x - new->x, 0);
8454 pt->y = Max(old->y - new->y, 0);
8459 /* For two overlapping frames, return the rect(s)
8460 in the old that do not intersect with the new. */
8463 CalcUpdateRects(old, new, size, update, nUpdates)
8464 XPoint * old; XPoint * new; int size;
8465 XRectangle update[]; int * nUpdates;
8469 /* If old = new (shouldn't happen) then nothing to draw */
8470 if (old->x == new->x && old->y == new->y) {
8474 /* Work out what bits overlap. Since we know the rects
8475 are the same size we don't need a full intersect calc. */
8477 /* Top or bottom edge? */
8478 if (new->y > old->y) {
8479 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8481 } else if (old->y > new->y) {
8482 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8483 size, old->y - new->y);
8486 /* Left or right edge - don't overlap any update calculated above. */
8487 if (new->x > old->x) {
8488 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8489 new->x - old->x, size - abs(new->y - old->y));
8491 } else if (old->x > new->x) {
8492 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8493 old->x - new->x, size - abs(new->y - old->y));
8500 /* Generate a series of frame coords from start->mid->finish.
8501 The movement rate doubles until the half way point is
8502 reached, then halves back down to the final destination,
8503 which gives a nice slow in/out effect. The algorithmn
8504 may seem to generate too many intermediates for short
8505 moves, but remember that the purpose is to attract the
8506 viewers attention to the piece about to be moved and
8507 then to where it ends up. Too few frames would be less
8511 Tween(start, mid, finish, factor, frames, nFrames)
8512 XPoint * start; XPoint * mid;
8513 XPoint * finish; int factor;
8514 XPoint frames[]; int * nFrames;
8516 int fraction, n, count;
8520 /* Slow in, stepping 1/16th, then 1/8th, ... */
8522 for (n = 0; n < factor; n++)
8524 for (n = 0; n < factor; n++) {
8525 frames[count].x = start->x + (mid->x - start->x) / fraction;
8526 frames[count].y = start->y + (mid->y - start->y) / fraction;
8528 fraction = fraction / 2;
8532 frames[count] = *mid;
8535 /* Slow out, stepping 1/2, then 1/4, ... */
8537 for (n = 0; n < factor; n++) {
8538 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8539 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8541 fraction = fraction * 2;
8546 /* Draw a piece on the screen without disturbing what's there */
8549 SelectGCMask(piece, clip, outline, mask)
8550 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8554 /* Bitmap for piece being moved. */
8555 if (appData.monoMode) {
8556 *mask = *pieceToSolid(piece);
8557 } else if (useImages) {
8559 *mask = xpmMask[piece];
8561 *mask = ximMaskPm[piece];
8564 *mask = *pieceToSolid(piece);
8567 /* GC for piece being moved. Square color doesn't matter, but
8568 since it gets modified we make a copy of the original. */
8570 if (appData.monoMode)
8575 if (appData.monoMode)
8580 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8582 /* Outline only used in mono mode and is not modified */
8584 *outline = bwPieceGC;
8586 *outline = wbPieceGC;
8590 OverlayPiece(piece, clip, outline, dest)
8591 ChessSquare piece; GC clip; GC outline; Drawable dest;
8596 /* Draw solid rectangle which will be clipped to shape of piece */
8597 XFillRectangle(xDisplay, dest, clip,
8598 0, 0, squareSize, squareSize);
8599 if (appData.monoMode)
8600 /* Also draw outline in contrasting color for black
8601 on black / white on white cases */
8602 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8603 0, 0, squareSize, squareSize, 0, 0, 1);
8605 /* Copy the piece */
8610 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8612 0, 0, squareSize, squareSize,
8617 /* Animate the movement of a single piece */
8620 BeginAnimation(anim, piece, startColor, start)
8628 /* The old buffer is initialised with the start square (empty) */
8629 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8630 anim->prevFrame = *start;
8632 /* The piece will be drawn using its own bitmap as a matte */
8633 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8634 XSetClipMask(xDisplay, anim->pieceGC, mask);
8638 AnimationFrame(anim, frame, piece)
8643 XRectangle updates[4];
8648 /* Save what we are about to draw into the new buffer */
8649 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8650 frame->x, frame->y, squareSize, squareSize,
8653 /* Erase bits of the previous frame */
8654 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8655 /* Where the new frame overlapped the previous,
8656 the contents in newBuf are wrong. */
8657 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8658 overlap.x, overlap.y,
8659 overlap.width, overlap.height,
8661 /* Repaint the areas in the old that don't overlap new */
8662 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8663 for (i = 0; i < count; i++)
8664 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8665 updates[i].x - anim->prevFrame.x,
8666 updates[i].y - anim->prevFrame.y,
8667 updates[i].width, updates[i].height,
8668 updates[i].x, updates[i].y);
8670 /* Easy when no overlap */
8671 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8672 0, 0, squareSize, squareSize,
8673 anim->prevFrame.x, anim->prevFrame.y);
8676 /* Save this frame for next time round */
8677 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8678 0, 0, squareSize, squareSize,
8680 anim->prevFrame = *frame;
8682 /* Draw piece over original screen contents, not current,
8683 and copy entire rect. Wipes out overlapping piece images. */
8684 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8685 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8686 0, 0, squareSize, squareSize,
8687 frame->x, frame->y);
8691 EndAnimation (anim, finish)
8695 XRectangle updates[4];
8700 /* The main code will redraw the final square, so we
8701 only need to erase the bits that don't overlap. */
8702 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8703 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8704 for (i = 0; i < count; i++)
8705 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8706 updates[i].x - anim->prevFrame.x,
8707 updates[i].y - anim->prevFrame.y,
8708 updates[i].width, updates[i].height,
8709 updates[i].x, updates[i].y);
8711 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8712 0, 0, squareSize, squareSize,
8713 anim->prevFrame.x, anim->prevFrame.y);
8718 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8720 ChessSquare piece; int startColor;
8721 XPoint * start; XPoint * finish;
8722 XPoint frames[]; int nFrames;
8726 BeginAnimation(anim, piece, startColor, start);
8727 for (n = 0; n < nFrames; n++) {
8728 AnimationFrame(anim, &(frames[n]), piece);
8729 FrameDelay(appData.animSpeed);
8731 EndAnimation(anim, finish);
8734 /* Main control logic for deciding what to animate and how */
8737 AnimateMove(board, fromX, fromY, toX, toY)
8746 XPoint start, finish, mid;
8747 XPoint frames[kFactor * 2 + 1];
8748 int nFrames, startColor, endColor;
8750 /* Are we animating? */
8751 if (!appData.animate || appData.blindfold)
8754 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8755 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8756 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8758 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8759 piece = board[fromY][fromX];
8760 if (piece >= EmptySquare) return;
8765 hop = (piece == WhiteKnight || piece == BlackKnight);
8768 if (appData.debugMode) {
8769 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8770 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8771 piece, fromX, fromY, toX, toY); }
8773 ScreenSquare(fromX, fromY, &start, &startColor);
8774 ScreenSquare(toX, toY, &finish, &endColor);
8777 /* Knight: make diagonal movement then straight */
8778 if (abs(toY - fromY) < abs(toX - fromX)) {
8779 mid.x = start.x + (finish.x - start.x) / 2;
8783 mid.y = start.y + (finish.y - start.y) / 2;
8786 mid.x = start.x + (finish.x - start.x) / 2;
8787 mid.y = start.y + (finish.y - start.y) / 2;
8790 /* Don't use as many frames for very short moves */
8791 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8792 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8794 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8795 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8797 /* Be sure end square is redrawn */
8798 damage[0][toY][toX] = True;
8802 DragPieceBegin(x, y)
8805 int boardX, boardY, color;
8808 /* Are we animating? */
8809 if (!appData.animateDragging || appData.blindfold)
8812 /* Figure out which square we start in and the
8813 mouse position relative to top left corner. */
8814 BoardSquare(x, y, &boardX, &boardY);
8815 player.startBoardX = boardX;
8816 player.startBoardY = boardY;
8817 ScreenSquare(boardX, boardY, &corner, &color);
8818 player.startSquare = corner;
8819 player.startColor = color;
8820 /* As soon as we start dragging, the piece will jump slightly to
8821 be centered over the mouse pointer. */
8822 player.mouseDelta.x = squareSize/2;
8823 player.mouseDelta.y = squareSize/2;
8824 /* Initialise animation */
8825 player.dragPiece = PieceForSquare(boardX, boardY);
8827 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8828 player.dragActive = True;
8829 BeginAnimation(&player, player.dragPiece, color, &corner);
8830 /* Mark this square as needing to be redrawn. Note that
8831 we don't remove the piece though, since logically (ie
8832 as seen by opponent) the move hasn't been made yet. */
8833 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8834 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8835 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8836 corner.x, corner.y, squareSize, squareSize,
8837 0, 0); // [HGM] zh: unstack in stead of grab
8838 damage[0][boardY][boardX] = True;
8840 player.dragActive = False;
8850 /* Are we animating? */
8851 if (!appData.animateDragging || appData.blindfold)
8855 if (! player.dragActive)
8857 /* Move piece, maintaining same relative position
8858 of mouse within square */
8859 corner.x = x - player.mouseDelta.x;
8860 corner.y = y - player.mouseDelta.y;
8861 AnimationFrame(&player, &corner, player.dragPiece);
8863 if (appData.highlightDragging) {
8865 BoardSquare(x, y, &boardX, &boardY);
8866 SetHighlights(fromX, fromY, boardX, boardY);
8875 int boardX, boardY, color;
8878 /* Are we animating? */
8879 if (!appData.animateDragging || appData.blindfold)
8883 if (! player.dragActive)
8885 /* Last frame in sequence is square piece is
8886 placed on, which may not match mouse exactly. */
8887 BoardSquare(x, y, &boardX, &boardY);
8888 ScreenSquare(boardX, boardY, &corner, &color);
8889 EndAnimation(&player, &corner);
8891 /* Be sure end square is redrawn */
8892 damage[0][boardY][boardX] = True;
8894 /* This prevents weird things happening with fast successive
8895 clicks which on my Sun at least can cause motion events
8896 without corresponding press/release. */
8897 player.dragActive = False;
8900 /* Handle expose event while piece being dragged */
8905 if (!player.dragActive || appData.blindfold)
8908 /* What we're doing: logically, the move hasn't been made yet,
8909 so the piece is still in it's original square. But visually
8910 it's being dragged around the board. So we erase the square
8911 that the piece is on and draw it at the last known drag point. */
8912 BlankSquare(player.startSquare.x, player.startSquare.y,
8913 player.startColor, EmptySquare, xBoardWindow);
8914 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8915 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8918 #include <sys/ioctl.h>
8919 int get_term_width()
8921 int fd, default_width;
8924 default_width = 79; // this is FICS default anyway...
8926 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8928 if (!ioctl(fd, TIOCGSIZE, &win))
8929 default_width = win.ts_cols;
8930 #elif defined(TIOCGWINSZ)
8932 if (!ioctl(fd, TIOCGWINSZ, &win))
8933 default_width = win.ws_col;
8935 return default_width;
8941 static int old_width = 0;
8942 int new_width = get_term_width();
8944 if (old_width != new_width)
8945 ics_printf("set width %d\n", new_width);
8946 old_width = new_width;
8949 void NotifyFrontendLogin()