2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
192 #include "frontend.h"
197 #include "xgamelist.h"
198 #include "xhistory.h"
199 #include "xedittags.h"
202 // must be moved to xengineoutput.h
204 void EngineOutputProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
206 void EvalGraphProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
214 #define usleep(t) _sleep2(((t)+500)/1000)
218 # define _(s) gettext (s)
219 # define N_(s) gettext_noop (s)
235 int main P((int argc, char **argv));
236 RETSIGTYPE CmailSigHandler P((int sig));
237 RETSIGTYPE IntSigHandler P((int sig));
238 RETSIGTYPE TermSizeSigHandler P((int sig));
239 void CreateGCs P((void));
240 void CreateXIMPieces P((void));
241 void CreateXPMPieces P((void));
242 void CreatePieces P((void));
243 void CreatePieceMenus P((void));
244 Widget CreateMenuBar P((Menu *mb));
245 Widget CreateButtonBar P ((MenuItem *mi));
246 char *FindFont P((char *pattern, int targetPxlSize));
247 void PieceMenuPopup P((Widget w, XEvent *event,
248 String *params, Cardinal *num_params));
249 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
250 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
251 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
252 u_int wreq, u_int hreq));
253 void CreateGrid P((void));
254 int EventToSquare P((int x, int limit));
255 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
256 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
257 void HandleUserMove P((Widget w, XEvent *event,
258 String *prms, Cardinal *nprms));
259 void AnimateUserMove P((Widget w, XEvent * event,
260 String * params, Cardinal * nParams));
261 void HandlePV P((Widget w, XEvent * event,
262 String * params, Cardinal * nParams));
263 void WhiteClock P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void BlackClock P((Widget w, XEvent *event,
266 String *prms, Cardinal *nprms));
267 void DrawPositionProc P((Widget w, XEvent *event,
268 String *prms, Cardinal *nprms));
269 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
271 void CommentPopUp P((char *title, char *label));
272 void CommentPopDown P((void));
273 void CommentCallback P((Widget w, XtPointer client_data,
274 XtPointer call_data));
275 void ICSInputBoxPopUp P((void));
276 void ICSInputBoxPopDown P((void));
277 void FileNamePopUp P((char *label, char *def,
278 FileProc proc, char *openMode));
279 void FileNamePopDown P((void));
280 void FileNameCallback P((Widget w, XtPointer client_data,
281 XtPointer call_data));
282 void FileNameAction P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionReplyAction P((Widget w, XEvent *event,
285 String *prms, Cardinal *nprms));
286 void AskQuestionProc P((Widget w, XEvent *event,
287 String *prms, Cardinal *nprms));
288 void AskQuestionPopDown P((void));
289 void PromotionPopDown P((void));
290 void PromotionCallback P((Widget w, XtPointer client_data,
291 XtPointer call_data));
292 void EditCommentPopDown P((void));
293 void EditCommentCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
296 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
297 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
298 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
302 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
304 void LoadPositionProc P((Widget w, XEvent *event,
305 String *prms, Cardinal *nprms));
306 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
308 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
310 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
314 void PastePositionProc P((Widget w, XEvent *event, String *prms,
316 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
317 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void SavePositionProc P((Widget w, XEvent *event,
320 String *prms, Cardinal *nprms));
321 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
324 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
328 void MachineWhiteProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void AnalyzeModeProc P((Widget w, XEvent *event,
331 String *prms, Cardinal *nprms));
332 void AnalyzeFileProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
336 void IcsClientProc P((Widget w, XEvent *event, String *prms,
338 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void EditPositionProc P((Widget w, XEvent *event,
340 String *prms, Cardinal *nprms));
341 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void EditCommentProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void IcsInputBoxProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void StopObservingProc P((Widget w, XEvent *event, String *prms,
362 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
364 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
371 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
373 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
376 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
378 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
380 void AutocommProc P((Widget w, XEvent *event, String *prms,
382 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void AutobsProc P((Widget w, XEvent *event, String *prms,
386 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
391 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
394 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
396 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
398 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
402 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
404 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
406 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
408 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
410 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
412 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
414 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
416 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
418 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
420 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void DisplayMove P((int moveNumber));
432 void DisplayTitle P((char *title));
433 void ICSInitScript P((void));
434 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
435 void ErrorPopUp P((char *title, char *text, int modal));
436 void ErrorPopDown P((void));
437 static char *ExpandPathName P((char *path));
438 static void CreateAnimVars P((void));
439 static void DragPieceMove P((int x, int y));
440 static void DrawDragPiece P((void));
441 char *ModeToWidgetName P((GameMode mode));
442 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void GameListOptionsPopDown P(());
451 void ShufflePopDown P(());
452 void EnginePopDown P(());
453 void UciPopDown P(());
454 void TimeControlPopDown P(());
455 void NewVariantPopDown P(());
456 void SettingsPopDown P(());
457 void update_ics_width P(());
458 int get_term_width P(());
459 int CopyMemoProc P(());
461 * XBoard depends on Xt R4 or higher
463 int xtVersion = XtSpecificationRelease;
468 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
469 jailSquareColor, highlightSquareColor, premoveHighlightColor;
470 Pixel lowTimeWarningColor;
471 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
472 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
473 wjPieceGC, bjPieceGC, prelineGC, countGC;
474 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
475 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
476 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
477 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
478 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
479 ICSInputShell, fileNameShell, askQuestionShell;
480 Widget historyShell, evalGraphShell, gameListShell;
481 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
482 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
483 Font clockFontID, coordFontID, countFontID;
484 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
485 XtAppContext appContext;
487 char *oldICSInteractionTitle;
491 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
493 Position commentX = -1, commentY = -1;
494 Dimension commentW, commentH;
495 typedef unsigned int BoardSize;
497 Boolean chessProgram;
499 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
500 int squareSize, smallLayout = 0, tinyLayout = 0,
501 marginW, marginH, // [HGM] for run-time resizing
502 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
503 ICSInputBoxUp = False, askQuestionUp = False,
504 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
505 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
506 Pixel timerForegroundPixel, timerBackgroundPixel;
507 Pixel buttonForegroundPixel, buttonBackgroundPixel;
508 char *chessDir, *programName, *programVersion,
509 *gameCopyFilename, *gamePasteFilename;
510 Boolean alwaysOnTop = False;
511 Boolean saveSettingsOnExit;
512 char *settingsFileName;
513 char *icsTextMenuString;
515 char *firstChessProgramNames;
516 char *secondChessProgramNames;
518 WindowPlacement wpMain;
519 WindowPlacement wpConsole;
520 WindowPlacement wpComment;
521 WindowPlacement wpMoveHistory;
522 WindowPlacement wpEvalGraph;
523 WindowPlacement wpEngineOutput;
524 WindowPlacement wpGameList;
525 WindowPlacement wpTags;
529 Pixmap pieceBitmap[2][(int)BlackPawn];
530 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
531 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
532 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
533 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
534 int useImages, useImageSqs;
535 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
536 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
537 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
538 XImage *ximLightSquare, *ximDarkSquare;
541 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
542 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
544 #define White(piece) ((int)(piece) < (int)BlackPawn)
546 /* Variables for doing smooth animation. This whole thing
547 would be much easier if the board was double-buffered,
548 but that would require a fairly major rewrite. */
553 GC blitGC, pieceGC, outlineGC;
554 XPoint startSquare, prevFrame, mouseDelta;
558 int startBoardX, startBoardY;
561 /* There can be two pieces being animated at once: a player
562 can begin dragging a piece before the remote opponent has moved. */
564 static AnimState game, player;
566 /* Bitmaps for use as masks when drawing XPM pieces.
567 Need one for each black and white piece. */
568 static Pixmap xpmMask[BlackKing + 1];
570 /* This magic number is the number of intermediate frames used
571 in each half of the animation. For short moves it's reduced
572 by 1. The total number of frames will be factor * 2 + 1. */
575 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
577 MenuItem fileMenu[] = {
578 {N_("New Game"), ResetProc},
579 {N_("New Shuffle Game ..."), ShuffleMenuProc},
580 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
581 {"----", NothingProc},
582 {N_("Load Game"), LoadGameProc},
583 {N_("Load Next Game"), LoadNextGameProc},
584 {N_("Load Previous Game"), LoadPrevGameProc},
585 {N_("Reload Same Game"), ReloadGameProc},
586 {N_("Save Game"), SaveGameProc},
587 {"----", NothingProc},
588 {N_("Copy Game"), CopyGameProc},
589 {N_("Paste Game"), PasteGameProc},
590 {"----", NothingProc},
591 {N_("Load Position"), LoadPositionProc},
592 {N_("Load Next Position"), LoadNextPositionProc},
593 {N_("Load Previous Position"), LoadPrevPositionProc},
594 {N_("Reload Same Position"), ReloadPositionProc},
595 {N_("Save Position"), SavePositionProc},
596 {"----", NothingProc},
597 {N_("Copy Position"), CopyPositionProc},
598 {N_("Paste Position"), PastePositionProc},
599 {"----", NothingProc},
600 {N_("Mail Move"), MailMoveProc},
601 {N_("Reload CMail Message"), ReloadCmailMsgProc},
602 {"----", NothingProc},
603 {N_("Exit"), QuitProc},
607 MenuItem modeMenu[] = {
608 {N_("Machine White"), MachineWhiteProc},
609 {N_("Machine Black"), MachineBlackProc},
610 {N_("Two Machines"), TwoMachinesProc},
611 {N_("Analysis Mode"), AnalyzeModeProc},
612 {N_("Analyze File"), AnalyzeFileProc },
613 {N_("ICS Client"), IcsClientProc},
614 {N_("Edit Game"), EditGameProc},
615 {N_("Edit Position"), EditPositionProc},
616 {N_("Training"), TrainingProc},
617 {"----", NothingProc},
618 {N_("Show Engine Output"), EngineOutputProc},
619 {N_("Show Evaluation Graph"), EvalGraphProc},
620 {N_("Show Game List"), ShowGameListProc},
621 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
622 {"----", NothingProc},
623 {N_("Edit Tags"), EditTagsProc},
624 {N_("Edit Comment"), EditCommentProc},
625 {N_("ICS Input Box"), IcsInputBoxProc},
626 {N_("Pause"), PauseProc},
630 MenuItem actionMenu[] = {
631 {N_("Accept"), AcceptProc},
632 {N_("Decline"), DeclineProc},
633 {N_("Rematch"), RematchProc},
634 {"----", NothingProc},
635 {N_("Call Flag"), CallFlagProc},
636 {N_("Draw"), DrawProc},
637 {N_("Adjourn"), AdjournProc},
638 {N_("Abort"), AbortProc},
639 {N_("Resign"), ResignProc},
640 {"----", NothingProc},
641 {N_("Stop Observing"), StopObservingProc},
642 {N_("Stop Examining"), StopExaminingProc},
643 {"----", NothingProc},
644 {N_("Adjudicate to White"), AdjuWhiteProc},
645 {N_("Adjudicate to Black"), AdjuBlackProc},
646 {N_("Adjudicate Draw"), AdjuDrawProc},
650 MenuItem stepMenu[] = {
651 {N_("Backward"), BackwardProc},
652 {N_("Forward"), ForwardProc},
653 {N_("Back to Start"), ToStartProc},
654 {N_("Forward to End"), ToEndProc},
655 {N_("Revert"), RevertProc},
656 {N_("Truncate Game"), TruncateGameProc},
657 {"----", NothingProc},
658 {N_("Move Now"), MoveNowProc},
659 {N_("Retract Move"), RetractMoveProc},
663 MenuItem optionsMenu[] = {
664 {N_("Flip View"), FlipViewProc},
665 {"----", NothingProc},
666 {N_("Adjudications ..."), EngineMenuProc},
667 {N_("General Settings ..."), UciMenuProc},
668 {N_("Engine #1 Settings ..."), FirstSettingsProc},
669 {N_("Engine #2 Settings ..."), SecondSettingsProc},
670 {N_("Time Control ..."), TimeControlProc},
671 {N_("Game List ..."), GameListOptionsPopUp},
672 {"----", NothingProc},
673 {N_("Always Queen"), AlwaysQueenProc},
674 {N_("Animate Dragging"), AnimateDraggingProc},
675 {N_("Animate Moving"), AnimateMovingProc},
676 {N_("Auto Comment"), AutocommProc},
677 {N_("Auto Flag"), AutoflagProc},
678 {N_("Auto Flip View"), AutoflipProc},
679 {N_("Auto Observe"), AutobsProc},
680 {N_("Auto Raise Board"), AutoraiseProc},
681 {N_("Auto Save"), AutosaveProc},
682 {N_("Blindfold"), BlindfoldProc},
683 {N_("Flash Moves"), FlashMovesProc},
684 {N_("Get Move List"), GetMoveListProc},
686 {N_("Highlight Dragging"), HighlightDraggingProc},
688 {N_("Highlight Last Move"), HighlightLastMoveProc},
689 {N_("Move Sound"), MoveSoundProc},
690 {N_("ICS Alarm"), IcsAlarmProc},
691 {N_("Old Save Style"), OldSaveStyleProc},
692 {N_("Periodic Updates"), PeriodicUpdatesProc},
693 {N_("Ponder Next Move"), PonderNextMoveProc},
694 {N_("Popup Exit Message"), PopupExitMessageProc},
695 {N_("Popup Move Errors"), PopupMoveErrorsProc},
696 {N_("Premove"), PremoveProc},
697 {N_("Quiet Play"), QuietPlayProc},
698 {N_("Show Coords"), ShowCoordsProc},
699 {N_("Hide Thinking"), HideThinkingProc},
700 {N_("Test Legality"), TestLegalityProc},
701 {"----", NothingProc},
702 {N_("Save Settings Now"), SaveSettingsProc},
703 {N_("Save Settings on Exit"), SaveOnExitProc},
707 MenuItem helpMenu[] = {
708 {N_("Info XBoard"), InfoProc},
709 {N_("Man XBoard"), ManProc},
710 {"----", NothingProc},
711 {N_("Hint"), HintProc},
712 {N_("Book"), BookProc},
713 {"----", NothingProc},
714 {N_("About XBoard"), AboutProc},
719 {N_("File"), fileMenu},
720 {N_("Mode"), modeMenu},
721 {N_("Action"), actionMenu},
722 {N_("Step"), stepMenu},
723 {N_("Options"), optionsMenu},
724 {N_("Help"), helpMenu},
728 #define PAUSE_BUTTON N_("P")
729 MenuItem buttonBar[] = {
732 {PAUSE_BUTTON, PauseProc},
738 #define PIECE_MENU_SIZE 18
739 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
740 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
741 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
742 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
743 N_("Empty square"), N_("Clear board") },
744 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
745 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
746 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
747 N_("Empty square"), N_("Clear board") }
749 /* must be in same order as PieceMenuStrings! */
750 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
751 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
752 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
753 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
754 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
755 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
756 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
757 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
758 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
761 #define DROP_MENU_SIZE 6
762 String dropMenuStrings[DROP_MENU_SIZE] = {
763 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
765 /* must be in same order as PieceMenuStrings! */
766 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
767 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
768 WhiteRook, WhiteQueen
776 DropMenuEnables dmEnables[] = {
794 { XtNborderWidth, 0 },
795 { XtNdefaultDistance, 0 },
799 { XtNborderWidth, 0 },
800 { XtNresizable, (XtArgVal) True },
804 { XtNborderWidth, 0 },
810 { XtNjustify, (XtArgVal) XtJustifyRight },
811 { XtNlabel, (XtArgVal) "..." },
812 { XtNresizable, (XtArgVal) True },
813 { XtNresize, (XtArgVal) False }
816 Arg messageArgs[] = {
817 { XtNjustify, (XtArgVal) XtJustifyLeft },
818 { XtNlabel, (XtArgVal) "..." },
819 { XtNresizable, (XtArgVal) True },
820 { XtNresize, (XtArgVal) False }
824 { XtNborderWidth, 0 },
825 { XtNjustify, (XtArgVal) XtJustifyLeft }
828 XtResource clientResources[] = {
829 { "flashCount", "flashCount", XtRInt, sizeof(int),
830 XtOffset(AppDataPtr, flashCount), XtRImmediate,
831 (XtPointer) FLASH_COUNT },
834 XrmOptionDescRec shellOptions[] = {
835 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
836 { "-flash", "flashCount", XrmoptionNoArg, "3" },
837 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
840 XtActionsRec boardActions[] = {
841 { "DrawPosition", DrawPositionProc },
842 { "HandleUserMove", HandleUserMove },
843 { "AnimateUserMove", AnimateUserMove },
844 { "HandlePV", HandlePV },
845 { "UnLoadPV", UnLoadPV },
846 { "FileNameAction", FileNameAction },
847 { "AskQuestionProc", AskQuestionProc },
848 { "AskQuestionReplyAction", AskQuestionReplyAction },
849 { "PieceMenuPopup", PieceMenuPopup },
850 { "WhiteClock", WhiteClock },
851 { "BlackClock", BlackClock },
852 { "Iconify", Iconify },
853 { "ResetProc", ResetProc },
854 { "LoadGameProc", LoadGameProc },
855 { "LoadNextGameProc", LoadNextGameProc },
856 { "LoadPrevGameProc", LoadPrevGameProc },
857 { "LoadSelectedProc", LoadSelectedProc },
858 { "SetFilterProc", SetFilterProc },
859 { "ReloadGameProc", ReloadGameProc },
860 { "LoadPositionProc", LoadPositionProc },
861 { "LoadNextPositionProc", LoadNextPositionProc },
862 { "LoadPrevPositionProc", LoadPrevPositionProc },
863 { "ReloadPositionProc", ReloadPositionProc },
864 { "CopyPositionProc", CopyPositionProc },
865 { "PastePositionProc", PastePositionProc },
866 { "CopyGameProc", CopyGameProc },
867 { "PasteGameProc", PasteGameProc },
868 { "SaveGameProc", SaveGameProc },
869 { "SavePositionProc", SavePositionProc },
870 { "MailMoveProc", MailMoveProc },
871 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
872 { "QuitProc", QuitProc },
873 { "MachineWhiteProc", MachineWhiteProc },
874 { "MachineBlackProc", MachineBlackProc },
875 { "AnalysisModeProc", AnalyzeModeProc },
876 { "AnalyzeFileProc", AnalyzeFileProc },
877 { "TwoMachinesProc", TwoMachinesProc },
878 { "IcsClientProc", IcsClientProc },
879 { "EditGameProc", EditGameProc },
880 { "EditPositionProc", EditPositionProc },
881 { "TrainingProc", EditPositionProc },
882 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
883 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
884 { "ShowGameListProc", ShowGameListProc },
885 { "ShowMoveListProc", HistoryShowProc},
886 { "EditTagsProc", EditCommentProc },
887 { "EditCommentProc", EditCommentProc },
888 { "IcsAlarmProc", IcsAlarmProc },
889 { "IcsInputBoxProc", IcsInputBoxProc },
890 { "PauseProc", PauseProc },
891 { "AcceptProc", AcceptProc },
892 { "DeclineProc", DeclineProc },
893 { "RematchProc", RematchProc },
894 { "CallFlagProc", CallFlagProc },
895 { "DrawProc", DrawProc },
896 { "AdjournProc", AdjournProc },
897 { "AbortProc", AbortProc },
898 { "ResignProc", ResignProc },
899 { "AdjuWhiteProc", AdjuWhiteProc },
900 { "AdjuBlackProc", AdjuBlackProc },
901 { "AdjuDrawProc", AdjuDrawProc },
902 { "EnterKeyProc", EnterKeyProc },
903 { "UpKeyProc", UpKeyProc },
904 { "DownKeyProc", DownKeyProc },
905 { "StopObservingProc", StopObservingProc },
906 { "StopExaminingProc", StopExaminingProc },
907 { "BackwardProc", BackwardProc },
908 { "ForwardProc", ForwardProc },
909 { "ToStartProc", ToStartProc },
910 { "ToEndProc", ToEndProc },
911 { "RevertProc", RevertProc },
912 { "TruncateGameProc", TruncateGameProc },
913 { "MoveNowProc", MoveNowProc },
914 { "RetractMoveProc", RetractMoveProc },
915 { "AlwaysQueenProc", AlwaysQueenProc },
916 { "AnimateDraggingProc", AnimateDraggingProc },
917 { "AnimateMovingProc", AnimateMovingProc },
918 { "AutoflagProc", AutoflagProc },
919 { "AutoflipProc", AutoflipProc },
920 { "AutobsProc", AutobsProc },
921 { "AutoraiseProc", AutoraiseProc },
922 { "AutosaveProc", AutosaveProc },
923 { "BlindfoldProc", BlindfoldProc },
924 { "FlashMovesProc", FlashMovesProc },
925 { "FlipViewProc", FlipViewProc },
926 { "GetMoveListProc", GetMoveListProc },
928 { "HighlightDraggingProc", HighlightDraggingProc },
930 { "HighlightLastMoveProc", HighlightLastMoveProc },
931 { "IcsAlarmProc", IcsAlarmProc },
932 { "MoveSoundProc", MoveSoundProc },
933 { "OldSaveStyleProc", OldSaveStyleProc },
934 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
935 { "PonderNextMoveProc", PonderNextMoveProc },
936 { "PopupExitMessageProc", PopupExitMessageProc },
937 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
938 { "PremoveProc", PremoveProc },
939 { "QuietPlayProc", QuietPlayProc },
940 { "ShowCoordsProc", ShowCoordsProc },
941 { "ShowThinkingProc", ShowThinkingProc },
942 { "HideThinkingProc", HideThinkingProc },
943 { "TestLegalityProc", TestLegalityProc },
944 { "SaveSettingsProc", SaveSettingsProc },
945 { "SaveOnExitProc", SaveOnExitProc },
946 { "InfoProc", InfoProc },
947 { "ManProc", ManProc },
948 { "HintProc", HintProc },
949 { "BookProc", BookProc },
950 { "AboutGameProc", AboutGameProc },
951 { "AboutProc", AboutProc },
952 { "DebugProc", DebugProc },
953 { "NothingProc", NothingProc },
954 { "CommentPopDown", (XtActionProc) CommentPopDown },
955 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
956 { "TagsPopDown", (XtActionProc) TagsPopDown },
957 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
958 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
959 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
960 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
961 { "GameListPopDown", (XtActionProc) GameListPopDown },
962 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
963 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
964 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
965 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
966 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
967 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
968 { "EnginePopDown", (XtActionProc) EnginePopDown },
969 { "UciPopDown", (XtActionProc) UciPopDown },
970 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
971 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
972 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
973 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
976 char globalTranslations[] =
977 ":<Key>R: ResignProc() \n \
978 :<Key>r: ResetProc() \n \
979 :<Key>g: LoadGameProc() \n \
980 :<Key>N: LoadNextGameProc() \n \
981 :<Key>P: LoadPrevGameProc() \n \
982 :<Key>Q: QuitProc() \n \
983 :<Key>F: ToEndProc() \n \
984 :<Key>f: ForwardProc() \n \
985 :<Key>B: ToStartProc() \n \
986 :<Key>b: BackwardProc() \n \
987 :<Key>p: PauseProc() \n \
988 :<Key>d: DrawProc() \n \
989 :<Key>t: CallFlagProc() \n \
990 :<Key>i: Iconify() \n \
991 :<Key>c: Iconify() \n \
992 :<Key>v: FlipViewProc() \n \
993 <KeyDown>Control_L: BackwardProc() \n \
994 <KeyUp>Control_L: ForwardProc() \n \
995 <KeyDown>Control_R: BackwardProc() \n \
996 <KeyUp>Control_R: ForwardProc() \n \
997 Shift<Key>1: AskQuestionProc(\"Direct command\",\
998 \"Send to chess program:\",,1) \n \
999 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1000 \"Send to second chess program:\",,2) \n";
1002 char boardTranslations[] =
1003 "<Btn1Down>: HandleUserMove() \n \
1004 <Btn1Up>: HandleUserMove() \n \
1005 <Btn1Motion>: AnimateUserMove() \n \
1006 <Btn3Motion>: HandlePV() \n \
1007 <Btn3Up>: PieceMenuPopup(menuB) \n \
1008 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1009 PieceMenuPopup(menuB) \n \
1010 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1011 PieceMenuPopup(menuW) \n \
1012 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1013 PieceMenuPopup(menuW) \n \
1014 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1015 PieceMenuPopup(menuB) \n";
1017 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1018 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1020 char ICSInputTranslations[] =
1021 "<Key>Up: UpKeyProc() \n "
1022 "<Key>Down: DownKeyProc() \n "
1023 "<Key>Return: EnterKeyProc() \n";
1025 String xboardResources[] = {
1026 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1027 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1028 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1033 /* Max possible square size */
1034 #define MAXSQSIZE 256
1036 static int xpm_avail[MAXSQSIZE];
1038 #ifdef HAVE_DIR_STRUCT
1040 /* Extract piece size from filename */
1042 xpm_getsize(name, len, ext)
1053 if ((p=strchr(name, '.')) == NULL ||
1054 StrCaseCmp(p+1, ext) != 0)
1060 while (*p && isdigit(*p))
1067 /* Setup xpm_avail */
1069 xpm_getavail(dirname, ext)
1077 for (i=0; i<MAXSQSIZE; ++i)
1080 if (appData.debugMode)
1081 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1083 dir = opendir(dirname);
1086 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1087 programName, dirname);
1091 while ((ent=readdir(dir)) != NULL) {
1092 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1093 if (i > 0 && i < MAXSQSIZE)
1103 xpm_print_avail(fp, ext)
1109 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1110 for (i=1; i<MAXSQSIZE; ++i) {
1116 /* Return XPM piecesize closest to size */
1118 xpm_closest_to(dirname, size, ext)
1124 int sm_diff = MAXSQSIZE;
1128 xpm_getavail(dirname, ext);
1130 if (appData.debugMode)
1131 xpm_print_avail(stderr, ext);
1133 for (i=1; i<MAXSQSIZE; ++i) {
1136 diff = (diff<0) ? -diff : diff;
1137 if (diff < sm_diff) {
1145 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1151 #else /* !HAVE_DIR_STRUCT */
1152 /* If we are on a system without a DIR struct, we can't
1153 read the directory, so we can't collect a list of
1154 filenames, etc., so we can't do any size-fitting. */
1156 xpm_closest_to(dirname, size, ext)
1161 fprintf(stderr, _("\
1162 Warning: No DIR structure found on this system --\n\
1163 Unable to autosize for XPM/XIM pieces.\n\
1164 Please report this error to frankm@hiwaay.net.\n\
1165 Include system type & operating system in message.\n"));
1168 #endif /* HAVE_DIR_STRUCT */
1170 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1171 "magenta", "cyan", "white" };
1175 TextColors textColors[(int)NColorClasses];
1177 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1179 parse_color(str, which)
1183 char *p, buf[100], *d;
1186 if (strlen(str) > 99) /* watch bounds on buf */
1191 for (i=0; i<which; ++i) {
1198 /* Could be looking at something like:
1200 .. in which case we want to stop on a comma also */
1201 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1205 return -1; /* Use default for empty field */
1208 if (which == 2 || isdigit(*p))
1211 while (*p && isalpha(*p))
1216 for (i=0; i<8; ++i) {
1217 if (!StrCaseCmp(buf, cnames[i]))
1218 return which? (i+40) : (i+30);
1220 if (!StrCaseCmp(buf, "default")) return -1;
1222 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1227 parse_cpair(cc, str)
1231 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1232 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1237 /* bg and attr are optional */
1238 textColors[(int)cc].bg = parse_color(str, 1);
1239 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1240 textColors[(int)cc].attr = 0;
1246 /* Arrange to catch delete-window events */
1247 Atom wm_delete_window;
1249 CatchDeleteWindow(Widget w, String procname)
1252 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1253 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1254 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1261 XtSetArg(args[0], XtNiconic, False);
1262 XtSetValues(shellWidget, args, 1);
1264 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1267 //---------------------------------------------------------------------------------------------------------
1268 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1271 #define CW_USEDEFAULT (1<<31)
1272 #define ICS_TEXT_MENU_SIZE 90
1273 #define DEBUG_FILE "xboard.debug"
1274 #define SetCurrentDirectory chdir
1275 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1279 // these two must some day move to frontend.h, when they are implemented
1280 Boolean GameListIsUp();
1282 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1285 // front-end part of option handling
1287 // [HGM] This platform-dependent table provides the location for storing the color info
1288 extern char *crWhite, * crBlack;
1292 &appData.whitePieceColor,
1293 &appData.blackPieceColor,
1294 &appData.lightSquareColor,
1295 &appData.darkSquareColor,
1296 &appData.highlightSquareColor,
1297 &appData.premoveHighlightColor,
1298 &appData.lowTimeWarningColor,
1309 // [HGM] font: keep a font for each square size, even non-stndard ones
1310 #define NUM_SIZES 18
1311 #define MAX_SIZE 130
1312 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1313 char *fontTable[NUM_FONTS][MAX_SIZE];
1316 ParseFont(char *name, int number)
1317 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1319 if(sscanf(name, "size%d:", &size)) {
1320 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1321 // defer processing it until we know if it matches our board size
1322 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1323 fontTable[number][size] = strdup(strchr(name, ':')+1);
1324 fontValid[number][size] = True;
1329 case 0: // CLOCK_FONT
1330 appData.clockFont = strdup(name);
1332 case 1: // MESSAGE_FONT
1333 appData.font = strdup(name);
1335 case 2: // COORD_FONT
1336 appData.coordFont = strdup(name);
1341 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1346 { // only 2 fonts currently
1347 appData.clockFont = CLOCK_FONT_NAME;
1348 appData.coordFont = COORD_FONT_NAME;
1349 appData.font = DEFAULT_FONT_NAME;
1354 { // no-op, until we identify the code for this already in XBoard and move it here
1358 ParseColor(int n, char *name)
1359 { // in XBoard, just copy the color-name string
1360 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1364 ParseTextAttribs(ColorClass cc, char *s)
1366 (&appData.colorShout)[cc] = strdup(s);
1370 ParseBoardSize(void *addr, char *name)
1372 appData.boardSize = strdup(name);
1377 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1381 SetCommPortDefaults()
1382 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1385 // [HGM] args: these three cases taken out to stay in front-end
1387 SaveFontArg(FILE *f, ArgDescriptor *ad)
1389 char *name, buf[MSG_SIZ];
1390 int i, n = (int)ad->argLoc;
1392 case 0: // CLOCK_FONT
1393 name = appData.clockFont;
1395 case 1: // MESSAGE_FONT
1396 name = appData.font;
1398 case 2: // COORD_FONT
1399 name = appData.coordFont;
1404 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1405 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1406 fontTable[n][squareSize] = strdup(name);
1407 fontValid[n][squareSize] = True;
1410 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1411 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1416 { // nothing to do, as the sounds are at all times represented by their text-string names already
1420 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1421 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1422 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1426 SaveColor(FILE *f, ArgDescriptor *ad)
1427 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1428 if(colorVariable[(int)ad->argLoc])
1429 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1433 SaveBoardSize(FILE *f, char *name, void *addr)
1434 { // wrapper to shield back-end from BoardSize & sizeInfo
1435 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1439 ParseCommPortSettings(char *s)
1440 { // no such option in XBoard (yet)
1443 extern Widget engineOutputShell;
1444 extern Widget tagsShell, editTagsShell;
1446 GetActualPlacement(Widget wg, WindowPlacement *wp)
1456 XtSetArg(args[i], XtNx, &x); i++;
1457 XtSetArg(args[i], XtNy, &y); i++;
1458 XtSetArg(args[i], XtNwidth, &w); i++;
1459 XtSetArg(args[i], XtNheight, &h); i++;
1460 XtGetValues(wg, args, i);
1469 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1470 // In XBoard this will have to wait until awareness of window parameters is implemented
1471 GetActualPlacement(shellWidget, &wpMain);
1472 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1473 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1474 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1475 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1476 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1477 else GetActualPlacement(editShell, &wpComment);
1478 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1479 else GetActualPlacement(editTagsShell, &wpTags);
1483 PrintCommPortSettings(FILE *f, char *name)
1484 { // This option does not exist in XBoard
1488 MySearchPath(char *installDir, char *name, char *fullname)
1489 { // just append installDir and name. Perhaps ExpandPath should be used here?
1490 name = ExpandPathName(name);
1491 if(name && name[0] == '/') strcpy(fullname, name); else {
1492 sprintf(fullname, "%s%c%s", installDir, '/', name);
1498 MyGetFullPathName(char *name, char *fullname)
1499 { // should use ExpandPath?
1500 name = ExpandPathName(name);
1501 strcpy(fullname, name);
1506 EnsureOnScreen(int *x, int *y, int minX, int minY)
1513 { // [HGM] args: allows testing if main window is realized from back-end
1514 return xBoardWindow != 0;
1518 PopUpStartupDialog()
1519 { // start menu not implemented in XBoard
1522 ConvertToLine(int argc, char **argv)
1524 static char line[128*1024], buf[1024];
1528 for(i=1; i<argc; i++) {
1529 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1530 && argv[i][0] != '{' )
1531 sprintf(buf, "{%s} ", argv[i]);
1532 else sprintf(buf, "%s ", argv[i]);
1535 line[strlen(line)-1] = NULLCHAR;
1539 //--------------------------------------------------------------------------------------------
1542 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1544 #define BoardSize int
1545 void InitDrawingSizes(BoardSize boardSize, int flags)
1546 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1547 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1549 XtGeometryResult gres;
1552 if(!formWidget) return;
1555 * Enable shell resizing.
1557 shellArgs[0].value = (XtArgVal) &w;
1558 shellArgs[1].value = (XtArgVal) &h;
1559 XtGetValues(shellWidget, shellArgs, 2);
1561 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1562 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1563 XtSetValues(shellWidget, &shellArgs[2], 4);
1565 XtSetArg(args[0], XtNdefaultDistance, &sep);
1566 XtGetValues(formWidget, args, 1);
1568 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1569 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1572 XtSetArg(args[0], XtNwidth, boardWidth);
1573 XtSetArg(args[1], XtNheight, boardHeight);
1574 XtSetValues(boardWidget, args, 2);
1576 timerWidth = (boardWidth - sep) / 2;
1577 XtSetArg(args[0], XtNwidth, timerWidth);
1578 XtSetValues(whiteTimerWidget, args, 1);
1579 XtSetValues(blackTimerWidget, args, 1);
1581 XawFormDoLayout(formWidget, False);
1583 if (appData.titleInWindow) {
1585 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1586 XtSetArg(args[i], XtNheight, &h); i++;
1587 XtGetValues(titleWidget, args, i);
1589 w = boardWidth - 2*bor;
1591 XtSetArg(args[0], XtNwidth, &w);
1592 XtGetValues(menuBarWidget, args, 1);
1593 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1596 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1597 if (gres != XtGeometryYes && appData.debugMode) {
1599 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1600 programName, gres, w, h, wr, hr);
1604 XawFormDoLayout(formWidget, True);
1607 * Inhibit shell resizing.
1609 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1610 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1611 shellArgs[4].value = shellArgs[2].value = w;
1612 shellArgs[5].value = shellArgs[3].value = h;
1613 XtSetValues(shellWidget, &shellArgs[0], 6);
1615 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1618 for(i=0; i<4; i++) {
1620 for(p=0; p<=(int)WhiteKing; p++)
1621 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1622 if(gameInfo.variant == VariantShogi) {
1623 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1624 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1625 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1626 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1627 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1630 if(gameInfo.variant == VariantGothic) {
1631 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1635 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1636 for(p=0; p<=(int)WhiteKing; p++)
1637 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1638 if(gameInfo.variant == VariantShogi) {
1639 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1640 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1641 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1642 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1643 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1646 if(gameInfo.variant == VariantGothic) {
1647 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1653 for(i=0; i<2; i++) {
1655 for(p=0; p<=(int)WhiteKing; p++)
1656 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1657 if(gameInfo.variant == VariantShogi) {
1658 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1659 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1660 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1661 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1662 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1665 if(gameInfo.variant == VariantGothic) {
1666 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1677 void EscapeExpand(char *p, char *q)
1678 { // [HGM] initstring: routine to shape up string arguments
1679 while(*p++ = *q++) if(p[-1] == '\\')
1681 case 'n': p[-1] = '\n'; break;
1682 case 'r': p[-1] = '\r'; break;
1683 case 't': p[-1] = '\t'; break;
1684 case '\\': p[-1] = '\\'; break;
1685 case 0: *p = 0; return;
1686 default: p[-1] = q[-1]; break;
1695 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1696 XSetWindowAttributes window_attributes;
1698 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1699 XrmValue vFrom, vTo;
1700 XtGeometryResult gres;
1703 int forceMono = False;
1705 srandom(time(0)); // [HGM] book: make random truly random
1707 setbuf(stdout, NULL);
1708 setbuf(stderr, NULL);
1711 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1712 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1716 programName = strrchr(argv[0], '/');
1717 if (programName == NULL)
1718 programName = argv[0];
1723 XtSetLanguageProc(NULL, NULL, NULL);
1724 bindtextdomain(PACKAGE, LOCALEDIR);
1725 textdomain(PACKAGE);
1729 XtAppInitialize(&appContext, "XBoard", shellOptions,
1730 XtNumber(shellOptions),
1731 &argc, argv, xboardResources, NULL, 0);
1732 appData.boardSize = "";
1733 InitAppData(ConvertToLine(argc, argv));
1735 if (p == NULL) p = "/tmp";
1736 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1737 gameCopyFilename = (char*) malloc(i);
1738 gamePasteFilename = (char*) malloc(i);
1739 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1740 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1742 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1743 clientResources, XtNumber(clientResources),
1746 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1747 static char buf[MSG_SIZ];
1748 EscapeExpand(buf, appData.initString);
1749 appData.initString = strdup(buf);
1750 EscapeExpand(buf, appData.secondInitString);
1751 appData.secondInitString = strdup(buf);
1752 EscapeExpand(buf, appData.firstComputerString);
1753 appData.firstComputerString = strdup(buf);
1754 EscapeExpand(buf, appData.secondComputerString);
1755 appData.secondComputerString = strdup(buf);
1758 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1761 if (chdir(chessDir) != 0) {
1762 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1768 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1769 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1770 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1771 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1774 setbuf(debugFP, NULL);
1777 /* [HGM,HR] make sure board size is acceptable */
1778 if(appData.NrFiles > BOARD_FILES ||
1779 appData.NrRanks > BOARD_RANKS )
1780 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1783 /* This feature does not work; animation needs a rewrite */
1784 appData.highlightDragging = FALSE;
1788 xDisplay = XtDisplay(shellWidget);
1789 xScreen = DefaultScreen(xDisplay);
1790 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1792 gameInfo.variant = StringToVariant(appData.variant);
1793 InitPosition(FALSE);
1796 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1798 if (isdigit(appData.boardSize[0])) {
1799 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1800 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1801 &fontPxlSize, &smallLayout, &tinyLayout);
1803 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1804 programName, appData.boardSize);
1808 /* Find some defaults; use the nearest known size */
1809 SizeDefaults *szd, *nearest;
1810 int distance = 99999;
1811 nearest = szd = sizeDefaults;
1812 while (szd->name != NULL) {
1813 if (abs(szd->squareSize - squareSize) < distance) {
1815 distance = abs(szd->squareSize - squareSize);
1816 if (distance == 0) break;
1820 if (i < 2) lineGap = nearest->lineGap;
1821 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1822 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1823 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1824 if (i < 6) smallLayout = nearest->smallLayout;
1825 if (i < 7) tinyLayout = nearest->tinyLayout;
1828 SizeDefaults *szd = sizeDefaults;
1829 if (*appData.boardSize == NULLCHAR) {
1830 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1831 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1834 if (szd->name == NULL) szd--;
1835 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1837 while (szd->name != NULL &&
1838 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1839 if (szd->name == NULL) {
1840 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1841 programName, appData.boardSize);
1845 squareSize = szd->squareSize;
1846 lineGap = szd->lineGap;
1847 clockFontPxlSize = szd->clockFontPxlSize;
1848 coordFontPxlSize = szd->coordFontPxlSize;
1849 fontPxlSize = szd->fontPxlSize;
1850 smallLayout = szd->smallLayout;
1851 tinyLayout = szd->tinyLayout;
1852 // [HGM] font: use defaults from settings file if available and not overruled
1854 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1855 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1856 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1857 appData.font = fontTable[MESSAGE_FONT][squareSize];
1858 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1859 appData.coordFont = fontTable[COORD_FONT][squareSize];
1861 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1862 if (strlen(appData.pixmapDirectory) > 0) {
1863 p = ExpandPathName(appData.pixmapDirectory);
1865 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1866 appData.pixmapDirectory);
1869 if (appData.debugMode) {
1870 fprintf(stderr, _("\
1871 XBoard square size (hint): %d\n\
1872 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1874 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1875 if (appData.debugMode) {
1876 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1880 /* [HR] height treated separately (hacked) */
1881 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1882 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1883 if (appData.showJail == 1) {
1884 /* Jail on top and bottom */
1885 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1886 XtSetArg(boardArgs[2], XtNheight,
1887 boardHeight + 2*(lineGap + squareSize));
1888 } else if (appData.showJail == 2) {
1890 XtSetArg(boardArgs[1], XtNwidth,
1891 boardWidth + 2*(lineGap + squareSize));
1892 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1895 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1896 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1900 * Determine what fonts to use.
1902 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1903 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1904 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1905 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1906 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1907 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1908 appData.font = FindFont(appData.font, fontPxlSize);
1909 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1910 countFontStruct = XQueryFont(xDisplay, countFontID);
1911 // appData.font = FindFont(appData.font, fontPxlSize);
1913 xdb = XtDatabase(xDisplay);
1914 XrmPutStringResource(&xdb, "*font", appData.font);
1917 * Detect if there are not enough colors available and adapt.
1919 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1920 appData.monoMode = True;
1923 if (!appData.monoMode) {
1924 vFrom.addr = (caddr_t) appData.lightSquareColor;
1925 vFrom.size = strlen(appData.lightSquareColor);
1926 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1927 if (vTo.addr == NULL) {
1928 appData.monoMode = True;
1931 lightSquareColor = *(Pixel *) vTo.addr;
1934 if (!appData.monoMode) {
1935 vFrom.addr = (caddr_t) appData.darkSquareColor;
1936 vFrom.size = strlen(appData.darkSquareColor);
1937 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1938 if (vTo.addr == NULL) {
1939 appData.monoMode = True;
1942 darkSquareColor = *(Pixel *) vTo.addr;
1945 if (!appData.monoMode) {
1946 vFrom.addr = (caddr_t) appData.whitePieceColor;
1947 vFrom.size = strlen(appData.whitePieceColor);
1948 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1949 if (vTo.addr == NULL) {
1950 appData.monoMode = True;
1953 whitePieceColor = *(Pixel *) vTo.addr;
1956 if (!appData.monoMode) {
1957 vFrom.addr = (caddr_t) appData.blackPieceColor;
1958 vFrom.size = strlen(appData.blackPieceColor);
1959 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1960 if (vTo.addr == NULL) {
1961 appData.monoMode = True;
1964 blackPieceColor = *(Pixel *) vTo.addr;
1968 if (!appData.monoMode) {
1969 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1970 vFrom.size = strlen(appData.highlightSquareColor);
1971 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1972 if (vTo.addr == NULL) {
1973 appData.monoMode = True;
1976 highlightSquareColor = *(Pixel *) vTo.addr;
1980 if (!appData.monoMode) {
1981 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1982 vFrom.size = strlen(appData.premoveHighlightColor);
1983 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1984 if (vTo.addr == NULL) {
1985 appData.monoMode = True;
1988 premoveHighlightColor = *(Pixel *) vTo.addr;
1993 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1996 if (appData.bitmapDirectory == NULL ||
1997 appData.bitmapDirectory[0] == NULLCHAR)
1998 appData.bitmapDirectory = DEF_BITMAP_DIR;
2001 if (appData.lowTimeWarning && !appData.monoMode) {
2002 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2003 vFrom.size = strlen(appData.lowTimeWarningColor);
2004 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2005 if (vTo.addr == NULL)
2006 appData.monoMode = True;
2008 lowTimeWarningColor = *(Pixel *) vTo.addr;
2011 if (appData.monoMode && appData.debugMode) {
2012 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2013 (unsigned long) XWhitePixel(xDisplay, xScreen),
2014 (unsigned long) XBlackPixel(xDisplay, xScreen));
2017 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2018 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2019 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2020 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2021 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2022 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2023 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2024 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2025 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2026 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2028 if (appData.colorize) {
2030 _("%s: can't parse color names; disabling colorization\n"),
2033 appData.colorize = FALSE;
2035 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2036 textColors[ColorNone].attr = 0;
2038 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2044 layoutName = "tinyLayout";
2045 } else if (smallLayout) {
2046 layoutName = "smallLayout";
2048 layoutName = "normalLayout";
2050 /* Outer layoutWidget is there only to provide a name for use in
2051 resources that depend on the layout style */
2053 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2054 layoutArgs, XtNumber(layoutArgs));
2056 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2057 formArgs, XtNumber(formArgs));
2058 XtSetArg(args[0], XtNdefaultDistance, &sep);
2059 XtGetValues(formWidget, args, 1);
2062 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2063 XtSetArg(args[0], XtNtop, XtChainTop);
2064 XtSetArg(args[1], XtNbottom, XtChainTop);
2065 XtSetArg(args[2], XtNright, XtChainLeft);
2066 XtSetValues(menuBarWidget, args, 3);
2068 widgetList[j++] = whiteTimerWidget =
2069 XtCreateWidget("whiteTime", labelWidgetClass,
2070 formWidget, timerArgs, XtNumber(timerArgs));
2071 XtSetArg(args[0], XtNfont, clockFontStruct);
2072 XtSetArg(args[1], XtNtop, XtChainTop);
2073 XtSetArg(args[2], XtNbottom, XtChainTop);
2074 XtSetValues(whiteTimerWidget, args, 3);
2076 widgetList[j++] = blackTimerWidget =
2077 XtCreateWidget("blackTime", labelWidgetClass,
2078 formWidget, timerArgs, XtNumber(timerArgs));
2079 XtSetArg(args[0], XtNfont, clockFontStruct);
2080 XtSetArg(args[1], XtNtop, XtChainTop);
2081 XtSetArg(args[2], XtNbottom, XtChainTop);
2082 XtSetValues(blackTimerWidget, args, 3);
2084 if (appData.titleInWindow) {
2085 widgetList[j++] = titleWidget =
2086 XtCreateWidget("title", labelWidgetClass, formWidget,
2087 titleArgs, XtNumber(titleArgs));
2088 XtSetArg(args[0], XtNtop, XtChainTop);
2089 XtSetArg(args[1], XtNbottom, XtChainTop);
2090 XtSetValues(titleWidget, args, 2);
2093 if (appData.showButtonBar) {
2094 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2095 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2096 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2097 XtSetArg(args[2], XtNtop, XtChainTop);
2098 XtSetArg(args[3], XtNbottom, XtChainTop);
2099 XtSetValues(buttonBarWidget, args, 4);
2102 widgetList[j++] = messageWidget =
2103 XtCreateWidget("message", labelWidgetClass, formWidget,
2104 messageArgs, XtNumber(messageArgs));
2105 XtSetArg(args[0], XtNtop, XtChainTop);
2106 XtSetArg(args[1], XtNbottom, XtChainTop);
2107 XtSetValues(messageWidget, args, 2);
2109 widgetList[j++] = boardWidget =
2110 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2111 XtNumber(boardArgs));
2113 XtManageChildren(widgetList, j);
2115 timerWidth = (boardWidth - sep) / 2;
2116 XtSetArg(args[0], XtNwidth, timerWidth);
2117 XtSetValues(whiteTimerWidget, args, 1);
2118 XtSetValues(blackTimerWidget, args, 1);
2120 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2121 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2122 XtGetValues(whiteTimerWidget, args, 2);
2124 if (appData.showButtonBar) {
2125 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2126 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2127 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2131 * formWidget uses these constraints but they are stored
2135 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2136 XtSetValues(menuBarWidget, args, i);
2137 if (appData.titleInWindow) {
2140 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2141 XtSetValues(whiteTimerWidget, args, i);
2143 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2144 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2145 XtSetValues(blackTimerWidget, args, i);
2147 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2148 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2149 XtSetValues(titleWidget, args, i);
2151 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2152 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2153 XtSetValues(messageWidget, args, i);
2154 if (appData.showButtonBar) {
2156 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2157 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2158 XtSetValues(buttonBarWidget, args, i);
2162 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2163 XtSetValues(whiteTimerWidget, args, i);
2165 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2166 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2167 XtSetValues(blackTimerWidget, args, i);
2169 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2170 XtSetValues(titleWidget, args, i);
2172 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2173 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2174 XtSetValues(messageWidget, args, i);
2175 if (appData.showButtonBar) {
2177 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2178 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2179 XtSetValues(buttonBarWidget, args, i);
2184 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2185 XtSetValues(whiteTimerWidget, args, i);
2187 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2188 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2189 XtSetValues(blackTimerWidget, args, i);
2191 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2192 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2193 XtSetValues(messageWidget, args, i);
2194 if (appData.showButtonBar) {
2196 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2197 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2198 XtSetValues(buttonBarWidget, args, i);
2202 XtSetArg(args[0], XtNfromVert, messageWidget);
2203 XtSetArg(args[1], XtNtop, XtChainTop);
2204 XtSetArg(args[2], XtNbottom, XtChainBottom);
2205 XtSetArg(args[3], XtNleft, XtChainLeft);
2206 XtSetArg(args[4], XtNright, XtChainRight);
2207 XtSetValues(boardWidget, args, 5);
2209 XtRealizeWidget(shellWidget);
2212 XtSetArg(args[0], XtNx, wpMain.x);
2213 XtSetArg(args[1], XtNy, wpMain.y);
2214 XtSetValues(shellWidget, args, 2);
2218 * Correct the width of the message and title widgets.
2219 * It is not known why some systems need the extra fudge term.
2220 * The value "2" is probably larger than needed.
2222 XawFormDoLayout(formWidget, False);
2224 #define WIDTH_FUDGE 2
2226 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2227 XtSetArg(args[i], XtNheight, &h); i++;
2228 XtGetValues(messageWidget, args, i);
2229 if (appData.showButtonBar) {
2231 XtSetArg(args[i], XtNwidth, &w); i++;
2232 XtGetValues(buttonBarWidget, args, i);
2233 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2235 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2238 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2239 if (gres != XtGeometryYes && appData.debugMode) {
2240 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2241 programName, gres, w, h, wr, hr);
2244 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2245 /* The size used for the child widget in layout lags one resize behind
2246 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2248 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2249 if (gres != XtGeometryYes && appData.debugMode) {
2250 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2251 programName, gres, w, h, wr, hr);
2254 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2255 XtSetArg(args[1], XtNright, XtChainRight);
2256 XtSetValues(messageWidget, args, 2);
2258 if (appData.titleInWindow) {
2260 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2261 XtSetArg(args[i], XtNheight, &h); i++;
2262 XtGetValues(titleWidget, args, i);
2264 w = boardWidth - 2*bor;
2266 XtSetArg(args[0], XtNwidth, &w);
2267 XtGetValues(menuBarWidget, args, 1);
2268 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2271 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2272 if (gres != XtGeometryYes && appData.debugMode) {
2274 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2275 programName, gres, w, h, wr, hr);
2278 XawFormDoLayout(formWidget, True);
2280 xBoardWindow = XtWindow(boardWidget);
2282 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2283 // not need to go into InitDrawingSizes().
2287 * Create X checkmark bitmap and initialize option menu checks.
2289 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2290 checkmark_bits, checkmark_width, checkmark_height);
2291 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2292 if (appData.alwaysPromoteToQueen) {
2293 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2296 if (appData.animateDragging) {
2297 XtSetValues(XtNameToWidget(menuBarWidget,
2298 "menuOptions.Animate Dragging"),
2301 if (appData.animate) {
2302 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2305 if (appData.autoComment) {
2306 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2309 if (appData.autoCallFlag) {
2310 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2313 if (appData.autoFlipView) {
2314 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2317 if (appData.autoObserve) {
2318 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2321 if (appData.autoRaiseBoard) {
2322 XtSetValues(XtNameToWidget(menuBarWidget,
2323 "menuOptions.Auto Raise Board"), args, 1);
2325 if (appData.autoSaveGames) {
2326 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2329 if (appData.saveGameFile[0] != NULLCHAR) {
2330 /* Can't turn this off from menu */
2331 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2333 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2337 if (appData.blindfold) {
2338 XtSetValues(XtNameToWidget(menuBarWidget,
2339 "menuOptions.Blindfold"), args, 1);
2341 if (appData.flashCount > 0) {
2342 XtSetValues(XtNameToWidget(menuBarWidget,
2343 "menuOptions.Flash Moves"),
2346 if (appData.getMoveList) {
2347 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2351 if (appData.highlightDragging) {
2352 XtSetValues(XtNameToWidget(menuBarWidget,
2353 "menuOptions.Highlight Dragging"),
2357 if (appData.highlightLastMove) {
2358 XtSetValues(XtNameToWidget(menuBarWidget,
2359 "menuOptions.Highlight Last Move"),
2362 if (appData.icsAlarm) {
2363 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2366 if (appData.ringBellAfterMoves) {
2367 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2370 if (appData.oldSaveStyle) {
2371 XtSetValues(XtNameToWidget(menuBarWidget,
2372 "menuOptions.Old Save Style"), args, 1);
2374 if (appData.periodicUpdates) {
2375 XtSetValues(XtNameToWidget(menuBarWidget,
2376 "menuOptions.Periodic Updates"), args, 1);
2378 if (appData.ponderNextMove) {
2379 XtSetValues(XtNameToWidget(menuBarWidget,
2380 "menuOptions.Ponder Next Move"), args, 1);
2382 if (appData.popupExitMessage) {
2383 XtSetValues(XtNameToWidget(menuBarWidget,
2384 "menuOptions.Popup Exit Message"), args, 1);
2386 if (appData.popupMoveErrors) {
2387 XtSetValues(XtNameToWidget(menuBarWidget,
2388 "menuOptions.Popup Move Errors"), args, 1);
2390 if (appData.premove) {
2391 XtSetValues(XtNameToWidget(menuBarWidget,
2392 "menuOptions.Premove"), args, 1);
2394 if (appData.quietPlay) {
2395 XtSetValues(XtNameToWidget(menuBarWidget,
2396 "menuOptions.Quiet Play"), args, 1);
2398 if (appData.showCoords) {
2399 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2402 if (appData.hideThinkingFromHuman) {
2403 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2406 if (appData.testLegality) {
2407 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2410 if (saveSettingsOnExit) {
2411 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2418 ReadBitmap(&wIconPixmap, "icon_white.bm",
2419 icon_white_bits, icon_white_width, icon_white_height);
2420 ReadBitmap(&bIconPixmap, "icon_black.bm",
2421 icon_black_bits, icon_black_width, icon_black_height);
2422 iconPixmap = wIconPixmap;
2424 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2425 XtSetValues(shellWidget, args, i);
2428 * Create a cursor for the board widget.
2430 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2431 XChangeWindowAttributes(xDisplay, xBoardWindow,
2432 CWCursor, &window_attributes);
2435 * Inhibit shell resizing.
2437 shellArgs[0].value = (XtArgVal) &w;
2438 shellArgs[1].value = (XtArgVal) &h;
2439 XtGetValues(shellWidget, shellArgs, 2);
2440 shellArgs[4].value = shellArgs[2].value = w;
2441 shellArgs[5].value = shellArgs[3].value = h;
2442 XtSetValues(shellWidget, &shellArgs[2], 4);
2443 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2444 marginH = h - boardHeight;
2446 CatchDeleteWindow(shellWidget, "QuitProc");
2451 if (appData.bitmapDirectory[0] != NULLCHAR) {
2458 /* Create regular pieces */
2459 if (!useImages) CreatePieces();
2464 if (appData.animate || appData.animateDragging)
2467 XtAugmentTranslations(formWidget,
2468 XtParseTranslationTable(globalTranslations));
2469 XtAugmentTranslations(boardWidget,
2470 XtParseTranslationTable(boardTranslations));
2471 XtAugmentTranslations(whiteTimerWidget,
2472 XtParseTranslationTable(whiteTranslations));
2473 XtAugmentTranslations(blackTimerWidget,
2474 XtParseTranslationTable(blackTranslations));
2476 /* Why is the following needed on some versions of X instead
2477 * of a translation? */
2478 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2479 (XtEventHandler) EventProc, NULL);
2482 /* [AS] Restore layout */
2483 if( wpMoveHistory.visible ) {
2487 if( wpEvalGraph.visible )
2492 if( wpEngineOutput.visible ) {
2493 EngineOutputPopUp();
2498 if (errorExitStatus == -1) {
2499 if (appData.icsActive) {
2500 /* We now wait until we see "login:" from the ICS before
2501 sending the logon script (problems with timestamp otherwise) */
2502 /*ICSInitScript();*/
2503 if (appData.icsInputBox) ICSInputBoxPopUp();
2507 signal(SIGWINCH, TermSizeSigHandler);
2509 signal(SIGINT, IntSigHandler);
2510 signal(SIGTERM, IntSigHandler);
2511 if (*appData.cmailGameName != NULLCHAR) {
2512 signal(SIGUSR1, CmailSigHandler);
2515 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2518 XtAppMainLoop(appContext);
2519 if (appData.debugMode) fclose(debugFP); // [DM] debug
2526 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2527 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2529 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2530 unlink(gameCopyFilename);
2531 unlink(gamePasteFilename);
2534 RETSIGTYPE TermSizeSigHandler(int sig)
2547 CmailSigHandler(sig)
2553 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2555 /* Activate call-back function CmailSigHandlerCallBack() */
2556 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2558 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2562 CmailSigHandlerCallBack(isr, closure, message, count, error)
2570 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2572 /**** end signal code ****/
2582 f = fopen(appData.icsLogon, "r");
2588 strcat(buf, appData.icsLogon);
2589 f = fopen(buf, "r");
2593 ProcessICSInitScript(f);
2600 EditCommentPopDown();
2615 if (!menuBarWidget) return;
2616 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2618 DisplayError("menuStep.Revert", 0);
2620 XtSetSensitive(w, !grey);
2625 SetMenuEnables(enab)
2629 if (!menuBarWidget) return;
2630 while (enab->name != NULL) {
2631 w = XtNameToWidget(menuBarWidget, enab->name);
2633 DisplayError(enab->name, 0);
2635 XtSetSensitive(w, enab->value);
2641 Enables icsEnables[] = {
2642 { "menuFile.Mail Move", False },
2643 { "menuFile.Reload CMail Message", False },
2644 { "menuMode.Machine Black", False },
2645 { "menuMode.Machine White", False },
2646 { "menuMode.Analysis Mode", False },
2647 { "menuMode.Analyze File", False },
2648 { "menuMode.Two Machines", False },
2650 { "menuHelp.Hint", False },
2651 { "menuHelp.Book", False },
2652 { "menuStep.Move Now", False },
2653 { "menuOptions.Periodic Updates", False },
2654 { "menuOptions.Hide Thinking", False },
2655 { "menuOptions.Ponder Next Move", False },
2660 Enables ncpEnables[] = {
2661 { "menuFile.Mail Move", False },
2662 { "menuFile.Reload CMail Message", False },
2663 { "menuMode.Machine White", False },
2664 { "menuMode.Machine Black", False },
2665 { "menuMode.Analysis Mode", False },
2666 { "menuMode.Analyze File", False },
2667 { "menuMode.Two Machines", False },
2668 { "menuMode.ICS Client", False },
2669 { "menuMode.ICS Input Box", False },
2670 { "Action", False },
2671 { "menuStep.Revert", False },
2672 { "menuStep.Move Now", False },
2673 { "menuStep.Retract Move", False },
2674 { "menuOptions.Auto Comment", False },
2675 { "menuOptions.Auto Flag", False },
2676 { "menuOptions.Auto Flip View", False },
2677 { "menuOptions.Auto Observe", False },
2678 { "menuOptions.Auto Raise Board", False },
2679 { "menuOptions.Get Move List", False },
2680 { "menuOptions.ICS Alarm", False },
2681 { "menuOptions.Move Sound", False },
2682 { "menuOptions.Quiet Play", False },
2683 { "menuOptions.Hide Thinking", False },
2684 { "menuOptions.Periodic Updates", False },
2685 { "menuOptions.Ponder Next Move", False },
2686 { "menuHelp.Hint", False },
2687 { "menuHelp.Book", False },
2691 Enables gnuEnables[] = {
2692 { "menuMode.ICS Client", False },
2693 { "menuMode.ICS Input Box", False },
2694 { "menuAction.Accept", False },
2695 { "menuAction.Decline", False },
2696 { "menuAction.Rematch", False },
2697 { "menuAction.Adjourn", False },
2698 { "menuAction.Stop Examining", False },
2699 { "menuAction.Stop Observing", False },
2700 { "menuStep.Revert", False },
2701 { "menuOptions.Auto Comment", False },
2702 { "menuOptions.Auto Observe", False },
2703 { "menuOptions.Auto Raise Board", False },
2704 { "menuOptions.Get Move List", False },
2705 { "menuOptions.Premove", False },
2706 { "menuOptions.Quiet Play", False },
2708 /* The next two options rely on SetCmailMode being called *after* */
2709 /* SetGNUMode so that when GNU is being used to give hints these */
2710 /* menu options are still available */
2712 { "menuFile.Mail Move", False },
2713 { "menuFile.Reload CMail Message", False },
2717 Enables cmailEnables[] = {
2719 { "menuAction.Call Flag", False },
2720 { "menuAction.Draw", True },
2721 { "menuAction.Adjourn", False },
2722 { "menuAction.Abort", False },
2723 { "menuAction.Stop Observing", False },
2724 { "menuAction.Stop Examining", False },
2725 { "menuFile.Mail Move", True },
2726 { "menuFile.Reload CMail Message", True },
2730 Enables trainingOnEnables[] = {
2731 { "menuMode.Edit Comment", False },
2732 { "menuMode.Pause", False },
2733 { "menuStep.Forward", False },
2734 { "menuStep.Backward", False },
2735 { "menuStep.Forward to End", False },
2736 { "menuStep.Back to Start", False },
2737 { "menuStep.Move Now", False },
2738 { "menuStep.Truncate Game", False },
2742 Enables trainingOffEnables[] = {
2743 { "menuMode.Edit Comment", True },
2744 { "menuMode.Pause", True },
2745 { "menuStep.Forward", True },
2746 { "menuStep.Backward", True },
2747 { "menuStep.Forward to End", True },
2748 { "menuStep.Back to Start", True },
2749 { "menuStep.Move Now", True },
2750 { "menuStep.Truncate Game", True },
2754 Enables machineThinkingEnables[] = {
2755 { "menuFile.Load Game", False },
2756 { "menuFile.Load Next Game", False },
2757 { "menuFile.Load Previous Game", False },
2758 { "menuFile.Reload Same Game", False },
2759 { "menuFile.Paste Game", False },
2760 { "menuFile.Load Position", False },
2761 { "menuFile.Load Next Position", False },
2762 { "menuFile.Load Previous Position", False },
2763 { "menuFile.Reload Same Position", False },
2764 { "menuFile.Paste Position", False },
2765 { "menuMode.Machine White", False },
2766 { "menuMode.Machine Black", False },
2767 { "menuMode.Two Machines", False },
2768 { "menuStep.Retract Move", False },
2772 Enables userThinkingEnables[] = {
2773 { "menuFile.Load Game", True },
2774 { "menuFile.Load Next Game", True },
2775 { "menuFile.Load Previous Game", True },
2776 { "menuFile.Reload Same Game", True },
2777 { "menuFile.Paste Game", True },
2778 { "menuFile.Load Position", True },
2779 { "menuFile.Load Next Position", True },
2780 { "menuFile.Load Previous Position", True },
2781 { "menuFile.Reload Same Position", True },
2782 { "menuFile.Paste Position", True },
2783 { "menuMode.Machine White", True },
2784 { "menuMode.Machine Black", True },
2785 { "menuMode.Two Machines", True },
2786 { "menuStep.Retract Move", True },
2792 SetMenuEnables(icsEnables);
2795 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2796 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2803 SetMenuEnables(ncpEnables);
2809 SetMenuEnables(gnuEnables);
2815 SetMenuEnables(cmailEnables);
2821 SetMenuEnables(trainingOnEnables);
2822 if (appData.showButtonBar) {
2823 XtSetSensitive(buttonBarWidget, False);
2829 SetTrainingModeOff()
2831 SetMenuEnables(trainingOffEnables);
2832 if (appData.showButtonBar) {
2833 XtSetSensitive(buttonBarWidget, True);
2838 SetUserThinkingEnables()
2840 if (appData.noChessProgram) return;
2841 SetMenuEnables(userThinkingEnables);
2845 SetMachineThinkingEnables()
2847 if (appData.noChessProgram) return;
2848 SetMenuEnables(machineThinkingEnables);
2850 case MachinePlaysBlack:
2851 case MachinePlaysWhite:
2852 case TwoMachinesPlay:
2853 XtSetSensitive(XtNameToWidget(menuBarWidget,
2854 ModeToWidgetName(gameMode)), True);
2861 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2862 #define HISTORY_SIZE 64
\r
2863 static char *history[HISTORY_SIZE];
\r
2864 int histIn = 0, histP = 0;
\r
2867 SaveInHistory(char *cmd)
\r
2869 if (history[histIn] != NULL) {
\r
2870 free(history[histIn]);
\r
2871 history[histIn] = NULL;
\r
2873 if (*cmd == NULLCHAR) return;
\r
2874 history[histIn] = StrSave(cmd);
\r
2875 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2876 if (history[histIn] != NULL) {
\r
2877 free(history[histIn]);
\r
2878 history[histIn] = NULL;
\r
2884 PrevInHistory(char *cmd)
\r
2887 if (histP == histIn) {
\r
2888 if (history[histIn] != NULL) free(history[histIn]);
\r
2889 history[histIn] = StrSave(cmd);
\r
2891 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2892 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2894 return history[histP];
\r
2900 if (histP == histIn) return NULL;
\r
2901 histP = (histP + 1) % HISTORY_SIZE;
\r
2902 return history[histP];
\r
2904 // end of borrowed code
\r
2906 #define Abs(n) ((n)<0 ? -(n) : (n))
2909 * Find a font that matches "pattern" that is as close as
2910 * possible to the targetPxlSize. Prefer fonts that are k
2911 * pixels smaller to fonts that are k pixels larger. The
2912 * pattern must be in the X Consortium standard format,
2913 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2914 * The return value should be freed with XtFree when no
2917 char *FindFont(pattern, targetPxlSize)
2921 char **fonts, *p, *best, *scalable, *scalableTail;
2922 int i, j, nfonts, minerr, err, pxlSize;
2925 char **missing_list;
2927 char *def_string, *base_fnt_lst, strInt[3];
2929 XFontStruct **fnt_list;
2931 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2932 sprintf(strInt, "%d", targetPxlSize);
2933 p = strstr(pattern, "--");
2934 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2935 strcat(base_fnt_lst, strInt);
2936 strcat(base_fnt_lst, strchr(p + 2, '-'));
2938 if ((fntSet = XCreateFontSet(xDisplay,
2942 &def_string)) == NULL) {
2944 fprintf(stderr, _("Unable to create font set.\n"));
2948 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2950 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2952 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2953 programName, pattern);
2961 for (i=0; i<nfonts; i++) {
2964 if (*p != '-') continue;
2966 if (*p == NULLCHAR) break;
2967 if (*p++ == '-') j++;
2969 if (j < 7) continue;
2972 scalable = fonts[i];
2975 err = pxlSize - targetPxlSize;
2976 if (Abs(err) < Abs(minerr) ||
2977 (minerr > 0 && err < 0 && -err == minerr)) {
2983 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2984 /* If the error is too big and there is a scalable font,
2985 use the scalable font. */
2986 int headlen = scalableTail - scalable;
2987 p = (char *) XtMalloc(strlen(scalable) + 10);
2988 while (isdigit(*scalableTail)) scalableTail++;
2989 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2991 p = (char *) XtMalloc(strlen(best) + 1);
2994 if (appData.debugMode) {
2995 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2996 pattern, targetPxlSize, p);
2999 if (missing_count > 0)
3000 XFreeStringList(missing_list);
3001 XFreeFontSet(xDisplay, fntSet);
3003 XFreeFontNames(fonts);
3010 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3011 | GCBackground | GCFunction | GCPlaneMask;
3012 XGCValues gc_values;
3015 gc_values.plane_mask = AllPlanes;
3016 gc_values.line_width = lineGap;
3017 gc_values.line_style = LineSolid;
3018 gc_values.function = GXcopy;
3020 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3021 gc_values.background = XBlackPixel(xDisplay, xScreen);
3022 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3024 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3025 gc_values.background = XWhitePixel(xDisplay, xScreen);
3026 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3027 XSetFont(xDisplay, coordGC, coordFontID);
3029 // [HGM] make font for holdings counts (white on black0
3030 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3031 gc_values.background = XBlackPixel(xDisplay, xScreen);
3032 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3033 XSetFont(xDisplay, countGC, countFontID);
3035 if (appData.monoMode) {
3036 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3037 gc_values.background = XWhitePixel(xDisplay, xScreen);
3038 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3040 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3041 gc_values.background = XBlackPixel(xDisplay, xScreen);
3042 lightSquareGC = wbPieceGC
3043 = XtGetGC(shellWidget, value_mask, &gc_values);
3045 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3046 gc_values.background = XWhitePixel(xDisplay, xScreen);
3047 darkSquareGC = bwPieceGC
3048 = XtGetGC(shellWidget, value_mask, &gc_values);
3050 if (DefaultDepth(xDisplay, xScreen) == 1) {
3051 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3052 gc_values.function = GXcopyInverted;
3053 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3054 gc_values.function = GXcopy;
3055 if (XBlackPixel(xDisplay, xScreen) == 1) {
3056 bwPieceGC = darkSquareGC;
3057 wbPieceGC = copyInvertedGC;
3059 bwPieceGC = copyInvertedGC;
3060 wbPieceGC = lightSquareGC;
3064 gc_values.foreground = highlightSquareColor;
3065 gc_values.background = highlightSquareColor;
3066 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3068 gc_values.foreground = premoveHighlightColor;
3069 gc_values.background = premoveHighlightColor;
3070 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3072 gc_values.foreground = lightSquareColor;
3073 gc_values.background = darkSquareColor;
3074 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3076 gc_values.foreground = darkSquareColor;
3077 gc_values.background = lightSquareColor;
3078 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3080 gc_values.foreground = jailSquareColor;
3081 gc_values.background = jailSquareColor;
3082 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3084 gc_values.foreground = whitePieceColor;
3085 gc_values.background = darkSquareColor;
3086 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3088 gc_values.foreground = whitePieceColor;
3089 gc_values.background = lightSquareColor;
3090 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3092 gc_values.foreground = whitePieceColor;
3093 gc_values.background = jailSquareColor;
3094 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3096 gc_values.foreground = blackPieceColor;
3097 gc_values.background = darkSquareColor;
3098 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3100 gc_values.foreground = blackPieceColor;
3101 gc_values.background = lightSquareColor;
3102 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3104 gc_values.foreground = blackPieceColor;
3105 gc_values.background = jailSquareColor;
3106 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3110 void loadXIM(xim, xmask, filename, dest, mask)
3123 fp = fopen(filename, "rb");
3125 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3132 for (y=0; y<h; ++y) {
3133 for (x=0; x<h; ++x) {
3138 XPutPixel(xim, x, y, blackPieceColor);
3140 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3143 XPutPixel(xim, x, y, darkSquareColor);
3145 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3148 XPutPixel(xim, x, y, whitePieceColor);
3150 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3153 XPutPixel(xim, x, y, lightSquareColor);
3155 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3161 /* create Pixmap of piece */
3162 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3164 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3167 /* create Pixmap of clipmask
3168 Note: We assume the white/black pieces have the same
3169 outline, so we make only 6 masks. This is okay
3170 since the XPM clipmask routines do the same. */
3172 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3174 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3177 /* now create the 1-bit version */
3178 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3181 values.foreground = 1;
3182 values.background = 0;
3184 /* Don't use XtGetGC, not read only */
3185 maskGC = XCreateGC(xDisplay, *mask,
3186 GCForeground | GCBackground, &values);
3187 XCopyPlane(xDisplay, temp, *mask, maskGC,
3188 0, 0, squareSize, squareSize, 0, 0, 1);
3189 XFreePixmap(xDisplay, temp);
3194 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3196 void CreateXIMPieces()
3201 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3206 /* The XSynchronize calls were copied from CreatePieces.
3207 Not sure if needed, but can't hurt */
3208 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3211 /* temp needed by loadXIM() */
3212 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3213 0, 0, ss, ss, AllPlanes, XYPixmap);
3215 if (strlen(appData.pixmapDirectory) == 0) {
3219 if (appData.monoMode) {
3220 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3224 fprintf(stderr, _("\nLoading XIMs...\n"));
3226 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3227 fprintf(stderr, "%d", piece+1);
3228 for (kind=0; kind<4; kind++) {
3229 fprintf(stderr, ".");
3230 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3231 ExpandPathName(appData.pixmapDirectory),
3232 piece <= (int) WhiteKing ? "" : "w",
3233 pieceBitmapNames[piece],
3235 ximPieceBitmap[kind][piece] =
3236 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3237 0, 0, ss, ss, AllPlanes, XYPixmap);
3238 if (appData.debugMode)
3239 fprintf(stderr, _("(File:%s:) "), buf);
3240 loadXIM(ximPieceBitmap[kind][piece],
3242 &(xpmPieceBitmap2[kind][piece]),
3243 &(ximMaskPm2[piece]));
3244 if(piece <= (int)WhiteKing)
3245 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3247 fprintf(stderr," ");
3249 /* Load light and dark squares */
3250 /* If the LSQ and DSQ pieces don't exist, we will
3251 draw them with solid squares. */
3252 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3253 if (access(buf, 0) != 0) {
3257 fprintf(stderr, _("light square "));
3259 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3260 0, 0, ss, ss, AllPlanes, XYPixmap);
3261 if (appData.debugMode)
3262 fprintf(stderr, _("(File:%s:) "), buf);
3264 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3265 fprintf(stderr, _("dark square "));
3266 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3267 ExpandPathName(appData.pixmapDirectory), ss);
3268 if (appData.debugMode)
3269 fprintf(stderr, _("(File:%s:) "), buf);
3271 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3272 0, 0, ss, ss, AllPlanes, XYPixmap);
3273 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3274 xpmJailSquare = xpmLightSquare;
3276 fprintf(stderr, _("Done.\n"));
3278 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3282 void CreateXPMPieces()
3286 u_int ss = squareSize;
3288 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3289 XpmColorSymbol symbols[4];
3291 /* The XSynchronize calls were copied from CreatePieces.
3292 Not sure if needed, but can't hurt */
3293 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3295 /* Setup translations so piece colors match square colors */
3296 symbols[0].name = "light_piece";
3297 symbols[0].value = appData.whitePieceColor;
3298 symbols[1].name = "dark_piece";
3299 symbols[1].value = appData.blackPieceColor;
3300 symbols[2].name = "light_square";
3301 symbols[2].value = appData.lightSquareColor;
3302 symbols[3].name = "dark_square";
3303 symbols[3].value = appData.darkSquareColor;
3305 attr.valuemask = XpmColorSymbols;
3306 attr.colorsymbols = symbols;
3307 attr.numsymbols = 4;
3309 if (appData.monoMode) {
3310 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3314 if (strlen(appData.pixmapDirectory) == 0) {
3315 XpmPieces* pieces = builtInXpms;
3318 while (pieces->size != squareSize && pieces->size) pieces++;
3319 if (!pieces->size) {
3320 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3323 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3324 for (kind=0; kind<4; kind++) {
3326 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3327 pieces->xpm[piece][kind],
3328 &(xpmPieceBitmap2[kind][piece]),
3329 NULL, &attr)) != 0) {
3330 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3334 if(piece <= (int) WhiteKing)
3335 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3339 xpmJailSquare = xpmLightSquare;
3343 fprintf(stderr, _("\nLoading XPMs...\n"));
3346 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3347 fprintf(stderr, "%d ", piece+1);
3348 for (kind=0; kind<4; kind++) {
3349 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3350 ExpandPathName(appData.pixmapDirectory),
3351 piece > (int) WhiteKing ? "w" : "",
3352 pieceBitmapNames[piece],
3354 if (appData.debugMode) {
3355 fprintf(stderr, _("(File:%s:) "), buf);
3357 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3358 &(xpmPieceBitmap2[kind][piece]),
3359 NULL, &attr)) != 0) {
3360 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3361 // [HGM] missing: read of unorthodox piece failed; substitute King.
3362 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3363 ExpandPathName(appData.pixmapDirectory),
3365 if (appData.debugMode) {
3366 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3368 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3369 &(xpmPieceBitmap2[kind][piece]),
3373 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3378 if(piece <= (int) WhiteKing)
3379 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3382 /* Load light and dark squares */
3383 /* If the LSQ and DSQ pieces don't exist, we will
3384 draw them with solid squares. */
3385 fprintf(stderr, _("light square "));
3386 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3387 if (access(buf, 0) != 0) {
3391 if (appData.debugMode)
3392 fprintf(stderr, _("(File:%s:) "), buf);
3394 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3395 &xpmLightSquare, NULL, &attr)) != 0) {
3396 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3399 fprintf(stderr, _("dark square "));
3400 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3401 ExpandPathName(appData.pixmapDirectory), ss);
3402 if (appData.debugMode) {
3403 fprintf(stderr, _("(File:%s:) "), buf);
3405 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3406 &xpmDarkSquare, NULL, &attr)) != 0) {
3407 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3411 xpmJailSquare = xpmLightSquare;
3412 fprintf(stderr, _("Done.\n"));
3414 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3417 #endif /* HAVE_LIBXPM */
3420 /* No built-in bitmaps */
3425 u_int ss = squareSize;
3427 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3430 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3431 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3432 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3433 pieceBitmapNames[piece],
3434 ss, kind == SOLID ? 's' : 'o');
3435 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3436 if(piece <= (int)WhiteKing)
3437 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3441 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3445 /* With built-in bitmaps */
3448 BuiltInBits* bib = builtInBits;
3451 u_int ss = squareSize;
3453 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3456 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3458 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3459 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3460 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3461 pieceBitmapNames[piece],
3462 ss, kind == SOLID ? 's' : 'o');
3463 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3464 bib->bits[kind][piece], ss, ss);
3465 if(piece <= (int)WhiteKing)
3466 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3470 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3475 void ReadBitmap(pm, name, bits, wreq, hreq)
3478 unsigned char bits[];
3484 char msg[MSG_SIZ], fullname[MSG_SIZ];
3486 if (*appData.bitmapDirectory != NULLCHAR) {
3487 strcpy(fullname, appData.bitmapDirectory);
3488 strcat(fullname, "/");
3489 strcat(fullname, name);
3490 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3491 &w, &h, pm, &x_hot, &y_hot);
3492 fprintf(stderr, "load %s\n", name);
3493 if (errcode != BitmapSuccess) {
3495 case BitmapOpenFailed:
3496 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3498 case BitmapFileInvalid:
3499 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3501 case BitmapNoMemory:
3502 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3506 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3510 fprintf(stderr, _("%s: %s...using built-in\n"),
3512 } else if (w != wreq || h != hreq) {
3514 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3515 programName, fullname, w, h, wreq, hreq);
3521 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3530 if (lineGap == 0) return;
3532 /* [HR] Split this into 2 loops for non-square boards. */
3534 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3535 gridSegments[i].x1 = 0;
3536 gridSegments[i].x2 =
3537 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3538 gridSegments[i].y1 = gridSegments[i].y2
3539 = lineGap / 2 + (i * (squareSize + lineGap));
3542 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3543 gridSegments[j + i].y1 = 0;
3544 gridSegments[j + i].y2 =
3545 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3546 gridSegments[j + i].x1 = gridSegments[j + i].x2
3547 = lineGap / 2 + (j * (squareSize + lineGap));
3551 static void MenuBarSelect(w, addr, index)
3556 XtActionProc proc = (XtActionProc) addr;
3558 (proc)(NULL, NULL, NULL, NULL);
3561 void CreateMenuBarPopup(parent, name, mb)
3571 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3574 XtSetArg(args[j], XtNleftMargin, 20); j++;
3575 XtSetArg(args[j], XtNrightMargin, 20); j++;
3577 while (mi->string != NULL) {
3578 if (strcmp(mi->string, "----") == 0) {
3579 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3582 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3583 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3585 XtAddCallback(entry, XtNcallback,
3586 (XtCallbackProc) MenuBarSelect,
3587 (caddr_t) mi->proc);
3593 Widget CreateMenuBar(mb)
3597 Widget anchor, menuBar;
3599 char menuName[MSG_SIZ];
3602 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3603 XtSetArg(args[j], XtNvSpace, 0); j++;
3604 XtSetArg(args[j], XtNborderWidth, 0); j++;
3605 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3606 formWidget, args, j);
3608 while (mb->name != NULL) {
3609 strcpy(menuName, "menu");
3610 strcat(menuName, mb->name);
3612 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3615 shortName[0] = _(mb->name)[0];
3616 shortName[1] = NULLCHAR;
3617 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3620 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3623 XtSetArg(args[j], XtNborderWidth, 0); j++;
3624 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3626 CreateMenuBarPopup(menuBar, menuName, mb);
3632 Widget CreateButtonBar(mi)
3636 Widget button, buttonBar;
3640 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3642 XtSetArg(args[j], XtNhSpace, 0); j++;
3644 XtSetArg(args[j], XtNborderWidth, 0); j++;
3645 XtSetArg(args[j], XtNvSpace, 0); j++;
3646 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3647 formWidget, args, j);
3649 while (mi->string != NULL) {
3652 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3653 XtSetArg(args[j], XtNborderWidth, 0); j++;
3655 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3656 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3657 buttonBar, args, j);
3658 XtAddCallback(button, XtNcallback,
3659 (XtCallbackProc) MenuBarSelect,
3660 (caddr_t) mi->proc);
3667 CreatePieceMenu(name, color)
3674 ChessSquare selection;
3676 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3677 boardWidget, args, 0);
3679 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3680 String item = pieceMenuStrings[color][i];
3682 if (strcmp(item, "----") == 0) {
3683 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3686 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3687 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3689 selection = pieceMenuTranslation[color][i];
3690 XtAddCallback(entry, XtNcallback,
3691 (XtCallbackProc) PieceMenuSelect,
3692 (caddr_t) selection);
3693 if (selection == WhitePawn || selection == BlackPawn) {
3694 XtSetArg(args[0], XtNpopupOnEntry, entry);
3695 XtSetValues(menu, args, 1);
3708 ChessSquare selection;
3710 whitePieceMenu = CreatePieceMenu("menuW", 0);
3711 blackPieceMenu = CreatePieceMenu("menuB", 1);
3713 XtRegisterGrabAction(PieceMenuPopup, True,
3714 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3715 GrabModeAsync, GrabModeAsync);
3717 XtSetArg(args[0], XtNlabel, _("Drop"));
3718 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3719 boardWidget, args, 1);
3720 for (i = 0; i < DROP_MENU_SIZE; i++) {
3721 String item = dropMenuStrings[i];
3723 if (strcmp(item, "----") == 0) {
3724 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3727 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3728 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3730 selection = dropMenuTranslation[i];
3731 XtAddCallback(entry, XtNcallback,
3732 (XtCallbackProc) DropMenuSelect,
3733 (caddr_t) selection);
3738 void SetupDropMenu()
3746 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3747 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3748 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3749 dmEnables[i].piece);
3750 XtSetSensitive(entry, p != NULL || !appData.testLegality
3751 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3752 && !appData.icsActive));
3754 while (p && *p++ == dmEnables[i].piece) count++;
3755 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3757 XtSetArg(args[j], XtNlabel, label); j++;
3758 XtSetValues(entry, args, j);
3762 void PieceMenuPopup(w, event, params, num_params)
3766 Cardinal *num_params;
3768 String whichMenu; int menuNr;
3769 if (event->type == ButtonRelease)
3770 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3771 else if (event->type == ButtonPress)
3772 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3774 case 0: whichMenu = params[0]; break;
3775 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3777 case -1: if (errorUp) ErrorPopDown();
3780 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3783 static void PieceMenuSelect(w, piece, junk)
3788 if (pmFromX < 0 || pmFromY < 0) return;
3789 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3792 static void DropMenuSelect(w, piece, junk)
3797 if (pmFromX < 0 || pmFromY < 0) return;
3798 DropMenuEvent(piece, pmFromX, pmFromY);
3801 void WhiteClock(w, event, prms, nprms)
3807 if (gameMode == EditPosition || gameMode == IcsExamining) {
3808 SetWhiteToPlayEvent();
3809 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3814 void BlackClock(w, event, prms, nprms)
3820 if (gameMode == EditPosition || gameMode == IcsExamining) {
3821 SetBlackToPlayEvent();
3822 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3829 * If the user selects on a border boundary, return -1; if off the board,
3830 * return -2. Otherwise map the event coordinate to the square.
3832 int EventToSquare(x, limit)
3840 if ((x % (squareSize + lineGap)) >= squareSize)
3842 x /= (squareSize + lineGap);
3848 static void do_flash_delay(msec)
3854 static void drawHighlight(file, rank, gc)
3860 if (lineGap == 0 || appData.blindfold) return;
3863 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3864 (squareSize + lineGap);
3865 y = lineGap/2 + rank * (squareSize + lineGap);
3867 x = lineGap/2 + file * (squareSize + lineGap);
3868 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3869 (squareSize + lineGap);
3872 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3873 squareSize+lineGap, squareSize+lineGap);
3876 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3877 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3880 SetHighlights(fromX, fromY, toX, toY)
3881 int fromX, fromY, toX, toY;
3883 if (hi1X != fromX || hi1Y != fromY) {
3884 if (hi1X >= 0 && hi1Y >= 0) {
3885 drawHighlight(hi1X, hi1Y, lineGC);
3887 } // [HGM] first erase both, then draw new!
3888 if (hi2X != toX || hi2Y != toY) {
3889 if (hi2X >= 0 && hi2Y >= 0) {
3890 drawHighlight(hi2X, hi2Y, lineGC);
3893 if (hi1X != fromX || hi1Y != fromY) {
3894 if (fromX >= 0 && fromY >= 0) {
3895 drawHighlight(fromX, fromY, highlineGC);
3898 if (hi2X != toX || hi2Y != toY) {
3899 if (toX >= 0 && toY >= 0) {
3900 drawHighlight(toX, toY, highlineGC);
3912 SetHighlights(-1, -1, -1, -1);
3917 SetPremoveHighlights(fromX, fromY, toX, toY)
3918 int fromX, fromY, toX, toY;
3920 if (pm1X != fromX || pm1Y != fromY) {
3921 if (pm1X >= 0 && pm1Y >= 0) {
3922 drawHighlight(pm1X, pm1Y, lineGC);
3924 if (fromX >= 0 && fromY >= 0) {
3925 drawHighlight(fromX, fromY, prelineGC);
3928 if (pm2X != toX || pm2Y != toY) {
3929 if (pm2X >= 0 && pm2Y >= 0) {
3930 drawHighlight(pm2X, pm2Y, lineGC);
3932 if (toX >= 0 && toY >= 0) {
3933 drawHighlight(toX, toY, prelineGC);
3943 ClearPremoveHighlights()
3945 SetPremoveHighlights(-1, -1, -1, -1);
3948 static void BlankSquare(x, y, color, piece, dest)
3953 if (useImages && useImageSqs) {
3957 pm = xpmLightSquare;
3962 case 2: /* neutral */
3967 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3968 squareSize, squareSize, x, y);
3978 case 2: /* neutral */
3983 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3988 I split out the routines to draw a piece so that I could
3989 make a generic flash routine.
3991 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3993 int square_color, x, y;
3996 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3997 switch (square_color) {
3999 case 2: /* neutral */
4001 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4002 ? *pieceToOutline(piece)
4003 : *pieceToSolid(piece),
4004 dest, bwPieceGC, 0, 0,
4005 squareSize, squareSize, x, y);
4008 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4009 ? *pieceToSolid(piece)
4010 : *pieceToOutline(piece),
4011 dest, wbPieceGC, 0, 0,
4012 squareSize, squareSize, x, y);
4017 static void monoDrawPiece(piece, square_color, x, y, dest)
4019 int square_color, x, y;
4022 switch (square_color) {
4024 case 2: /* neutral */
4026 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4027 ? *pieceToOutline(piece)
4028 : *pieceToSolid(piece),
4029 dest, bwPieceGC, 0, 0,
4030 squareSize, squareSize, x, y, 1);
4033 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4034 ? *pieceToSolid(piece)
4035 : *pieceToOutline(piece),
4036 dest, wbPieceGC, 0, 0,
4037 squareSize, squareSize, x, y, 1);
4042 static void colorDrawPiece(piece, square_color, x, y, dest)
4044 int square_color, x, y;
4047 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4048 switch (square_color) {
4050 XCopyPlane(xDisplay, *pieceToSolid(piece),
4051 dest, (int) piece < (int) BlackPawn
4052 ? wlPieceGC : blPieceGC, 0, 0,
4053 squareSize, squareSize, x, y, 1);
4056 XCopyPlane(xDisplay, *pieceToSolid(piece),
4057 dest, (int) piece < (int) BlackPawn
4058 ? wdPieceGC : bdPieceGC, 0, 0,
4059 squareSize, squareSize, x, y, 1);
4061 case 2: /* neutral */
4063 XCopyPlane(xDisplay, *pieceToSolid(piece),
4064 dest, (int) piece < (int) BlackPawn
4065 ? wjPieceGC : bjPieceGC, 0, 0,
4066 squareSize, squareSize, x, y, 1);
4071 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4073 int square_color, x, y;
4078 switch (square_color) {
4080 case 2: /* neutral */
4082 if ((int)piece < (int) BlackPawn) {
4090 if ((int)piece < (int) BlackPawn) {
4098 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4099 dest, wlPieceGC, 0, 0,
4100 squareSize, squareSize, x, y);
4103 typedef void (*DrawFunc)();
4105 DrawFunc ChooseDrawFunc()
4107 if (appData.monoMode) {
4108 if (DefaultDepth(xDisplay, xScreen) == 1) {
4109 return monoDrawPiece_1bit;
4111 return monoDrawPiece;
4115 return colorDrawPieceImage;
4117 return colorDrawPiece;
4121 /* [HR] determine square color depending on chess variant. */
4122 static int SquareColor(row, column)
4127 if (gameInfo.variant == VariantXiangqi) {
4128 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4130 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4132 } else if (row <= 4) {
4138 square_color = ((column + row) % 2) == 1;
4141 /* [hgm] holdings: next line makes all holdings squares light */
4142 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4144 return square_color;
4147 void DrawSquare(row, column, piece, do_flash)
4148 int row, column, do_flash;
4151 int square_color, x, y, direction, font_ascent, font_descent;
4154 XCharStruct overall;
4158 /* Calculate delay in milliseconds (2-delays per complete flash) */
4159 flash_delay = 500 / appData.flashRate;
4162 x = lineGap + ((BOARD_WIDTH-1)-column) *
4163 (squareSize + lineGap);
4164 y = lineGap + row * (squareSize + lineGap);
4166 x = lineGap + column * (squareSize + lineGap);
4167 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4168 (squareSize + lineGap);
4171 square_color = SquareColor(row, column);
4173 if ( // [HGM] holdings: blank out area between board and holdings
4174 column == BOARD_LEFT-1 || column == BOARD_RGHT
4175 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4176 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4177 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4179 // [HGM] print piece counts next to holdings
4180 string[1] = NULLCHAR;
4181 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4182 string[0] = '0' + piece;
4183 XTextExtents(countFontStruct, string, 1, &direction,
4184 &font_ascent, &font_descent, &overall);
4185 if (appData.monoMode) {
4186 XDrawImageString(xDisplay, xBoardWindow, countGC,
4187 x + squareSize - overall.width - 2,
4188 y + font_ascent + 1, string, 1);
4190 XDrawString(xDisplay, xBoardWindow, countGC,
4191 x + squareSize - overall.width - 2,
4192 y + font_ascent + 1, string, 1);
4195 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4196 string[0] = '0' + piece;
4197 XTextExtents(countFontStruct, string, 1, &direction,
4198 &font_ascent, &font_descent, &overall);
4199 if (appData.monoMode) {
4200 XDrawImageString(xDisplay, xBoardWindow, countGC,
4201 x + 2, y + font_ascent + 1, string, 1);
4203 XDrawString(xDisplay, xBoardWindow, countGC,
4204 x + 2, y + font_ascent + 1, string, 1);
4208 if (piece == EmptySquare || appData.blindfold) {
4209 BlankSquare(x, y, square_color, piece, xBoardWindow);
4211 drawfunc = ChooseDrawFunc();
4212 if (do_flash && appData.flashCount > 0) {
4213 for (i=0; i<appData.flashCount; ++i) {
4215 drawfunc(piece, square_color, x, y, xBoardWindow);
4216 XSync(xDisplay, False);
4217 do_flash_delay(flash_delay);
4219 BlankSquare(x, y, square_color, piece, xBoardWindow);
4220 XSync(xDisplay, False);
4221 do_flash_delay(flash_delay);
4224 drawfunc(piece, square_color, x, y, xBoardWindow);
4228 string[1] = NULLCHAR;
4229 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4230 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4231 string[0] = 'a' + column - BOARD_LEFT;
4232 XTextExtents(coordFontStruct, string, 1, &direction,
4233 &font_ascent, &font_descent, &overall);
4234 if (appData.monoMode) {
4235 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4236 x + squareSize - overall.width - 2,
4237 y + squareSize - font_descent - 1, string, 1);
4239 XDrawString(xDisplay, xBoardWindow, coordGC,
4240 x + squareSize - overall.width - 2,
4241 y + squareSize - font_descent - 1, string, 1);
4244 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4245 string[0] = ONE + row;
4246 XTextExtents(coordFontStruct, string, 1, &direction,
4247 &font_ascent, &font_descent, &overall);
4248 if (appData.monoMode) {
4249 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4250 x + 2, y + font_ascent + 1, string, 1);
4252 XDrawString(xDisplay, xBoardWindow, coordGC,
4253 x + 2, y + font_ascent + 1, string, 1);
4256 if(marker[row][column]) {
4257 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4258 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4263 /* Why is this needed on some versions of X? */
4264 void EventProc(widget, unused, event)
4269 if (!XtIsRealized(widget))
4272 switch (event->type) {
4274 if (event->xexpose.count > 0) return; /* no clipping is done */
4275 XDrawPosition(widget, True, NULL);
4278 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4285 void DrawPosition(fullRedraw, board)
4286 /*Boolean*/int fullRedraw;
4289 XDrawPosition(boardWidget, fullRedraw, board);
4292 /* Returns 1 if there are "too many" differences between b1 and b2
4293 (i.e. more than 1 move was made) */
4294 static int too_many_diffs(b1, b2)
4300 for (i=0; i<BOARD_HEIGHT; ++i) {
4301 for (j=0; j<BOARD_WIDTH; ++j) {
4302 if (b1[i][j] != b2[i][j]) {
4303 if (++c > 4) /* Castling causes 4 diffs */
4312 /* Matrix describing castling maneuvers */
4313 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4314 static int castling_matrix[4][5] = {
4315 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4316 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4317 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4318 { 7, 7, 4, 5, 6 } /* 0-0, black */
4321 /* Checks whether castling occurred. If it did, *rrow and *rcol
4322 are set to the destination (row,col) of the rook that moved.
4324 Returns 1 if castling occurred, 0 if not.
4326 Note: Only handles a max of 1 castling move, so be sure
4327 to call too_many_diffs() first.
4329 static int check_castle_draw(newb, oldb, rrow, rcol)
4336 /* For each type of castling... */
4337 for (i=0; i<4; ++i) {
4338 r = castling_matrix[i];
4340 /* Check the 4 squares involved in the castling move */
4342 for (j=1; j<=4; ++j) {
4343 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4350 /* All 4 changed, so it must be a castling move */
4359 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4360 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4362 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4365 void DrawSeekBackground( int left, int top, int right, int bottom )
4367 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4370 void DrawSeekText(char *buf, int x, int y)
4372 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4375 void DrawSeekDot(int x, int y, int colorNr)
4377 int square = colorNr & 0x80;
4380 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4382 XFillRectangle(xDisplay, xBoardWindow, color,
4383 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4385 XFillArc(xDisplay, xBoardWindow, color,
4386 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4389 static int damage[BOARD_RANKS][BOARD_FILES];
4392 * event handler for redrawing the board
4394 void XDrawPosition(w, repaint, board)
4396 /*Boolean*/int repaint;
4400 static int lastFlipView = 0;
4401 static int lastBoardValid = 0;
4402 static Board lastBoard;
4406 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4408 if (board == NULL) {
4409 if (!lastBoardValid) return;
4412 if (!lastBoardValid || lastFlipView != flipView) {
4413 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4414 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4419 * It would be simpler to clear the window with XClearWindow()
4420 * but this causes a very distracting flicker.
4423 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4425 /* If too much changes (begin observing new game, etc.), don't
4427 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4429 /* Special check for castling so we don't flash both the king
4430 and the rook (just flash the king). */
4432 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4433 /* Draw rook with NO flashing. King will be drawn flashing later */
4434 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4435 lastBoard[rrow][rcol] = board[rrow][rcol];
4439 /* First pass -- Draw (newly) empty squares and repair damage.
4440 This prevents you from having a piece show up twice while it
4441 is flashing on its new square */
4442 for (i = 0; i < BOARD_HEIGHT; i++)
4443 for (j = 0; j < BOARD_WIDTH; j++)
4444 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4446 DrawSquare(i, j, board[i][j], 0);
4447 damage[i][j] = False;
4450 /* Second pass -- Draw piece(s) in new position and flash them */
4451 for (i = 0; i < BOARD_HEIGHT; i++)
4452 for (j = 0; j < BOARD_WIDTH; j++)
4453 if (board[i][j] != lastBoard[i][j]) {
4454 DrawSquare(i, j, board[i][j], do_flash);
4458 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4459 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4461 for (i = 0; i < BOARD_HEIGHT; i++)
4462 for (j = 0; j < BOARD_WIDTH; j++) {
4463 DrawSquare(i, j, board[i][j], 0);
4464 damage[i][j] = False;
4468 CopyBoard(lastBoard, board);
4470 lastFlipView = flipView;
4472 /* Draw highlights */
4473 if (pm1X >= 0 && pm1Y >= 0) {
4474 drawHighlight(pm1X, pm1Y, prelineGC);
4476 if (pm2X >= 0 && pm2Y >= 0) {
4477 drawHighlight(pm2X, pm2Y, prelineGC);
4479 if (hi1X >= 0 && hi1Y >= 0) {
4480 drawHighlight(hi1X, hi1Y, highlineGC);
4482 if (hi2X >= 0 && hi2Y >= 0) {
4483 drawHighlight(hi2X, hi2Y, highlineGC);
4486 /* If piece being dragged around board, must redraw that too */
4489 XSync(xDisplay, False);
4494 * event handler for redrawing the board
4496 void DrawPositionProc(w, event, prms, nprms)
4502 XDrawPosition(w, True, NULL);
4507 * event handler for parsing user moves
4509 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4510 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4511 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4512 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4513 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4514 // and at the end FinishMove() to perform the move after optional promotion popups.
4515 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4516 void HandleUserMove(w, event, prms, nprms)
4522 if (w != boardWidget || errorExitStatus != -1) return;
4525 if (event->type == ButtonPress) {
4526 XtPopdown(promotionShell);
4527 XtDestroyWidget(promotionShell);
4528 promotionUp = False;
4536 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4537 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4538 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4541 void AnimateUserMove (Widget w, XEvent * event,
4542 String * params, Cardinal * nParams)
4544 DragPieceMove(event->xmotion.x, event->xmotion.y);
4547 void HandlePV (Widget w, XEvent * event,
4548 String * params, Cardinal * nParams)
4549 { // [HGM] pv: walk PV
4550 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4553 Widget CommentCreate(name, text, mutable, callback, lines)
4555 int /*Boolean*/ mutable;
4556 XtCallbackProc callback;
4560 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4565 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4566 XtGetValues(boardWidget, args, j);
4569 XtSetArg(args[j], XtNresizable, True); j++;
4572 XtCreatePopupShell(name, topLevelShellWidgetClass,
4573 shellWidget, args, j);
4576 XtCreatePopupShell(name, transientShellWidgetClass,
4577 shellWidget, args, j);
4580 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4581 layoutArgs, XtNumber(layoutArgs));
4583 XtCreateManagedWidget("form", formWidgetClass, layout,
4584 formArgs, XtNumber(formArgs));
4588 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4589 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4591 XtSetArg(args[j], XtNstring, text); j++;
4592 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4593 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4594 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4595 XtSetArg(args[j], XtNright, XtChainRight); j++;
4596 XtSetArg(args[j], XtNresizable, True); j++;
4597 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4598 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4599 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4600 XtSetArg(args[j], XtNautoFill, True); j++;
4601 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4603 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4607 XtSetArg(args[j], XtNfromVert, edit); j++;
4608 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4609 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4610 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4611 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4613 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4614 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4617 XtSetArg(args[j], XtNfromVert, edit); j++;
4618 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4619 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4620 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4621 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4622 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4624 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4625 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4628 XtSetArg(args[j], XtNfromVert, edit); j++;
4629 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4630 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4631 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4632 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4633 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4635 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4636 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4639 XtSetArg(args[j], XtNfromVert, edit); j++;
4640 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4641 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4642 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4643 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4645 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4646 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4649 XtSetArg(args[j], XtNfromVert, edit); j++;
4650 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4651 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4652 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4653 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4654 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4656 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4657 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4660 XtRealizeWidget(shell);
4662 if (commentX == -1) {
4665 Dimension pw_height;
4666 Dimension ew_height;
4669 XtSetArg(args[j], XtNheight, &ew_height); j++;
4670 XtGetValues(edit, args, j);
4673 XtSetArg(args[j], XtNheight, &pw_height); j++;
4674 XtGetValues(shell, args, j);
4675 commentH = pw_height + (lines - 1) * ew_height;
4676 commentW = bw_width - 16;
4678 XSync(xDisplay, False);
4680 /* This code seems to tickle an X bug if it is executed too soon
4681 after xboard starts up. The coordinates get transformed as if
4682 the main window was positioned at (0, 0).
4684 XtTranslateCoords(shellWidget,
4685 (bw_width - commentW) / 2, 0 - commentH / 2,
4686 &commentX, &commentY);
4688 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4689 RootWindowOfScreen(XtScreen(shellWidget)),
4690 (bw_width - commentW) / 2, 0 - commentH / 2,
4695 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4698 if(wpComment.width > 0) {
4699 commentX = wpComment.x;
4700 commentY = wpComment.y;
4701 commentW = wpComment.width;
4702 commentH = wpComment.height;
4706 XtSetArg(args[j], XtNheight, commentH); j++;
4707 XtSetArg(args[j], XtNwidth, commentW); j++;
4708 XtSetArg(args[j], XtNx, commentX); j++;
4709 XtSetArg(args[j], XtNy, commentY); j++;
4710 XtSetValues(shell, args, j);
4711 XtSetKeyboardFocus(shell, edit);
4716 /* Used for analysis window and ICS input window */
4717 Widget MiscCreate(name, text, mutable, callback, lines)
4719 int /*Boolean*/ mutable;
4720 XtCallbackProc callback;
4724 Widget shell, layout, form, edit;
4726 Dimension bw_width, pw_height, ew_height, w, h;
4732 XtSetArg(args[j], XtNresizable, True); j++;
4735 XtCreatePopupShell(name, topLevelShellWidgetClass,
4736 shellWidget, args, j);
4739 XtCreatePopupShell(name, transientShellWidgetClass,
4740 shellWidget, args, j);
4743 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4744 layoutArgs, XtNumber(layoutArgs));
4746 XtCreateManagedWidget("form", formWidgetClass, layout,
4747 formArgs, XtNumber(formArgs));
4751 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4752 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4754 XtSetArg(args[j], XtNstring, text); j++;
4755 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4756 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4757 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4758 XtSetArg(args[j], XtNright, XtChainRight); j++;
4759 XtSetArg(args[j], XtNresizable, True); j++;
4760 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4761 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4762 XtSetArg(args[j], XtNautoFill, True); j++;
4763 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4765 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4767 XtRealizeWidget(shell);
4770 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4771 XtGetValues(boardWidget, args, j);
4774 XtSetArg(args[j], XtNheight, &ew_height); j++;
4775 XtGetValues(edit, args, j);
4778 XtSetArg(args[j], XtNheight, &pw_height); j++;
4779 XtGetValues(shell, args, j);
4780 h = pw_height + (lines - 1) * ew_height;
4783 XSync(xDisplay, False);
4785 /* This code seems to tickle an X bug if it is executed too soon
4786 after xboard starts up. The coordinates get transformed as if
4787 the main window was positioned at (0, 0).
4789 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4791 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4792 RootWindowOfScreen(XtScreen(shellWidget)),
4793 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4797 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4800 XtSetArg(args[j], XtNheight, h); j++;
4801 XtSetArg(args[j], XtNwidth, w); j++;
4802 XtSetArg(args[j], XtNx, x); j++;
4803 XtSetArg(args[j], XtNy, y); j++;
4804 XtSetValues(shell, args, j);
4810 static int savedIndex; /* gross that this is global */
4812 void EditCommentPopUp(index, title, text)
4821 if (text == NULL) text = "";
4823 if (editShell == NULL) {
4825 CommentCreate(title, text, True, EditCommentCallback, 4);
4826 XtRealizeWidget(editShell);
4827 CatchDeleteWindow(editShell, "EditCommentPopDown");
4829 edit = XtNameToWidget(editShell, "*form.text");
4831 XtSetArg(args[j], XtNstring, text); j++;
4832 XtSetValues(edit, args, j);
4834 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4835 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4836 XtSetValues(editShell, args, j);
4839 XtPopup(editShell, XtGrabNone);
4843 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4844 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4848 void EditCommentCallback(w, client_data, call_data)
4850 XtPointer client_data, call_data;
4858 XtSetArg(args[j], XtNlabel, &name); j++;
4859 XtGetValues(w, args, j);
4861 if (strcmp(name, _("ok")) == 0) {
4862 edit = XtNameToWidget(editShell, "*form.text");
4864 XtSetArg(args[j], XtNstring, &val); j++;
4865 XtGetValues(edit, args, j);
4866 ReplaceComment(savedIndex, val);
4867 EditCommentPopDown();
4868 } else if (strcmp(name, _("cancel")) == 0) {
4869 EditCommentPopDown();
4870 } else if (strcmp(name, _("clear")) == 0) {
4871 edit = XtNameToWidget(editShell, "*form.text");
4872 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4873 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4877 void EditCommentPopDown()
4882 if (!editUp) return;
4884 XtSetArg(args[j], XtNx, &commentX); j++;
4885 XtSetArg(args[j], XtNy, &commentY); j++;
4886 XtSetArg(args[j], XtNheight, &commentH); j++;
4887 XtSetArg(args[j], XtNwidth, &commentW); j++;
4888 XtGetValues(editShell, args, j);
4889 XtPopdown(editShell);
4892 XtSetArg(args[j], XtNleftBitmap, None); j++;
4893 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4897 void ICSInputBoxPopUp()
4902 char *title = _("ICS Input");
4905 if (ICSInputShell == NULL) {
4906 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4907 tr = XtParseTranslationTable(ICSInputTranslations);
4908 edit = XtNameToWidget(ICSInputShell, "*form.text");
4909 XtOverrideTranslations(edit, tr);
4910 XtRealizeWidget(ICSInputShell);
4911 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4914 edit = XtNameToWidget(ICSInputShell, "*form.text");
4916 XtSetArg(args[j], XtNstring, ""); j++;
4917 XtSetValues(edit, args, j);
4919 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4920 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4921 XtSetValues(ICSInputShell, args, j);
4924 XtPopup(ICSInputShell, XtGrabNone);
4925 XtSetKeyboardFocus(ICSInputShell, edit);
4927 ICSInputBoxUp = True;
4929 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4930 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4934 void ICSInputSendText()
4941 edit = XtNameToWidget(ICSInputShell, "*form.text");
4943 XtSetArg(args[j], XtNstring, &val); j++;
4944 XtGetValues(edit, args, j);
4946 SendMultiLineToICS(val);
4947 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4948 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4951 void ICSInputBoxPopDown()
4956 if (!ICSInputBoxUp) return;
4958 XtPopdown(ICSInputShell);
4959 ICSInputBoxUp = False;
4961 XtSetArg(args[j], XtNleftBitmap, None); j++;
4962 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4966 void CommentPopUp(title, text)
4973 if (commentShell == NULL) {
4975 CommentCreate(title, text, False, CommentCallback, 4);
4976 XtRealizeWidget(commentShell);
4977 CatchDeleteWindow(commentShell, "CommentPopDown");
4979 edit = XtNameToWidget(commentShell, "*form.text");
4981 XtSetArg(args[j], XtNstring, text); j++;
4982 XtSetValues(edit, args, j);
4984 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4985 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4986 XtSetValues(commentShell, args, j);
4989 XtPopup(commentShell, XtGrabNone);
4990 XSync(xDisplay, False);
4995 void CommentCallback(w, client_data, call_data)
4997 XtPointer client_data, call_data;
5004 XtSetArg(args[j], XtNlabel, &name); j++;
5005 XtGetValues(w, args, j);
5007 if (strcmp(name, _("close")) == 0) {
5009 } else if (strcmp(name, _("edit")) == 0) {
5016 void CommentPopDown()
5021 if (!commentUp) return;
5023 XtSetArg(args[j], XtNx, &commentX); j++;
5024 XtSetArg(args[j], XtNy, &commentY); j++;
5025 XtSetArg(args[j], XtNwidth, &commentW); j++;
5026 XtSetArg(args[j], XtNheight, &commentH); j++;
5027 XtGetValues(commentShell, args, j);
5028 XtPopdown(commentShell);
5029 XSync(xDisplay, False);
5033 void FileNamePopUp(label, def, proc, openMode)
5040 Widget popup, layout, dialog, edit;
5046 fileProc = proc; /* I can't see a way not */
5047 fileOpenMode = openMode; /* to use globals here */
5050 XtSetArg(args[i], XtNresizable, True); i++;
5051 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
5052 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
5053 fileNameShell = popup =
5054 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
5055 shellWidget, args, i);
5058 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
5059 layoutArgs, XtNumber(layoutArgs));
5062 XtSetArg(args[i], XtNlabel, label); i++;
5063 XtSetArg(args[i], XtNvalue, def); i++;
5064 XtSetArg(args[i], XtNborderWidth, 0); i++;
5065 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
5068 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
5069 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
5070 (XtPointer) dialog);
5072 XtRealizeWidget(popup);
5073 CatchDeleteWindow(popup, "FileNamePopDown");
5075 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
5076 &x, &y, &win_x, &win_y, &mask);
5078 XtSetArg(args[0], XtNx, x - 10);
5079 XtSetArg(args[1], XtNy, y - 30);
5080 XtSetValues(popup, args, 2);
5082 XtPopup(popup, XtGrabExclusive);
5085 edit = XtNameToWidget(dialog, "*value");
5086 XtSetKeyboardFocus(popup, edit);
5089 void FileNamePopDown()
5091 if (!filenameUp) return;
5092 XtPopdown(fileNameShell);
5093 XtDestroyWidget(fileNameShell);
5098 void FileNameCallback(w, client_data, call_data)
5100 XtPointer client_data, call_data;
5105 XtSetArg(args[0], XtNlabel, &name);
5106 XtGetValues(w, args, 1);
5108 if (strcmp(name, _("cancel")) == 0) {
5113 FileNameAction(w, NULL, NULL, NULL);
5116 void FileNameAction(w, event, prms, nprms)
5128 name = XawDialogGetValueString(w = XtParent(w));
5130 if ((name != NULL) && (*name != NULLCHAR)) {
5132 XtPopdown(w = XtParent(XtParent(w)));
5136 p = strrchr(buf, ' ');
5143 fullname = ExpandPathName(buf);
5145 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5148 f = fopen(fullname, fileOpenMode);
5150 DisplayError(_("Failed to open file"), errno);
5152 (void) (*fileProc)(f, index, buf);
5159 XtPopdown(w = XtParent(XtParent(w)));
5165 void PromotionPopUp()
5168 Widget dialog, layout;
5170 Dimension bw_width, pw_width;
5174 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5175 XtGetValues(boardWidget, args, j);
5178 XtSetArg(args[j], XtNresizable, True); j++;
5179 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5181 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5182 shellWidget, args, j);
5184 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5185 layoutArgs, XtNumber(layoutArgs));
5188 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5189 XtSetArg(args[j], XtNborderWidth, 0); j++;
5190 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5193 if(gameInfo.variant != VariantShogi) {
5194 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5195 (XtPointer) dialog);
5196 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5197 (XtPointer) dialog);
5198 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5199 (XtPointer) dialog);
5200 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5201 (XtPointer) dialog);
5202 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5203 gameInfo.variant == VariantGiveaway) {
5204 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5205 (XtPointer) dialog);
5207 if(gameInfo.variant == VariantCapablanca ||
5208 gameInfo.variant == VariantGothic ||
5209 gameInfo.variant == VariantCapaRandom) {
5210 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5211 (XtPointer) dialog);
5212 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5213 (XtPointer) dialog);
5215 } else // [HGM] shogi
5217 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5218 (XtPointer) dialog);
5219 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5220 (XtPointer) dialog);
5222 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5223 (XtPointer) dialog);
5225 XtRealizeWidget(promotionShell);
5226 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5229 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5230 XtGetValues(promotionShell, args, j);
5232 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5233 lineGap + squareSize/3 +
5234 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5235 0 : 6*(squareSize + lineGap)), &x, &y);
5238 XtSetArg(args[j], XtNx, x); j++;
5239 XtSetArg(args[j], XtNy, y); j++;
5240 XtSetValues(promotionShell, args, j);
5242 XtPopup(promotionShell, XtGrabNone);
5247 void PromotionPopDown()
5249 if (!promotionUp) return;
5250 XtPopdown(promotionShell);
5251 XtDestroyWidget(promotionShell);
5252 promotionUp = False;
5255 void PromotionCallback(w, client_data, call_data)
5257 XtPointer client_data, call_data;
5263 XtSetArg(args[0], XtNlabel, &name);
5264 XtGetValues(w, args, 1);
5268 if (fromX == -1) return;
5270 if (strcmp(name, _("cancel")) == 0) {
5274 } else if (strcmp(name, _("Knight")) == 0) {
5276 } else if (strcmp(name, _("Promote")) == 0) {
5278 } else if (strcmp(name, _("Defer")) == 0) {
5281 promoChar = ToLower(name[0]);
5284 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5286 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5287 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5292 void ErrorCallback(w, client_data, call_data)
5294 XtPointer client_data, call_data;
5297 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5299 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5305 if (!errorUp) return;
5307 XtPopdown(errorShell);
5308 XtDestroyWidget(errorShell);
5309 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5312 void ErrorPopUp(title, label, modal)
5313 char *title, *label;
5317 Widget dialog, layout;
5321 Dimension bw_width, pw_width;
5322 Dimension pw_height;
5326 XtSetArg(args[i], XtNresizable, True); i++;
5327 XtSetArg(args[i], XtNtitle, title); i++;
5329 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5330 shellWidget, args, i);
5332 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5333 layoutArgs, XtNumber(layoutArgs));
5336 XtSetArg(args[i], XtNlabel, label); i++;
5337 XtSetArg(args[i], XtNborderWidth, 0); i++;
5338 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5341 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5343 XtRealizeWidget(errorShell);
5344 CatchDeleteWindow(errorShell, "ErrorPopDown");
5347 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5348 XtGetValues(boardWidget, args, i);
5350 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5351 XtSetArg(args[i], XtNheight, &pw_height); i++;
5352 XtGetValues(errorShell, args, i);
5355 /* This code seems to tickle an X bug if it is executed too soon
5356 after xboard starts up. The coordinates get transformed as if
5357 the main window was positioned at (0, 0).
5359 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5360 0 - pw_height + squareSize / 3, &x, &y);
5362 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5363 RootWindowOfScreen(XtScreen(boardWidget)),
5364 (bw_width - pw_width) / 2,
5365 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5369 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5372 XtSetArg(args[i], XtNx, x); i++;
5373 XtSetArg(args[i], XtNy, y); i++;
5374 XtSetValues(errorShell, args, i);
5377 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5380 /* Disable all user input other than deleting the window */
5381 static int frozen = 0;
5385 /* Grab by a widget that doesn't accept input */
5386 XtAddGrab(messageWidget, TRUE, FALSE);
5390 /* Undo a FreezeUI */
5393 if (!frozen) return;
5394 XtRemoveGrab(messageWidget);
5398 char *ModeToWidgetName(mode)
5402 case BeginningOfGame:
5403 if (appData.icsActive)
5404 return "menuMode.ICS Client";
5405 else if (appData.noChessProgram ||
5406 *appData.cmailGameName != NULLCHAR)
5407 return "menuMode.Edit Game";
5409 return "menuMode.Machine Black";
5410 case MachinePlaysBlack:
5411 return "menuMode.Machine Black";
5412 case MachinePlaysWhite:
5413 return "menuMode.Machine White";
5415 return "menuMode.Analysis Mode";
5417 return "menuMode.Analyze File";
5418 case TwoMachinesPlay:
5419 return "menuMode.Two Machines";
5421 return "menuMode.Edit Game";
5422 case PlayFromGameFile:
5423 return "menuFile.Load Game";
5425 return "menuMode.Edit Position";
5427 return "menuMode.Training";
5428 case IcsPlayingWhite:
5429 case IcsPlayingBlack:
5433 return "menuMode.ICS Client";
5440 void ModeHighlight()
5443 static int oldPausing = FALSE;
5444 static GameMode oldmode = (GameMode) -1;
5447 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5449 if (pausing != oldPausing) {
5450 oldPausing = pausing;
5452 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5454 XtSetArg(args[0], XtNleftBitmap, None);
5456 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5459 if (appData.showButtonBar) {
5460 /* Always toggle, don't set. Previous code messes up when
5461 invoked while the button is pressed, as releasing it
5462 toggles the state again. */
5465 XtSetArg(args[0], XtNbackground, &oldbg);
5466 XtSetArg(args[1], XtNforeground, &oldfg);
5467 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5469 XtSetArg(args[0], XtNbackground, oldfg);
5470 XtSetArg(args[1], XtNforeground, oldbg);
5472 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5476 wname = ModeToWidgetName(oldmode);
5477 if (wname != NULL) {
5478 XtSetArg(args[0], XtNleftBitmap, None);
5479 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5481 wname = ModeToWidgetName(gameMode);
5482 if (wname != NULL) {
5483 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5484 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5488 /* Maybe all the enables should be handled here, not just this one */
5489 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5490 gameMode == Training || gameMode == PlayFromGameFile);
5495 * Button/menu procedures
5497 void ResetProc(w, event, prms, nprms)
5506 int LoadGamePopUp(f, gameNumber, title)
5511 cmailMsgLoaded = FALSE;
5512 if (gameNumber == 0) {
5513 int error = GameListBuild(f);
5515 DisplayError(_("Cannot build game list"), error);
5516 } else if (!ListEmpty(&gameList) &&
5517 ((ListGame *) gameList.tailPred)->number > 1) {
5518 GameListPopUp(f, title);
5524 return LoadGame(f, gameNumber, title, FALSE);
5527 void LoadGameProc(w, event, prms, nprms)
5533 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5536 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5539 void LoadNextGameProc(w, event, prms, nprms)
5548 void LoadPrevGameProc(w, event, prms, nprms)
5557 void ReloadGameProc(w, event, prms, nprms)
5566 void LoadNextPositionProc(w, event, prms, nprms)
5575 void LoadPrevPositionProc(w, event, prms, nprms)
5584 void ReloadPositionProc(w, event, prms, nprms)
5593 void LoadPositionProc(w, event, prms, nprms)
5599 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5602 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5605 void SaveGameProc(w, event, prms, nprms)
5611 FileNamePopUp(_("Save game file name?"),
5612 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5616 void SavePositionProc(w, event, prms, nprms)
5622 FileNamePopUp(_("Save position file name?"),
5623 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5627 void ReloadCmailMsgProc(w, event, prms, nprms)
5633 ReloadCmailMsgEvent(FALSE);
5636 void MailMoveProc(w, event, prms, nprms)
5645 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5646 char *selected_fen_position=NULL;
5649 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5650 Atom *type_return, XtPointer *value_return,
5651 unsigned long *length_return, int *format_return)
5653 char *selection_tmp;
5655 if (!selected_fen_position) return False; /* should never happen */
5656 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5657 /* note: since no XtSelectionDoneProc was registered, Xt will
5658 * automatically call XtFree on the value returned. So have to
5659 * make a copy of it allocated with XtMalloc */
5660 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5661 strcpy(selection_tmp, selected_fen_position);
5663 *value_return=selection_tmp;
5664 *length_return=strlen(selection_tmp);
5665 *type_return=*target;
5666 *format_return = 8; /* bits per byte */
5668 } else if (*target == XA_TARGETS(xDisplay)) {
5669 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5670 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5671 targets_tmp[1] = XA_STRING;
5672 *value_return = targets_tmp;
5673 *type_return = XA_ATOM;
5675 *format_return = 8 * sizeof(Atom);
5676 if (*format_return > 32) {
5677 *length_return *= *format_return / 32;
5678 *format_return = 32;
5686 /* note: when called from menu all parameters are NULL, so no clue what the
5687 * Widget which was clicked on was, or what the click event was
5689 void CopyPositionProc(w, event, prms, nprms)
5696 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5697 * have a notion of a position that is selected but not copied.
5698 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5700 if(gameMode == EditPosition) EditPositionDone(TRUE);
5701 if (selected_fen_position) free(selected_fen_position);
5702 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5703 if (!selected_fen_position) return;
5704 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5706 SendPositionSelection,
5707 NULL/* lose_ownership_proc */ ,
5708 NULL/* transfer_done_proc */);
5709 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5711 SendPositionSelection,
5712 NULL/* lose_ownership_proc */ ,
5713 NULL/* transfer_done_proc */);
5716 /* function called when the data to Paste is ready */
5718 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5719 Atom *type, XtPointer value, unsigned long *len, int *format)
5722 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5723 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5724 EditPositionPasteFEN(fenstr);
5728 /* called when Paste Position button is pressed,
5729 * all parameters will be NULL */
5730 void PastePositionProc(w, event, prms, nprms)
5736 XtGetSelectionValue(menuBarWidget,
5737 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5738 /* (XtSelectionCallbackProc) */ PastePositionCB,
5739 NULL, /* client_data passed to PastePositionCB */
5741 /* better to use the time field from the event that triggered the
5742 * call to this function, but that isn't trivial to get
5750 SendGameSelection(Widget w, Atom *selection, Atom *target,
5751 Atom *type_return, XtPointer *value_return,
5752 unsigned long *length_return, int *format_return)
5754 char *selection_tmp;
5756 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5757 FILE* f = fopen(gameCopyFilename, "r");
5760 if (f == NULL) return False;
5764 selection_tmp = XtMalloc(len + 1);
5765 count = fread(selection_tmp, 1, len, f);
5767 XtFree(selection_tmp);
5770 selection_tmp[len] = NULLCHAR;
5771 *value_return = selection_tmp;
5772 *length_return = len;
5773 *type_return = *target;
5774 *format_return = 8; /* bits per byte */
5776 } else if (*target == XA_TARGETS(xDisplay)) {
5777 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5778 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5779 targets_tmp[1] = XA_STRING;
5780 *value_return = targets_tmp;
5781 *type_return = XA_ATOM;
5783 *format_return = 8 * sizeof(Atom);
5784 if (*format_return > 32) {
5785 *length_return *= *format_return / 32;
5786 *format_return = 32;
5794 /* note: when called from menu all parameters are NULL, so no clue what the
5795 * Widget which was clicked on was, or what the click event was
5797 void CopyGameProc(w, event, prms, nprms)
5805 ret = SaveGameToFile(gameCopyFilename, FALSE);
5809 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5810 * have a notion of a game that is selected but not copied.
5811 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5813 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5816 NULL/* lose_ownership_proc */ ,
5817 NULL/* transfer_done_proc */);
5818 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5821 NULL/* lose_ownership_proc */ ,
5822 NULL/* transfer_done_proc */);
5825 /* function called when the data to Paste is ready */
5827 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5828 Atom *type, XtPointer value, unsigned long *len, int *format)
5831 if (value == NULL || *len == 0) {
5832 return; /* nothing had been selected to copy */
5834 f = fopen(gamePasteFilename, "w");
5836 DisplayError(_("Can't open temp file"), errno);
5839 fwrite(value, 1, *len, f);
5842 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5845 /* called when Paste Game button is pressed,
5846 * all parameters will be NULL */
5847 void PasteGameProc(w, event, prms, nprms)
5853 XtGetSelectionValue(menuBarWidget,
5854 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5855 /* (XtSelectionCallbackProc) */ PasteGameCB,
5856 NULL, /* client_data passed to PasteGameCB */
5858 /* better to use the time field from the event that triggered the
5859 * call to this function, but that isn't trivial to get
5869 SaveGameProc(NULL, NULL, NULL, NULL);
5873 void QuitProc(w, event, prms, nprms)
5882 void PauseProc(w, event, prms, nprms)
5892 void MachineBlackProc(w, event, prms, nprms)
5898 MachineBlackEvent();
5901 void MachineWhiteProc(w, event, prms, nprms)
5907 MachineWhiteEvent();
5910 void AnalyzeModeProc(w, event, prms, nprms)
5918 if (!first.analysisSupport) {
5919 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5920 DisplayError(buf, 0);
5923 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5924 if (appData.icsActive) {
5925 if (gameMode != IcsObserving) {
5926 sprintf(buf,_("You are not observing a game"));
5927 DisplayError(buf, 0);
5929 if (appData.icsEngineAnalyze) {
5930 if (appData.debugMode)
5931 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5937 /* if enable, use want disable icsEngineAnalyze */
5938 if (appData.icsEngineAnalyze) {
5943 appData.icsEngineAnalyze = TRUE;
5944 if (appData.debugMode)
5945 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5947 if (!appData.showThinking)
5948 ShowThinkingProc(w,event,prms,nprms);
5953 void AnalyzeFileProc(w, event, prms, nprms)
5959 if (!first.analysisSupport) {
5961 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5962 DisplayError(buf, 0);
5967 if (!appData.showThinking)
5968 ShowThinkingProc(w,event,prms,nprms);
5971 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5972 AnalysisPeriodicEvent(1);
5975 void TwoMachinesProc(w, event, prms, nprms)
5984 void IcsClientProc(w, event, prms, nprms)
5993 void EditGameProc(w, event, prms, nprms)
6002 void EditPositionProc(w, event, prms, nprms)
6008 EditPositionEvent();
6011 void TrainingProc(w, event, prms, nprms)
6020 void EditCommentProc(w, event, prms, nprms)
6027 EditCommentPopDown();
6033 void IcsInputBoxProc(w, event, prms, nprms)
6039 if (ICSInputBoxUp) {
6040 ICSInputBoxPopDown();
6046 void AcceptProc(w, event, prms, nprms)
6055 void DeclineProc(w, event, prms, nprms)
6064 void RematchProc(w, event, prms, nprms)
6073 void CallFlagProc(w, event, prms, nprms)
6082 void DrawProc(w, event, prms, nprms)
6091 void AbortProc(w, event, prms, nprms)
6100 void AdjournProc(w, event, prms, nprms)
6109 void ResignProc(w, event, prms, nprms)
6118 void AdjuWhiteProc(w, event, prms, nprms)
6124 UserAdjudicationEvent(+1);
6127 void AdjuBlackProc(w, event, prms, nprms)
6133 UserAdjudicationEvent(-1);
6136 void AdjuDrawProc(w, event, prms, nprms)
6142 UserAdjudicationEvent(0);
6145 void EnterKeyProc(w, event, prms, nprms)
6151 if (ICSInputBoxUp == True)
6155 void UpKeyProc(w, event, prms, nprms)
6160 { // [HGM] input: let up-arrow recall previous line from history
6167 if (!ICSInputBoxUp) return;
6168 edit = XtNameToWidget(ICSInputShell, "*form.text");
6170 XtSetArg(args[j], XtNstring, &val); j++;
6171 XtGetValues(edit, args, j);
6172 val = PrevInHistory(val);
6173 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6174 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6176 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6177 XawTextReplace(edit, 0, 0, &t);
6178 XawTextSetInsertionPoint(edit, 9999);
6182 void DownKeyProc(w, event, prms, nprms)
6187 { // [HGM] input: let down-arrow recall next line from history
6192 if (!ICSInputBoxUp) return;
6193 edit = XtNameToWidget(ICSInputShell, "*form.text");
6194 val = NextInHistory();
6195 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6196 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6198 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6199 XawTextReplace(edit, 0, 0, &t);
6200 XawTextSetInsertionPoint(edit, 9999);
6204 void StopObservingProc(w, event, prms, nprms)
6210 StopObservingEvent();
6213 void StopExaminingProc(w, event, prms, nprms)
6219 StopExaminingEvent();
6223 void ForwardProc(w, event, prms, nprms)
6233 void BackwardProc(w, event, prms, nprms)
6242 void ToStartProc(w, event, prms, nprms)
6251 void ToEndProc(w, event, prms, nprms)
6260 void RevertProc(w, event, prms, nprms)
6269 void TruncateGameProc(w, event, prms, nprms)
6275 TruncateGameEvent();
6277 void RetractMoveProc(w, event, prms, nprms)
6286 void MoveNowProc(w, event, prms, nprms)
6296 void AlwaysQueenProc(w, event, prms, nprms)
6304 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6306 if (appData.alwaysPromoteToQueen) {
6307 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6309 XtSetArg(args[0], XtNleftBitmap, None);
6311 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6315 void AnimateDraggingProc(w, event, prms, nprms)
6323 appData.animateDragging = !appData.animateDragging;
6325 if (appData.animateDragging) {
6326 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6329 XtSetArg(args[0], XtNleftBitmap, None);
6331 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6335 void AnimateMovingProc(w, event, prms, nprms)
6343 appData.animate = !appData.animate;
6345 if (appData.animate) {
6346 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6349 XtSetArg(args[0], XtNleftBitmap, None);
6351 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6355 void AutocommProc(w, event, prms, nprms)
6363 appData.autoComment = !appData.autoComment;
6365 if (appData.autoComment) {
6366 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6368 XtSetArg(args[0], XtNleftBitmap, None);
6370 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6375 void AutoflagProc(w, event, prms, nprms)
6383 appData.autoCallFlag = !appData.autoCallFlag;
6385 if (appData.autoCallFlag) {
6386 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6388 XtSetArg(args[0], XtNleftBitmap, None);
6390 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6394 void AutoflipProc(w, event, prms, nprms)
6402 appData.autoFlipView = !appData.autoFlipView;
6404 if (appData.autoFlipView) {
6405 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6407 XtSetArg(args[0], XtNleftBitmap, None);
6409 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6413 void AutobsProc(w, event, prms, nprms)
6421 appData.autoObserve = !appData.autoObserve;
6423 if (appData.autoObserve) {
6424 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6426 XtSetArg(args[0], XtNleftBitmap, None);
6428 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6432 void AutoraiseProc(w, event, prms, nprms)
6440 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6442 if (appData.autoRaiseBoard) {
6443 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6445 XtSetArg(args[0], XtNleftBitmap, None);
6447 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6451 void AutosaveProc(w, event, prms, nprms)
6459 appData.autoSaveGames = !appData.autoSaveGames;
6461 if (appData.autoSaveGames) {
6462 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6464 XtSetArg(args[0], XtNleftBitmap, None);
6466 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6470 void BlindfoldProc(w, event, prms, nprms)
6478 appData.blindfold = !appData.blindfold;
6480 if (appData.blindfold) {
6481 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6483 XtSetArg(args[0], XtNleftBitmap, None);
6485 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6488 DrawPosition(True, NULL);
6491 void TestLegalityProc(w, event, prms, nprms)
6499 appData.testLegality = !appData.testLegality;
6501 if (appData.testLegality) {
6502 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6504 XtSetArg(args[0], XtNleftBitmap, None);
6506 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6511 void FlashMovesProc(w, event, prms, nprms)
6519 if (appData.flashCount == 0) {
6520 appData.flashCount = 3;
6522 appData.flashCount = -appData.flashCount;
6525 if (appData.flashCount > 0) {
6526 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6528 XtSetArg(args[0], XtNleftBitmap, None);
6530 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6534 void FlipViewProc(w, event, prms, nprms)
6540 flipView = !flipView;
6541 DrawPosition(True, NULL);
6544 void GetMoveListProc(w, event, prms, nprms)
6552 appData.getMoveList = !appData.getMoveList;
6554 if (appData.getMoveList) {
6555 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6558 XtSetArg(args[0], XtNleftBitmap, None);
6560 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6565 void HighlightDraggingProc(w, event, prms, nprms)
6573 appData.highlightDragging = !appData.highlightDragging;
6575 if (appData.highlightDragging) {
6576 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6578 XtSetArg(args[0], XtNleftBitmap, None);
6580 XtSetValues(XtNameToWidget(menuBarWidget,
6581 "menuOptions.Highlight Dragging"), args, 1);
6585 void HighlightLastMoveProc(w, event, prms, nprms)
6593 appData.highlightLastMove = !appData.highlightLastMove;
6595 if (appData.highlightLastMove) {
6596 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6598 XtSetArg(args[0], XtNleftBitmap, None);
6600 XtSetValues(XtNameToWidget(menuBarWidget,
6601 "menuOptions.Highlight Last Move"), args, 1);
6604 void IcsAlarmProc(w, event, prms, nprms)
6612 appData.icsAlarm = !appData.icsAlarm;
6614 if (appData.icsAlarm) {
6615 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6617 XtSetArg(args[0], XtNleftBitmap, None);
6619 XtSetValues(XtNameToWidget(menuBarWidget,
6620 "menuOptions.ICS Alarm"), args, 1);
6623 void MoveSoundProc(w, event, prms, nprms)
6631 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6633 if (appData.ringBellAfterMoves) {
6634 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6636 XtSetArg(args[0], XtNleftBitmap, None);
6638 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6643 void OldSaveStyleProc(w, event, prms, nprms)
6651 appData.oldSaveStyle = !appData.oldSaveStyle;
6653 if (appData.oldSaveStyle) {
6654 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6656 XtSetArg(args[0], XtNleftBitmap, None);
6658 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6662 void PeriodicUpdatesProc(w, event, prms, nprms)
6670 PeriodicUpdatesEvent(!appData.periodicUpdates);
6672 if (appData.periodicUpdates) {
6673 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6675 XtSetArg(args[0], XtNleftBitmap, None);
6677 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6681 void PonderNextMoveProc(w, event, prms, nprms)
6689 PonderNextMoveEvent(!appData.ponderNextMove);
6691 if (appData.ponderNextMove) {
6692 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6694 XtSetArg(args[0], XtNleftBitmap, None);
6696 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6700 void PopupExitMessageProc(w, event, prms, nprms)
6708 appData.popupExitMessage = !appData.popupExitMessage;
6710 if (appData.popupExitMessage) {
6711 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6713 XtSetArg(args[0], XtNleftBitmap, None);
6715 XtSetValues(XtNameToWidget(menuBarWidget,
6716 "menuOptions.Popup Exit Message"), args, 1);
6719 void PopupMoveErrorsProc(w, event, prms, nprms)
6727 appData.popupMoveErrors = !appData.popupMoveErrors;
6729 if (appData.popupMoveErrors) {
6730 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6732 XtSetArg(args[0], XtNleftBitmap, None);
6734 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6738 void PremoveProc(w, event, prms, nprms)
6746 appData.premove = !appData.premove;
6748 if (appData.premove) {
6749 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6751 XtSetArg(args[0], XtNleftBitmap, None);
6753 XtSetValues(XtNameToWidget(menuBarWidget,
6754 "menuOptions.Premove"), args, 1);
6757 void QuietPlayProc(w, event, prms, nprms)
6765 appData.quietPlay = !appData.quietPlay;
6767 if (appData.quietPlay) {
6768 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6770 XtSetArg(args[0], XtNleftBitmap, None);
6772 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6776 void ShowCoordsProc(w, event, prms, nprms)
6784 appData.showCoords = !appData.showCoords;
6786 if (appData.showCoords) {
6787 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6789 XtSetArg(args[0], XtNleftBitmap, None);
6791 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6794 DrawPosition(True, NULL);
6797 void ShowThinkingProc(w, event, prms, nprms)
6803 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6804 ShowThinkingEvent();
6807 void HideThinkingProc(w, event, prms, nprms)
6815 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6816 ShowThinkingEvent();
6818 if (appData.hideThinkingFromHuman) {
6819 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6821 XtSetArg(args[0], XtNleftBitmap, None);
6823 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6827 void SaveOnExitProc(w, event, prms, nprms)
6835 saveSettingsOnExit = !saveSettingsOnExit;
6837 if (saveSettingsOnExit) {
6838 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6840 XtSetArg(args[0], XtNleftBitmap, None);
6842 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6846 void SaveSettingsProc(w, event, prms, nprms)
6852 SaveSettings(settingsFileName);
6855 void InfoProc(w, event, prms, nprms)
6862 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6867 void ManProc(w, event, prms, nprms)
6875 if (nprms && *nprms > 0)
6879 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6883 void HintProc(w, event, prms, nprms)
6892 void BookProc(w, event, prms, nprms)
6901 void AboutProc(w, event, prms, nprms)
6909 char *zippy = " (with Zippy code)";
6913 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6914 programVersion, zippy,
6915 "Copyright 1991 Digital Equipment Corporation",
6916 "Enhancements Copyright 1992-2009 Free Software Foundation",
6917 "Enhancements Copyright 2005 Alessandro Scotti",
6918 PACKAGE, " is free software and carries NO WARRANTY;",
6919 "see the file COPYING for more information.");
6920 ErrorPopUp(_("About XBoard"), buf, FALSE);
6923 void DebugProc(w, event, prms, nprms)
6929 appData.debugMode = !appData.debugMode;
6932 void AboutGameProc(w, event, prms, nprms)
6941 void NothingProc(w, event, prms, nprms)
6950 void Iconify(w, event, prms, nprms)
6959 XtSetArg(args[0], XtNiconic, True);
6960 XtSetValues(shellWidget, args, 1);
6963 void DisplayMessage(message, extMessage)
6964 char *message, *extMessage;
6966 /* display a message in the message widget */
6975 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6980 message = extMessage;
6984 /* need to test if messageWidget already exists, since this function
6985 can also be called during the startup, if for example a Xresource
6986 is not set up correctly */
6989 XtSetArg(arg, XtNlabel, message);
6990 XtSetValues(messageWidget, &arg, 1);
6996 void DisplayTitle(text)
7001 char title[MSG_SIZ];
7004 if (text == NULL) text = "";
7006 if (appData.titleInWindow) {
7008 XtSetArg(args[i], XtNlabel, text); i++;
7009 XtSetValues(titleWidget, args, i);
7012 if (*text != NULLCHAR) {
7014 strcpy(title, text);
7015 } else if (appData.icsActive) {
7016 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7017 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7018 } else if (appData.cmailGameName[0] != NULLCHAR) {
7019 snprintf(icon, sizeof(icon), "%s", "CMail");
7020 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7022 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7023 } else if (gameInfo.variant == VariantGothic) {
7024 strcpy(icon, programName);
7025 strcpy(title, GOTHIC);
7028 } else if (gameInfo.variant == VariantFalcon) {
7029 strcpy(icon, programName);
7030 strcpy(title, FALCON);
7032 } else if (appData.noChessProgram) {
7033 strcpy(icon, programName);
7034 strcpy(title, programName);
7036 strcpy(icon, first.tidy);
7037 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7040 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7041 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7042 XtSetValues(shellWidget, args, i);
7046 void DisplayError(message, error)
7053 if (appData.debugMode || appData.matchMode) {
7054 fprintf(stderr, "%s: %s\n", programName, message);
7057 if (appData.debugMode || appData.matchMode) {
7058 fprintf(stderr, "%s: %s: %s\n",
7059 programName, message, strerror(error));
7061 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7064 ErrorPopUp(_("Error"), message, FALSE);
7068 void DisplayMoveError(message)
7073 DrawPosition(FALSE, NULL);
7074 if (appData.debugMode || appData.matchMode) {
7075 fprintf(stderr, "%s: %s\n", programName, message);
7077 if (appData.popupMoveErrors) {
7078 ErrorPopUp(_("Error"), message, FALSE);
7080 DisplayMessage(message, "");
7085 void DisplayFatalError(message, error, status)
7091 errorExitStatus = status;
7093 fprintf(stderr, "%s: %s\n", programName, message);
7095 fprintf(stderr, "%s: %s: %s\n",
7096 programName, message, strerror(error));
7097 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7100 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7101 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7107 void DisplayInformation(message)
7111 ErrorPopUp(_("Information"), message, TRUE);
7114 void DisplayNote(message)
7118 ErrorPopUp(_("Note"), message, FALSE);
7122 NullXErrorCheck(dpy, error_event)
7124 XErrorEvent *error_event;
7129 void DisplayIcsInteractionTitle(message)
7132 if (oldICSInteractionTitle == NULL) {
7133 /* Magic to find the old window title, adapted from vim */
7134 char *wina = getenv("WINDOWID");
7136 Window win = (Window) atoi(wina);
7137 Window root, parent, *children;
7138 unsigned int nchildren;
7139 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7141 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7142 if (!XQueryTree(xDisplay, win, &root, &parent,
7143 &children, &nchildren)) break;
7144 if (children) XFree((void *)children);
7145 if (parent == root || parent == 0) break;
7148 XSetErrorHandler(oldHandler);
7150 if (oldICSInteractionTitle == NULL) {
7151 oldICSInteractionTitle = "xterm";
7154 printf("\033]0;%s\007", message);
7158 char pendingReplyPrefix[MSG_SIZ];
7159 ProcRef pendingReplyPR;
7161 void AskQuestionProc(w, event, prms, nprms)
7168 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7172 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7175 void AskQuestionPopDown()
7177 if (!askQuestionUp) return;
7178 XtPopdown(askQuestionShell);
7179 XtDestroyWidget(askQuestionShell);
7180 askQuestionUp = False;
7183 void AskQuestionReplyAction(w, event, prms, nprms)
7193 reply = XawDialogGetValueString(w = XtParent(w));
7194 strcpy(buf, pendingReplyPrefix);
7195 if (*buf) strcat(buf, " ");
7198 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7199 AskQuestionPopDown();
7201 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7204 void AskQuestionCallback(w, client_data, call_data)
7206 XtPointer client_data, call_data;
7211 XtSetArg(args[0], XtNlabel, &name);
7212 XtGetValues(w, args, 1);
7214 if (strcmp(name, _("cancel")) == 0) {
7215 AskQuestionPopDown();
7217 AskQuestionReplyAction(w, NULL, NULL, NULL);
7221 void AskQuestion(title, question, replyPrefix, pr)
7222 char *title, *question, *replyPrefix;
7226 Widget popup, layout, dialog, edit;
7232 strcpy(pendingReplyPrefix, replyPrefix);
7233 pendingReplyPR = pr;
7236 XtSetArg(args[i], XtNresizable, True); i++;
7237 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7238 askQuestionShell = popup =
7239 XtCreatePopupShell(title, transientShellWidgetClass,
7240 shellWidget, args, i);
7243 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7244 layoutArgs, XtNumber(layoutArgs));
7247 XtSetArg(args[i], XtNlabel, question); i++;
7248 XtSetArg(args[i], XtNvalue, ""); i++;
7249 XtSetArg(args[i], XtNborderWidth, 0); i++;
7250 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7253 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7254 (XtPointer) dialog);
7255 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7256 (XtPointer) dialog);
7258 XtRealizeWidget(popup);
7259 CatchDeleteWindow(popup, "AskQuestionPopDown");
7261 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7262 &x, &y, &win_x, &win_y, &mask);
7264 XtSetArg(args[0], XtNx, x - 10);
7265 XtSetArg(args[1], XtNy, y - 30);
7266 XtSetValues(popup, args, 2);
7268 XtPopup(popup, XtGrabExclusive);
7269 askQuestionUp = True;
7271 edit = XtNameToWidget(dialog, "*value");
7272 XtSetKeyboardFocus(popup, edit);
7280 if (*name == NULLCHAR) {
7282 } else if (strcmp(name, "$") == 0) {
7283 putc(BELLCHAR, stderr);
7286 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7294 PlaySound(appData.soundMove);
7300 PlaySound(appData.soundIcsWin);
7306 PlaySound(appData.soundIcsLoss);
7312 PlaySound(appData.soundIcsDraw);
7316 PlayIcsUnfinishedSound()
7318 PlaySound(appData.soundIcsUnfinished);
7324 PlaySound(appData.soundIcsAlarm);
7330 system("stty echo");
7336 system("stty -echo");
7340 Colorize(cc, continuation)
7345 int count, outCount, error;
7347 if (textColors[(int)cc].bg > 0) {
7348 if (textColors[(int)cc].fg > 0) {
7349 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7350 textColors[(int)cc].fg, textColors[(int)cc].bg);
7352 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7353 textColors[(int)cc].bg);
7356 if (textColors[(int)cc].fg > 0) {
7357 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7358 textColors[(int)cc].fg);
7360 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7363 count = strlen(buf);
7364 outCount = OutputToProcess(NoProc, buf, count, &error);
7365 if (outCount < count) {
7366 DisplayFatalError(_("Error writing to display"), error, 1);
7369 if (continuation) return;
7372 PlaySound(appData.soundShout);
7375 PlaySound(appData.soundSShout);
7378 PlaySound(appData.soundChannel1);
7381 PlaySound(appData.soundChannel);
7384 PlaySound(appData.soundKibitz);
7387 PlaySound(appData.soundTell);
7389 case ColorChallenge:
7390 PlaySound(appData.soundChallenge);
7393 PlaySound(appData.soundRequest);
7396 PlaySound(appData.soundSeek);
7407 return getpwuid(getuid())->pw_name;
7410 static char *ExpandPathName(path)
7413 static char static_buf[2000];
7414 char *d, *s, buf[2000];
7420 while (*s && isspace(*s))
7429 if (*(s+1) == '/') {
7430 strcpy(d, getpwuid(getuid())->pw_dir);
7435 *strchr(buf, '/') = 0;
7436 pwd = getpwnam(buf);
7439 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7443 strcpy(d, pwd->pw_dir);
7444 strcat(d, strchr(s+1, '/'));
7455 static char host_name[MSG_SIZ];
7457 #if HAVE_GETHOSTNAME
7458 gethostname(host_name, MSG_SIZ);
7460 #else /* not HAVE_GETHOSTNAME */
7461 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7462 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7464 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7466 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7467 #endif /* not HAVE_GETHOSTNAME */
7470 XtIntervalId delayedEventTimerXID = 0;
7471 DelayedEventCallback delayedEventCallback = 0;
7476 delayedEventTimerXID = 0;
7477 delayedEventCallback();
7481 ScheduleDelayedEvent(cb, millisec)
7482 DelayedEventCallback cb; long millisec;
7484 if(delayedEventTimerXID && delayedEventCallback == cb)
7485 // [HGM] alive: replace, rather than add or flush identical event
7486 XtRemoveTimeOut(delayedEventTimerXID);
7487 delayedEventCallback = cb;
7488 delayedEventTimerXID =
7489 XtAppAddTimeOut(appContext, millisec,
7490 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7493 DelayedEventCallback
7496 if (delayedEventTimerXID) {
7497 return delayedEventCallback;
7504 CancelDelayedEvent()
7506 if (delayedEventTimerXID) {
7507 XtRemoveTimeOut(delayedEventTimerXID);
7508 delayedEventTimerXID = 0;
7512 XtIntervalId loadGameTimerXID = 0;
7514 int LoadGameTimerRunning()
7516 return loadGameTimerXID != 0;
7519 int StopLoadGameTimer()
7521 if (loadGameTimerXID != 0) {
7522 XtRemoveTimeOut(loadGameTimerXID);
7523 loadGameTimerXID = 0;
7531 LoadGameTimerCallback(arg, id)
7535 loadGameTimerXID = 0;
7540 StartLoadGameTimer(millisec)
7544 XtAppAddTimeOut(appContext, millisec,
7545 (XtTimerCallbackProc) LoadGameTimerCallback,
7549 XtIntervalId analysisClockXID = 0;
7552 AnalysisClockCallback(arg, id)
7556 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7557 || appData.icsEngineAnalyze) { // [DM]
7558 AnalysisPeriodicEvent(0);
7559 StartAnalysisClock();
7564 StartAnalysisClock()
7567 XtAppAddTimeOut(appContext, 2000,
7568 (XtTimerCallbackProc) AnalysisClockCallback,
7572 XtIntervalId clockTimerXID = 0;
7574 int ClockTimerRunning()
7576 return clockTimerXID != 0;
7579 int StopClockTimer()
7581 if (clockTimerXID != 0) {
7582 XtRemoveTimeOut(clockTimerXID);
7591 ClockTimerCallback(arg, id)
7600 StartClockTimer(millisec)
7604 XtAppAddTimeOut(appContext, millisec,
7605 (XtTimerCallbackProc) ClockTimerCallback,
7610 DisplayTimerLabel(w, color, timer, highlight)
7619 /* check for low time warning */
7620 Pixel foregroundOrWarningColor = timerForegroundPixel;
7623 appData.lowTimeWarning &&
7624 (timer / 1000) < appData.icsAlarmTime)
7625 foregroundOrWarningColor = lowTimeWarningColor;
7627 if (appData.clockMode) {
7628 sprintf(buf, "%s: %s", color, TimeString(timer));
7629 XtSetArg(args[0], XtNlabel, buf);
7631 sprintf(buf, "%s ", color);
7632 XtSetArg(args[0], XtNlabel, buf);
7637 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7638 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7640 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7641 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7644 XtSetValues(w, args, 3);
7648 DisplayWhiteClock(timeRemaining, highlight)
7654 if(appData.noGUI) return;
7655 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7656 if (highlight && iconPixmap == bIconPixmap) {
7657 iconPixmap = wIconPixmap;
7658 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7659 XtSetValues(shellWidget, args, 1);
7664 DisplayBlackClock(timeRemaining, highlight)
7670 if(appData.noGUI) return;
7671 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7672 if (highlight && iconPixmap == wIconPixmap) {
7673 iconPixmap = bIconPixmap;
7674 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7675 XtSetValues(shellWidget, args, 1);
7693 int StartChildProcess(cmdLine, dir, pr)
7700 int to_prog[2], from_prog[2];
7704 if (appData.debugMode) {
7705 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7708 /* We do NOT feed the cmdLine to the shell; we just
7709 parse it into blank-separated arguments in the
7710 most simple-minded way possible.
7713 strcpy(buf, cmdLine);
7716 while(*p == ' ') p++;
7718 if(*p == '"' || *p == '\'')
7719 p = strchr(++argv[i-1], *p);
7720 else p = strchr(p, ' ');
7721 if (p == NULL) break;
7726 SetUpChildIO(to_prog, from_prog);
7728 if ((pid = fork()) == 0) {
7730 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7731 close(to_prog[1]); // first close the unused pipe ends
7732 close(from_prog[0]);
7733 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7734 dup2(from_prog[1], 1);
7735 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7736 close(from_prog[1]); // and closing again loses one of the pipes!
7737 if(fileno(stderr) >= 2) // better safe than sorry...
7738 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7740 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7745 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7747 execvp(argv[0], argv);
7749 /* If we get here, exec failed */
7754 /* Parent process */
7756 close(from_prog[1]);
7758 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7761 cp->fdFrom = from_prog[0];
7762 cp->fdTo = to_prog[1];
7767 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7768 static RETSIGTYPE AlarmCallBack(int n)
7774 DestroyChildProcess(pr, signalType)
7778 ChildProc *cp = (ChildProc *) pr;
7780 if (cp->kind != CPReal) return;
7782 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7783 signal(SIGALRM, AlarmCallBack);
7785 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7786 kill(cp->pid, SIGKILL); // kill it forcefully
7787 wait((int *) 0); // and wait again
7791 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7793 /* Process is exiting either because of the kill or because of
7794 a quit command sent by the backend; either way, wait for it to die.
7803 InterruptChildProcess(pr)
7806 ChildProc *cp = (ChildProc *) pr;
7808 if (cp->kind != CPReal) return;
7809 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7812 int OpenTelnet(host, port, pr)
7817 char cmdLine[MSG_SIZ];
7819 if (port[0] == NULLCHAR) {
7820 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7822 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7824 return StartChildProcess(cmdLine, "", pr);
7827 int OpenTCP(host, port, pr)
7833 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7834 #else /* !OMIT_SOCKETS */
7836 struct sockaddr_in sa;
7838 unsigned short uport;
7841 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7845 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7846 sa.sin_family = AF_INET;
7847 sa.sin_addr.s_addr = INADDR_ANY;
7848 uport = (unsigned short) 0;
7849 sa.sin_port = htons(uport);
7850 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7854 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7855 if (!(hp = gethostbyname(host))) {
7857 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7858 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7859 hp->h_addrtype = AF_INET;
7861 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7862 hp->h_addr_list[0] = (char *) malloc(4);
7863 hp->h_addr_list[0][0] = b0;
7864 hp->h_addr_list[0][1] = b1;
7865 hp->h_addr_list[0][2] = b2;
7866 hp->h_addr_list[0][3] = b3;
7871 sa.sin_family = hp->h_addrtype;
7872 uport = (unsigned short) atoi(port);
7873 sa.sin_port = htons(uport);
7874 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7876 if (connect(s, (struct sockaddr *) &sa,
7877 sizeof(struct sockaddr_in)) < 0) {
7881 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7888 #endif /* !OMIT_SOCKETS */
7893 int OpenCommPort(name, pr)
7900 fd = open(name, 2, 0);
7901 if (fd < 0) return errno;
7903 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7913 int OpenLoopback(pr)
7919 SetUpChildIO(to, from);
7921 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7924 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7931 int OpenRcmd(host, user, cmd, pr)
7932 char *host, *user, *cmd;
7935 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7939 #define INPUT_SOURCE_BUF_SIZE 8192
7948 char buf[INPUT_SOURCE_BUF_SIZE];
7953 DoInputCallback(closure, source, xid)
7958 InputSource *is = (InputSource *) closure;
7963 if (is->lineByLine) {
7964 count = read(is->fd, is->unused,
7965 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7967 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7970 is->unused += count;
7972 while (p < is->unused) {
7973 q = memchr(p, '\n', is->unused - p);
7974 if (q == NULL) break;
7976 (is->func)(is, is->closure, p, q - p, 0);
7980 while (p < is->unused) {
7985 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7990 (is->func)(is, is->closure, is->buf, count, error);
7994 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8001 ChildProc *cp = (ChildProc *) pr;
8003 is = (InputSource *) calloc(1, sizeof(InputSource));
8004 is->lineByLine = lineByLine;
8008 is->fd = fileno(stdin);
8010 is->kind = cp->kind;
8011 is->fd = cp->fdFrom;
8014 is->unused = is->buf;
8017 is->xid = XtAppAddInput(appContext, is->fd,
8018 (XtPointer) (XtInputReadMask),
8019 (XtInputCallbackProc) DoInputCallback,
8021 is->closure = closure;
8022 return (InputSourceRef) is;
8026 RemoveInputSource(isr)
8029 InputSource *is = (InputSource *) isr;
8031 if (is->xid == 0) return;
8032 XtRemoveInput(is->xid);
8036 int OutputToProcess(pr, message, count, outError)
8042 static int line = 0;
8043 ChildProc *cp = (ChildProc *) pr;
8048 if (appData.noJoin || !appData.useInternalWrap)
8049 outCount = fwrite(message, 1, count, stdout);
8052 int width = get_term_width();
8053 int len = wrap(NULL, message, count, width, &line);
8054 char *msg = malloc(len);
8058 outCount = fwrite(message, 1, count, stdout);
8061 dbgchk = wrap(msg, message, count, width, &line);
8062 if (dbgchk != len && appData.debugMode)
8063 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8064 outCount = fwrite(msg, 1, dbgchk, stdout);
8070 outCount = write(cp->fdTo, message, count);
8080 /* Output message to process, with "ms" milliseconds of delay
8081 between each character. This is needed when sending the logon
8082 script to ICC, which for some reason doesn't like the
8083 instantaneous send. */
8084 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8091 ChildProc *cp = (ChildProc *) pr;
8096 r = write(cp->fdTo, message++, 1);
8109 /**** Animation code by Hugh Fisher, DCS, ANU.
8111 Known problem: if a window overlapping the board is
8112 moved away while a piece is being animated underneath,
8113 the newly exposed area won't be updated properly.
8114 I can live with this.
8116 Known problem: if you look carefully at the animation
8117 of pieces in mono mode, they are being drawn as solid
8118 shapes without interior detail while moving. Fixing
8119 this would be a major complication for minimal return.
8122 /* Masks for XPM pieces. Black and white pieces can have
8123 different shapes, but in the interest of retaining my
8124 sanity pieces must have the same outline on both light
8125 and dark squares, and all pieces must use the same
8126 background square colors/images. */
8128 static int xpmDone = 0;
8131 CreateAnimMasks (pieceDepth)
8138 unsigned long plane;
8141 /* Need a bitmap just to get a GC with right depth */
8142 buf = XCreatePixmap(xDisplay, xBoardWindow,
8144 values.foreground = 1;
8145 values.background = 0;
8146 /* Don't use XtGetGC, not read only */
8147 maskGC = XCreateGC(xDisplay, buf,
8148 GCForeground | GCBackground, &values);
8149 XFreePixmap(xDisplay, buf);
8151 buf = XCreatePixmap(xDisplay, xBoardWindow,
8152 squareSize, squareSize, pieceDepth);
8153 values.foreground = XBlackPixel(xDisplay, xScreen);
8154 values.background = XWhitePixel(xDisplay, xScreen);
8155 bufGC = XCreateGC(xDisplay, buf,
8156 GCForeground | GCBackground, &values);
8158 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8159 /* Begin with empty mask */
8160 if(!xpmDone) // [HGM] pieces: keep using existing
8161 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8162 squareSize, squareSize, 1);
8163 XSetFunction(xDisplay, maskGC, GXclear);
8164 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8165 0, 0, squareSize, squareSize);
8167 /* Take a copy of the piece */
8172 XSetFunction(xDisplay, bufGC, GXcopy);
8173 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8175 0, 0, squareSize, squareSize, 0, 0);
8177 /* XOR the background (light) over the piece */
8178 XSetFunction(xDisplay, bufGC, GXxor);
8180 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8181 0, 0, squareSize, squareSize, 0, 0);
8183 XSetForeground(xDisplay, bufGC, lightSquareColor);
8184 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8187 /* We now have an inverted piece image with the background
8188 erased. Construct mask by just selecting all the non-zero
8189 pixels - no need to reconstruct the original image. */
8190 XSetFunction(xDisplay, maskGC, GXor);
8192 /* Might be quicker to download an XImage and create bitmap
8193 data from it rather than this N copies per piece, but it
8194 only takes a fraction of a second and there is a much
8195 longer delay for loading the pieces. */
8196 for (n = 0; n < pieceDepth; n ++) {
8197 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8198 0, 0, squareSize, squareSize,
8204 XFreePixmap(xDisplay, buf);
8205 XFreeGC(xDisplay, bufGC);
8206 XFreeGC(xDisplay, maskGC);
8210 InitAnimState (anim, info)
8212 XWindowAttributes * info;
8217 /* Each buffer is square size, same depth as window */
8218 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8219 squareSize, squareSize, info->depth);
8220 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8221 squareSize, squareSize, info->depth);
8223 /* Create a plain GC for blitting */
8224 mask = GCForeground | GCBackground | GCFunction |
8225 GCPlaneMask | GCGraphicsExposures;
8226 values.foreground = XBlackPixel(xDisplay, xScreen);
8227 values.background = XWhitePixel(xDisplay, xScreen);
8228 values.function = GXcopy;
8229 values.plane_mask = AllPlanes;
8230 values.graphics_exposures = False;
8231 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8233 /* Piece will be copied from an existing context at
8234 the start of each new animation/drag. */
8235 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8237 /* Outline will be a read-only copy of an existing */
8238 anim->outlineGC = None;
8244 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8245 XWindowAttributes info;
8247 if (xpmDone && gameInfo.variant == old) return;
8248 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8249 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8251 InitAnimState(&game, &info);
8252 InitAnimState(&player, &info);
8254 /* For XPM pieces, we need bitmaps to use as masks. */
8256 CreateAnimMasks(info.depth);
8262 static Boolean frameWaiting;
8264 static RETSIGTYPE FrameAlarm (sig)
8267 frameWaiting = False;
8268 /* In case System-V style signals. Needed?? */
8269 signal(SIGALRM, FrameAlarm);
8276 struct itimerval delay;
8278 XSync(xDisplay, False);
8281 frameWaiting = True;
8282 signal(SIGALRM, FrameAlarm);
8283 delay.it_interval.tv_sec =
8284 delay.it_value.tv_sec = time / 1000;
8285 delay.it_interval.tv_usec =
8286 delay.it_value.tv_usec = (time % 1000) * 1000;
8287 setitimer(ITIMER_REAL, &delay, NULL);
8288 while (frameWaiting) pause();
8289 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8290 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8291 setitimer(ITIMER_REAL, &delay, NULL);
8301 XSync(xDisplay, False);
8303 usleep(time * 1000);
8308 /* Convert board position to corner of screen rect and color */
8311 ScreenSquare(column, row, pt, color)
8312 int column; int row; XPoint * pt; int * color;
8315 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8316 pt->y = lineGap + row * (squareSize + lineGap);
8318 pt->x = lineGap + column * (squareSize + lineGap);
8319 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8321 *color = SquareColor(row, column);
8324 /* Convert window coords to square */
8327 BoardSquare(x, y, column, row)
8328 int x; int y; int * column; int * row;
8330 *column = EventToSquare(x, BOARD_WIDTH);
8331 if (flipView && *column >= 0)
8332 *column = BOARD_WIDTH - 1 - *column;
8333 *row = EventToSquare(y, BOARD_HEIGHT);
8334 if (!flipView && *row >= 0)
8335 *row = BOARD_HEIGHT - 1 - *row;
8340 #undef Max /* just in case */
8342 #define Max(a, b) ((a) > (b) ? (a) : (b))
8343 #define Min(a, b) ((a) < (b) ? (a) : (b))
8346 SetRect(rect, x, y, width, height)
8347 XRectangle * rect; int x; int y; int width; int height;
8351 rect->width = width;
8352 rect->height = height;
8355 /* Test if two frames overlap. If they do, return
8356 intersection rect within old and location of
8357 that rect within new. */
8360 Intersect(old, new, size, area, pt)
8361 XPoint * old; XPoint * new;
8362 int size; XRectangle * area; XPoint * pt;
8364 if (old->x > new->x + size || new->x > old->x + size ||
8365 old->y > new->y + size || new->y > old->y + size) {
8368 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8369 size - abs(old->x - new->x), size - abs(old->y - new->y));
8370 pt->x = Max(old->x - new->x, 0);
8371 pt->y = Max(old->y - new->y, 0);
8376 /* For two overlapping frames, return the rect(s)
8377 in the old that do not intersect with the new. */
8380 CalcUpdateRects(old, new, size, update, nUpdates)
8381 XPoint * old; XPoint * new; int size;
8382 XRectangle update[]; int * nUpdates;
8386 /* If old = new (shouldn't happen) then nothing to draw */
8387 if (old->x == new->x && old->y == new->y) {
8391 /* Work out what bits overlap. Since we know the rects
8392 are the same size we don't need a full intersect calc. */
8394 /* Top or bottom edge? */
8395 if (new->y > old->y) {
8396 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8398 } else if (old->y > new->y) {
8399 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8400 size, old->y - new->y);
8403 /* Left or right edge - don't overlap any update calculated above. */
8404 if (new->x > old->x) {
8405 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8406 new->x - old->x, size - abs(new->y - old->y));
8408 } else if (old->x > new->x) {
8409 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8410 old->x - new->x, size - abs(new->y - old->y));
8417 /* Generate a series of frame coords from start->mid->finish.
8418 The movement rate doubles until the half way point is
8419 reached, then halves back down to the final destination,
8420 which gives a nice slow in/out effect. The algorithmn
8421 may seem to generate too many intermediates for short
8422 moves, but remember that the purpose is to attract the
8423 viewers attention to the piece about to be moved and
8424 then to where it ends up. Too few frames would be less
8428 Tween(start, mid, finish, factor, frames, nFrames)
8429 XPoint * start; XPoint * mid;
8430 XPoint * finish; int factor;
8431 XPoint frames[]; int * nFrames;
8433 int fraction, n, count;
8437 /* Slow in, stepping 1/16th, then 1/8th, ... */
8439 for (n = 0; n < factor; n++)
8441 for (n = 0; n < factor; n++) {
8442 frames[count].x = start->x + (mid->x - start->x) / fraction;
8443 frames[count].y = start->y + (mid->y - start->y) / fraction;
8445 fraction = fraction / 2;
8449 frames[count] = *mid;
8452 /* Slow out, stepping 1/2, then 1/4, ... */
8454 for (n = 0; n < factor; n++) {
8455 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8456 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8458 fraction = fraction * 2;
8463 /* Draw a piece on the screen without disturbing what's there */
8466 SelectGCMask(piece, clip, outline, mask)
8467 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8471 /* Bitmap for piece being moved. */
8472 if (appData.monoMode) {
8473 *mask = *pieceToSolid(piece);
8474 } else if (useImages) {
8476 *mask = xpmMask[piece];
8478 *mask = ximMaskPm[piece];
8481 *mask = *pieceToSolid(piece);
8484 /* GC for piece being moved. Square color doesn't matter, but
8485 since it gets modified we make a copy of the original. */
8487 if (appData.monoMode)
8492 if (appData.monoMode)
8497 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8499 /* Outline only used in mono mode and is not modified */
8501 *outline = bwPieceGC;
8503 *outline = wbPieceGC;
8507 OverlayPiece(piece, clip, outline, dest)
8508 ChessSquare piece; GC clip; GC outline; Drawable dest;
8513 /* Draw solid rectangle which will be clipped to shape of piece */
8514 XFillRectangle(xDisplay, dest, clip,
8515 0, 0, squareSize, squareSize);
8516 if (appData.monoMode)
8517 /* Also draw outline in contrasting color for black
8518 on black / white on white cases */
8519 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8520 0, 0, squareSize, squareSize, 0, 0, 1);
8522 /* Copy the piece */
8527 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8529 0, 0, squareSize, squareSize,
8534 /* Animate the movement of a single piece */
8537 BeginAnimation(anim, piece, startColor, start)
8545 /* The old buffer is initialised with the start square (empty) */
8546 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8547 anim->prevFrame = *start;
8549 /* The piece will be drawn using its own bitmap as a matte */
8550 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8551 XSetClipMask(xDisplay, anim->pieceGC, mask);
8555 AnimationFrame(anim, frame, piece)
8560 XRectangle updates[4];
8565 /* Save what we are about to draw into the new buffer */
8566 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8567 frame->x, frame->y, squareSize, squareSize,
8570 /* Erase bits of the previous frame */
8571 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8572 /* Where the new frame overlapped the previous,
8573 the contents in newBuf are wrong. */
8574 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8575 overlap.x, overlap.y,
8576 overlap.width, overlap.height,
8578 /* Repaint the areas in the old that don't overlap new */
8579 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8580 for (i = 0; i < count; i++)
8581 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8582 updates[i].x - anim->prevFrame.x,
8583 updates[i].y - anim->prevFrame.y,
8584 updates[i].width, updates[i].height,
8585 updates[i].x, updates[i].y);
8587 /* Easy when no overlap */
8588 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8589 0, 0, squareSize, squareSize,
8590 anim->prevFrame.x, anim->prevFrame.y);
8593 /* Save this frame for next time round */
8594 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8595 0, 0, squareSize, squareSize,
8597 anim->prevFrame = *frame;
8599 /* Draw piece over original screen contents, not current,
8600 and copy entire rect. Wipes out overlapping piece images. */
8601 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8602 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8603 0, 0, squareSize, squareSize,
8604 frame->x, frame->y);
8608 EndAnimation (anim, finish)
8612 XRectangle updates[4];
8617 /* The main code will redraw the final square, so we
8618 only need to erase the bits that don't overlap. */
8619 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8620 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8621 for (i = 0; i < count; i++)
8622 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8623 updates[i].x - anim->prevFrame.x,
8624 updates[i].y - anim->prevFrame.y,
8625 updates[i].width, updates[i].height,
8626 updates[i].x, updates[i].y);
8628 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8629 0, 0, squareSize, squareSize,
8630 anim->prevFrame.x, anim->prevFrame.y);
8635 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8637 ChessSquare piece; int startColor;
8638 XPoint * start; XPoint * finish;
8639 XPoint frames[]; int nFrames;
8643 BeginAnimation(anim, piece, startColor, start);
8644 for (n = 0; n < nFrames; n++) {
8645 AnimationFrame(anim, &(frames[n]), piece);
8646 FrameDelay(appData.animSpeed);
8648 EndAnimation(anim, finish);
8651 /* Main control logic for deciding what to animate and how */
8654 AnimateMove(board, fromX, fromY, toX, toY)
8663 XPoint start, finish, mid;
8664 XPoint frames[kFactor * 2 + 1];
8665 int nFrames, startColor, endColor;
8667 /* Are we animating? */
8668 if (!appData.animate || appData.blindfold)
8671 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8672 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8673 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8675 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8676 piece = board[fromY][fromX];
8677 if (piece >= EmptySquare) return;
8682 hop = (piece == WhiteKnight || piece == BlackKnight);
8685 if (appData.debugMode) {
8686 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8687 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8688 piece, fromX, fromY, toX, toY); }
8690 ScreenSquare(fromX, fromY, &start, &startColor);
8691 ScreenSquare(toX, toY, &finish, &endColor);
8694 /* Knight: make diagonal movement then straight */
8695 if (abs(toY - fromY) < abs(toX - fromX)) {
8696 mid.x = start.x + (finish.x - start.x) / 2;
8700 mid.y = start.y + (finish.y - start.y) / 2;
8703 mid.x = start.x + (finish.x - start.x) / 2;
8704 mid.y = start.y + (finish.y - start.y) / 2;
8707 /* Don't use as many frames for very short moves */
8708 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8709 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8711 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8712 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8714 /* Be sure end square is redrawn */
8715 damage[toY][toX] = True;
8719 DragPieceBegin(x, y)
8722 int boardX, boardY, color;
8725 /* Are we animating? */
8726 if (!appData.animateDragging || appData.blindfold)
8729 /* Figure out which square we start in and the
8730 mouse position relative to top left corner. */
8731 BoardSquare(x, y, &boardX, &boardY);
8732 player.startBoardX = boardX;
8733 player.startBoardY = boardY;
8734 ScreenSquare(boardX, boardY, &corner, &color);
8735 player.startSquare = corner;
8736 player.startColor = color;
8737 /* As soon as we start dragging, the piece will jump slightly to
8738 be centered over the mouse pointer. */
8739 player.mouseDelta.x = squareSize/2;
8740 player.mouseDelta.y = squareSize/2;
8741 /* Initialise animation */
8742 player.dragPiece = PieceForSquare(boardX, boardY);
8744 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8745 player.dragActive = True;
8746 BeginAnimation(&player, player.dragPiece, color, &corner);
8747 /* Mark this square as needing to be redrawn. Note that
8748 we don't remove the piece though, since logically (ie
8749 as seen by opponent) the move hasn't been made yet. */
8750 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8751 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8752 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8753 corner.x, corner.y, squareSize, squareSize,
8754 0, 0); // [HGM] zh: unstack in stead of grab
8755 damage[boardY][boardX] = True;
8757 player.dragActive = False;
8767 /* Are we animating? */
8768 if (!appData.animateDragging || appData.blindfold)
8772 if (! player.dragActive)
8774 /* Move piece, maintaining same relative position
8775 of mouse within square */
8776 corner.x = x - player.mouseDelta.x;
8777 corner.y = y - player.mouseDelta.y;
8778 AnimationFrame(&player, &corner, player.dragPiece);
8780 if (appData.highlightDragging) {
8782 BoardSquare(x, y, &boardX, &boardY);
8783 SetHighlights(fromX, fromY, boardX, boardY);
8792 int boardX, boardY, color;
8795 /* Are we animating? */
8796 if (!appData.animateDragging || appData.blindfold)
8800 if (! player.dragActive)
8802 /* Last frame in sequence is square piece is
8803 placed on, which may not match mouse exactly. */
8804 BoardSquare(x, y, &boardX, &boardY);
8805 ScreenSquare(boardX, boardY, &corner, &color);
8806 EndAnimation(&player, &corner);
8808 /* Be sure end square is redrawn */
8809 damage[boardY][boardX] = True;
8811 /* This prevents weird things happening with fast successive
8812 clicks which on my Sun at least can cause motion events
8813 without corresponding press/release. */
8814 player.dragActive = False;
8817 /* Handle expose event while piece being dragged */
8822 if (!player.dragActive || appData.blindfold)
8825 /* What we're doing: logically, the move hasn't been made yet,
8826 so the piece is still in it's original square. But visually
8827 it's being dragged around the board. So we erase the square
8828 that the piece is on and draw it at the last known drag point. */
8829 BlankSquare(player.startSquare.x, player.startSquare.y,
8830 player.startColor, EmptySquare, xBoardWindow);
8831 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8832 damage[player.startBoardY][player.startBoardX] = TRUE;
8835 #include <sys/ioctl.h>
8836 int get_term_width()
8838 int fd, default_width;
8841 default_width = 79; // this is FICS default anyway...
8843 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8845 if (!ioctl(fd, TIOCGSIZE, &win))
8846 default_width = win.ts_cols;
8847 #elif defined(TIOCGWINSZ)
8849 if (!ioctl(fd, TIOCGWINSZ, &win))
8850 default_width = win.ws_col;
8852 return default_width;
8855 void update_ics_width()
8857 static int old_width = 0;
8858 int new_width = get_term_width();
8860 if (old_width != new_width)
8861 ics_printf("set width %d\n", new_width);
8862 old_width = new_width;
8865 void NotifyFrontendLogin()