2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
192 #include "frontend.h"
197 #include "xgamelist.h"
198 #include "xhistory.h"
199 #include "xedittags.h"
202 // must be moved to xengineoutput.h
204 void EngineOutputProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
206 void EvalGraphProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
214 #define usleep(t) _sleep2(((t)+500)/1000)
218 # define _(s) gettext (s)
219 # define N_(s) gettext_noop (s)
235 int main P((int argc, char **argv));
236 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
237 char *init_path, char *mode, int (*show_entry)(), char **name_return));
238 RETSIGTYPE CmailSigHandler P((int sig));
239 RETSIGTYPE IntSigHandler P((int sig));
240 RETSIGTYPE TermSizeSigHandler P((int sig));
241 void CreateGCs P((void));
242 void CreateXIMPieces P((void));
243 void CreateXPMPieces P((void));
244 void CreatePieces P((void));
245 void CreatePieceMenus P((void));
246 Widget CreateMenuBar P((Menu *mb));
247 Widget CreateButtonBar P ((MenuItem *mi));
248 char *FindFont P((char *pattern, int targetPxlSize));
249 void PieceMenuPopup P((Widget w, XEvent *event,
250 String *params, Cardinal *num_params));
251 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
252 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
253 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
254 u_int wreq, u_int hreq));
255 void CreateGrid P((void));
256 int EventToSquare P((int x, int limit));
257 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
258 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
259 void HandleUserMove P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void AnimateUserMove P((Widget w, XEvent * event,
262 String * params, Cardinal * nParams));
263 void HandlePV P((Widget w, XEvent * event,
264 String * params, Cardinal * nParams));
265 void SelectPV P((Widget w, XEvent * event,
266 String * params, Cardinal * nParams));
267 void StopPV P((Widget w, XEvent * event,
268 String * params, Cardinal * nParams));
269 void WhiteClock P((Widget w, XEvent *event,
270 String *prms, Cardinal *nprms));
271 void BlackClock P((Widget w, XEvent *event,
272 String *prms, Cardinal *nprms));
273 void DrawPositionProc P((Widget w, XEvent *event,
274 String *prms, Cardinal *nprms));
275 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
277 void CommentClick P((Widget w, XEvent * event,
278 String * params, Cardinal * nParams));
279 void CommentPopUp P((char *title, char *label));
280 void CommentPopDown P((void));
281 void CommentCallback P((Widget w, XtPointer client_data,
282 XtPointer call_data));
283 void ICSInputBoxPopUp P((void));
284 void ICSInputBoxPopDown P((void));
285 void FileNamePopUp P((char *label, char *def,
286 FileProc proc, char *openMode));
287 void FileNamePopDown P((void));
288 void FileNameCallback P((Widget w, XtPointer client_data,
289 XtPointer call_data));
290 void FileNameAction P((Widget w, XEvent *event,
291 String *prms, Cardinal *nprms));
292 void AskQuestionReplyAction P((Widget w, XEvent *event,
293 String *prms, Cardinal *nprms));
294 void AskQuestionProc P((Widget w, XEvent *event,
295 String *prms, Cardinal *nprms));
296 void AskQuestionPopDown P((void));
297 void PromotionPopDown P((void));
298 void PromotionCallback P((Widget w, XtPointer client_data,
299 XtPointer call_data));
300 void EditCommentPopDown P((void));
301 void EditCommentCallback P((Widget w, XtPointer client_data,
302 XtPointer call_data));
303 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
304 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
305 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
306 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
308 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
310 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
312 void LoadPositionProc P((Widget w, XEvent *event,
313 String *prms, Cardinal *nprms));
314 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
316 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
318 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
320 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
322 void PastePositionProc P((Widget w, XEvent *event, String *prms,
324 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void SavePositionProc P((Widget w, XEvent *event,
328 String *prms, Cardinal *nprms));
329 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
332 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
336 void MachineWhiteProc P((Widget w, XEvent *event,
337 String *prms, Cardinal *nprms));
338 void AnalyzeModeProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AnalyzeFileProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
344 void IcsClientProc P((Widget w, XEvent *event, String *prms,
346 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void EditPositionProc P((Widget w, XEvent *event,
348 String *prms, Cardinal *nprms));
349 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void EditCommentProc P((Widget w, XEvent *event,
351 String *prms, Cardinal *nprms));
352 void IcsInputBoxProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void StopObservingProc P((Widget w, XEvent *event, String *prms,
370 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
372 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
381 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
383 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
386 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
388 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
390 void AutocommProc P((Widget w, XEvent *event, String *prms,
392 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void AutobsProc P((Widget w, XEvent *event, String *prms,
396 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
401 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
404 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
406 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
408 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
412 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
414 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
416 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
418 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
420 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
424 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
426 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
428 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
430 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void DisplayMove P((int moveNumber));
442 void DisplayTitle P((char *title));
443 void ICSInitScript P((void));
444 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
445 void ErrorPopUp P((char *title, char *text, int modal));
446 void ErrorPopDown P((void));
447 static char *ExpandPathName P((char *path));
448 static void CreateAnimVars P((void));
449 static void DragPieceMove P((int x, int y));
450 static void DrawDragPiece P((void));
451 char *ModeToWidgetName P((GameMode mode));
452 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void GameListOptionsPopDown P(());
461 void ShufflePopDown P(());
462 void EnginePopDown P(());
463 void UciPopDown P(());
464 void TimeControlPopDown P(());
465 void NewVariantPopDown P(());
466 void SettingsPopDown P(());
467 void update_ics_width P(());
468 int get_term_width P(());
469 int CopyMemoProc P(());
471 * XBoard depends on Xt R4 or higher
473 int xtVersion = XtSpecificationRelease;
478 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
479 jailSquareColor, highlightSquareColor, premoveHighlightColor;
480 Pixel lowTimeWarningColor;
481 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
482 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
483 wjPieceGC, bjPieceGC, prelineGC, countGC;
484 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
485 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
486 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
487 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
488 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
489 ICSInputShell, fileNameShell, askQuestionShell;
490 Widget historyShell, evalGraphShell, gameListShell;
491 int hOffset; // [HGM] dual
492 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
493 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
494 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
495 Font clockFontID, coordFontID, countFontID;
496 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
497 XtAppContext appContext;
499 char *oldICSInteractionTitle;
503 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
505 Position commentX = -1, commentY = -1;
506 Dimension commentW, commentH;
507 typedef unsigned int BoardSize;
509 Boolean chessProgram;
511 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
512 int squareSize, smallLayout = 0, tinyLayout = 0,
513 marginW, marginH, // [HGM] for run-time resizing
514 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
515 ICSInputBoxUp = False, askQuestionUp = False,
516 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
517 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
518 Pixel timerForegroundPixel, timerBackgroundPixel;
519 Pixel buttonForegroundPixel, buttonBackgroundPixel;
520 char *chessDir, *programName, *programVersion,
521 *gameCopyFilename, *gamePasteFilename;
522 Boolean alwaysOnTop = False;
523 Boolean saveSettingsOnExit;
524 char *settingsFileName;
525 char *icsTextMenuString;
527 char *firstChessProgramNames;
528 char *secondChessProgramNames;
530 WindowPlacement wpMain;
531 WindowPlacement wpConsole;
532 WindowPlacement wpComment;
533 WindowPlacement wpMoveHistory;
534 WindowPlacement wpEvalGraph;
535 WindowPlacement wpEngineOutput;
536 WindowPlacement wpGameList;
537 WindowPlacement wpTags;
541 Pixmap pieceBitmap[2][(int)BlackPawn];
542 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
543 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
544 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
545 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
546 int useImages, useImageSqs;
547 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
548 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
549 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
550 XImage *ximLightSquare, *ximDarkSquare;
553 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
554 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
556 #define White(piece) ((int)(piece) < (int)BlackPawn)
558 /* Variables for doing smooth animation. This whole thing
559 would be much easier if the board was double-buffered,
560 but that would require a fairly major rewrite. */
565 GC blitGC, pieceGC, outlineGC;
566 XPoint startSquare, prevFrame, mouseDelta;
570 int startBoardX, startBoardY;
573 /* There can be two pieces being animated at once: a player
574 can begin dragging a piece before the remote opponent has moved. */
576 static AnimState game, player;
578 /* Bitmaps for use as masks when drawing XPM pieces.
579 Need one for each black and white piece. */
580 static Pixmap xpmMask[BlackKing + 1];
582 /* This magic number is the number of intermediate frames used
583 in each half of the animation. For short moves it's reduced
584 by 1. The total number of frames will be factor * 2 + 1. */
587 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
589 MenuItem fileMenu[] = {
590 {N_("New Game"), ResetProc},
591 {N_("New Shuffle Game ..."), ShuffleMenuProc},
592 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
593 {"----", NothingProc},
594 {N_("Load Game"), LoadGameProc},
595 {N_("Load Next Game"), LoadNextGameProc},
596 {N_("Load Previous Game"), LoadPrevGameProc},
597 {N_("Reload Same Game"), ReloadGameProc},
598 {N_("Save Game"), SaveGameProc},
599 {"----", NothingProc},
600 {N_("Copy Game"), CopyGameProc},
601 {N_("Paste Game"), PasteGameProc},
602 {"----", NothingProc},
603 {N_("Load Position"), LoadPositionProc},
604 {N_("Load Next Position"), LoadNextPositionProc},
605 {N_("Load Previous Position"), LoadPrevPositionProc},
606 {N_("Reload Same Position"), ReloadPositionProc},
607 {N_("Save Position"), SavePositionProc},
608 {"----", NothingProc},
609 {N_("Copy Position"), CopyPositionProc},
610 {N_("Paste Position"), PastePositionProc},
611 {"----", NothingProc},
612 {N_("Mail Move"), MailMoveProc},
613 {N_("Reload CMail Message"), ReloadCmailMsgProc},
614 {"----", NothingProc},
615 {N_("Exit"), QuitProc},
619 MenuItem modeMenu[] = {
620 {N_("Machine White"), MachineWhiteProc},
621 {N_("Machine Black"), MachineBlackProc},
622 {N_("Two Machines"), TwoMachinesProc},
623 {N_("Analysis Mode"), AnalyzeModeProc},
624 {N_("Analyze File"), AnalyzeFileProc },
625 {N_("ICS Client"), IcsClientProc},
626 {N_("Edit Game"), EditGameProc},
627 {N_("Edit Position"), EditPositionProc},
628 {N_("Training"), TrainingProc},
629 {"----", NothingProc},
630 {N_("Show Engine Output"), EngineOutputProc},
631 {N_("Show Evaluation Graph"), EvalGraphProc},
632 {N_("Show Game List"), ShowGameListProc},
633 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
634 {"----", NothingProc},
635 {N_("Edit Tags"), EditTagsProc},
636 {N_("Edit Comment"), EditCommentProc},
637 {N_("ICS Input Box"), IcsInputBoxProc},
638 {N_("Pause"), PauseProc},
642 MenuItem actionMenu[] = {
643 {N_("Accept"), AcceptProc},
644 {N_("Decline"), DeclineProc},
645 {N_("Rematch"), RematchProc},
646 {"----", NothingProc},
647 {N_("Call Flag"), CallFlagProc},
648 {N_("Draw"), DrawProc},
649 {N_("Adjourn"), AdjournProc},
650 {N_("Abort"), AbortProc},
651 {N_("Resign"), ResignProc},
652 {"----", NothingProc},
653 {N_("Stop Observing"), StopObservingProc},
654 {N_("Stop Examining"), StopExaminingProc},
655 {N_("Upload to Examine"), UploadProc},
656 {"----", NothingProc},
657 {N_("Adjudicate to White"), AdjuWhiteProc},
658 {N_("Adjudicate to Black"), AdjuBlackProc},
659 {N_("Adjudicate Draw"), AdjuDrawProc},
663 MenuItem stepMenu[] = {
664 {N_("Backward"), BackwardProc},
665 {N_("Forward"), ForwardProc},
666 {N_("Back to Start"), ToStartProc},
667 {N_("Forward to End"), ToEndProc},
668 {N_("Revert"), RevertProc},
669 {N_("Annotate"), AnnotateProc},
670 {N_("Truncate Game"), TruncateGameProc},
671 {"----", NothingProc},
672 {N_("Move Now"), MoveNowProc},
673 {N_("Retract Move"), RetractMoveProc},
677 MenuItem optionsMenu[] = {
678 {N_("Flip View"), FlipViewProc},
679 {"----", NothingProc},
680 {N_("Adjudications ..."), EngineMenuProc},
681 {N_("General Settings ..."), UciMenuProc},
682 {N_("Engine #1 Settings ..."), FirstSettingsProc},
683 {N_("Engine #2 Settings ..."), SecondSettingsProc},
684 {N_("Time Control ..."), TimeControlProc},
685 {N_("Game List ..."), GameListOptionsPopUp},
686 {"----", NothingProc},
687 {N_("Always Queen"), AlwaysQueenProc},
688 {N_("Animate Dragging"), AnimateDraggingProc},
689 {N_("Animate Moving"), AnimateMovingProc},
690 {N_("Auto Comment"), AutocommProc},
691 {N_("Auto Flag"), AutoflagProc},
692 {N_("Auto Flip View"), AutoflipProc},
693 {N_("Auto Observe"), AutobsProc},
694 {N_("Auto Raise Board"), AutoraiseProc},
695 {N_("Auto Save"), AutosaveProc},
696 {N_("Blindfold"), BlindfoldProc},
697 {N_("Flash Moves"), FlashMovesProc},
698 {N_("Get Move List"), GetMoveListProc},
700 {N_("Highlight Dragging"), HighlightDraggingProc},
702 {N_("Highlight Last Move"), HighlightLastMoveProc},
703 {N_("Move Sound"), MoveSoundProc},
704 {N_("ICS Alarm"), IcsAlarmProc},
705 {N_("Old Save Style"), OldSaveStyleProc},
706 {N_("Periodic Updates"), PeriodicUpdatesProc},
707 {N_("Ponder Next Move"), PonderNextMoveProc},
708 {N_("Popup Exit Message"), PopupExitMessageProc},
709 {N_("Popup Move Errors"), PopupMoveErrorsProc},
710 {N_("Premove"), PremoveProc},
711 {N_("Quiet Play"), QuietPlayProc},
712 {N_("Show Coords"), ShowCoordsProc},
713 {N_("Hide Thinking"), HideThinkingProc},
714 {N_("Test Legality"), TestLegalityProc},
715 {"----", NothingProc},
716 {N_("Save Settings Now"), SaveSettingsProc},
717 {N_("Save Settings on Exit"), SaveOnExitProc},
721 MenuItem helpMenu[] = {
722 {N_("Info XBoard"), InfoProc},
723 {N_("Man XBoard"), ManProc},
724 {"----", NothingProc},
725 {N_("Hint"), HintProc},
726 {N_("Book"), BookProc},
727 {"----", NothingProc},
728 {N_("About XBoard"), AboutProc},
733 {N_("File"), fileMenu},
734 {N_("Mode"), modeMenu},
735 {N_("Action"), actionMenu},
736 {N_("Step"), stepMenu},
737 {N_("Options"), optionsMenu},
738 {N_("Help"), helpMenu},
742 #define PAUSE_BUTTON N_("P")
743 MenuItem buttonBar[] = {
746 {PAUSE_BUTTON, PauseProc},
752 #define PIECE_MENU_SIZE 18
753 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
754 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
755 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
756 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
757 N_("Empty square"), N_("Clear board") },
758 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
759 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
760 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
761 N_("Empty square"), N_("Clear board") }
763 /* must be in same order as PieceMenuStrings! */
764 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
765 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
766 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
767 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
768 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
769 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
770 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
771 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
772 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
775 #define DROP_MENU_SIZE 6
776 String dropMenuStrings[DROP_MENU_SIZE] = {
777 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
779 /* must be in same order as PieceMenuStrings! */
780 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
781 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
782 WhiteRook, WhiteQueen
790 DropMenuEnables dmEnables[] = {
808 { XtNborderWidth, 0 },
809 { XtNdefaultDistance, 0 },
813 { XtNborderWidth, 0 },
814 { XtNresizable, (XtArgVal) True },
818 { XtNborderWidth, 0 },
824 { XtNjustify, (XtArgVal) XtJustifyRight },
825 { XtNlabel, (XtArgVal) "..." },
826 { XtNresizable, (XtArgVal) True },
827 { XtNresize, (XtArgVal) False }
830 Arg messageArgs[] = {
831 { XtNjustify, (XtArgVal) XtJustifyLeft },
832 { XtNlabel, (XtArgVal) "..." },
833 { XtNresizable, (XtArgVal) True },
834 { XtNresize, (XtArgVal) False }
838 { XtNborderWidth, 0 },
839 { XtNjustify, (XtArgVal) XtJustifyLeft }
842 XtResource clientResources[] = {
843 { "flashCount", "flashCount", XtRInt, sizeof(int),
844 XtOffset(AppDataPtr, flashCount), XtRImmediate,
845 (XtPointer) FLASH_COUNT },
848 XrmOptionDescRec shellOptions[] = {
849 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
850 { "-flash", "flashCount", XrmoptionNoArg, "3" },
851 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
854 XtActionsRec boardActions[] = {
855 { "DrawPosition", DrawPositionProc },
856 { "HandleUserMove", HandleUserMove },
857 { "AnimateUserMove", AnimateUserMove },
858 { "HandlePV", HandlePV },
859 { "SelectPV", SelectPV },
860 { "StopPV", StopPV },
861 { "FileNameAction", FileNameAction },
862 { "AskQuestionProc", AskQuestionProc },
863 { "AskQuestionReplyAction", AskQuestionReplyAction },
864 { "PieceMenuPopup", PieceMenuPopup },
865 { "WhiteClock", WhiteClock },
866 { "BlackClock", BlackClock },
867 { "Iconify", Iconify },
868 { "ResetProc", ResetProc },
869 { "NewVariantProc", NewVariantProc },
870 { "LoadGameProc", LoadGameProc },
871 { "LoadNextGameProc", LoadNextGameProc },
872 { "LoadPrevGameProc", LoadPrevGameProc },
873 { "LoadSelectedProc", LoadSelectedProc },
874 { "SetFilterProc", SetFilterProc },
875 { "ReloadGameProc", ReloadGameProc },
876 { "LoadPositionProc", LoadPositionProc },
877 { "LoadNextPositionProc", LoadNextPositionProc },
878 { "LoadPrevPositionProc", LoadPrevPositionProc },
879 { "ReloadPositionProc", ReloadPositionProc },
880 { "CopyPositionProc", CopyPositionProc },
881 { "PastePositionProc", PastePositionProc },
882 { "CopyGameProc", CopyGameProc },
883 { "PasteGameProc", PasteGameProc },
884 { "SaveGameProc", SaveGameProc },
885 { "SavePositionProc", SavePositionProc },
886 { "MailMoveProc", MailMoveProc },
887 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
888 { "QuitProc", QuitProc },
889 { "MachineWhiteProc", MachineWhiteProc },
890 { "MachineBlackProc", MachineBlackProc },
891 { "AnalysisModeProc", AnalyzeModeProc },
892 { "AnalyzeFileProc", AnalyzeFileProc },
893 { "TwoMachinesProc", TwoMachinesProc },
894 { "IcsClientProc", IcsClientProc },
895 { "EditGameProc", EditGameProc },
896 { "EditPositionProc", EditPositionProc },
897 { "TrainingProc", EditPositionProc },
898 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
899 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
900 { "ShowGameListProc", ShowGameListProc },
901 { "ShowMoveListProc", HistoryShowProc},
902 { "EditTagsProc", EditCommentProc },
903 { "EditCommentProc", EditCommentProc },
904 { "IcsAlarmProc", IcsAlarmProc },
905 { "IcsInputBoxProc", IcsInputBoxProc },
906 { "PauseProc", PauseProc },
907 { "AcceptProc", AcceptProc },
908 { "DeclineProc", DeclineProc },
909 { "RematchProc", RematchProc },
910 { "CallFlagProc", CallFlagProc },
911 { "DrawProc", DrawProc },
912 { "AdjournProc", AdjournProc },
913 { "AbortProc", AbortProc },
914 { "ResignProc", ResignProc },
915 { "AdjuWhiteProc", AdjuWhiteProc },
916 { "AdjuBlackProc", AdjuBlackProc },
917 { "AdjuDrawProc", AdjuDrawProc },
918 { "EnterKeyProc", EnterKeyProc },
919 { "UpKeyProc", UpKeyProc },
920 { "DownKeyProc", DownKeyProc },
921 { "StopObservingProc", StopObservingProc },
922 { "StopExaminingProc", StopExaminingProc },
923 { "UploadProc", UploadProc },
924 { "BackwardProc", BackwardProc },
925 { "ForwardProc", ForwardProc },
926 { "ToStartProc", ToStartProc },
927 { "ToEndProc", ToEndProc },
928 { "RevertProc", RevertProc },
929 { "AnnotateProc", AnnotateProc },
930 { "TruncateGameProc", TruncateGameProc },
931 { "MoveNowProc", MoveNowProc },
932 { "RetractMoveProc", RetractMoveProc },
933 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
934 { "UciMenuProc", (XtActionProc) UciMenuProc },
935 { "TimeControlProc", (XtActionProc) TimeControlProc },
936 { "AlwaysQueenProc", AlwaysQueenProc },
937 { "AnimateDraggingProc", AnimateDraggingProc },
938 { "AnimateMovingProc", AnimateMovingProc },
939 { "AutoflagProc", AutoflagProc },
940 { "AutoflipProc", AutoflipProc },
941 { "AutobsProc", AutobsProc },
942 { "AutoraiseProc", AutoraiseProc },
943 { "AutosaveProc", AutosaveProc },
944 { "BlindfoldProc", BlindfoldProc },
945 { "FlashMovesProc", FlashMovesProc },
946 { "FlipViewProc", FlipViewProc },
947 { "GetMoveListProc", GetMoveListProc },
949 { "HighlightDraggingProc", HighlightDraggingProc },
951 { "HighlightLastMoveProc", HighlightLastMoveProc },
952 { "IcsAlarmProc", IcsAlarmProc },
953 { "MoveSoundProc", MoveSoundProc },
954 { "OldSaveStyleProc", OldSaveStyleProc },
955 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
956 { "PonderNextMoveProc", PonderNextMoveProc },
957 { "PopupExitMessageProc", PopupExitMessageProc },
958 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
959 { "PremoveProc", PremoveProc },
960 { "QuietPlayProc", QuietPlayProc },
961 { "ShowCoordsProc", ShowCoordsProc },
962 { "ShowThinkingProc", ShowThinkingProc },
963 { "HideThinkingProc", HideThinkingProc },
964 { "TestLegalityProc", TestLegalityProc },
965 { "SaveSettingsProc", SaveSettingsProc },
966 { "SaveOnExitProc", SaveOnExitProc },
967 { "InfoProc", InfoProc },
968 { "ManProc", ManProc },
969 { "HintProc", HintProc },
970 { "BookProc", BookProc },
971 { "AboutGameProc", AboutGameProc },
972 { "AboutProc", AboutProc },
973 { "DebugProc", DebugProc },
974 { "NothingProc", NothingProc },
975 { "CommentClick", (XtActionProc) CommentClick },
976 { "CommentPopDown", (XtActionProc) CommentPopDown },
977 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
978 { "TagsPopDown", (XtActionProc) TagsPopDown },
979 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
980 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
981 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
982 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
983 { "GameListPopDown", (XtActionProc) GameListPopDown },
984 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
985 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
986 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
987 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
988 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
989 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
990 { "EnginePopDown", (XtActionProc) EnginePopDown },
991 { "UciPopDown", (XtActionProc) UciPopDown },
992 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
993 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
994 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
995 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
998 char globalTranslations[] =
999 ":<Key>F9: ResignProc() \n \
1000 :Ctrl<Key>n: ResetProc() \n \
1001 :Meta<Key>V: NewVariantProc() \n \
1002 :Ctrl<Key>o: LoadGameProc() \n \
1003 :Meta<Key>Next: LoadNextGameProc() \n \
1004 :Meta<Key>Prior: LoadPrevGameProc() \n \
1005 :Ctrl<Key>s: SaveGameProc() \n \
1006 :Ctrl<Key>c: CopyGameProc() \n \
1007 :Ctrl<Key>v: PasteGameProc() \n \
1008 :Ctrl<Key>O: LoadPositionProc() \n \
1009 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1010 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1011 :Ctrl<Key>S: SavePositionProc() \n \
1012 :Ctrl<Key>C: CopyPositionProc() \n \
1013 :Ctrl<Key>V: PastePositionProc() \n \
1014 :Ctrl<Key>q: QuitProc() \n \
1015 :Ctrl<Key>w: MachineWhiteProc() \n \
1016 :Ctrl<Key>b: MachineBlackProc() \n \
1017 :Ctrl<Key>t: TwoMachinesProc() \n \
1018 :Ctrl<Key>a: AnalysisModeProc() \n \
1019 :Ctrl<Key>f: AnalyzeFileProc() \n \
1020 :Ctrl<Key>e: EditGameProc() \n \
1021 :Ctrl<Key>E: EditPositionProc() \n \
1022 :Meta<Key>O: EngineOutputProc() \n \
1023 :Meta<Key>E: EvalGraphProc() \n \
1024 :Meta<Key>G: ShowGameListProc() \n \
1025 :Meta<Key>H: ShowMoveListProc() \n \
1026 :<Key>Pause: PauseProc() \n \
1027 :<Key>F3: AcceptProc() \n \
1028 :<Key>F4: DeclineProc() \n \
1029 :<Key>F12: RematchProc() \n \
1030 :<Key>F5: CallFlagProc() \n \
1031 :<Key>F6: DrawProc() \n \
1032 :<Key>F7: AdjournProc() \n \
1033 :<Key>F8: AbortProc() \n \
1034 :<Key>F10: StopObservingProc() \n \
1035 :<Key>F11: StopExaminingProc() \n \
1036 :Meta Ctrl<Key>F12: DebugProc() \n \
1037 :Meta<Key>End: ToEndProc() \n \
1038 :Meta<Key>Right: ForwardProc() \n \
1039 :Meta<Key>Home: ToStartProc() \n \
1040 :Meta<Key>Left: BackwardProc() \n \
1041 :Ctrl<Key>m: MoveNowProc() \n \
1042 :Ctrl<Key>x: RetractMoveProc() \n \
1043 :Meta<Key>J: EngineMenuProc() \n \
1044 :Meta<Key>U: UciMenuProc() \n \
1045 :Meta<Key>T: TimeControlProc() \n \
1046 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1047 :Ctrl<Key>F: AutoflagProc() \n \
1048 :Ctrl<Key>A: AnimateMovingProc() \n \
1049 :Ctrl<Key>P: PonderNextMoveProc() \n \
1050 :Ctrl<Key>L: TestLegalityProc() \n \
1051 :Ctrl<Key>H: HideThinkingProc() \n \
1052 :<Key>-: Iconify() \n \
1053 :<Key>F1: ManProc() \n \
1054 :<Key>F2: FlipViewProc() \n \
1055 <KeyDown>.: BackwardProc() \n \
1056 <KeyUp>.: ForwardProc() \n \
1057 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1058 \"Send to chess program:\",,1) \n \
1059 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1060 \"Send to second chess program:\",,2) \n";
1062 char boardTranslations[] =
1063 "<Btn1Down>: HandleUserMove() \n \
1064 <Btn1Up>: HandleUserMove() \n \
1065 <Btn1Motion>: AnimateUserMove() \n \
1066 <Btn3Motion>: HandlePV() \n \
1067 <Btn3Up>: PieceMenuPopup(menuB) \n \
1068 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1069 PieceMenuPopup(menuB) \n \
1070 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1071 PieceMenuPopup(menuW) \n \
1072 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1073 PieceMenuPopup(menuW) \n \
1074 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1075 PieceMenuPopup(menuB) \n";
1077 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1078 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1080 char ICSInputTranslations[] =
1081 "<Key>Up: UpKeyProc() \n "
1082 "<Key>Down: DownKeyProc() \n "
1083 "<Key>Return: EnterKeyProc() \n";
1085 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1086 // as the widget is destroyed before the up-click can call extend-end
1087 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1089 String xboardResources[] = {
1090 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1091 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1092 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1097 /* Max possible square size */
1098 #define MAXSQSIZE 256
1100 static int xpm_avail[MAXSQSIZE];
1102 #ifdef HAVE_DIR_STRUCT
1104 /* Extract piece size from filename */
1106 xpm_getsize(name, len, ext)
1117 if ((p=strchr(name, '.')) == NULL ||
1118 StrCaseCmp(p+1, ext) != 0)
1124 while (*p && isdigit(*p))
1131 /* Setup xpm_avail */
1133 xpm_getavail(dirname, ext)
1141 for (i=0; i<MAXSQSIZE; ++i)
1144 if (appData.debugMode)
1145 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1147 dir = opendir(dirname);
1150 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1151 programName, dirname);
1155 while ((ent=readdir(dir)) != NULL) {
1156 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1157 if (i > 0 && i < MAXSQSIZE)
1167 xpm_print_avail(fp, ext)
1173 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1174 for (i=1; i<MAXSQSIZE; ++i) {
1180 /* Return XPM piecesize closest to size */
1182 xpm_closest_to(dirname, size, ext)
1188 int sm_diff = MAXSQSIZE;
1192 xpm_getavail(dirname, ext);
1194 if (appData.debugMode)
1195 xpm_print_avail(stderr, ext);
1197 for (i=1; i<MAXSQSIZE; ++i) {
1200 diff = (diff<0) ? -diff : diff;
1201 if (diff < sm_diff) {
1209 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1215 #else /* !HAVE_DIR_STRUCT */
1216 /* If we are on a system without a DIR struct, we can't
1217 read the directory, so we can't collect a list of
1218 filenames, etc., so we can't do any size-fitting. */
1220 xpm_closest_to(dirname, size, ext)
1225 fprintf(stderr, _("\
1226 Warning: No DIR structure found on this system --\n\
1227 Unable to autosize for XPM/XIM pieces.\n\
1228 Please report this error to frankm@hiwaay.net.\n\
1229 Include system type & operating system in message.\n"));
1232 #endif /* HAVE_DIR_STRUCT */
1234 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1235 "magenta", "cyan", "white" };
1239 TextColors textColors[(int)NColorClasses];
1241 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1243 parse_color(str, which)
1247 char *p, buf[100], *d;
1250 if (strlen(str) > 99) /* watch bounds on buf */
1255 for (i=0; i<which; ++i) {
1262 /* Could be looking at something like:
1264 .. in which case we want to stop on a comma also */
1265 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1269 return -1; /* Use default for empty field */
1272 if (which == 2 || isdigit(*p))
1275 while (*p && isalpha(*p))
1280 for (i=0; i<8; ++i) {
1281 if (!StrCaseCmp(buf, cnames[i]))
1282 return which? (i+40) : (i+30);
1284 if (!StrCaseCmp(buf, "default")) return -1;
1286 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1291 parse_cpair(cc, str)
1295 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1296 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1301 /* bg and attr are optional */
1302 textColors[(int)cc].bg = parse_color(str, 1);
1303 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1304 textColors[(int)cc].attr = 0;
1310 /* Arrange to catch delete-window events */
1311 Atom wm_delete_window;
1313 CatchDeleteWindow(Widget w, String procname)
1316 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1317 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1318 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1325 XtSetArg(args[0], XtNiconic, False);
1326 XtSetValues(shellWidget, args, 1);
1328 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1331 //---------------------------------------------------------------------------------------------------------
1332 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1335 #define CW_USEDEFAULT (1<<31)
1336 #define ICS_TEXT_MENU_SIZE 90
1337 #define DEBUG_FILE "xboard.debug"
1338 #define SetCurrentDirectory chdir
1339 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1343 // these two must some day move to frontend.h, when they are implemented
1344 Boolean GameListIsUp();
1346 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1349 // front-end part of option handling
1351 // [HGM] This platform-dependent table provides the location for storing the color info
1352 extern char *crWhite, * crBlack;
1356 &appData.whitePieceColor,
1357 &appData.blackPieceColor,
1358 &appData.lightSquareColor,
1359 &appData.darkSquareColor,
1360 &appData.highlightSquareColor,
1361 &appData.premoveHighlightColor,
1362 &appData.lowTimeWarningColor,
1373 // [HGM] font: keep a font for each square size, even non-stndard ones
1374 #define NUM_SIZES 18
1375 #define MAX_SIZE 130
1376 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1377 char *fontTable[NUM_FONTS][MAX_SIZE];
1380 ParseFont(char *name, int number)
1381 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1383 if(sscanf(name, "size%d:", &size)) {
1384 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1385 // defer processing it until we know if it matches our board size
1386 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1387 fontTable[number][size] = strdup(strchr(name, ':')+1);
1388 fontValid[number][size] = True;
1393 case 0: // CLOCK_FONT
1394 appData.clockFont = strdup(name);
1396 case 1: // MESSAGE_FONT
1397 appData.font = strdup(name);
1399 case 2: // COORD_FONT
1400 appData.coordFont = strdup(name);
1405 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1410 { // only 2 fonts currently
1411 appData.clockFont = CLOCK_FONT_NAME;
1412 appData.coordFont = COORD_FONT_NAME;
1413 appData.font = DEFAULT_FONT_NAME;
1418 { // no-op, until we identify the code for this already in XBoard and move it here
1422 ParseColor(int n, char *name)
1423 { // in XBoard, just copy the color-name string
1424 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1428 ParseTextAttribs(ColorClass cc, char *s)
1430 (&appData.colorShout)[cc] = strdup(s);
1434 ParseBoardSize(void *addr, char *name)
1436 appData.boardSize = strdup(name);
1441 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1445 SetCommPortDefaults()
1446 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1449 // [HGM] args: these three cases taken out to stay in front-end
1451 SaveFontArg(FILE *f, ArgDescriptor *ad)
1453 char *name, buf[MSG_SIZ];
1454 int i, n = (int)ad->argLoc;
1456 case 0: // CLOCK_FONT
1457 name = appData.clockFont;
1459 case 1: // MESSAGE_FONT
1460 name = appData.font;
1462 case 2: // COORD_FONT
1463 name = appData.coordFont;
1468 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1469 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1470 fontTable[n][squareSize] = strdup(name);
1471 fontValid[n][squareSize] = True;
1474 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1475 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1480 { // nothing to do, as the sounds are at all times represented by their text-string names already
1484 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1485 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1486 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1490 SaveColor(FILE *f, ArgDescriptor *ad)
1491 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1492 if(colorVariable[(int)ad->argLoc])
1493 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1497 SaveBoardSize(FILE *f, char *name, void *addr)
1498 { // wrapper to shield back-end from BoardSize & sizeInfo
1499 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1503 ParseCommPortSettings(char *s)
1504 { // no such option in XBoard (yet)
1507 extern Widget engineOutputShell;
1508 extern Widget tagsShell, editTagsShell;
1510 GetActualPlacement(Widget wg, WindowPlacement *wp)
1520 XtSetArg(args[i], XtNx, &x); i++;
1521 XtSetArg(args[i], XtNy, &y); i++;
1522 XtSetArg(args[i], XtNwidth, &w); i++;
1523 XtSetArg(args[i], XtNheight, &h); i++;
1524 XtGetValues(wg, args, i);
1533 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1534 // In XBoard this will have to wait until awareness of window parameters is implemented
1535 GetActualPlacement(shellWidget, &wpMain);
1536 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1537 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1538 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1539 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1540 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1541 else GetActualPlacement(editShell, &wpComment);
1542 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1543 else GetActualPlacement(editTagsShell, &wpTags);
1547 PrintCommPortSettings(FILE *f, char *name)
1548 { // This option does not exist in XBoard
1552 MySearchPath(char *installDir, char *name, char *fullname)
1553 { // just append installDir and name. Perhaps ExpandPath should be used here?
1554 name = ExpandPathName(name);
1555 if(name && name[0] == '/') strcpy(fullname, name); else {
1556 sprintf(fullname, "%s%c%s", installDir, '/', name);
1562 MyGetFullPathName(char *name, char *fullname)
1563 { // should use ExpandPath?
1564 name = ExpandPathName(name);
1565 strcpy(fullname, name);
1570 EnsureOnScreen(int *x, int *y, int minX, int minY)
1577 { // [HGM] args: allows testing if main window is realized from back-end
1578 return xBoardWindow != 0;
1582 PopUpStartupDialog()
1583 { // start menu not implemented in XBoard
1586 ConvertToLine(int argc, char **argv)
1588 static char line[128*1024], buf[1024];
1592 for(i=1; i<argc; i++) {
1593 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1594 && argv[i][0] != '{' )
1595 sprintf(buf, "{%s} ", argv[i]);
1596 else sprintf(buf, "%s ", argv[i]);
1599 line[strlen(line)-1] = NULLCHAR;
1603 //--------------------------------------------------------------------------------------------
1605 extern Boolean twoBoards, partnerUp;
1608 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1610 #define BoardSize int
1611 void InitDrawingSizes(BoardSize boardSize, int flags)
1612 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1613 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1615 XtGeometryResult gres;
1618 if(!formWidget) return;
1621 * Enable shell resizing.
1623 shellArgs[0].value = (XtArgVal) &w;
1624 shellArgs[1].value = (XtArgVal) &h;
1625 XtGetValues(shellWidget, shellArgs, 2);
1627 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1628 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1629 XtSetValues(shellWidget, &shellArgs[2], 4);
1631 XtSetArg(args[0], XtNdefaultDistance, &sep);
1632 XtGetValues(formWidget, args, 1);
1634 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1635 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1637 hOffset = boardWidth + 10;
1638 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1639 secondSegments[i] = gridSegments[i];
1640 secondSegments[i].x1 += hOffset;
1641 secondSegments[i].x2 += hOffset;
1644 XtSetArg(args[0], XtNwidth, boardWidth);
1645 XtSetArg(args[1], XtNheight, boardHeight);
1646 XtSetValues(boardWidget, args, 2);
1648 timerWidth = (boardWidth - sep) / 2;
1649 XtSetArg(args[0], XtNwidth, timerWidth);
1650 XtSetValues(whiteTimerWidget, args, 1);
1651 XtSetValues(blackTimerWidget, args, 1);
1653 XawFormDoLayout(formWidget, False);
1655 if (appData.titleInWindow) {
1657 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1658 XtSetArg(args[i], XtNheight, &h); i++;
1659 XtGetValues(titleWidget, args, i);
1661 w = boardWidth - 2*bor;
1663 XtSetArg(args[0], XtNwidth, &w);
1664 XtGetValues(menuBarWidget, args, 1);
1665 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1668 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1669 if (gres != XtGeometryYes && appData.debugMode) {
1671 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1672 programName, gres, w, h, wr, hr);
1676 XawFormDoLayout(formWidget, True);
1679 * Inhibit shell resizing.
1681 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1682 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1683 shellArgs[4].value = shellArgs[2].value = w;
1684 shellArgs[5].value = shellArgs[3].value = h;
1685 XtSetValues(shellWidget, &shellArgs[0], 6);
1687 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1690 for(i=0; i<4; i++) {
1692 for(p=0; p<=(int)WhiteKing; p++)
1693 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1694 if(gameInfo.variant == VariantShogi) {
1695 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1696 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1697 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1698 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1699 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1702 if(gameInfo.variant == VariantGothic) {
1703 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1707 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1708 for(p=0; p<=(int)WhiteKing; p++)
1709 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1710 if(gameInfo.variant == VariantShogi) {
1711 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1712 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1713 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1714 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1715 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1718 if(gameInfo.variant == VariantGothic) {
1719 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1725 for(i=0; i<2; i++) {
1727 for(p=0; p<=(int)WhiteKing; p++)
1728 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1729 if(gameInfo.variant == VariantShogi) {
1730 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1731 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1732 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1733 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1734 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1737 if(gameInfo.variant == VariantGothic) {
1738 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1754 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1755 XSetWindowAttributes window_attributes;
1757 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1758 XrmValue vFrom, vTo;
1759 XtGeometryResult gres;
1762 int forceMono = False;
1764 srandom(time(0)); // [HGM] book: make random truly random
1766 setbuf(stdout, NULL);
1767 setbuf(stderr, NULL);
1770 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1771 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1775 programName = strrchr(argv[0], '/');
1776 if (programName == NULL)
1777 programName = argv[0];
1782 XtSetLanguageProc(NULL, NULL, NULL);
1783 bindtextdomain(PACKAGE, LOCALEDIR);
1784 textdomain(PACKAGE);
1788 XtAppInitialize(&appContext, "XBoard", shellOptions,
1789 XtNumber(shellOptions),
1790 &argc, argv, xboardResources, NULL, 0);
1791 appData.boardSize = "";
1792 InitAppData(ConvertToLine(argc, argv));
1794 if (p == NULL) p = "/tmp";
1795 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1796 gameCopyFilename = (char*) malloc(i);
1797 gamePasteFilename = (char*) malloc(i);
1798 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1799 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1801 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1802 clientResources, XtNumber(clientResources),
1805 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1806 static char buf[MSG_SIZ];
1807 EscapeExpand(buf, appData.initString);
1808 appData.initString = strdup(buf);
1809 EscapeExpand(buf, appData.secondInitString);
1810 appData.secondInitString = strdup(buf);
1811 EscapeExpand(buf, appData.firstComputerString);
1812 appData.firstComputerString = strdup(buf);
1813 EscapeExpand(buf, appData.secondComputerString);
1814 appData.secondComputerString = strdup(buf);
1817 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1820 if (chdir(chessDir) != 0) {
1821 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1827 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1828 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1829 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1830 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1833 setbuf(debugFP, NULL);
1836 /* [HGM,HR] make sure board size is acceptable */
1837 if(appData.NrFiles > BOARD_FILES ||
1838 appData.NrRanks > BOARD_RANKS )
1839 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1842 /* This feature does not work; animation needs a rewrite */
1843 appData.highlightDragging = FALSE;
1847 xDisplay = XtDisplay(shellWidget);
1848 xScreen = DefaultScreen(xDisplay);
1849 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1851 gameInfo.variant = StringToVariant(appData.variant);
1852 InitPosition(FALSE);
1855 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1857 if (isdigit(appData.boardSize[0])) {
1858 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1859 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1860 &fontPxlSize, &smallLayout, &tinyLayout);
1862 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1863 programName, appData.boardSize);
1867 /* Find some defaults; use the nearest known size */
1868 SizeDefaults *szd, *nearest;
1869 int distance = 99999;
1870 nearest = szd = sizeDefaults;
1871 while (szd->name != NULL) {
1872 if (abs(szd->squareSize - squareSize) < distance) {
1874 distance = abs(szd->squareSize - squareSize);
1875 if (distance == 0) break;
1879 if (i < 2) lineGap = nearest->lineGap;
1880 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1881 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1882 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1883 if (i < 6) smallLayout = nearest->smallLayout;
1884 if (i < 7) tinyLayout = nearest->tinyLayout;
1887 SizeDefaults *szd = sizeDefaults;
1888 if (*appData.boardSize == NULLCHAR) {
1889 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1890 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1893 if (szd->name == NULL) szd--;
1894 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1896 while (szd->name != NULL &&
1897 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1898 if (szd->name == NULL) {
1899 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1900 programName, appData.boardSize);
1904 squareSize = szd->squareSize;
1905 lineGap = szd->lineGap;
1906 clockFontPxlSize = szd->clockFontPxlSize;
1907 coordFontPxlSize = szd->coordFontPxlSize;
1908 fontPxlSize = szd->fontPxlSize;
1909 smallLayout = szd->smallLayout;
1910 tinyLayout = szd->tinyLayout;
1911 // [HGM] font: use defaults from settings file if available and not overruled
1913 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1914 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1915 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1916 appData.font = fontTable[MESSAGE_FONT][squareSize];
1917 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1918 appData.coordFont = fontTable[COORD_FONT][squareSize];
1920 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1921 if (strlen(appData.pixmapDirectory) > 0) {
1922 p = ExpandPathName(appData.pixmapDirectory);
1924 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1925 appData.pixmapDirectory);
1928 if (appData.debugMode) {
1929 fprintf(stderr, _("\
1930 XBoard square size (hint): %d\n\
1931 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1933 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1934 if (appData.debugMode) {
1935 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1939 /* [HR] height treated separately (hacked) */
1940 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1941 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1942 if (appData.showJail == 1) {
1943 /* Jail on top and bottom */
1944 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1945 XtSetArg(boardArgs[2], XtNheight,
1946 boardHeight + 2*(lineGap + squareSize));
1947 } else if (appData.showJail == 2) {
1949 XtSetArg(boardArgs[1], XtNwidth,
1950 boardWidth + 2*(lineGap + squareSize));
1951 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1954 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1955 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1959 * Determine what fonts to use.
1961 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1962 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1963 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1964 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1965 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1966 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1967 appData.font = FindFont(appData.font, fontPxlSize);
1968 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1969 countFontStruct = XQueryFont(xDisplay, countFontID);
1970 // appData.font = FindFont(appData.font, fontPxlSize);
1972 xdb = XtDatabase(xDisplay);
1973 XrmPutStringResource(&xdb, "*font", appData.font);
1976 * Detect if there are not enough colors available and adapt.
1978 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1979 appData.monoMode = True;
1982 if (!appData.monoMode) {
1983 vFrom.addr = (caddr_t) appData.lightSquareColor;
1984 vFrom.size = strlen(appData.lightSquareColor);
1985 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1986 if (vTo.addr == NULL) {
1987 appData.monoMode = True;
1990 lightSquareColor = *(Pixel *) vTo.addr;
1993 if (!appData.monoMode) {
1994 vFrom.addr = (caddr_t) appData.darkSquareColor;
1995 vFrom.size = strlen(appData.darkSquareColor);
1996 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1997 if (vTo.addr == NULL) {
1998 appData.monoMode = True;
2001 darkSquareColor = *(Pixel *) vTo.addr;
2004 if (!appData.monoMode) {
2005 vFrom.addr = (caddr_t) appData.whitePieceColor;
2006 vFrom.size = strlen(appData.whitePieceColor);
2007 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2008 if (vTo.addr == NULL) {
2009 appData.monoMode = True;
2012 whitePieceColor = *(Pixel *) vTo.addr;
2015 if (!appData.monoMode) {
2016 vFrom.addr = (caddr_t) appData.blackPieceColor;
2017 vFrom.size = strlen(appData.blackPieceColor);
2018 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2019 if (vTo.addr == NULL) {
2020 appData.monoMode = True;
2023 blackPieceColor = *(Pixel *) vTo.addr;
2027 if (!appData.monoMode) {
2028 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2029 vFrom.size = strlen(appData.highlightSquareColor);
2030 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2031 if (vTo.addr == NULL) {
2032 appData.monoMode = True;
2035 highlightSquareColor = *(Pixel *) vTo.addr;
2039 if (!appData.monoMode) {
2040 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2041 vFrom.size = strlen(appData.premoveHighlightColor);
2042 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2043 if (vTo.addr == NULL) {
2044 appData.monoMode = True;
2047 premoveHighlightColor = *(Pixel *) vTo.addr;
2052 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2055 if (appData.bitmapDirectory == NULL ||
2056 appData.bitmapDirectory[0] == NULLCHAR)
2057 appData.bitmapDirectory = DEF_BITMAP_DIR;
2060 if (appData.lowTimeWarning && !appData.monoMode) {
2061 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2062 vFrom.size = strlen(appData.lowTimeWarningColor);
2063 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2064 if (vTo.addr == NULL)
2065 appData.monoMode = True;
2067 lowTimeWarningColor = *(Pixel *) vTo.addr;
2070 if (appData.monoMode && appData.debugMode) {
2071 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2072 (unsigned long) XWhitePixel(xDisplay, xScreen),
2073 (unsigned long) XBlackPixel(xDisplay, xScreen));
2076 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2077 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2078 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2079 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2080 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2081 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2082 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2083 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2084 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2085 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2087 if (appData.colorize) {
2089 _("%s: can't parse color names; disabling colorization\n"),
2092 appData.colorize = FALSE;
2094 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2095 textColors[ColorNone].attr = 0;
2097 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2103 layoutName = "tinyLayout";
2104 } else if (smallLayout) {
2105 layoutName = "smallLayout";
2107 layoutName = "normalLayout";
2109 /* Outer layoutWidget is there only to provide a name for use in
2110 resources that depend on the layout style */
2112 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2113 layoutArgs, XtNumber(layoutArgs));
2115 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2116 formArgs, XtNumber(formArgs));
2117 XtSetArg(args[0], XtNdefaultDistance, &sep);
2118 XtGetValues(formWidget, args, 1);
2121 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2122 XtSetArg(args[0], XtNtop, XtChainTop);
2123 XtSetArg(args[1], XtNbottom, XtChainTop);
2124 XtSetArg(args[2], XtNright, XtChainLeft);
2125 XtSetValues(menuBarWidget, args, 3);
2127 widgetList[j++] = whiteTimerWidget =
2128 XtCreateWidget("whiteTime", labelWidgetClass,
2129 formWidget, timerArgs, XtNumber(timerArgs));
2130 XtSetArg(args[0], XtNfont, clockFontStruct);
2131 XtSetArg(args[1], XtNtop, XtChainTop);
2132 XtSetArg(args[2], XtNbottom, XtChainTop);
2133 XtSetValues(whiteTimerWidget, args, 3);
2135 widgetList[j++] = blackTimerWidget =
2136 XtCreateWidget("blackTime", labelWidgetClass,
2137 formWidget, timerArgs, XtNumber(timerArgs));
2138 XtSetArg(args[0], XtNfont, clockFontStruct);
2139 XtSetArg(args[1], XtNtop, XtChainTop);
2140 XtSetArg(args[2], XtNbottom, XtChainTop);
2141 XtSetValues(blackTimerWidget, args, 3);
2143 if (appData.titleInWindow) {
2144 widgetList[j++] = titleWidget =
2145 XtCreateWidget("title", labelWidgetClass, formWidget,
2146 titleArgs, XtNumber(titleArgs));
2147 XtSetArg(args[0], XtNtop, XtChainTop);
2148 XtSetArg(args[1], XtNbottom, XtChainTop);
2149 XtSetValues(titleWidget, args, 2);
2152 if (appData.showButtonBar) {
2153 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2154 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2155 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2156 XtSetArg(args[2], XtNtop, XtChainTop);
2157 XtSetArg(args[3], XtNbottom, XtChainTop);
2158 XtSetValues(buttonBarWidget, args, 4);
2161 widgetList[j++] = messageWidget =
2162 XtCreateWidget("message", labelWidgetClass, formWidget,
2163 messageArgs, XtNumber(messageArgs));
2164 XtSetArg(args[0], XtNtop, XtChainTop);
2165 XtSetArg(args[1], XtNbottom, XtChainTop);
2166 XtSetValues(messageWidget, args, 2);
2168 widgetList[j++] = boardWidget =
2169 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2170 XtNumber(boardArgs));
2172 XtManageChildren(widgetList, j);
2174 timerWidth = (boardWidth - sep) / 2;
2175 XtSetArg(args[0], XtNwidth, timerWidth);
2176 XtSetValues(whiteTimerWidget, args, 1);
2177 XtSetValues(blackTimerWidget, args, 1);
2179 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2180 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2181 XtGetValues(whiteTimerWidget, args, 2);
2183 if (appData.showButtonBar) {
2184 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2185 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2186 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2190 * formWidget uses these constraints but they are stored
2194 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2195 XtSetValues(menuBarWidget, args, i);
2196 if (appData.titleInWindow) {
2199 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2200 XtSetValues(whiteTimerWidget, args, i);
2202 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2203 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2204 XtSetValues(blackTimerWidget, args, i);
2206 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2207 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2208 XtSetValues(titleWidget, args, i);
2210 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2211 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2212 XtSetValues(messageWidget, args, i);
2213 if (appData.showButtonBar) {
2215 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2216 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2217 XtSetValues(buttonBarWidget, args, i);
2221 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2222 XtSetValues(whiteTimerWidget, args, i);
2224 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2225 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2226 XtSetValues(blackTimerWidget, args, i);
2228 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2229 XtSetValues(titleWidget, args, i);
2231 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2232 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2233 XtSetValues(messageWidget, args, i);
2234 if (appData.showButtonBar) {
2236 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2237 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2238 XtSetValues(buttonBarWidget, args, i);
2243 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2244 XtSetValues(whiteTimerWidget, args, i);
2246 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2247 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2248 XtSetValues(blackTimerWidget, args, i);
2250 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2251 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2252 XtSetValues(messageWidget, args, i);
2253 if (appData.showButtonBar) {
2255 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2256 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2257 XtSetValues(buttonBarWidget, args, i);
2261 XtSetArg(args[0], XtNfromVert, messageWidget);
2262 XtSetArg(args[1], XtNtop, XtChainTop);
2263 XtSetArg(args[2], XtNbottom, XtChainBottom);
2264 XtSetArg(args[3], XtNleft, XtChainLeft);
2265 XtSetArg(args[4], XtNright, XtChainRight);
2266 XtSetValues(boardWidget, args, 5);
2268 XtRealizeWidget(shellWidget);
2271 XtSetArg(args[0], XtNx, wpMain.x);
2272 XtSetArg(args[1], XtNy, wpMain.y);
2273 XtSetValues(shellWidget, args, 2);
2277 * Correct the width of the message and title widgets.
2278 * It is not known why some systems need the extra fudge term.
2279 * The value "2" is probably larger than needed.
2281 XawFormDoLayout(formWidget, False);
2283 #define WIDTH_FUDGE 2
2285 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2286 XtSetArg(args[i], XtNheight, &h); i++;
2287 XtGetValues(messageWidget, args, i);
2288 if (appData.showButtonBar) {
2290 XtSetArg(args[i], XtNwidth, &w); i++;
2291 XtGetValues(buttonBarWidget, args, i);
2292 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2294 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2297 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2298 if (gres != XtGeometryYes && appData.debugMode) {
2299 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2300 programName, gres, w, h, wr, hr);
2303 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2304 /* The size used for the child widget in layout lags one resize behind
2305 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2307 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2308 if (gres != XtGeometryYes && appData.debugMode) {
2309 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2310 programName, gres, w, h, wr, hr);
2313 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2314 XtSetArg(args[1], XtNright, XtChainRight);
2315 XtSetValues(messageWidget, args, 2);
2317 if (appData.titleInWindow) {
2319 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2320 XtSetArg(args[i], XtNheight, &h); i++;
2321 XtGetValues(titleWidget, args, i);
2323 w = boardWidth - 2*bor;
2325 XtSetArg(args[0], XtNwidth, &w);
2326 XtGetValues(menuBarWidget, args, 1);
2327 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2330 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2331 if (gres != XtGeometryYes && appData.debugMode) {
2333 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2334 programName, gres, w, h, wr, hr);
2337 XawFormDoLayout(formWidget, True);
2339 xBoardWindow = XtWindow(boardWidget);
2341 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2342 // not need to go into InitDrawingSizes().
2346 * Create X checkmark bitmap and initialize option menu checks.
2348 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2349 checkmark_bits, checkmark_width, checkmark_height);
2350 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2351 if (appData.alwaysPromoteToQueen) {
2352 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2355 if (appData.animateDragging) {
2356 XtSetValues(XtNameToWidget(menuBarWidget,
2357 "menuOptions.Animate Dragging"),
2360 if (appData.animate) {
2361 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2364 if (appData.autoComment) {
2365 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2368 if (appData.autoCallFlag) {
2369 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2372 if (appData.autoFlipView) {
2373 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2376 if (appData.autoObserve) {
2377 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2380 if (appData.autoRaiseBoard) {
2381 XtSetValues(XtNameToWidget(menuBarWidget,
2382 "menuOptions.Auto Raise Board"), args, 1);
2384 if (appData.autoSaveGames) {
2385 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2388 if (appData.saveGameFile[0] != NULLCHAR) {
2389 /* Can't turn this off from menu */
2390 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2392 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2396 if (appData.blindfold) {
2397 XtSetValues(XtNameToWidget(menuBarWidget,
2398 "menuOptions.Blindfold"), args, 1);
2400 if (appData.flashCount > 0) {
2401 XtSetValues(XtNameToWidget(menuBarWidget,
2402 "menuOptions.Flash Moves"),
2405 if (appData.getMoveList) {
2406 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2410 if (appData.highlightDragging) {
2411 XtSetValues(XtNameToWidget(menuBarWidget,
2412 "menuOptions.Highlight Dragging"),
2416 if (appData.highlightLastMove) {
2417 XtSetValues(XtNameToWidget(menuBarWidget,
2418 "menuOptions.Highlight Last Move"),
2421 if (appData.icsAlarm) {
2422 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2425 if (appData.ringBellAfterMoves) {
2426 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2429 if (appData.oldSaveStyle) {
2430 XtSetValues(XtNameToWidget(menuBarWidget,
2431 "menuOptions.Old Save Style"), args, 1);
2433 if (appData.periodicUpdates) {
2434 XtSetValues(XtNameToWidget(menuBarWidget,
2435 "menuOptions.Periodic Updates"), args, 1);
2437 if (appData.ponderNextMove) {
2438 XtSetValues(XtNameToWidget(menuBarWidget,
2439 "menuOptions.Ponder Next Move"), args, 1);
2441 if (appData.popupExitMessage) {
2442 XtSetValues(XtNameToWidget(menuBarWidget,
2443 "menuOptions.Popup Exit Message"), args, 1);
2445 if (appData.popupMoveErrors) {
2446 XtSetValues(XtNameToWidget(menuBarWidget,
2447 "menuOptions.Popup Move Errors"), args, 1);
2449 if (appData.premove) {
2450 XtSetValues(XtNameToWidget(menuBarWidget,
2451 "menuOptions.Premove"), args, 1);
2453 if (appData.quietPlay) {
2454 XtSetValues(XtNameToWidget(menuBarWidget,
2455 "menuOptions.Quiet Play"), args, 1);
2457 if (appData.showCoords) {
2458 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2461 if (appData.hideThinkingFromHuman) {
2462 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2465 if (appData.testLegality) {
2466 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2469 if (saveSettingsOnExit) {
2470 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2477 ReadBitmap(&wIconPixmap, "icon_white.bm",
2478 icon_white_bits, icon_white_width, icon_white_height);
2479 ReadBitmap(&bIconPixmap, "icon_black.bm",
2480 icon_black_bits, icon_black_width, icon_black_height);
2481 iconPixmap = wIconPixmap;
2483 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2484 XtSetValues(shellWidget, args, i);
2487 * Create a cursor for the board widget.
2489 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2490 XChangeWindowAttributes(xDisplay, xBoardWindow,
2491 CWCursor, &window_attributes);
2494 * Inhibit shell resizing.
2496 shellArgs[0].value = (XtArgVal) &w;
2497 shellArgs[1].value = (XtArgVal) &h;
2498 XtGetValues(shellWidget, shellArgs, 2);
2499 shellArgs[4].value = shellArgs[2].value = w;
2500 shellArgs[5].value = shellArgs[3].value = h;
2501 XtSetValues(shellWidget, &shellArgs[2], 4);
2502 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2503 marginH = h - boardHeight;
2505 CatchDeleteWindow(shellWidget, "QuitProc");
2510 if (appData.bitmapDirectory[0] != NULLCHAR) {
2517 /* Create regular pieces */
2518 if (!useImages) CreatePieces();
2523 if (appData.animate || appData.animateDragging)
2526 XtAugmentTranslations(formWidget,
2527 XtParseTranslationTable(globalTranslations));
2528 XtAugmentTranslations(boardWidget,
2529 XtParseTranslationTable(boardTranslations));
2530 XtAugmentTranslations(whiteTimerWidget,
2531 XtParseTranslationTable(whiteTranslations));
2532 XtAugmentTranslations(blackTimerWidget,
2533 XtParseTranslationTable(blackTranslations));
2535 /* Why is the following needed on some versions of X instead
2536 * of a translation? */
2537 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2538 (XtEventHandler) EventProc, NULL);
2541 /* [AS] Restore layout */
2542 if( wpMoveHistory.visible ) {
2546 if( wpEvalGraph.visible )
2551 if( wpEngineOutput.visible ) {
2552 EngineOutputPopUp();
2557 if (errorExitStatus == -1) {
2558 if (appData.icsActive) {
2559 /* We now wait until we see "login:" from the ICS before
2560 sending the logon script (problems with timestamp otherwise) */
2561 /*ICSInitScript();*/
2562 if (appData.icsInputBox) ICSInputBoxPopUp();
2566 signal(SIGWINCH, TermSizeSigHandler);
2568 signal(SIGINT, IntSigHandler);
2569 signal(SIGTERM, IntSigHandler);
2570 if (*appData.cmailGameName != NULLCHAR) {
2571 signal(SIGUSR1, CmailSigHandler);
2574 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2576 XtSetKeyboardFocus(shellWidget, formWidget);
2578 XtAppMainLoop(appContext);
2579 if (appData.debugMode) fclose(debugFP); // [DM] debug
2586 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2587 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2589 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2590 unlink(gameCopyFilename);
2591 unlink(gamePasteFilename);
2594 RETSIGTYPE TermSizeSigHandler(int sig)
2607 CmailSigHandler(sig)
2613 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2615 /* Activate call-back function CmailSigHandlerCallBack() */
2616 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2618 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2622 CmailSigHandlerCallBack(isr, closure, message, count, error)
2630 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2632 /**** end signal code ****/
2642 f = fopen(appData.icsLogon, "r");
2648 strcat(buf, appData.icsLogon);
2649 f = fopen(buf, "r");
2653 ProcessICSInitScript(f);
2660 EditCommentPopDown();
2675 if (!menuBarWidget) return;
2676 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2678 DisplayError("menuStep.Revert", 0);
2680 XtSetSensitive(w, !grey);
2682 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2684 DisplayError("menuStep.Annotate", 0);
2686 XtSetSensitive(w, !grey);
2691 SetMenuEnables(enab)
2695 if (!menuBarWidget) return;
2696 while (enab->name != NULL) {
2697 w = XtNameToWidget(menuBarWidget, enab->name);
2699 DisplayError(enab->name, 0);
2701 XtSetSensitive(w, enab->value);
2707 Enables icsEnables[] = {
2708 { "menuFile.Mail Move", False },
2709 { "menuFile.Reload CMail Message", False },
2710 { "menuMode.Machine Black", False },
2711 { "menuMode.Machine White", False },
2712 { "menuMode.Analysis Mode", False },
2713 { "menuMode.Analyze File", False },
2714 { "menuMode.Two Machines", False },
2716 { "menuHelp.Hint", False },
2717 { "menuHelp.Book", False },
2718 { "menuStep.Move Now", False },
2719 { "menuOptions.Periodic Updates", False },
2720 { "menuOptions.Hide Thinking", False },
2721 { "menuOptions.Ponder Next Move", False },
2723 { "menuStep.Annotate", False },
2727 Enables ncpEnables[] = {
2728 { "menuFile.Mail Move", False },
2729 { "menuFile.Reload CMail Message", False },
2730 { "menuMode.Machine White", False },
2731 { "menuMode.Machine Black", False },
2732 { "menuMode.Analysis Mode", False },
2733 { "menuMode.Analyze File", False },
2734 { "menuMode.Two Machines", False },
2735 { "menuMode.ICS Client", False },
2736 { "menuMode.ICS Input Box", False },
2737 { "Action", False },
2738 { "menuStep.Revert", False },
2739 { "menuStep.Annotate", False },
2740 { "menuStep.Move Now", False },
2741 { "menuStep.Retract Move", False },
2742 { "menuOptions.Auto Comment", False },
2743 { "menuOptions.Auto Flag", False },
2744 { "menuOptions.Auto Flip View", False },
2745 { "menuOptions.Auto Observe", False },
2746 { "menuOptions.Auto Raise Board", False },
2747 { "menuOptions.Get Move List", False },
2748 { "menuOptions.ICS Alarm", False },
2749 { "menuOptions.Move Sound", False },
2750 { "menuOptions.Quiet Play", False },
2751 { "menuOptions.Hide Thinking", False },
2752 { "menuOptions.Periodic Updates", False },
2753 { "menuOptions.Ponder Next Move", False },
2754 { "menuHelp.Hint", False },
2755 { "menuHelp.Book", False },
2759 Enables gnuEnables[] = {
2760 { "menuMode.ICS Client", False },
2761 { "menuMode.ICS Input Box", False },
2762 { "menuAction.Accept", False },
2763 { "menuAction.Decline", False },
2764 { "menuAction.Rematch", False },
2765 { "menuAction.Adjourn", False },
2766 { "menuAction.Stop Examining", False },
2767 { "menuAction.Stop Observing", False },
2768 { "menuAction.Upload to Examine", False },
2769 { "menuStep.Revert", False },
2770 { "menuStep.Annotate", False },
2771 { "menuOptions.Auto Comment", False },
2772 { "menuOptions.Auto Observe", False },
2773 { "menuOptions.Auto Raise Board", False },
2774 { "menuOptions.Get Move List", False },
2775 { "menuOptions.Premove", False },
2776 { "menuOptions.Quiet Play", False },
2778 /* The next two options rely on SetCmailMode being called *after* */
2779 /* SetGNUMode so that when GNU is being used to give hints these */
2780 /* menu options are still available */
2782 { "menuFile.Mail Move", False },
2783 { "menuFile.Reload CMail Message", False },
2787 Enables cmailEnables[] = {
2789 { "menuAction.Call Flag", False },
2790 { "menuAction.Draw", True },
2791 { "menuAction.Adjourn", False },
2792 { "menuAction.Abort", False },
2793 { "menuAction.Stop Observing", False },
2794 { "menuAction.Stop Examining", False },
2795 { "menuFile.Mail Move", True },
2796 { "menuFile.Reload CMail Message", True },
2800 Enables trainingOnEnables[] = {
2801 { "menuMode.Edit Comment", False },
2802 { "menuMode.Pause", False },
2803 { "menuStep.Forward", False },
2804 { "menuStep.Backward", False },
2805 { "menuStep.Forward to End", False },
2806 { "menuStep.Back to Start", False },
2807 { "menuStep.Move Now", False },
2808 { "menuStep.Truncate Game", False },
2812 Enables trainingOffEnables[] = {
2813 { "menuMode.Edit Comment", True },
2814 { "menuMode.Pause", True },
2815 { "menuStep.Forward", True },
2816 { "menuStep.Backward", True },
2817 { "menuStep.Forward to End", True },
2818 { "menuStep.Back to Start", True },
2819 { "menuStep.Move Now", True },
2820 { "menuStep.Truncate Game", True },
2824 Enables machineThinkingEnables[] = {
2825 { "menuFile.Load Game", False },
2826 { "menuFile.Load Next Game", False },
2827 { "menuFile.Load Previous Game", False },
2828 { "menuFile.Reload Same Game", False },
2829 { "menuFile.Paste Game", False },
2830 { "menuFile.Load Position", False },
2831 { "menuFile.Load Next Position", False },
2832 { "menuFile.Load Previous Position", False },
2833 { "menuFile.Reload Same Position", False },
2834 { "menuFile.Paste Position", False },
2835 { "menuMode.Machine White", False },
2836 { "menuMode.Machine Black", False },
2837 { "menuMode.Two Machines", False },
2838 { "menuStep.Retract Move", False },
2842 Enables userThinkingEnables[] = {
2843 { "menuFile.Load Game", True },
2844 { "menuFile.Load Next Game", True },
2845 { "menuFile.Load Previous Game", True },
2846 { "menuFile.Reload Same Game", True },
2847 { "menuFile.Paste Game", True },
2848 { "menuFile.Load Position", True },
2849 { "menuFile.Load Next Position", True },
2850 { "menuFile.Load Previous Position", True },
2851 { "menuFile.Reload Same Position", True },
2852 { "menuFile.Paste Position", True },
2853 { "menuMode.Machine White", True },
2854 { "menuMode.Machine Black", True },
2855 { "menuMode.Two Machines", True },
2856 { "menuStep.Retract Move", True },
2862 SetMenuEnables(icsEnables);
2865 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2866 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2873 SetMenuEnables(ncpEnables);
2879 SetMenuEnables(gnuEnables);
2885 SetMenuEnables(cmailEnables);
2891 SetMenuEnables(trainingOnEnables);
2892 if (appData.showButtonBar) {
2893 XtSetSensitive(buttonBarWidget, False);
2899 SetTrainingModeOff()
2901 SetMenuEnables(trainingOffEnables);
2902 if (appData.showButtonBar) {
2903 XtSetSensitive(buttonBarWidget, True);
2908 SetUserThinkingEnables()
2910 if (appData.noChessProgram) return;
2911 SetMenuEnables(userThinkingEnables);
2915 SetMachineThinkingEnables()
2917 if (appData.noChessProgram) return;
2918 SetMenuEnables(machineThinkingEnables);
2920 case MachinePlaysBlack:
2921 case MachinePlaysWhite:
2922 case TwoMachinesPlay:
2923 XtSetSensitive(XtNameToWidget(menuBarWidget,
2924 ModeToWidgetName(gameMode)), True);
2931 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2932 #define HISTORY_SIZE 64
\r
2933 static char *history[HISTORY_SIZE];
\r
2934 int histIn = 0, histP = 0;
\r
2937 SaveInHistory(char *cmd)
\r
2939 if (history[histIn] != NULL) {
\r
2940 free(history[histIn]);
\r
2941 history[histIn] = NULL;
\r
2943 if (*cmd == NULLCHAR) return;
\r
2944 history[histIn] = StrSave(cmd);
\r
2945 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2946 if (history[histIn] != NULL) {
\r
2947 free(history[histIn]);
\r
2948 history[histIn] = NULL;
\r
2954 PrevInHistory(char *cmd)
\r
2957 if (histP == histIn) {
\r
2958 if (history[histIn] != NULL) free(history[histIn]);
\r
2959 history[histIn] = StrSave(cmd);
\r
2961 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2962 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2964 return history[histP];
\r
2970 if (histP == histIn) return NULL;
\r
2971 histP = (histP + 1) % HISTORY_SIZE;
\r
2972 return history[histP];
\r
2974 // end of borrowed code
\r
2976 #define Abs(n) ((n)<0 ? -(n) : (n))
2979 * Find a font that matches "pattern" that is as close as
2980 * possible to the targetPxlSize. Prefer fonts that are k
2981 * pixels smaller to fonts that are k pixels larger. The
2982 * pattern must be in the X Consortium standard format,
2983 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2984 * The return value should be freed with XtFree when no
2987 char *FindFont(pattern, targetPxlSize)
2991 char **fonts, *p, *best, *scalable, *scalableTail;
2992 int i, j, nfonts, minerr, err, pxlSize;
2995 char **missing_list;
2997 char *def_string, *base_fnt_lst, strInt[3];
2999 XFontStruct **fnt_list;
3001 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3002 sprintf(strInt, "%d", targetPxlSize);
3003 p = strstr(pattern, "--");
3004 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3005 strcat(base_fnt_lst, strInt);
3006 strcat(base_fnt_lst, strchr(p + 2, '-'));
3008 if ((fntSet = XCreateFontSet(xDisplay,
3012 &def_string)) == NULL) {
3014 fprintf(stderr, _("Unable to create font set.\n"));
3018 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3020 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3022 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3023 programName, pattern);
3031 for (i=0; i<nfonts; i++) {
3034 if (*p != '-') continue;
3036 if (*p == NULLCHAR) break;
3037 if (*p++ == '-') j++;
3039 if (j < 7) continue;
3042 scalable = fonts[i];
3045 err = pxlSize - targetPxlSize;
3046 if (Abs(err) < Abs(minerr) ||
3047 (minerr > 0 && err < 0 && -err == minerr)) {
3053 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3054 /* If the error is too big and there is a scalable font,
3055 use the scalable font. */
3056 int headlen = scalableTail - scalable;
3057 p = (char *) XtMalloc(strlen(scalable) + 10);
3058 while (isdigit(*scalableTail)) scalableTail++;
3059 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3061 p = (char *) XtMalloc(strlen(best) + 1);
3064 if (appData.debugMode) {
3065 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3066 pattern, targetPxlSize, p);
3069 if (missing_count > 0)
3070 XFreeStringList(missing_list);
3071 XFreeFontSet(xDisplay, fntSet);
3073 XFreeFontNames(fonts);
3080 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3081 | GCBackground | GCFunction | GCPlaneMask;
3082 XGCValues gc_values;
3085 gc_values.plane_mask = AllPlanes;
3086 gc_values.line_width = lineGap;
3087 gc_values.line_style = LineSolid;
3088 gc_values.function = GXcopy;
3090 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3091 gc_values.background = XBlackPixel(xDisplay, xScreen);
3092 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3094 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3095 gc_values.background = XWhitePixel(xDisplay, xScreen);
3096 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3097 XSetFont(xDisplay, coordGC, coordFontID);
3099 // [HGM] make font for holdings counts (white on black0
3100 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3101 gc_values.background = XBlackPixel(xDisplay, xScreen);
3102 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3103 XSetFont(xDisplay, countGC, countFontID);
3105 if (appData.monoMode) {
3106 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3107 gc_values.background = XWhitePixel(xDisplay, xScreen);
3108 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3110 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3111 gc_values.background = XBlackPixel(xDisplay, xScreen);
3112 lightSquareGC = wbPieceGC
3113 = XtGetGC(shellWidget, value_mask, &gc_values);
3115 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3116 gc_values.background = XWhitePixel(xDisplay, xScreen);
3117 darkSquareGC = bwPieceGC
3118 = XtGetGC(shellWidget, value_mask, &gc_values);
3120 if (DefaultDepth(xDisplay, xScreen) == 1) {
3121 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3122 gc_values.function = GXcopyInverted;
3123 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3124 gc_values.function = GXcopy;
3125 if (XBlackPixel(xDisplay, xScreen) == 1) {
3126 bwPieceGC = darkSquareGC;
3127 wbPieceGC = copyInvertedGC;
3129 bwPieceGC = copyInvertedGC;
3130 wbPieceGC = lightSquareGC;
3134 gc_values.foreground = highlightSquareColor;
3135 gc_values.background = highlightSquareColor;
3136 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3138 gc_values.foreground = premoveHighlightColor;
3139 gc_values.background = premoveHighlightColor;
3140 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3142 gc_values.foreground = lightSquareColor;
3143 gc_values.background = darkSquareColor;
3144 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3146 gc_values.foreground = darkSquareColor;
3147 gc_values.background = lightSquareColor;
3148 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3150 gc_values.foreground = jailSquareColor;
3151 gc_values.background = jailSquareColor;
3152 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3154 gc_values.foreground = whitePieceColor;
3155 gc_values.background = darkSquareColor;
3156 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3158 gc_values.foreground = whitePieceColor;
3159 gc_values.background = lightSquareColor;
3160 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3162 gc_values.foreground = whitePieceColor;
3163 gc_values.background = jailSquareColor;
3164 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3166 gc_values.foreground = blackPieceColor;
3167 gc_values.background = darkSquareColor;
3168 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3170 gc_values.foreground = blackPieceColor;
3171 gc_values.background = lightSquareColor;
3172 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3174 gc_values.foreground = blackPieceColor;
3175 gc_values.background = jailSquareColor;
3176 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3180 void loadXIM(xim, xmask, filename, dest, mask)
3193 fp = fopen(filename, "rb");
3195 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3202 for (y=0; y<h; ++y) {
3203 for (x=0; x<h; ++x) {
3208 XPutPixel(xim, x, y, blackPieceColor);
3210 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3213 XPutPixel(xim, x, y, darkSquareColor);
3215 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3218 XPutPixel(xim, x, y, whitePieceColor);
3220 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3223 XPutPixel(xim, x, y, lightSquareColor);
3225 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3231 /* create Pixmap of piece */
3232 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3234 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3237 /* create Pixmap of clipmask
3238 Note: We assume the white/black pieces have the same
3239 outline, so we make only 6 masks. This is okay
3240 since the XPM clipmask routines do the same. */
3242 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3244 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3247 /* now create the 1-bit version */
3248 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3251 values.foreground = 1;
3252 values.background = 0;
3254 /* Don't use XtGetGC, not read only */
3255 maskGC = XCreateGC(xDisplay, *mask,
3256 GCForeground | GCBackground, &values);
3257 XCopyPlane(xDisplay, temp, *mask, maskGC,
3258 0, 0, squareSize, squareSize, 0, 0, 1);
3259 XFreePixmap(xDisplay, temp);
3264 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3266 void CreateXIMPieces()
3271 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3276 /* The XSynchronize calls were copied from CreatePieces.
3277 Not sure if needed, but can't hurt */
3278 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3281 /* temp needed by loadXIM() */
3282 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3283 0, 0, ss, ss, AllPlanes, XYPixmap);
3285 if (strlen(appData.pixmapDirectory) == 0) {
3289 if (appData.monoMode) {
3290 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3294 fprintf(stderr, _("\nLoading XIMs...\n"));
3296 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3297 fprintf(stderr, "%d", piece+1);
3298 for (kind=0; kind<4; kind++) {
3299 fprintf(stderr, ".");
3300 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3301 ExpandPathName(appData.pixmapDirectory),
3302 piece <= (int) WhiteKing ? "" : "w",
3303 pieceBitmapNames[piece],
3305 ximPieceBitmap[kind][piece] =
3306 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3307 0, 0, ss, ss, AllPlanes, XYPixmap);
3308 if (appData.debugMode)
3309 fprintf(stderr, _("(File:%s:) "), buf);
3310 loadXIM(ximPieceBitmap[kind][piece],
3312 &(xpmPieceBitmap2[kind][piece]),
3313 &(ximMaskPm2[piece]));
3314 if(piece <= (int)WhiteKing)
3315 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3317 fprintf(stderr," ");
3319 /* Load light and dark squares */
3320 /* If the LSQ and DSQ pieces don't exist, we will
3321 draw them with solid squares. */
3322 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3323 if (access(buf, 0) != 0) {
3327 fprintf(stderr, _("light square "));
3329 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3330 0, 0, ss, ss, AllPlanes, XYPixmap);
3331 if (appData.debugMode)
3332 fprintf(stderr, _("(File:%s:) "), buf);
3334 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3335 fprintf(stderr, _("dark square "));
3336 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3337 ExpandPathName(appData.pixmapDirectory), ss);
3338 if (appData.debugMode)
3339 fprintf(stderr, _("(File:%s:) "), buf);
3341 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3342 0, 0, ss, ss, AllPlanes, XYPixmap);
3343 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3344 xpmJailSquare = xpmLightSquare;
3346 fprintf(stderr, _("Done.\n"));
3348 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3352 void CreateXPMPieces()
3356 u_int ss = squareSize;
3358 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3359 XpmColorSymbol symbols[4];
3361 /* The XSynchronize calls were copied from CreatePieces.
3362 Not sure if needed, but can't hurt */
3363 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3365 /* Setup translations so piece colors match square colors */
3366 symbols[0].name = "light_piece";
3367 symbols[0].value = appData.whitePieceColor;
3368 symbols[1].name = "dark_piece";
3369 symbols[1].value = appData.blackPieceColor;
3370 symbols[2].name = "light_square";
3371 symbols[2].value = appData.lightSquareColor;
3372 symbols[3].name = "dark_square";
3373 symbols[3].value = appData.darkSquareColor;
3375 attr.valuemask = XpmColorSymbols;
3376 attr.colorsymbols = symbols;
3377 attr.numsymbols = 4;
3379 if (appData.monoMode) {
3380 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3384 if (strlen(appData.pixmapDirectory) == 0) {
3385 XpmPieces* pieces = builtInXpms;
3388 while (pieces->size != squareSize && pieces->size) pieces++;
3389 if (!pieces->size) {
3390 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3393 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3394 for (kind=0; kind<4; kind++) {
3396 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3397 pieces->xpm[piece][kind],
3398 &(xpmPieceBitmap2[kind][piece]),
3399 NULL, &attr)) != 0) {
3400 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3404 if(piece <= (int) WhiteKing)
3405 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3409 xpmJailSquare = xpmLightSquare;
3413 fprintf(stderr, _("\nLoading XPMs...\n"));
3416 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3417 fprintf(stderr, "%d ", piece+1);
3418 for (kind=0; kind<4; kind++) {
3419 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3420 ExpandPathName(appData.pixmapDirectory),
3421 piece > (int) WhiteKing ? "w" : "",
3422 pieceBitmapNames[piece],
3424 if (appData.debugMode) {
3425 fprintf(stderr, _("(File:%s:) "), buf);
3427 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3428 &(xpmPieceBitmap2[kind][piece]),
3429 NULL, &attr)) != 0) {
3430 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3431 // [HGM] missing: read of unorthodox piece failed; substitute King.
3432 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3433 ExpandPathName(appData.pixmapDirectory),
3435 if (appData.debugMode) {
3436 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3438 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3439 &(xpmPieceBitmap2[kind][piece]),
3443 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3448 if(piece <= (int) WhiteKing)
3449 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3452 /* Load light and dark squares */
3453 /* If the LSQ and DSQ pieces don't exist, we will
3454 draw them with solid squares. */
3455 fprintf(stderr, _("light square "));
3456 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3457 if (access(buf, 0) != 0) {
3461 if (appData.debugMode)
3462 fprintf(stderr, _("(File:%s:) "), buf);
3464 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3465 &xpmLightSquare, NULL, &attr)) != 0) {
3466 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3469 fprintf(stderr, _("dark square "));
3470 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3471 ExpandPathName(appData.pixmapDirectory), ss);
3472 if (appData.debugMode) {
3473 fprintf(stderr, _("(File:%s:) "), buf);
3475 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3476 &xpmDarkSquare, NULL, &attr)) != 0) {
3477 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3481 xpmJailSquare = xpmLightSquare;
3482 fprintf(stderr, _("Done.\n"));
3484 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3487 #endif /* HAVE_LIBXPM */
3490 /* No built-in bitmaps */
3495 u_int ss = squareSize;
3497 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3500 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3501 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3502 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3503 pieceBitmapNames[piece],
3504 ss, kind == SOLID ? 's' : 'o');
3505 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3506 if(piece <= (int)WhiteKing)
3507 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3511 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3515 /* With built-in bitmaps */
3518 BuiltInBits* bib = builtInBits;
3521 u_int ss = squareSize;
3523 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3526 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3528 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3529 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3530 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3531 pieceBitmapNames[piece],
3532 ss, kind == SOLID ? 's' : 'o');
3533 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3534 bib->bits[kind][piece], ss, ss);
3535 if(piece <= (int)WhiteKing)
3536 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3540 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3545 void ReadBitmap(pm, name, bits, wreq, hreq)
3548 unsigned char bits[];
3554 char msg[MSG_SIZ], fullname[MSG_SIZ];
3556 if (*appData.bitmapDirectory != NULLCHAR) {
3557 strcpy(fullname, appData.bitmapDirectory);
3558 strcat(fullname, "/");
3559 strcat(fullname, name);
3560 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3561 &w, &h, pm, &x_hot, &y_hot);
3562 fprintf(stderr, "load %s\n", name);
3563 if (errcode != BitmapSuccess) {
3565 case BitmapOpenFailed:
3566 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3568 case BitmapFileInvalid:
3569 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3571 case BitmapNoMemory:
3572 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3576 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3580 fprintf(stderr, _("%s: %s...using built-in\n"),
3582 } else if (w != wreq || h != hreq) {
3584 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3585 programName, fullname, w, h, wreq, hreq);
3591 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3600 if (lineGap == 0) return;
3602 /* [HR] Split this into 2 loops for non-square boards. */
3604 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3605 gridSegments[i].x1 = 0;
3606 gridSegments[i].x2 =
3607 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3608 gridSegments[i].y1 = gridSegments[i].y2
3609 = lineGap / 2 + (i * (squareSize + lineGap));
3612 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3613 gridSegments[j + i].y1 = 0;
3614 gridSegments[j + i].y2 =
3615 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3616 gridSegments[j + i].x1 = gridSegments[j + i].x2
3617 = lineGap / 2 + (j * (squareSize + lineGap));
3621 static void MenuBarSelect(w, addr, index)
3626 XtActionProc proc = (XtActionProc) addr;
3628 (proc)(NULL, NULL, NULL, NULL);
3631 void CreateMenuBarPopup(parent, name, mb)
3641 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3644 XtSetArg(args[j], XtNleftMargin, 20); j++;
3645 XtSetArg(args[j], XtNrightMargin, 20); j++;
3647 while (mi->string != NULL) {
3648 if (strcmp(mi->string, "----") == 0) {
3649 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3652 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3653 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3655 XtAddCallback(entry, XtNcallback,
3656 (XtCallbackProc) MenuBarSelect,
3657 (caddr_t) mi->proc);
3663 Widget CreateMenuBar(mb)
3667 Widget anchor, menuBar;
3669 char menuName[MSG_SIZ];
3672 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3673 XtSetArg(args[j], XtNvSpace, 0); j++;
3674 XtSetArg(args[j], XtNborderWidth, 0); j++;
3675 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3676 formWidget, args, j);
3678 while (mb->name != NULL) {
3679 strcpy(menuName, "menu");
3680 strcat(menuName, mb->name);
3682 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3685 shortName[0] = _(mb->name)[0];
3686 shortName[1] = NULLCHAR;
3687 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3690 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3693 XtSetArg(args[j], XtNborderWidth, 0); j++;
3694 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3696 CreateMenuBarPopup(menuBar, menuName, mb);
3702 Widget CreateButtonBar(mi)
3706 Widget button, buttonBar;
3710 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3712 XtSetArg(args[j], XtNhSpace, 0); j++;
3714 XtSetArg(args[j], XtNborderWidth, 0); j++;
3715 XtSetArg(args[j], XtNvSpace, 0); j++;
3716 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3717 formWidget, args, j);
3719 while (mi->string != NULL) {
3722 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3723 XtSetArg(args[j], XtNborderWidth, 0); j++;
3725 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3726 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3727 buttonBar, args, j);
3728 XtAddCallback(button, XtNcallback,
3729 (XtCallbackProc) MenuBarSelect,
3730 (caddr_t) mi->proc);
3737 CreatePieceMenu(name, color)
3744 ChessSquare selection;
3746 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3747 boardWidget, args, 0);
3749 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3750 String item = pieceMenuStrings[color][i];
3752 if (strcmp(item, "----") == 0) {
3753 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3756 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3757 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3759 selection = pieceMenuTranslation[color][i];
3760 XtAddCallback(entry, XtNcallback,
3761 (XtCallbackProc) PieceMenuSelect,
3762 (caddr_t) selection);
3763 if (selection == WhitePawn || selection == BlackPawn) {
3764 XtSetArg(args[0], XtNpopupOnEntry, entry);
3765 XtSetValues(menu, args, 1);
3778 ChessSquare selection;
3780 whitePieceMenu = CreatePieceMenu("menuW", 0);
3781 blackPieceMenu = CreatePieceMenu("menuB", 1);
3783 XtRegisterGrabAction(PieceMenuPopup, True,
3784 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3785 GrabModeAsync, GrabModeAsync);
3787 XtSetArg(args[0], XtNlabel, _("Drop"));
3788 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3789 boardWidget, args, 1);
3790 for (i = 0; i < DROP_MENU_SIZE; i++) {
3791 String item = dropMenuStrings[i];
3793 if (strcmp(item, "----") == 0) {
3794 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3797 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3798 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3800 selection = dropMenuTranslation[i];
3801 XtAddCallback(entry, XtNcallback,
3802 (XtCallbackProc) DropMenuSelect,
3803 (caddr_t) selection);
3808 void SetupDropMenu()
3816 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3817 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3818 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3819 dmEnables[i].piece);
3820 XtSetSensitive(entry, p != NULL || !appData.testLegality
3821 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3822 && !appData.icsActive));
3824 while (p && *p++ == dmEnables[i].piece) count++;
3825 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3827 XtSetArg(args[j], XtNlabel, label); j++;
3828 XtSetValues(entry, args, j);
3832 void PieceMenuPopup(w, event, params, num_params)
3836 Cardinal *num_params;
3838 String whichMenu; int menuNr;
3839 if (event->type == ButtonRelease)
3840 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3841 else if (event->type == ButtonPress)
3842 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3844 case 0: whichMenu = params[0]; break;
3845 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3847 case -1: if (errorUp) ErrorPopDown();
3850 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3853 static void PieceMenuSelect(w, piece, junk)
3858 if (pmFromX < 0 || pmFromY < 0) return;
3859 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3862 static void DropMenuSelect(w, piece, junk)
3867 if (pmFromX < 0 || pmFromY < 0) return;
3868 DropMenuEvent(piece, pmFromX, pmFromY);
3871 void WhiteClock(w, event, prms, nprms)
3877 if (gameMode == EditPosition || gameMode == IcsExamining) {
3878 SetWhiteToPlayEvent();
3879 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3884 void BlackClock(w, event, prms, nprms)
3890 if (gameMode == EditPosition || gameMode == IcsExamining) {
3891 SetBlackToPlayEvent();
3892 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3899 * If the user selects on a border boundary, return -1; if off the board,
3900 * return -2. Otherwise map the event coordinate to the square.
3902 int EventToSquare(x, limit)
3910 if ((x % (squareSize + lineGap)) >= squareSize)
3912 x /= (squareSize + lineGap);
3918 static void do_flash_delay(msec)
3924 static void drawHighlight(file, rank, gc)
3930 if (lineGap == 0 || appData.blindfold) return;
3933 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3934 (squareSize + lineGap);
3935 y = lineGap/2 + rank * (squareSize + lineGap);
3937 x = lineGap/2 + file * (squareSize + lineGap);
3938 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3939 (squareSize + lineGap);
3942 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3943 squareSize+lineGap, squareSize+lineGap);
3946 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3947 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3950 SetHighlights(fromX, fromY, toX, toY)
3951 int fromX, fromY, toX, toY;
3953 if (hi1X != fromX || hi1Y != fromY) {
3954 if (hi1X >= 0 && hi1Y >= 0) {
3955 drawHighlight(hi1X, hi1Y, lineGC);
3957 } // [HGM] first erase both, then draw new!
3958 if (hi2X != toX || hi2Y != toY) {
3959 if (hi2X >= 0 && hi2Y >= 0) {
3960 drawHighlight(hi2X, hi2Y, lineGC);
3963 if (hi1X != fromX || hi1Y != fromY) {
3964 if (fromX >= 0 && fromY >= 0) {
3965 drawHighlight(fromX, fromY, highlineGC);
3968 if (hi2X != toX || hi2Y != toY) {
3969 if (toX >= 0 && toY >= 0) {
3970 drawHighlight(toX, toY, highlineGC);
3982 SetHighlights(-1, -1, -1, -1);
3987 SetPremoveHighlights(fromX, fromY, toX, toY)
3988 int fromX, fromY, toX, toY;
3990 if (pm1X != fromX || pm1Y != fromY) {
3991 if (pm1X >= 0 && pm1Y >= 0) {
3992 drawHighlight(pm1X, pm1Y, lineGC);
3994 if (fromX >= 0 && fromY >= 0) {
3995 drawHighlight(fromX, fromY, prelineGC);
3998 if (pm2X != toX || pm2Y != toY) {
3999 if (pm2X >= 0 && pm2Y >= 0) {
4000 drawHighlight(pm2X, pm2Y, lineGC);
4002 if (toX >= 0 && toY >= 0) {
4003 drawHighlight(toX, toY, prelineGC);
4013 ClearPremoveHighlights()
4015 SetPremoveHighlights(-1, -1, -1, -1);
4018 static void BlankSquare(x, y, color, piece, dest)
4023 if (useImages && useImageSqs) {
4027 pm = xpmLightSquare;
4032 case 2: /* neutral */
4037 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4038 squareSize, squareSize, x, y);
4048 case 2: /* neutral */
4053 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4058 I split out the routines to draw a piece so that I could
4059 make a generic flash routine.
4061 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4063 int square_color, x, y;
4066 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4067 switch (square_color) {
4069 case 2: /* neutral */
4071 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4072 ? *pieceToOutline(piece)
4073 : *pieceToSolid(piece),
4074 dest, bwPieceGC, 0, 0,
4075 squareSize, squareSize, x, y);
4078 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4079 ? *pieceToSolid(piece)
4080 : *pieceToOutline(piece),
4081 dest, wbPieceGC, 0, 0,
4082 squareSize, squareSize, x, y);
4087 static void monoDrawPiece(piece, square_color, x, y, dest)
4089 int square_color, x, y;
4092 switch (square_color) {
4094 case 2: /* neutral */
4096 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4097 ? *pieceToOutline(piece)
4098 : *pieceToSolid(piece),
4099 dest, bwPieceGC, 0, 0,
4100 squareSize, squareSize, x, y, 1);
4103 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4104 ? *pieceToSolid(piece)
4105 : *pieceToOutline(piece),
4106 dest, wbPieceGC, 0, 0,
4107 squareSize, squareSize, x, y, 1);
4112 static void colorDrawPiece(piece, square_color, x, y, dest)
4114 int square_color, x, y;
4117 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4118 switch (square_color) {
4120 XCopyPlane(xDisplay, *pieceToSolid(piece),
4121 dest, (int) piece < (int) BlackPawn
4122 ? wlPieceGC : blPieceGC, 0, 0,
4123 squareSize, squareSize, x, y, 1);
4126 XCopyPlane(xDisplay, *pieceToSolid(piece),
4127 dest, (int) piece < (int) BlackPawn
4128 ? wdPieceGC : bdPieceGC, 0, 0,
4129 squareSize, squareSize, x, y, 1);
4131 case 2: /* neutral */
4133 XCopyPlane(xDisplay, *pieceToSolid(piece),
4134 dest, (int) piece < (int) BlackPawn
4135 ? wjPieceGC : bjPieceGC, 0, 0,
4136 squareSize, squareSize, x, y, 1);
4141 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4143 int square_color, x, y;
4148 switch (square_color) {
4150 case 2: /* neutral */
4152 if ((int)piece < (int) BlackPawn) {
4160 if ((int)piece < (int) BlackPawn) {
4168 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4169 dest, wlPieceGC, 0, 0,
4170 squareSize, squareSize, x, y);
4173 typedef void (*DrawFunc)();
4175 DrawFunc ChooseDrawFunc()
4177 if (appData.monoMode) {
4178 if (DefaultDepth(xDisplay, xScreen) == 1) {
4179 return monoDrawPiece_1bit;
4181 return monoDrawPiece;
4185 return colorDrawPieceImage;
4187 return colorDrawPiece;
4191 /* [HR] determine square color depending on chess variant. */
4192 static int SquareColor(row, column)
4197 if (gameInfo.variant == VariantXiangqi) {
4198 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4200 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4202 } else if (row <= 4) {
4208 square_color = ((column + row) % 2) == 1;
4211 /* [hgm] holdings: next line makes all holdings squares light */
4212 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4214 return square_color;
4217 void DrawSquare(row, column, piece, do_flash)
4218 int row, column, do_flash;
4221 int square_color, x, y, direction, font_ascent, font_descent;
4224 XCharStruct overall;
4228 /* Calculate delay in milliseconds (2-delays per complete flash) */
4229 flash_delay = 500 / appData.flashRate;
4232 x = lineGap + ((BOARD_WIDTH-1)-column) *
4233 (squareSize + lineGap);
4234 y = lineGap + row * (squareSize + lineGap);
4236 x = lineGap + column * (squareSize + lineGap);
4237 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4238 (squareSize + lineGap);
4241 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4243 square_color = SquareColor(row, column);
4245 if ( // [HGM] holdings: blank out area between board and holdings
4246 column == BOARD_LEFT-1 || column == BOARD_RGHT
4247 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4248 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4249 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4251 // [HGM] print piece counts next to holdings
4252 string[1] = NULLCHAR;
4253 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4254 string[0] = '0' + piece;
4255 XTextExtents(countFontStruct, string, 1, &direction,
4256 &font_ascent, &font_descent, &overall);
4257 if (appData.monoMode) {
4258 XDrawImageString(xDisplay, xBoardWindow, countGC,
4259 x + squareSize - overall.width - 2,
4260 y + font_ascent + 1, string, 1);
4262 XDrawString(xDisplay, xBoardWindow, countGC,
4263 x + squareSize - overall.width - 2,
4264 y + font_ascent + 1, string, 1);
4267 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4268 string[0] = '0' + piece;
4269 XTextExtents(countFontStruct, string, 1, &direction,
4270 &font_ascent, &font_descent, &overall);
4271 if (appData.monoMode) {
4272 XDrawImageString(xDisplay, xBoardWindow, countGC,
4273 x + 2, y + font_ascent + 1, string, 1);
4275 XDrawString(xDisplay, xBoardWindow, countGC,
4276 x + 2, y + font_ascent + 1, string, 1);
4280 if (piece == EmptySquare || appData.blindfold) {
4281 BlankSquare(x, y, square_color, piece, xBoardWindow);
4283 drawfunc = ChooseDrawFunc();
4284 if (do_flash && appData.flashCount > 0) {
4285 for (i=0; i<appData.flashCount; ++i) {
4287 drawfunc(piece, square_color, x, y, xBoardWindow);
4288 XSync(xDisplay, False);
4289 do_flash_delay(flash_delay);
4291 BlankSquare(x, y, square_color, piece, xBoardWindow);
4292 XSync(xDisplay, False);
4293 do_flash_delay(flash_delay);
4296 drawfunc(piece, square_color, x, y, xBoardWindow);
4300 string[1] = NULLCHAR;
4301 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4302 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4303 string[0] = 'a' + column - BOARD_LEFT;
4304 XTextExtents(coordFontStruct, string, 1, &direction,
4305 &font_ascent, &font_descent, &overall);
4306 if (appData.monoMode) {
4307 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4308 x + squareSize - overall.width - 2,
4309 y + squareSize - font_descent - 1, string, 1);
4311 XDrawString(xDisplay, xBoardWindow, coordGC,
4312 x + squareSize - overall.width - 2,
4313 y + squareSize - font_descent - 1, string, 1);
4316 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4317 string[0] = ONE + row;
4318 XTextExtents(coordFontStruct, string, 1, &direction,
4319 &font_ascent, &font_descent, &overall);
4320 if (appData.monoMode) {
4321 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4322 x + 2, y + font_ascent + 1, string, 1);
4324 XDrawString(xDisplay, xBoardWindow, coordGC,
4325 x + 2, y + font_ascent + 1, string, 1);
4328 if(!partnerUp && marker[row][column]) {
4329 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4330 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4335 /* Why is this needed on some versions of X? */
4336 void EventProc(widget, unused, event)
4341 if (!XtIsRealized(widget))
4344 switch (event->type) {
4346 if (event->xexpose.count > 0) return; /* no clipping is done */
4347 XDrawPosition(widget, True, NULL);
4348 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4349 flipView = !flipView; partnerUp = !partnerUp;
4350 XDrawPosition(widget, True, NULL);
4351 flipView = !flipView; partnerUp = !partnerUp;
4355 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4362 void DrawPosition(fullRedraw, board)
4363 /*Boolean*/int fullRedraw;
4366 XDrawPosition(boardWidget, fullRedraw, board);
4369 /* Returns 1 if there are "too many" differences between b1 and b2
4370 (i.e. more than 1 move was made) */
4371 static int too_many_diffs(b1, b2)
4377 for (i=0; i<BOARD_HEIGHT; ++i) {
4378 for (j=0; j<BOARD_WIDTH; ++j) {
4379 if (b1[i][j] != b2[i][j]) {
4380 if (++c > 4) /* Castling causes 4 diffs */
4389 /* Matrix describing castling maneuvers */
4390 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4391 static int castling_matrix[4][5] = {
4392 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4393 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4394 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4395 { 7, 7, 4, 5, 6 } /* 0-0, black */
4398 /* Checks whether castling occurred. If it did, *rrow and *rcol
4399 are set to the destination (row,col) of the rook that moved.
4401 Returns 1 if castling occurred, 0 if not.
4403 Note: Only handles a max of 1 castling move, so be sure
4404 to call too_many_diffs() first.
4406 static int check_castle_draw(newb, oldb, rrow, rcol)
4413 /* For each type of castling... */
4414 for (i=0; i<4; ++i) {
4415 r = castling_matrix[i];
4417 /* Check the 4 squares involved in the castling move */
4419 for (j=1; j<=4; ++j) {
4420 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4427 /* All 4 changed, so it must be a castling move */
4436 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4437 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4439 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4442 void DrawSeekBackground( int left, int top, int right, int bottom )
4444 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4447 void DrawSeekText(char *buf, int x, int y)
4449 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4452 void DrawSeekDot(int x, int y, int colorNr)
4454 int square = colorNr & 0x80;
4457 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4459 XFillRectangle(xDisplay, xBoardWindow, color,
4460 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4462 XFillArc(xDisplay, xBoardWindow, color,
4463 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4466 static int damage[2][BOARD_RANKS][BOARD_FILES];
4469 * event handler for redrawing the board
4471 void XDrawPosition(w, repaint, board)
4473 /*Boolean*/int repaint;
4477 static int lastFlipView = 0;
4478 static int lastBoardValid[2] = {0, 0};
4479 static Board lastBoard[2];
4482 int nr = twoBoards*partnerUp;
4484 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4486 if (board == NULL) {
4487 if (!lastBoardValid) return;
4488 board = lastBoard[nr];
4490 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4491 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4492 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4497 * It would be simpler to clear the window with XClearWindow()
4498 * but this causes a very distracting flicker.
4501 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4503 /* If too much changes (begin observing new game, etc.), don't
4505 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4507 /* Special check for castling so we don't flash both the king
4508 and the rook (just flash the king). */
4510 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4511 /* Draw rook with NO flashing. King will be drawn flashing later */
4512 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4513 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4517 /* First pass -- Draw (newly) empty squares and repair damage.
4518 This prevents you from having a piece show up twice while it
4519 is flashing on its new square */
4520 for (i = 0; i < BOARD_HEIGHT; i++)
4521 for (j = 0; j < BOARD_WIDTH; j++)
4522 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4523 || damage[nr][i][j]) {
4524 DrawSquare(i, j, board[i][j], 0);
4525 damage[nr][i][j] = False;
4528 /* Second pass -- Draw piece(s) in new position and flash them */
4529 for (i = 0; i < BOARD_HEIGHT; i++)
4530 for (j = 0; j < BOARD_WIDTH; j++)
4531 if (board[i][j] != lastBoard[nr][i][j]) {
4532 DrawSquare(i, j, board[i][j], do_flash);
4536 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4537 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4538 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4540 for (i = 0; i < BOARD_HEIGHT; i++)
4541 for (j = 0; j < BOARD_WIDTH; j++) {
4542 DrawSquare(i, j, board[i][j], 0);
4543 damage[nr][i][j] = False;
4547 CopyBoard(lastBoard[nr], board);
4548 lastBoardValid[nr] = 1;
4549 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4550 lastFlipView = flipView;
4552 /* Draw highlights */
4553 if (pm1X >= 0 && pm1Y >= 0) {
4554 drawHighlight(pm1X, pm1Y, prelineGC);
4556 if (pm2X >= 0 && pm2Y >= 0) {
4557 drawHighlight(pm2X, pm2Y, prelineGC);
4559 if (hi1X >= 0 && hi1Y >= 0) {
4560 drawHighlight(hi1X, hi1Y, highlineGC);
4562 if (hi2X >= 0 && hi2Y >= 0) {
4563 drawHighlight(hi2X, hi2Y, highlineGC);
4566 /* If piece being dragged around board, must redraw that too */
4569 XSync(xDisplay, False);
4574 * event handler for redrawing the board
4576 void DrawPositionProc(w, event, prms, nprms)
4582 XDrawPosition(w, True, NULL);
4587 * event handler for parsing user moves
4589 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4590 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4591 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4592 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4593 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4594 // and at the end FinishMove() to perform the move after optional promotion popups.
4595 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4596 void HandleUserMove(w, event, prms, nprms)
4602 if (w != boardWidget || errorExitStatus != -1) return;
4605 if (event->type == ButtonPress) {
4606 XtPopdown(promotionShell);
4607 XtDestroyWidget(promotionShell);
4608 promotionUp = False;
4616 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4617 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4618 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4621 void AnimateUserMove (Widget w, XEvent * event,
4622 String * params, Cardinal * nParams)
4624 DragPieceMove(event->xmotion.x, event->xmotion.y);
4627 void HandlePV (Widget w, XEvent * event,
4628 String * params, Cardinal * nParams)
4629 { // [HGM] pv: walk PV
4630 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4633 Widget CommentCreate(name, text, mutable, callback, lines)
4635 int /*Boolean*/ mutable;
4636 XtCallbackProc callback;
4640 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4645 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4646 XtGetValues(boardWidget, args, j);
4649 XtSetArg(args[j], XtNresizable, True); j++;
4652 XtCreatePopupShell(name, topLevelShellWidgetClass,
4653 shellWidget, args, j);
4656 XtCreatePopupShell(name, transientShellWidgetClass,
4657 shellWidget, args, j);
4660 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4661 layoutArgs, XtNumber(layoutArgs));
4663 XtCreateManagedWidget("form", formWidgetClass, layout,
4664 formArgs, XtNumber(formArgs));
4668 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4669 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4671 XtSetArg(args[j], XtNstring, text); j++;
4672 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4673 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4674 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4675 XtSetArg(args[j], XtNright, XtChainRight); j++;
4676 XtSetArg(args[j], XtNresizable, True); j++;
4677 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4678 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4679 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4680 XtSetArg(args[j], XtNautoFill, True); j++;
4681 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4683 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4684 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4688 XtSetArg(args[j], XtNfromVert, edit); j++;
4689 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4690 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4691 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4692 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4694 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4695 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4698 XtSetArg(args[j], XtNfromVert, edit); j++;
4699 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4700 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4701 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4702 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4703 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4705 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4706 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4709 XtSetArg(args[j], XtNfromVert, edit); j++;
4710 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4711 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4712 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4713 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4714 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4716 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4717 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4720 XtSetArg(args[j], XtNfromVert, edit); j++;
4721 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4722 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4723 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4724 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4726 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4727 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4730 XtSetArg(args[j], XtNfromVert, edit); j++;
4731 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4732 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4733 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4734 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4735 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4737 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4738 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4741 XtRealizeWidget(shell);
4743 if (commentX == -1) {
4746 Dimension pw_height;
4747 Dimension ew_height;
4750 XtSetArg(args[j], XtNheight, &ew_height); j++;
4751 XtGetValues(edit, args, j);
4754 XtSetArg(args[j], XtNheight, &pw_height); j++;
4755 XtGetValues(shell, args, j);
4756 commentH = pw_height + (lines - 1) * ew_height;
4757 commentW = bw_width - 16;
4759 XSync(xDisplay, False);
4761 /* This code seems to tickle an X bug if it is executed too soon
4762 after xboard starts up. The coordinates get transformed as if
4763 the main window was positioned at (0, 0).
4765 XtTranslateCoords(shellWidget,
4766 (bw_width - commentW) / 2, 0 - commentH / 2,
4767 &commentX, &commentY);
4769 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4770 RootWindowOfScreen(XtScreen(shellWidget)),
4771 (bw_width - commentW) / 2, 0 - commentH / 2,
4776 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4779 if(wpComment.width > 0) {
4780 commentX = wpComment.x;
4781 commentY = wpComment.y;
4782 commentW = wpComment.width;
4783 commentH = wpComment.height;
4787 XtSetArg(args[j], XtNheight, commentH); j++;
4788 XtSetArg(args[j], XtNwidth, commentW); j++;
4789 XtSetArg(args[j], XtNx, commentX); j++;
4790 XtSetArg(args[j], XtNy, commentY); j++;
4791 XtSetValues(shell, args, j);
4792 XtSetKeyboardFocus(shell, edit);
4797 /* Used for analysis window and ICS input window */
4798 Widget MiscCreate(name, text, mutable, callback, lines)
4800 int /*Boolean*/ mutable;
4801 XtCallbackProc callback;
4805 Widget shell, layout, form, edit;
4807 Dimension bw_width, pw_height, ew_height, w, h;
4813 XtSetArg(args[j], XtNresizable, True); j++;
4816 XtCreatePopupShell(name, topLevelShellWidgetClass,
4817 shellWidget, args, j);
4820 XtCreatePopupShell(name, transientShellWidgetClass,
4821 shellWidget, args, j);
4824 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4825 layoutArgs, XtNumber(layoutArgs));
4827 XtCreateManagedWidget("form", formWidgetClass, layout,
4828 formArgs, XtNumber(formArgs));
4832 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4833 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4835 XtSetArg(args[j], XtNstring, text); j++;
4836 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4837 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4838 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4839 XtSetArg(args[j], XtNright, XtChainRight); j++;
4840 XtSetArg(args[j], XtNresizable, True); j++;
4841 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4842 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4843 XtSetArg(args[j], XtNautoFill, True); j++;
4844 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4846 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4848 XtRealizeWidget(shell);
4851 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4852 XtGetValues(boardWidget, args, j);
4855 XtSetArg(args[j], XtNheight, &ew_height); j++;
4856 XtGetValues(edit, args, j);
4859 XtSetArg(args[j], XtNheight, &pw_height); j++;
4860 XtGetValues(shell, args, j);
4861 h = pw_height + (lines - 1) * ew_height;
4864 XSync(xDisplay, False);
4866 /* This code seems to tickle an X bug if it is executed too soon
4867 after xboard starts up. The coordinates get transformed as if
4868 the main window was positioned at (0, 0).
4870 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4872 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4873 RootWindowOfScreen(XtScreen(shellWidget)),
4874 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4878 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4881 XtSetArg(args[j], XtNheight, h); j++;
4882 XtSetArg(args[j], XtNwidth, w); j++;
4883 XtSetArg(args[j], XtNx, x); j++;
4884 XtSetArg(args[j], XtNy, y); j++;
4885 XtSetValues(shell, args, j);
4891 static int savedIndex; /* gross that this is global */
4893 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4896 XawTextPosition index, dummy;
4899 XawTextGetSelectionPos(w, &index, &dummy);
4900 XtSetArg(arg, XtNstring, &val);
4901 XtGetValues(w, &arg, 1);
4902 ReplaceComment(savedIndex, val);
4903 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4904 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4907 void EditCommentPopUp(index, title, text)
4916 if (text == NULL) text = "";
4918 if (editShell == NULL) {
4920 CommentCreate(title, text, True, EditCommentCallback, 4);
4921 XtRealizeWidget(editShell);
4922 CatchDeleteWindow(editShell, "EditCommentPopDown");
4924 edit = XtNameToWidget(editShell, "*form.text");
4926 XtSetArg(args[j], XtNstring, text); j++;
4927 XtSetValues(edit, args, j);
4929 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4930 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4931 XtSetValues(editShell, args, j);
4934 XtPopup(editShell, XtGrabNone);
4938 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4939 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4943 void EditCommentCallback(w, client_data, call_data)
4945 XtPointer client_data, call_data;
4953 XtSetArg(args[j], XtNlabel, &name); j++;
4954 XtGetValues(w, args, j);
4956 if (strcmp(name, _("ok")) == 0) {
4957 edit = XtNameToWidget(editShell, "*form.text");
4959 XtSetArg(args[j], XtNstring, &val); j++;
4960 XtGetValues(edit, args, j);
4961 ReplaceComment(savedIndex, val);
4962 EditCommentPopDown();
4963 } else if (strcmp(name, _("cancel")) == 0) {
4964 EditCommentPopDown();
4965 } else if (strcmp(name, _("clear")) == 0) {
4966 edit = XtNameToWidget(editShell, "*form.text");
4967 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4968 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4972 void EditCommentPopDown()
4977 if (!editUp) return;
4979 XtSetArg(args[j], XtNx, &commentX); j++;
4980 XtSetArg(args[j], XtNy, &commentY); j++;
4981 XtSetArg(args[j], XtNheight, &commentH); j++;
4982 XtSetArg(args[j], XtNwidth, &commentW); j++;
4983 XtGetValues(editShell, args, j);
4984 XtPopdown(editShell);
4987 XtSetArg(args[j], XtNleftBitmap, None); j++;
4988 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4992 void ICSInputBoxPopUp()
4997 char *title = _("ICS Input");
5000 if (ICSInputShell == NULL) {
5001 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5002 tr = XtParseTranslationTable(ICSInputTranslations);
5003 edit = XtNameToWidget(ICSInputShell, "*form.text");
5004 XtOverrideTranslations(edit, tr);
5005 XtRealizeWidget(ICSInputShell);
5006 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5009 edit = XtNameToWidget(ICSInputShell, "*form.text");
5011 XtSetArg(args[j], XtNstring, ""); j++;
5012 XtSetValues(edit, args, j);
5014 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5015 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5016 XtSetValues(ICSInputShell, args, j);
5019 XtPopup(ICSInputShell, XtGrabNone);
5020 XtSetKeyboardFocus(ICSInputShell, edit);
5022 ICSInputBoxUp = True;
5024 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5025 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5029 void ICSInputSendText()
5036 edit = XtNameToWidget(ICSInputShell, "*form.text");
5038 XtSetArg(args[j], XtNstring, &val); j++;
5039 XtGetValues(edit, args, j);
5041 SendMultiLineToICS(val);
5042 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5043 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5046 void ICSInputBoxPopDown()
5051 if (!ICSInputBoxUp) return;
5053 XtPopdown(ICSInputShell);
5054 ICSInputBoxUp = False;
5056 XtSetArg(args[j], XtNleftBitmap, None); j++;
5057 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5061 void CommentPopUp(title, text)
5068 savedIndex = currentMove; // [HGM] vari
5069 if (commentShell == NULL) {
5071 CommentCreate(title, text, False, CommentCallback, 4);
5072 XtRealizeWidget(commentShell);
5073 CatchDeleteWindow(commentShell, "CommentPopDown");
5075 edit = XtNameToWidget(commentShell, "*form.text");
5077 XtSetArg(args[j], XtNstring, text); j++;
5078 XtSetValues(edit, args, j);
5080 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5081 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5082 XtSetValues(commentShell, args, j);
5085 XtPopup(commentShell, XtGrabNone);
5086 XSync(xDisplay, False);
5091 void CommentCallback(w, client_data, call_data)
5093 XtPointer client_data, call_data;
5100 XtSetArg(args[j], XtNlabel, &name); j++;
5101 XtGetValues(w, args, j);
5103 if (strcmp(name, _("close")) == 0) {
5105 } else if (strcmp(name, _("edit")) == 0) {
5112 void CommentPopDown()
5117 if (!commentUp) return;
5119 XtSetArg(args[j], XtNx, &commentX); j++;
5120 XtSetArg(args[j], XtNy, &commentY); j++;
5121 XtSetArg(args[j], XtNwidth, &commentW); j++;
5122 XtSetArg(args[j], XtNheight, &commentH); j++;
5123 XtGetValues(commentShell, args, j);
5124 XtPopdown(commentShell);
5125 XSync(xDisplay, False);
5129 void FileNamePopUp(label, def, proc, openMode)
5136 Widget popup, layout, dialog, edit;
5142 fileProc = proc; /* I can't see a way not */
5143 fileOpenMode = openMode; /* to use globals here */
5144 { // [HGM] use file-selector dialog stolen from Ghostview
5146 int index; // this is not supported yet
5148 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5149 NULL, openMode, NULL, &name))
5150 (void) (*fileProc)(f, index=0, name);
5154 void FileNamePopDown()
5156 if (!filenameUp) return;
5157 XtPopdown(fileNameShell);
5158 XtDestroyWidget(fileNameShell);
5163 void FileNameCallback(w, client_data, call_data)
5165 XtPointer client_data, call_data;
5170 XtSetArg(args[0], XtNlabel, &name);
5171 XtGetValues(w, args, 1);
5173 if (strcmp(name, _("cancel")) == 0) {
5178 FileNameAction(w, NULL, NULL, NULL);
5181 void FileNameAction(w, event, prms, nprms)
5193 name = XawDialogGetValueString(w = XtParent(w));
5195 if ((name != NULL) && (*name != NULLCHAR)) {
5197 XtPopdown(w = XtParent(XtParent(w)));
5201 p = strrchr(buf, ' ');
5208 fullname = ExpandPathName(buf);
5210 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5213 f = fopen(fullname, fileOpenMode);
5215 DisplayError(_("Failed to open file"), errno);
5217 (void) (*fileProc)(f, index, buf);
5224 XtPopdown(w = XtParent(XtParent(w)));
5230 void PromotionPopUp()
5233 Widget dialog, layout;
5235 Dimension bw_width, pw_width;
5239 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5240 XtGetValues(boardWidget, args, j);
5243 XtSetArg(args[j], XtNresizable, True); j++;
5244 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5246 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5247 shellWidget, args, j);
5249 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5250 layoutArgs, XtNumber(layoutArgs));
5253 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5254 XtSetArg(args[j], XtNborderWidth, 0); j++;
5255 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5258 if(gameInfo.variant != VariantShogi) {
5259 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5260 (XtPointer) dialog);
5261 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5262 (XtPointer) dialog);
5263 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5264 (XtPointer) dialog);
5265 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5266 (XtPointer) dialog);
5267 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5268 gameInfo.variant == VariantGiveaway) {
5269 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5270 (XtPointer) dialog);
5272 if(gameInfo.variant == VariantCapablanca ||
5273 gameInfo.variant == VariantGothic ||
5274 gameInfo.variant == VariantCapaRandom) {
5275 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5276 (XtPointer) dialog);
5277 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5278 (XtPointer) dialog);
5280 } else // [HGM] shogi
5282 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5283 (XtPointer) dialog);
5284 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5285 (XtPointer) dialog);
5287 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5288 (XtPointer) dialog);
5290 XtRealizeWidget(promotionShell);
5291 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5294 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5295 XtGetValues(promotionShell, args, j);
5297 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5298 lineGap + squareSize/3 +
5299 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5300 0 : 6*(squareSize + lineGap)), &x, &y);
5303 XtSetArg(args[j], XtNx, x); j++;
5304 XtSetArg(args[j], XtNy, y); j++;
5305 XtSetValues(promotionShell, args, j);
5307 XtPopup(promotionShell, XtGrabNone);
5312 void PromotionPopDown()
5314 if (!promotionUp) return;
5315 XtPopdown(promotionShell);
5316 XtDestroyWidget(promotionShell);
5317 promotionUp = False;
5320 void PromotionCallback(w, client_data, call_data)
5322 XtPointer client_data, call_data;
5328 XtSetArg(args[0], XtNlabel, &name);
5329 XtGetValues(w, args, 1);
5333 if (fromX == -1) return;
5335 if (strcmp(name, _("cancel")) == 0) {
5339 } else if (strcmp(name, _("Knight")) == 0) {
5341 } else if (strcmp(name, _("Promote")) == 0) {
5343 } else if (strcmp(name, _("Defer")) == 0) {
5346 promoChar = ToLower(name[0]);
5349 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5351 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5352 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5357 void ErrorCallback(w, client_data, call_data)
5359 XtPointer client_data, call_data;
5362 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5364 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5370 if (!errorUp) return;
5372 XtPopdown(errorShell);
5373 XtDestroyWidget(errorShell);
5374 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5377 void ErrorPopUp(title, label, modal)
5378 char *title, *label;
5382 Widget dialog, layout;
5386 Dimension bw_width, pw_width;
5387 Dimension pw_height;
5391 XtSetArg(args[i], XtNresizable, True); i++;
5392 XtSetArg(args[i], XtNtitle, title); i++;
5394 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5395 shellWidget, args, i);
5397 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5398 layoutArgs, XtNumber(layoutArgs));
5401 XtSetArg(args[i], XtNlabel, label); i++;
5402 XtSetArg(args[i], XtNborderWidth, 0); i++;
5403 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5406 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5408 XtRealizeWidget(errorShell);
5409 CatchDeleteWindow(errorShell, "ErrorPopDown");
5412 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5413 XtGetValues(boardWidget, args, i);
5415 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5416 XtSetArg(args[i], XtNheight, &pw_height); i++;
5417 XtGetValues(errorShell, args, i);
5420 /* This code seems to tickle an X bug if it is executed too soon
5421 after xboard starts up. The coordinates get transformed as if
5422 the main window was positioned at (0, 0).
5424 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5425 0 - pw_height + squareSize / 3, &x, &y);
5427 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5428 RootWindowOfScreen(XtScreen(boardWidget)),
5429 (bw_width - pw_width) / 2,
5430 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5434 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5437 XtSetArg(args[i], XtNx, x); i++;
5438 XtSetArg(args[i], XtNy, y); i++;
5439 XtSetValues(errorShell, args, i);
5442 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5445 /* Disable all user input other than deleting the window */
5446 static int frozen = 0;
5450 /* Grab by a widget that doesn't accept input */
5451 XtAddGrab(messageWidget, TRUE, FALSE);
5455 /* Undo a FreezeUI */
5458 if (!frozen) return;
5459 XtRemoveGrab(messageWidget);
5463 char *ModeToWidgetName(mode)
5467 case BeginningOfGame:
5468 if (appData.icsActive)
5469 return "menuMode.ICS Client";
5470 else if (appData.noChessProgram ||
5471 *appData.cmailGameName != NULLCHAR)
5472 return "menuMode.Edit Game";
5474 return "menuMode.Machine Black";
5475 case MachinePlaysBlack:
5476 return "menuMode.Machine Black";
5477 case MachinePlaysWhite:
5478 return "menuMode.Machine White";
5480 return "menuMode.Analysis Mode";
5482 return "menuMode.Analyze File";
5483 case TwoMachinesPlay:
5484 return "menuMode.Two Machines";
5486 return "menuMode.Edit Game";
5487 case PlayFromGameFile:
5488 return "menuFile.Load Game";
5490 return "menuMode.Edit Position";
5492 return "menuMode.Training";
5493 case IcsPlayingWhite:
5494 case IcsPlayingBlack:
5498 return "menuMode.ICS Client";
5505 void ModeHighlight()
5508 static int oldPausing = FALSE;
5509 static GameMode oldmode = (GameMode) -1;
5512 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5514 if (pausing != oldPausing) {
5515 oldPausing = pausing;
5517 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5519 XtSetArg(args[0], XtNleftBitmap, None);
5521 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5524 if (appData.showButtonBar) {
5525 /* Always toggle, don't set. Previous code messes up when
5526 invoked while the button is pressed, as releasing it
5527 toggles the state again. */
5530 XtSetArg(args[0], XtNbackground, &oldbg);
5531 XtSetArg(args[1], XtNforeground, &oldfg);
5532 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5534 XtSetArg(args[0], XtNbackground, oldfg);
5535 XtSetArg(args[1], XtNforeground, oldbg);
5537 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5541 wname = ModeToWidgetName(oldmode);
5542 if (wname != NULL) {
5543 XtSetArg(args[0], XtNleftBitmap, None);
5544 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5546 wname = ModeToWidgetName(gameMode);
5547 if (wname != NULL) {
5548 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5549 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5553 /* Maybe all the enables should be handled here, not just this one */
5554 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5555 gameMode == Training || gameMode == PlayFromGameFile);
5560 * Button/menu procedures
5562 void ResetProc(w, event, prms, nprms)
5571 int LoadGamePopUp(f, gameNumber, title)
5576 cmailMsgLoaded = FALSE;
5577 if (gameNumber == 0) {
5578 int error = GameListBuild(f);
5580 DisplayError(_("Cannot build game list"), error);
5581 } else if (!ListEmpty(&gameList) &&
5582 ((ListGame *) gameList.tailPred)->number > 1) {
5583 GameListPopUp(f, title);
5589 return LoadGame(f, gameNumber, title, FALSE);
5592 void LoadGameProc(w, event, prms, nprms)
5598 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5601 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5604 void LoadNextGameProc(w, event, prms, nprms)
5613 void LoadPrevGameProc(w, event, prms, nprms)
5622 void ReloadGameProc(w, event, prms, nprms)
5631 void LoadNextPositionProc(w, event, prms, nprms)
5640 void LoadPrevPositionProc(w, event, prms, nprms)
5649 void ReloadPositionProc(w, event, prms, nprms)
5658 void LoadPositionProc(w, event, prms, nprms)
5664 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5667 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5670 void SaveGameProc(w, event, prms, nprms)
5676 FileNamePopUp(_("Save game file name?"),
5677 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5681 void SavePositionProc(w, event, prms, nprms)
5687 FileNamePopUp(_("Save position file name?"),
5688 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5692 void ReloadCmailMsgProc(w, event, prms, nprms)
5698 ReloadCmailMsgEvent(FALSE);
5701 void MailMoveProc(w, event, prms, nprms)
5710 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5711 char *selected_fen_position=NULL;
5714 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5715 Atom *type_return, XtPointer *value_return,
5716 unsigned long *length_return, int *format_return)
5718 char *selection_tmp;
5720 if (!selected_fen_position) return False; /* should never happen */
5721 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5722 /* note: since no XtSelectionDoneProc was registered, Xt will
5723 * automatically call XtFree on the value returned. So have to
5724 * make a copy of it allocated with XtMalloc */
5725 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5726 strcpy(selection_tmp, selected_fen_position);
5728 *value_return=selection_tmp;
5729 *length_return=strlen(selection_tmp);
5730 *type_return=*target;
5731 *format_return = 8; /* bits per byte */
5733 } else if (*target == XA_TARGETS(xDisplay)) {
5734 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5735 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5736 targets_tmp[1] = XA_STRING;
5737 *value_return = targets_tmp;
5738 *type_return = XA_ATOM;
5740 *format_return = 8 * sizeof(Atom);
5741 if (*format_return > 32) {
5742 *length_return *= *format_return / 32;
5743 *format_return = 32;
5751 /* note: when called from menu all parameters are NULL, so no clue what the
5752 * Widget which was clicked on was, or what the click event was
5754 void CopyPositionProc(w, event, prms, nprms)
5761 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5762 * have a notion of a position that is selected but not copied.
5763 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5765 if(gameMode == EditPosition) EditPositionDone(TRUE);
5766 if (selected_fen_position) free(selected_fen_position);
5767 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5768 if (!selected_fen_position) return;
5769 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5771 SendPositionSelection,
5772 NULL/* lose_ownership_proc */ ,
5773 NULL/* transfer_done_proc */);
5774 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5776 SendPositionSelection,
5777 NULL/* lose_ownership_proc */ ,
5778 NULL/* transfer_done_proc */);
5781 /* function called when the data to Paste is ready */
5783 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5784 Atom *type, XtPointer value, unsigned long *len, int *format)
5787 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5788 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5789 EditPositionPasteFEN(fenstr);
5793 /* called when Paste Position button is pressed,
5794 * all parameters will be NULL */
5795 void PastePositionProc(w, event, prms, nprms)
5801 XtGetSelectionValue(menuBarWidget,
5802 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5803 /* (XtSelectionCallbackProc) */ PastePositionCB,
5804 NULL, /* client_data passed to PastePositionCB */
5806 /* better to use the time field from the event that triggered the
5807 * call to this function, but that isn't trivial to get
5815 SendGameSelection(Widget w, Atom *selection, Atom *target,
5816 Atom *type_return, XtPointer *value_return,
5817 unsigned long *length_return, int *format_return)
5819 char *selection_tmp;
5821 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5822 FILE* f = fopen(gameCopyFilename, "r");
5825 if (f == NULL) return False;
5829 selection_tmp = XtMalloc(len + 1);
5830 count = fread(selection_tmp, 1, len, f);
5832 XtFree(selection_tmp);
5835 selection_tmp[len] = NULLCHAR;
5836 *value_return = selection_tmp;
5837 *length_return = len;
5838 *type_return = *target;
5839 *format_return = 8; /* bits per byte */
5841 } else if (*target == XA_TARGETS(xDisplay)) {
5842 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5843 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5844 targets_tmp[1] = XA_STRING;
5845 *value_return = targets_tmp;
5846 *type_return = XA_ATOM;
5848 *format_return = 8 * sizeof(Atom);
5849 if (*format_return > 32) {
5850 *length_return *= *format_return / 32;
5851 *format_return = 32;
5859 /* note: when called from menu all parameters are NULL, so no clue what the
5860 * Widget which was clicked on was, or what the click event was
5862 void CopyGameProc(w, event, prms, nprms)
5870 ret = SaveGameToFile(gameCopyFilename, FALSE);
5874 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5875 * have a notion of a game that is selected but not copied.
5876 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5878 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5881 NULL/* lose_ownership_proc */ ,
5882 NULL/* transfer_done_proc */);
5883 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5886 NULL/* lose_ownership_proc */ ,
5887 NULL/* transfer_done_proc */);
5890 /* function called when the data to Paste is ready */
5892 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5893 Atom *type, XtPointer value, unsigned long *len, int *format)
5896 if (value == NULL || *len == 0) {
5897 return; /* nothing had been selected to copy */
5899 f = fopen(gamePasteFilename, "w");
5901 DisplayError(_("Can't open temp file"), errno);
5904 fwrite(value, 1, *len, f);
5907 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5910 /* called when Paste Game button is pressed,
5911 * all parameters will be NULL */
5912 void PasteGameProc(w, event, prms, nprms)
5918 XtGetSelectionValue(menuBarWidget,
5919 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5920 /* (XtSelectionCallbackProc) */ PasteGameCB,
5921 NULL, /* client_data passed to PasteGameCB */
5923 /* better to use the time field from the event that triggered the
5924 * call to this function, but that isn't trivial to get
5934 SaveGameProc(NULL, NULL, NULL, NULL);
5938 void QuitProc(w, event, prms, nprms)
5947 void PauseProc(w, event, prms, nprms)
5957 void MachineBlackProc(w, event, prms, nprms)
5963 MachineBlackEvent();
5966 void MachineWhiteProc(w, event, prms, nprms)
5972 MachineWhiteEvent();
5975 void AnalyzeModeProc(w, event, prms, nprms)
5983 if (!first.analysisSupport) {
5984 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5985 DisplayError(buf, 0);
5988 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5989 if (appData.icsActive) {
5990 if (gameMode != IcsObserving) {
5991 sprintf(buf,_("You are not observing a game"));
5992 DisplayError(buf, 0);
5994 if (appData.icsEngineAnalyze) {
5995 if (appData.debugMode)
5996 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6002 /* if enable, use want disable icsEngineAnalyze */
6003 if (appData.icsEngineAnalyze) {
6008 appData.icsEngineAnalyze = TRUE;
6009 if (appData.debugMode)
6010 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6012 if (!appData.showThinking)
6013 ShowThinkingProc(w,event,prms,nprms);
6018 void AnalyzeFileProc(w, event, prms, nprms)
6024 if (!first.analysisSupport) {
6026 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6027 DisplayError(buf, 0);
6032 if (!appData.showThinking)
6033 ShowThinkingProc(w,event,prms,nprms);
6036 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6037 AnalysisPeriodicEvent(1);
6040 void TwoMachinesProc(w, event, prms, nprms)
6049 void IcsClientProc(w, event, prms, nprms)
6058 void EditGameProc(w, event, prms, nprms)
6067 void EditPositionProc(w, event, prms, nprms)
6073 EditPositionEvent();
6076 void TrainingProc(w, event, prms, nprms)
6085 void EditCommentProc(w, event, prms, nprms)
6092 EditCommentPopDown();
6098 void IcsInputBoxProc(w, event, prms, nprms)
6104 if (ICSInputBoxUp) {
6105 ICSInputBoxPopDown();
6111 void AcceptProc(w, event, prms, nprms)
6120 void DeclineProc(w, event, prms, nprms)
6129 void RematchProc(w, event, prms, nprms)
6138 void CallFlagProc(w, event, prms, nprms)
6147 void DrawProc(w, event, prms, nprms)
6156 void AbortProc(w, event, prms, nprms)
6165 void AdjournProc(w, event, prms, nprms)
6174 void ResignProc(w, event, prms, nprms)
6183 void AdjuWhiteProc(w, event, prms, nprms)
6189 UserAdjudicationEvent(+1);
6192 void AdjuBlackProc(w, event, prms, nprms)
6198 UserAdjudicationEvent(-1);
6201 void AdjuDrawProc(w, event, prms, nprms)
6207 UserAdjudicationEvent(0);
6210 void EnterKeyProc(w, event, prms, nprms)
6216 if (ICSInputBoxUp == True)
6220 void UpKeyProc(w, event, prms, nprms)
6225 { // [HGM] input: let up-arrow recall previous line from history
6232 if (!ICSInputBoxUp) return;
6233 edit = XtNameToWidget(ICSInputShell, "*form.text");
6235 XtSetArg(args[j], XtNstring, &val); j++;
6236 XtGetValues(edit, args, j);
6237 val = PrevInHistory(val);
6238 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6239 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6241 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6242 XawTextReplace(edit, 0, 0, &t);
6243 XawTextSetInsertionPoint(edit, 9999);
6247 void DownKeyProc(w, event, prms, nprms)
6252 { // [HGM] input: let down-arrow recall next line from history
6257 if (!ICSInputBoxUp) return;
6258 edit = XtNameToWidget(ICSInputShell, "*form.text");
6259 val = NextInHistory();
6260 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6261 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6263 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6264 XawTextReplace(edit, 0, 0, &t);
6265 XawTextSetInsertionPoint(edit, 9999);
6269 void StopObservingProc(w, event, prms, nprms)
6275 StopObservingEvent();
6278 void StopExaminingProc(w, event, prms, nprms)
6284 StopExaminingEvent();
6287 void UploadProc(w, event, prms, nprms)
6297 void ForwardProc(w, event, prms, nprms)
6307 void BackwardProc(w, event, prms, nprms)
6316 void ToStartProc(w, event, prms, nprms)
6325 void ToEndProc(w, event, prms, nprms)
6334 void RevertProc(w, event, prms, nprms)
6343 void AnnotateProc(w, event, prms, nprms)
6352 void TruncateGameProc(w, event, prms, nprms)
6358 TruncateGameEvent();
6360 void RetractMoveProc(w, event, prms, nprms)
6369 void MoveNowProc(w, event, prms, nprms)
6379 void AlwaysQueenProc(w, event, prms, nprms)
6387 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6389 if (appData.alwaysPromoteToQueen) {
6390 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6392 XtSetArg(args[0], XtNleftBitmap, None);
6394 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6398 void AnimateDraggingProc(w, event, prms, nprms)
6406 appData.animateDragging = !appData.animateDragging;
6408 if (appData.animateDragging) {
6409 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6412 XtSetArg(args[0], XtNleftBitmap, None);
6414 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6418 void AnimateMovingProc(w, event, prms, nprms)
6426 appData.animate = !appData.animate;
6428 if (appData.animate) {
6429 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6432 XtSetArg(args[0], XtNleftBitmap, None);
6434 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6438 void AutocommProc(w, event, prms, nprms)
6446 appData.autoComment = !appData.autoComment;
6448 if (appData.autoComment) {
6449 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6451 XtSetArg(args[0], XtNleftBitmap, None);
6453 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6458 void AutoflagProc(w, event, prms, nprms)
6466 appData.autoCallFlag = !appData.autoCallFlag;
6468 if (appData.autoCallFlag) {
6469 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6471 XtSetArg(args[0], XtNleftBitmap, None);
6473 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6477 void AutoflipProc(w, event, prms, nprms)
6485 appData.autoFlipView = !appData.autoFlipView;
6487 if (appData.autoFlipView) {
6488 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6490 XtSetArg(args[0], XtNleftBitmap, None);
6492 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6496 void AutobsProc(w, event, prms, nprms)
6504 appData.autoObserve = !appData.autoObserve;
6506 if (appData.autoObserve) {
6507 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6509 XtSetArg(args[0], XtNleftBitmap, None);
6511 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6515 void AutoraiseProc(w, event, prms, nprms)
6523 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6525 if (appData.autoRaiseBoard) {
6526 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6528 XtSetArg(args[0], XtNleftBitmap, None);
6530 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6534 void AutosaveProc(w, event, prms, nprms)
6542 appData.autoSaveGames = !appData.autoSaveGames;
6544 if (appData.autoSaveGames) {
6545 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6547 XtSetArg(args[0], XtNleftBitmap, None);
6549 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6553 void BlindfoldProc(w, event, prms, nprms)
6561 appData.blindfold = !appData.blindfold;
6563 if (appData.blindfold) {
6564 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6566 XtSetArg(args[0], XtNleftBitmap, None);
6568 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6571 DrawPosition(True, NULL);
6574 void TestLegalityProc(w, event, prms, nprms)
6582 appData.testLegality = !appData.testLegality;
6584 if (appData.testLegality) {
6585 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6587 XtSetArg(args[0], XtNleftBitmap, None);
6589 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6594 void FlashMovesProc(w, event, prms, nprms)
6602 if (appData.flashCount == 0) {
6603 appData.flashCount = 3;
6605 appData.flashCount = -appData.flashCount;
6608 if (appData.flashCount > 0) {
6609 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6611 XtSetArg(args[0], XtNleftBitmap, None);
6613 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6617 void FlipViewProc(w, event, prms, nprms)
6623 flipView = !flipView;
6624 DrawPosition(True, NULL);
6627 void GetMoveListProc(w, event, prms, nprms)
6635 appData.getMoveList = !appData.getMoveList;
6637 if (appData.getMoveList) {
6638 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6641 XtSetArg(args[0], XtNleftBitmap, None);
6643 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6648 void HighlightDraggingProc(w, event, prms, nprms)
6656 appData.highlightDragging = !appData.highlightDragging;
6658 if (appData.highlightDragging) {
6659 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6661 XtSetArg(args[0], XtNleftBitmap, None);
6663 XtSetValues(XtNameToWidget(menuBarWidget,
6664 "menuOptions.Highlight Dragging"), args, 1);
6668 void HighlightLastMoveProc(w, event, prms, nprms)
6676 appData.highlightLastMove = !appData.highlightLastMove;
6678 if (appData.highlightLastMove) {
6679 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6681 XtSetArg(args[0], XtNleftBitmap, None);
6683 XtSetValues(XtNameToWidget(menuBarWidget,
6684 "menuOptions.Highlight Last Move"), args, 1);
6687 void IcsAlarmProc(w, event, prms, nprms)
6695 appData.icsAlarm = !appData.icsAlarm;
6697 if (appData.icsAlarm) {
6698 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6700 XtSetArg(args[0], XtNleftBitmap, None);
6702 XtSetValues(XtNameToWidget(menuBarWidget,
6703 "menuOptions.ICS Alarm"), args, 1);
6706 void MoveSoundProc(w, event, prms, nprms)
6714 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6716 if (appData.ringBellAfterMoves) {
6717 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6719 XtSetArg(args[0], XtNleftBitmap, None);
6721 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6726 void OldSaveStyleProc(w, event, prms, nprms)
6734 appData.oldSaveStyle = !appData.oldSaveStyle;
6736 if (appData.oldSaveStyle) {
6737 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6739 XtSetArg(args[0], XtNleftBitmap, None);
6741 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6745 void PeriodicUpdatesProc(w, event, prms, nprms)
6753 PeriodicUpdatesEvent(!appData.periodicUpdates);
6755 if (appData.periodicUpdates) {
6756 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6758 XtSetArg(args[0], XtNleftBitmap, None);
6760 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6764 void PonderNextMoveProc(w, event, prms, nprms)
6772 PonderNextMoveEvent(!appData.ponderNextMove);
6774 if (appData.ponderNextMove) {
6775 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6777 XtSetArg(args[0], XtNleftBitmap, None);
6779 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6783 void PopupExitMessageProc(w, event, prms, nprms)
6791 appData.popupExitMessage = !appData.popupExitMessage;
6793 if (appData.popupExitMessage) {
6794 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6796 XtSetArg(args[0], XtNleftBitmap, None);
6798 XtSetValues(XtNameToWidget(menuBarWidget,
6799 "menuOptions.Popup Exit Message"), args, 1);
6802 void PopupMoveErrorsProc(w, event, prms, nprms)
6810 appData.popupMoveErrors = !appData.popupMoveErrors;
6812 if (appData.popupMoveErrors) {
6813 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6815 XtSetArg(args[0], XtNleftBitmap, None);
6817 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6821 void PremoveProc(w, event, prms, nprms)
6829 appData.premove = !appData.premove;
6831 if (appData.premove) {
6832 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6834 XtSetArg(args[0], XtNleftBitmap, None);
6836 XtSetValues(XtNameToWidget(menuBarWidget,
6837 "menuOptions.Premove"), args, 1);
6840 void QuietPlayProc(w, event, prms, nprms)
6848 appData.quietPlay = !appData.quietPlay;
6850 if (appData.quietPlay) {
6851 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6853 XtSetArg(args[0], XtNleftBitmap, None);
6855 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6859 void ShowCoordsProc(w, event, prms, nprms)
6867 appData.showCoords = !appData.showCoords;
6869 if (appData.showCoords) {
6870 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6872 XtSetArg(args[0], XtNleftBitmap, None);
6874 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6877 DrawPosition(True, NULL);
6880 void ShowThinkingProc(w, event, prms, nprms)
6886 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6887 ShowThinkingEvent();
6890 void HideThinkingProc(w, event, prms, nprms)
6898 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6899 ShowThinkingEvent();
6901 if (appData.hideThinkingFromHuman) {
6902 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6904 XtSetArg(args[0], XtNleftBitmap, None);
6906 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6910 void SaveOnExitProc(w, event, prms, nprms)
6918 saveSettingsOnExit = !saveSettingsOnExit;
6920 if (saveSettingsOnExit) {
6921 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6923 XtSetArg(args[0], XtNleftBitmap, None);
6925 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6929 void SaveSettingsProc(w, event, prms, nprms)
6935 SaveSettings(settingsFileName);
6938 void InfoProc(w, event, prms, nprms)
6945 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6950 void ManProc(w, event, prms, nprms)
6958 if (nprms && *nprms > 0)
6962 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6966 void HintProc(w, event, prms, nprms)
6975 void BookProc(w, event, prms, nprms)
6984 void AboutProc(w, event, prms, nprms)
6992 char *zippy = " (with Zippy code)";
6996 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6997 programVersion, zippy,
6998 "Copyright 1991 Digital Equipment Corporation",
6999 "Enhancements Copyright 1992-2009 Free Software Foundation",
7000 "Enhancements Copyright 2005 Alessandro Scotti",
7001 PACKAGE, " is free software and carries NO WARRANTY;",
7002 "see the file COPYING for more information.");
7003 ErrorPopUp(_("About XBoard"), buf, FALSE);
7006 void DebugProc(w, event, prms, nprms)
7012 appData.debugMode = !appData.debugMode;
7015 void AboutGameProc(w, event, prms, nprms)
7024 void NothingProc(w, event, prms, nprms)
7033 void Iconify(w, event, prms, nprms)
7042 XtSetArg(args[0], XtNiconic, True);
7043 XtSetValues(shellWidget, args, 1);
7046 void DisplayMessage(message, extMessage)
7047 char *message, *extMessage;
7049 /* display a message in the message widget */
7058 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7063 message = extMessage;
7067 /* need to test if messageWidget already exists, since this function
7068 can also be called during the startup, if for example a Xresource
7069 is not set up correctly */
7072 XtSetArg(arg, XtNlabel, message);
7073 XtSetValues(messageWidget, &arg, 1);
7079 void DisplayTitle(text)
7084 char title[MSG_SIZ];
7087 if (text == NULL) text = "";
7089 if (appData.titleInWindow) {
7091 XtSetArg(args[i], XtNlabel, text); i++;
7092 XtSetValues(titleWidget, args, i);
7095 if (*text != NULLCHAR) {
7097 strcpy(title, text);
7098 } else if (appData.icsActive) {
7099 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7100 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7101 } else if (appData.cmailGameName[0] != NULLCHAR) {
7102 snprintf(icon, sizeof(icon), "%s", "CMail");
7103 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7105 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7106 } else if (gameInfo.variant == VariantGothic) {
7107 strcpy(icon, programName);
7108 strcpy(title, GOTHIC);
7111 } else if (gameInfo.variant == VariantFalcon) {
7112 strcpy(icon, programName);
7113 strcpy(title, FALCON);
7115 } else if (appData.noChessProgram) {
7116 strcpy(icon, programName);
7117 strcpy(title, programName);
7119 strcpy(icon, first.tidy);
7120 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7123 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7124 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7125 XtSetValues(shellWidget, args, i);
7129 void DisplayError(message, error)
7136 if (appData.debugMode || appData.matchMode) {
7137 fprintf(stderr, "%s: %s\n", programName, message);
7140 if (appData.debugMode || appData.matchMode) {
7141 fprintf(stderr, "%s: %s: %s\n",
7142 programName, message, strerror(error));
7144 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7147 ErrorPopUp(_("Error"), message, FALSE);
7151 void DisplayMoveError(message)
7156 DrawPosition(FALSE, NULL);
7157 if (appData.debugMode || appData.matchMode) {
7158 fprintf(stderr, "%s: %s\n", programName, message);
7160 if (appData.popupMoveErrors) {
7161 ErrorPopUp(_("Error"), message, FALSE);
7163 DisplayMessage(message, "");
7168 void DisplayFatalError(message, error, status)
7174 errorExitStatus = status;
7176 fprintf(stderr, "%s: %s\n", programName, message);
7178 fprintf(stderr, "%s: %s: %s\n",
7179 programName, message, strerror(error));
7180 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7183 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7184 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7190 void DisplayInformation(message)
7194 ErrorPopUp(_("Information"), message, TRUE);
7197 void DisplayNote(message)
7201 ErrorPopUp(_("Note"), message, FALSE);
7205 NullXErrorCheck(dpy, error_event)
7207 XErrorEvent *error_event;
7212 void DisplayIcsInteractionTitle(message)
7215 if (oldICSInteractionTitle == NULL) {
7216 /* Magic to find the old window title, adapted from vim */
7217 char *wina = getenv("WINDOWID");
7219 Window win = (Window) atoi(wina);
7220 Window root, parent, *children;
7221 unsigned int nchildren;
7222 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7224 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7225 if (!XQueryTree(xDisplay, win, &root, &parent,
7226 &children, &nchildren)) break;
7227 if (children) XFree((void *)children);
7228 if (parent == root || parent == 0) break;
7231 XSetErrorHandler(oldHandler);
7233 if (oldICSInteractionTitle == NULL) {
7234 oldICSInteractionTitle = "xterm";
7237 printf("\033]0;%s\007", message);
7241 char pendingReplyPrefix[MSG_SIZ];
7242 ProcRef pendingReplyPR;
7244 void AskQuestionProc(w, event, prms, nprms)
7251 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7255 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7258 void AskQuestionPopDown()
7260 if (!askQuestionUp) return;
7261 XtPopdown(askQuestionShell);
7262 XtDestroyWidget(askQuestionShell);
7263 askQuestionUp = False;
7266 void AskQuestionReplyAction(w, event, prms, nprms)
7276 reply = XawDialogGetValueString(w = XtParent(w));
7277 strcpy(buf, pendingReplyPrefix);
7278 if (*buf) strcat(buf, " ");
7281 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7282 AskQuestionPopDown();
7284 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7287 void AskQuestionCallback(w, client_data, call_data)
7289 XtPointer client_data, call_data;
7294 XtSetArg(args[0], XtNlabel, &name);
7295 XtGetValues(w, args, 1);
7297 if (strcmp(name, _("cancel")) == 0) {
7298 AskQuestionPopDown();
7300 AskQuestionReplyAction(w, NULL, NULL, NULL);
7304 void AskQuestion(title, question, replyPrefix, pr)
7305 char *title, *question, *replyPrefix;
7309 Widget popup, layout, dialog, edit;
7315 strcpy(pendingReplyPrefix, replyPrefix);
7316 pendingReplyPR = pr;
7319 XtSetArg(args[i], XtNresizable, True); i++;
7320 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7321 askQuestionShell = popup =
7322 XtCreatePopupShell(title, transientShellWidgetClass,
7323 shellWidget, args, i);
7326 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7327 layoutArgs, XtNumber(layoutArgs));
7330 XtSetArg(args[i], XtNlabel, question); i++;
7331 XtSetArg(args[i], XtNvalue, ""); i++;
7332 XtSetArg(args[i], XtNborderWidth, 0); i++;
7333 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7336 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7337 (XtPointer) dialog);
7338 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7339 (XtPointer) dialog);
7341 XtRealizeWidget(popup);
7342 CatchDeleteWindow(popup, "AskQuestionPopDown");
7344 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7345 &x, &y, &win_x, &win_y, &mask);
7347 XtSetArg(args[0], XtNx, x - 10);
7348 XtSetArg(args[1], XtNy, y - 30);
7349 XtSetValues(popup, args, 2);
7351 XtPopup(popup, XtGrabExclusive);
7352 askQuestionUp = True;
7354 edit = XtNameToWidget(dialog, "*value");
7355 XtSetKeyboardFocus(popup, edit);
7363 if (*name == NULLCHAR) {
7365 } else if (strcmp(name, "$") == 0) {
7366 putc(BELLCHAR, stderr);
7369 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7377 PlaySound(appData.soundMove);
7383 PlaySound(appData.soundIcsWin);
7389 PlaySound(appData.soundIcsLoss);
7395 PlaySound(appData.soundIcsDraw);
7399 PlayIcsUnfinishedSound()
7401 PlaySound(appData.soundIcsUnfinished);
7407 PlaySound(appData.soundIcsAlarm);
7413 system("stty echo");
7419 system("stty -echo");
7423 Colorize(cc, continuation)
7428 int count, outCount, error;
7430 if (textColors[(int)cc].bg > 0) {
7431 if (textColors[(int)cc].fg > 0) {
7432 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7433 textColors[(int)cc].fg, textColors[(int)cc].bg);
7435 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7436 textColors[(int)cc].bg);
7439 if (textColors[(int)cc].fg > 0) {
7440 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7441 textColors[(int)cc].fg);
7443 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7446 count = strlen(buf);
7447 outCount = OutputToProcess(NoProc, buf, count, &error);
7448 if (outCount < count) {
7449 DisplayFatalError(_("Error writing to display"), error, 1);
7452 if (continuation) return;
7455 PlaySound(appData.soundShout);
7458 PlaySound(appData.soundSShout);
7461 PlaySound(appData.soundChannel1);
7464 PlaySound(appData.soundChannel);
7467 PlaySound(appData.soundKibitz);
7470 PlaySound(appData.soundTell);
7472 case ColorChallenge:
7473 PlaySound(appData.soundChallenge);
7476 PlaySound(appData.soundRequest);
7479 PlaySound(appData.soundSeek);
7490 return getpwuid(getuid())->pw_name;
7493 static char *ExpandPathName(path)
7496 static char static_buf[2000];
7497 char *d, *s, buf[2000];
7503 while (*s && isspace(*s))
7512 if (*(s+1) == '/') {
7513 strcpy(d, getpwuid(getuid())->pw_dir);
7518 *strchr(buf, '/') = 0;
7519 pwd = getpwnam(buf);
7522 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7526 strcpy(d, pwd->pw_dir);
7527 strcat(d, strchr(s+1, '/'));
7538 static char host_name[MSG_SIZ];
7540 #if HAVE_GETHOSTNAME
7541 gethostname(host_name, MSG_SIZ);
7543 #else /* not HAVE_GETHOSTNAME */
7544 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7545 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7547 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7549 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7550 #endif /* not HAVE_GETHOSTNAME */
7553 XtIntervalId delayedEventTimerXID = 0;
7554 DelayedEventCallback delayedEventCallback = 0;
7559 delayedEventTimerXID = 0;
7560 delayedEventCallback();
7564 ScheduleDelayedEvent(cb, millisec)
7565 DelayedEventCallback cb; long millisec;
7567 if(delayedEventTimerXID && delayedEventCallback == cb)
7568 // [HGM] alive: replace, rather than add or flush identical event
7569 XtRemoveTimeOut(delayedEventTimerXID);
7570 delayedEventCallback = cb;
7571 delayedEventTimerXID =
7572 XtAppAddTimeOut(appContext, millisec,
7573 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7576 DelayedEventCallback
7579 if (delayedEventTimerXID) {
7580 return delayedEventCallback;
7587 CancelDelayedEvent()
7589 if (delayedEventTimerXID) {
7590 XtRemoveTimeOut(delayedEventTimerXID);
7591 delayedEventTimerXID = 0;
7595 XtIntervalId loadGameTimerXID = 0;
7597 int LoadGameTimerRunning()
7599 return loadGameTimerXID != 0;
7602 int StopLoadGameTimer()
7604 if (loadGameTimerXID != 0) {
7605 XtRemoveTimeOut(loadGameTimerXID);
7606 loadGameTimerXID = 0;
7614 LoadGameTimerCallback(arg, id)
7618 loadGameTimerXID = 0;
7623 StartLoadGameTimer(millisec)
7627 XtAppAddTimeOut(appContext, millisec,
7628 (XtTimerCallbackProc) LoadGameTimerCallback,
7632 XtIntervalId analysisClockXID = 0;
7635 AnalysisClockCallback(arg, id)
7639 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7640 || appData.icsEngineAnalyze) { // [DM]
7641 AnalysisPeriodicEvent(0);
7642 StartAnalysisClock();
7647 StartAnalysisClock()
7650 XtAppAddTimeOut(appContext, 2000,
7651 (XtTimerCallbackProc) AnalysisClockCallback,
7655 XtIntervalId clockTimerXID = 0;
7657 int ClockTimerRunning()
7659 return clockTimerXID != 0;
7662 int StopClockTimer()
7664 if (clockTimerXID != 0) {
7665 XtRemoveTimeOut(clockTimerXID);
7674 ClockTimerCallback(arg, id)
7683 StartClockTimer(millisec)
7687 XtAppAddTimeOut(appContext, millisec,
7688 (XtTimerCallbackProc) ClockTimerCallback,
7693 DisplayTimerLabel(w, color, timer, highlight)
7702 /* check for low time warning */
7703 Pixel foregroundOrWarningColor = timerForegroundPixel;
7706 appData.lowTimeWarning &&
7707 (timer / 1000) < appData.icsAlarmTime)
7708 foregroundOrWarningColor = lowTimeWarningColor;
7710 if (appData.clockMode) {
7711 sprintf(buf, "%s: %s", color, TimeString(timer));
7712 XtSetArg(args[0], XtNlabel, buf);
7714 sprintf(buf, "%s ", color);
7715 XtSetArg(args[0], XtNlabel, buf);
7720 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7721 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7723 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7724 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7727 XtSetValues(w, args, 3);
7731 DisplayWhiteClock(timeRemaining, highlight)
7737 if(appData.noGUI) return;
7738 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7739 if (highlight && iconPixmap == bIconPixmap) {
7740 iconPixmap = wIconPixmap;
7741 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7742 XtSetValues(shellWidget, args, 1);
7747 DisplayBlackClock(timeRemaining, highlight)
7753 if(appData.noGUI) return;
7754 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7755 if (highlight && iconPixmap == wIconPixmap) {
7756 iconPixmap = bIconPixmap;
7757 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7758 XtSetValues(shellWidget, args, 1);
7776 int StartChildProcess(cmdLine, dir, pr)
7783 int to_prog[2], from_prog[2];
7787 if (appData.debugMode) {
7788 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7791 /* We do NOT feed the cmdLine to the shell; we just
7792 parse it into blank-separated arguments in the
7793 most simple-minded way possible.
7796 strcpy(buf, cmdLine);
7799 while(*p == ' ') p++;
7801 if(*p == '"' || *p == '\'')
7802 p = strchr(++argv[i-1], *p);
7803 else p = strchr(p, ' ');
7804 if (p == NULL) break;
7809 SetUpChildIO(to_prog, from_prog);
7811 if ((pid = fork()) == 0) {
7813 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7814 close(to_prog[1]); // first close the unused pipe ends
7815 close(from_prog[0]);
7816 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7817 dup2(from_prog[1], 1);
7818 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7819 close(from_prog[1]); // and closing again loses one of the pipes!
7820 if(fileno(stderr) >= 2) // better safe than sorry...
7821 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7823 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7828 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7830 execvp(argv[0], argv);
7832 /* If we get here, exec failed */
7837 /* Parent process */
7839 close(from_prog[1]);
7841 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7844 cp->fdFrom = from_prog[0];
7845 cp->fdTo = to_prog[1];
7850 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7851 static RETSIGTYPE AlarmCallBack(int n)
7857 DestroyChildProcess(pr, signalType)
7861 ChildProc *cp = (ChildProc *) pr;
7863 if (cp->kind != CPReal) return;
7865 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7866 signal(SIGALRM, AlarmCallBack);
7868 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7869 kill(cp->pid, SIGKILL); // kill it forcefully
7870 wait((int *) 0); // and wait again
7874 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7876 /* Process is exiting either because of the kill or because of
7877 a quit command sent by the backend; either way, wait for it to die.
7886 InterruptChildProcess(pr)
7889 ChildProc *cp = (ChildProc *) pr;
7891 if (cp->kind != CPReal) return;
7892 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7895 int OpenTelnet(host, port, pr)
7900 char cmdLine[MSG_SIZ];
7902 if (port[0] == NULLCHAR) {
7903 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7905 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7907 return StartChildProcess(cmdLine, "", pr);
7910 int OpenTCP(host, port, pr)
7916 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7917 #else /* !OMIT_SOCKETS */
7919 struct sockaddr_in sa;
7921 unsigned short uport;
7924 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7928 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7929 sa.sin_family = AF_INET;
7930 sa.sin_addr.s_addr = INADDR_ANY;
7931 uport = (unsigned short) 0;
7932 sa.sin_port = htons(uport);
7933 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7937 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7938 if (!(hp = gethostbyname(host))) {
7940 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7941 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7942 hp->h_addrtype = AF_INET;
7944 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7945 hp->h_addr_list[0] = (char *) malloc(4);
7946 hp->h_addr_list[0][0] = b0;
7947 hp->h_addr_list[0][1] = b1;
7948 hp->h_addr_list[0][2] = b2;
7949 hp->h_addr_list[0][3] = b3;
7954 sa.sin_family = hp->h_addrtype;
7955 uport = (unsigned short) atoi(port);
7956 sa.sin_port = htons(uport);
7957 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7959 if (connect(s, (struct sockaddr *) &sa,
7960 sizeof(struct sockaddr_in)) < 0) {
7964 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7971 #endif /* !OMIT_SOCKETS */
7976 int OpenCommPort(name, pr)
7983 fd = open(name, 2, 0);
7984 if (fd < 0) return errno;
7986 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7996 int OpenLoopback(pr)
8002 SetUpChildIO(to, from);
8004 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8007 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8014 int OpenRcmd(host, user, cmd, pr)
8015 char *host, *user, *cmd;
8018 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8022 #define INPUT_SOURCE_BUF_SIZE 8192
8031 char buf[INPUT_SOURCE_BUF_SIZE];
8036 DoInputCallback(closure, source, xid)
8041 InputSource *is = (InputSource *) closure;
8046 if (is->lineByLine) {
8047 count = read(is->fd, is->unused,
8048 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8050 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8053 is->unused += count;
8055 while (p < is->unused) {
8056 q = memchr(p, '\n', is->unused - p);
8057 if (q == NULL) break;
8059 (is->func)(is, is->closure, p, q - p, 0);
8063 while (p < is->unused) {
8068 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8073 (is->func)(is, is->closure, is->buf, count, error);
8077 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8084 ChildProc *cp = (ChildProc *) pr;
8086 is = (InputSource *) calloc(1, sizeof(InputSource));
8087 is->lineByLine = lineByLine;
8091 is->fd = fileno(stdin);
8093 is->kind = cp->kind;
8094 is->fd = cp->fdFrom;
8097 is->unused = is->buf;
8100 is->xid = XtAppAddInput(appContext, is->fd,
8101 (XtPointer) (XtInputReadMask),
8102 (XtInputCallbackProc) DoInputCallback,
8104 is->closure = closure;
8105 return (InputSourceRef) is;
8109 RemoveInputSource(isr)
8112 InputSource *is = (InputSource *) isr;
8114 if (is->xid == 0) return;
8115 XtRemoveInput(is->xid);
8119 int OutputToProcess(pr, message, count, outError)
8125 static int line = 0;
8126 ChildProc *cp = (ChildProc *) pr;
8131 if (appData.noJoin || !appData.useInternalWrap)
8132 outCount = fwrite(message, 1, count, stdout);
8135 int width = get_term_width();
8136 int len = wrap(NULL, message, count, width, &line);
8137 char *msg = malloc(len);
8141 outCount = fwrite(message, 1, count, stdout);
8144 dbgchk = wrap(msg, message, count, width, &line);
8145 if (dbgchk != len && appData.debugMode)
8146 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8147 outCount = fwrite(msg, 1, dbgchk, stdout);
8153 outCount = write(cp->fdTo, message, count);
8163 /* Output message to process, with "ms" milliseconds of delay
8164 between each character. This is needed when sending the logon
8165 script to ICC, which for some reason doesn't like the
8166 instantaneous send. */
8167 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8174 ChildProc *cp = (ChildProc *) pr;
8179 r = write(cp->fdTo, message++, 1);
8192 /**** Animation code by Hugh Fisher, DCS, ANU.
8194 Known problem: if a window overlapping the board is
8195 moved away while a piece is being animated underneath,
8196 the newly exposed area won't be updated properly.
8197 I can live with this.
8199 Known problem: if you look carefully at the animation
8200 of pieces in mono mode, they are being drawn as solid
8201 shapes without interior detail while moving. Fixing
8202 this would be a major complication for minimal return.
8205 /* Masks for XPM pieces. Black and white pieces can have
8206 different shapes, but in the interest of retaining my
8207 sanity pieces must have the same outline on both light
8208 and dark squares, and all pieces must use the same
8209 background square colors/images. */
8211 static int xpmDone = 0;
8214 CreateAnimMasks (pieceDepth)
8221 unsigned long plane;
8224 /* Need a bitmap just to get a GC with right depth */
8225 buf = XCreatePixmap(xDisplay, xBoardWindow,
8227 values.foreground = 1;
8228 values.background = 0;
8229 /* Don't use XtGetGC, not read only */
8230 maskGC = XCreateGC(xDisplay, buf,
8231 GCForeground | GCBackground, &values);
8232 XFreePixmap(xDisplay, buf);
8234 buf = XCreatePixmap(xDisplay, xBoardWindow,
8235 squareSize, squareSize, pieceDepth);
8236 values.foreground = XBlackPixel(xDisplay, xScreen);
8237 values.background = XWhitePixel(xDisplay, xScreen);
8238 bufGC = XCreateGC(xDisplay, buf,
8239 GCForeground | GCBackground, &values);
8241 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8242 /* Begin with empty mask */
8243 if(!xpmDone) // [HGM] pieces: keep using existing
8244 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8245 squareSize, squareSize, 1);
8246 XSetFunction(xDisplay, maskGC, GXclear);
8247 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8248 0, 0, squareSize, squareSize);
8250 /* Take a copy of the piece */
8255 XSetFunction(xDisplay, bufGC, GXcopy);
8256 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8258 0, 0, squareSize, squareSize, 0, 0);
8260 /* XOR the background (light) over the piece */
8261 XSetFunction(xDisplay, bufGC, GXxor);
8263 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8264 0, 0, squareSize, squareSize, 0, 0);
8266 XSetForeground(xDisplay, bufGC, lightSquareColor);
8267 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8270 /* We now have an inverted piece image with the background
8271 erased. Construct mask by just selecting all the non-zero
8272 pixels - no need to reconstruct the original image. */
8273 XSetFunction(xDisplay, maskGC, GXor);
8275 /* Might be quicker to download an XImage and create bitmap
8276 data from it rather than this N copies per piece, but it
8277 only takes a fraction of a second and there is a much
8278 longer delay for loading the pieces. */
8279 for (n = 0; n < pieceDepth; n ++) {
8280 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8281 0, 0, squareSize, squareSize,
8287 XFreePixmap(xDisplay, buf);
8288 XFreeGC(xDisplay, bufGC);
8289 XFreeGC(xDisplay, maskGC);
8293 InitAnimState (anim, info)
8295 XWindowAttributes * info;
8300 /* Each buffer is square size, same depth as window */
8301 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8302 squareSize, squareSize, info->depth);
8303 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8304 squareSize, squareSize, info->depth);
8306 /* Create a plain GC for blitting */
8307 mask = GCForeground | GCBackground | GCFunction |
8308 GCPlaneMask | GCGraphicsExposures;
8309 values.foreground = XBlackPixel(xDisplay, xScreen);
8310 values.background = XWhitePixel(xDisplay, xScreen);
8311 values.function = GXcopy;
8312 values.plane_mask = AllPlanes;
8313 values.graphics_exposures = False;
8314 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8316 /* Piece will be copied from an existing context at
8317 the start of each new animation/drag. */
8318 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8320 /* Outline will be a read-only copy of an existing */
8321 anim->outlineGC = None;
8327 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8328 XWindowAttributes info;
8330 if (xpmDone && gameInfo.variant == old) return;
8331 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8332 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8334 InitAnimState(&game, &info);
8335 InitAnimState(&player, &info);
8337 /* For XPM pieces, we need bitmaps to use as masks. */
8339 CreateAnimMasks(info.depth);
8345 static Boolean frameWaiting;
8347 static RETSIGTYPE FrameAlarm (sig)
8350 frameWaiting = False;
8351 /* In case System-V style signals. Needed?? */
8352 signal(SIGALRM, FrameAlarm);
8359 struct itimerval delay;
8361 XSync(xDisplay, False);
8364 frameWaiting = True;
8365 signal(SIGALRM, FrameAlarm);
8366 delay.it_interval.tv_sec =
8367 delay.it_value.tv_sec = time / 1000;
8368 delay.it_interval.tv_usec =
8369 delay.it_value.tv_usec = (time % 1000) * 1000;
8370 setitimer(ITIMER_REAL, &delay, NULL);
8371 while (frameWaiting) pause();
8372 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8373 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8374 setitimer(ITIMER_REAL, &delay, NULL);
8384 XSync(xDisplay, False);
8386 usleep(time * 1000);
8391 /* Convert board position to corner of screen rect and color */
8394 ScreenSquare(column, row, pt, color)
8395 int column; int row; XPoint * pt; int * color;
8398 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8399 pt->y = lineGap + row * (squareSize + lineGap);
8401 pt->x = lineGap + column * (squareSize + lineGap);
8402 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8404 *color = SquareColor(row, column);
8407 /* Convert window coords to square */
8410 BoardSquare(x, y, column, row)
8411 int x; int y; int * column; int * row;
8413 *column = EventToSquare(x, BOARD_WIDTH);
8414 if (flipView && *column >= 0)
8415 *column = BOARD_WIDTH - 1 - *column;
8416 *row = EventToSquare(y, BOARD_HEIGHT);
8417 if (!flipView && *row >= 0)
8418 *row = BOARD_HEIGHT - 1 - *row;
8423 #undef Max /* just in case */
8425 #define Max(a, b) ((a) > (b) ? (a) : (b))
8426 #define Min(a, b) ((a) < (b) ? (a) : (b))
8429 SetRect(rect, x, y, width, height)
8430 XRectangle * rect; int x; int y; int width; int height;
8434 rect->width = width;
8435 rect->height = height;
8438 /* Test if two frames overlap. If they do, return
8439 intersection rect within old and location of
8440 that rect within new. */
8443 Intersect(old, new, size, area, pt)
8444 XPoint * old; XPoint * new;
8445 int size; XRectangle * area; XPoint * pt;
8447 if (old->x > new->x + size || new->x > old->x + size ||
8448 old->y > new->y + size || new->y > old->y + size) {
8451 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8452 size - abs(old->x - new->x), size - abs(old->y - new->y));
8453 pt->x = Max(old->x - new->x, 0);
8454 pt->y = Max(old->y - new->y, 0);
8459 /* For two overlapping frames, return the rect(s)
8460 in the old that do not intersect with the new. */
8463 CalcUpdateRects(old, new, size, update, nUpdates)
8464 XPoint * old; XPoint * new; int size;
8465 XRectangle update[]; int * nUpdates;
8469 /* If old = new (shouldn't happen) then nothing to draw */
8470 if (old->x == new->x && old->y == new->y) {
8474 /* Work out what bits overlap. Since we know the rects
8475 are the same size we don't need a full intersect calc. */
8477 /* Top or bottom edge? */
8478 if (new->y > old->y) {
8479 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8481 } else if (old->y > new->y) {
8482 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8483 size, old->y - new->y);
8486 /* Left or right edge - don't overlap any update calculated above. */
8487 if (new->x > old->x) {
8488 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8489 new->x - old->x, size - abs(new->y - old->y));
8491 } else if (old->x > new->x) {
8492 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8493 old->x - new->x, size - abs(new->y - old->y));
8500 /* Generate a series of frame coords from start->mid->finish.
8501 The movement rate doubles until the half way point is
8502 reached, then halves back down to the final destination,
8503 which gives a nice slow in/out effect. The algorithmn
8504 may seem to generate too many intermediates for short
8505 moves, but remember that the purpose is to attract the
8506 viewers attention to the piece about to be moved and
8507 then to where it ends up. Too few frames would be less
8511 Tween(start, mid, finish, factor, frames, nFrames)
8512 XPoint * start; XPoint * mid;
8513 XPoint * finish; int factor;
8514 XPoint frames[]; int * nFrames;
8516 int fraction, n, count;
8520 /* Slow in, stepping 1/16th, then 1/8th, ... */
8522 for (n = 0; n < factor; n++)
8524 for (n = 0; n < factor; n++) {
8525 frames[count].x = start->x + (mid->x - start->x) / fraction;
8526 frames[count].y = start->y + (mid->y - start->y) / fraction;
8528 fraction = fraction / 2;
8532 frames[count] = *mid;
8535 /* Slow out, stepping 1/2, then 1/4, ... */
8537 for (n = 0; n < factor; n++) {
8538 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8539 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8541 fraction = fraction * 2;
8546 /* Draw a piece on the screen without disturbing what's there */
8549 SelectGCMask(piece, clip, outline, mask)
8550 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8554 /* Bitmap for piece being moved. */
8555 if (appData.monoMode) {
8556 *mask = *pieceToSolid(piece);
8557 } else if (useImages) {
8559 *mask = xpmMask[piece];
8561 *mask = ximMaskPm[piece];
8564 *mask = *pieceToSolid(piece);
8567 /* GC for piece being moved. Square color doesn't matter, but
8568 since it gets modified we make a copy of the original. */
8570 if (appData.monoMode)
8575 if (appData.monoMode)
8580 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8582 /* Outline only used in mono mode and is not modified */
8584 *outline = bwPieceGC;
8586 *outline = wbPieceGC;
8590 OverlayPiece(piece, clip, outline, dest)
8591 ChessSquare piece; GC clip; GC outline; Drawable dest;
8596 /* Draw solid rectangle which will be clipped to shape of piece */
8597 XFillRectangle(xDisplay, dest, clip,
8598 0, 0, squareSize, squareSize);
8599 if (appData.monoMode)
8600 /* Also draw outline in contrasting color for black
8601 on black / white on white cases */
8602 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8603 0, 0, squareSize, squareSize, 0, 0, 1);
8605 /* Copy the piece */
8610 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8612 0, 0, squareSize, squareSize,
8617 /* Animate the movement of a single piece */
8620 BeginAnimation(anim, piece, startColor, start)
8628 /* The old buffer is initialised with the start square (empty) */
8629 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8630 anim->prevFrame = *start;
8632 /* The piece will be drawn using its own bitmap as a matte */
8633 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8634 XSetClipMask(xDisplay, anim->pieceGC, mask);
8638 AnimationFrame(anim, frame, piece)
8643 XRectangle updates[4];
8648 /* Save what we are about to draw into the new buffer */
8649 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8650 frame->x, frame->y, squareSize, squareSize,
8653 /* Erase bits of the previous frame */
8654 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8655 /* Where the new frame overlapped the previous,
8656 the contents in newBuf are wrong. */
8657 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8658 overlap.x, overlap.y,
8659 overlap.width, overlap.height,
8661 /* Repaint the areas in the old that don't overlap new */
8662 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8663 for (i = 0; i < count; i++)
8664 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8665 updates[i].x - anim->prevFrame.x,
8666 updates[i].y - anim->prevFrame.y,
8667 updates[i].width, updates[i].height,
8668 updates[i].x, updates[i].y);
8670 /* Easy when no overlap */
8671 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8672 0, 0, squareSize, squareSize,
8673 anim->prevFrame.x, anim->prevFrame.y);
8676 /* Save this frame for next time round */
8677 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8678 0, 0, squareSize, squareSize,
8680 anim->prevFrame = *frame;
8682 /* Draw piece over original screen contents, not current,
8683 and copy entire rect. Wipes out overlapping piece images. */
8684 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8685 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8686 0, 0, squareSize, squareSize,
8687 frame->x, frame->y);
8691 EndAnimation (anim, finish)
8695 XRectangle updates[4];
8700 /* The main code will redraw the final square, so we
8701 only need to erase the bits that don't overlap. */
8702 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8703 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8704 for (i = 0; i < count; i++)
8705 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8706 updates[i].x - anim->prevFrame.x,
8707 updates[i].y - anim->prevFrame.y,
8708 updates[i].width, updates[i].height,
8709 updates[i].x, updates[i].y);
8711 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8712 0, 0, squareSize, squareSize,
8713 anim->prevFrame.x, anim->prevFrame.y);
8718 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8720 ChessSquare piece; int startColor;
8721 XPoint * start; XPoint * finish;
8722 XPoint frames[]; int nFrames;
8726 BeginAnimation(anim, piece, startColor, start);
8727 for (n = 0; n < nFrames; n++) {
8728 AnimationFrame(anim, &(frames[n]), piece);
8729 FrameDelay(appData.animSpeed);
8731 EndAnimation(anim, finish);
8734 /* Main control logic for deciding what to animate and how */
8737 AnimateMove(board, fromX, fromY, toX, toY)
8746 XPoint start, finish, mid;
8747 XPoint frames[kFactor * 2 + 1];
8748 int nFrames, startColor, endColor;
8750 /* Are we animating? */
8751 if (!appData.animate || appData.blindfold)
8754 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8755 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8756 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8758 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8759 piece = board[fromY][fromX];
8760 if (piece >= EmptySquare) return;
8765 hop = (piece == WhiteKnight || piece == BlackKnight);
8768 if (appData.debugMode) {
8769 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8770 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8771 piece, fromX, fromY, toX, toY); }
8773 ScreenSquare(fromX, fromY, &start, &startColor);
8774 ScreenSquare(toX, toY, &finish, &endColor);
8777 /* Knight: make diagonal movement then straight */
8778 if (abs(toY - fromY) < abs(toX - fromX)) {
8779 mid.x = start.x + (finish.x - start.x) / 2;
8783 mid.y = start.y + (finish.y - start.y) / 2;
8786 mid.x = start.x + (finish.x - start.x) / 2;
8787 mid.y = start.y + (finish.y - start.y) / 2;
8790 /* Don't use as many frames for very short moves */
8791 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8792 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8794 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8795 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8797 /* Be sure end square is redrawn */
8798 damage[0][toY][toX] = True;
8802 DragPieceBegin(x, y)
8805 int boardX, boardY, color;
8808 /* Are we animating? */
8809 if (!appData.animateDragging || appData.blindfold)
8812 /* Figure out which square we start in and the
8813 mouse position relative to top left corner. */
8814 BoardSquare(x, y, &boardX, &boardY);
8815 player.startBoardX = boardX;
8816 player.startBoardY = boardY;
8817 ScreenSquare(boardX, boardY, &corner, &color);
8818 player.startSquare = corner;
8819 player.startColor = color;
8820 /* As soon as we start dragging, the piece will jump slightly to
8821 be centered over the mouse pointer. */
8822 player.mouseDelta.x = squareSize/2;
8823 player.mouseDelta.y = squareSize/2;
8824 /* Initialise animation */
8825 player.dragPiece = PieceForSquare(boardX, boardY);
8827 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8828 player.dragActive = True;
8829 BeginAnimation(&player, player.dragPiece, color, &corner);
8830 /* Mark this square as needing to be redrawn. Note that
8831 we don't remove the piece though, since logically (ie
8832 as seen by opponent) the move hasn't been made yet. */
8833 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8834 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8835 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8836 corner.x, corner.y, squareSize, squareSize,
8837 0, 0); // [HGM] zh: unstack in stead of grab
8838 damage[0][boardY][boardX] = True;
8840 player.dragActive = False;
8850 /* Are we animating? */
8851 if (!appData.animateDragging || appData.blindfold)
8855 if (! player.dragActive)
8857 /* Move piece, maintaining same relative position
8858 of mouse within square */
8859 corner.x = x - player.mouseDelta.x;
8860 corner.y = y - player.mouseDelta.y;
8861 AnimationFrame(&player, &corner, player.dragPiece);
8863 if (appData.highlightDragging) {
8865 BoardSquare(x, y, &boardX, &boardY);
8866 SetHighlights(fromX, fromY, boardX, boardY);
8875 int boardX, boardY, color;
8878 /* Are we animating? */
8879 if (!appData.animateDragging || appData.blindfold)
8883 if (! player.dragActive)
8885 /* Last frame in sequence is square piece is
8886 placed on, which may not match mouse exactly. */
8887 BoardSquare(x, y, &boardX, &boardY);
8888 ScreenSquare(boardX, boardY, &corner, &color);
8889 EndAnimation(&player, &corner);
8891 /* Be sure end square is redrawn */
8892 damage[0][boardY][boardX] = True;
8894 /* This prevents weird things happening with fast successive
8895 clicks which on my Sun at least can cause motion events
8896 without corresponding press/release. */
8897 player.dragActive = False;
8900 /* Handle expose event while piece being dragged */
8905 if (!player.dragActive || appData.blindfold)
8908 /* What we're doing: logically, the move hasn't been made yet,
8909 so the piece is still in it's original square. But visually
8910 it's being dragged around the board. So we erase the square
8911 that the piece is on and draw it at the last known drag point. */
8912 BlankSquare(player.startSquare.x, player.startSquare.y,
8913 player.startColor, EmptySquare, xBoardWindow);
8914 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8915 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8918 #include <sys/ioctl.h>
8919 int get_term_width()
8921 int fd, default_width;
8924 default_width = 79; // this is FICS default anyway...
8926 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8928 if (!ioctl(fd, TIOCGSIZE, &win))
8929 default_width = win.ts_cols;
8930 #elif defined(TIOCGWINSZ)
8932 if (!ioctl(fd, TIOCGWINSZ, &win))
8933 default_width = win.ws_col;
8935 return default_width;
8938 void update_ics_width()
8940 static int old_width = 0;
8941 int new_width = get_term_width();
8943 if (old_width != new_width)
8944 ics_printf("set width %d\n", new_width);
8945 old_width = new_width;
8948 void NotifyFrontendLogin()