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] == '/')
1556 safeStrCpy(fullname, name, MSG_SIZ );
1558 sprintf(fullname, "%s%c%s", installDir, '/', name);
1564 MyGetFullPathName(char *name, char *fullname)
1565 { // should use ExpandPath?
1566 name = ExpandPathName(name);
1567 safeStrCpy(fullname, name, MSG_SIZ );
1572 EnsureOnScreen(int *x, int *y, int minX, int minY)
1579 { // [HGM] args: allows testing if main window is realized from back-end
1580 return xBoardWindow != 0;
1584 PopUpStartupDialog()
1585 { // start menu not implemented in XBoard
1588 ConvertToLine(int argc, char **argv)
1590 static char line[128*1024], buf[1024];
1594 for(i=1; i<argc; i++) {
1595 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1596 && argv[i][0] != '{' )
1597 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1599 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1602 line[strlen(line)-1] = NULLCHAR;
1606 //--------------------------------------------------------------------------------------------
1608 extern Boolean twoBoards, partnerUp;
1611 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1613 #define BoardSize int
1614 void InitDrawingSizes(BoardSize boardSize, int flags)
1615 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1616 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1618 XtGeometryResult gres;
1621 if(!formWidget) return;
1624 * Enable shell resizing.
1626 shellArgs[0].value = (XtArgVal) &w;
1627 shellArgs[1].value = (XtArgVal) &h;
1628 XtGetValues(shellWidget, shellArgs, 2);
1630 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1631 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1632 XtSetValues(shellWidget, &shellArgs[2], 4);
1634 XtSetArg(args[0], XtNdefaultDistance, &sep);
1635 XtGetValues(formWidget, args, 1);
1637 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1638 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1640 hOffset = boardWidth + 10;
1641 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1642 secondSegments[i] = gridSegments[i];
1643 secondSegments[i].x1 += hOffset;
1644 secondSegments[i].x2 += hOffset;
1647 XtSetArg(args[0], XtNwidth, boardWidth);
1648 XtSetArg(args[1], XtNheight, boardHeight);
1649 XtSetValues(boardWidget, args, 2);
1651 timerWidth = (boardWidth - sep) / 2;
1652 XtSetArg(args[0], XtNwidth, timerWidth);
1653 XtSetValues(whiteTimerWidget, args, 1);
1654 XtSetValues(blackTimerWidget, args, 1);
1656 XawFormDoLayout(formWidget, False);
1658 if (appData.titleInWindow) {
1660 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1661 XtSetArg(args[i], XtNheight, &h); i++;
1662 XtGetValues(titleWidget, args, i);
1664 w = boardWidth - 2*bor;
1666 XtSetArg(args[0], XtNwidth, &w);
1667 XtGetValues(menuBarWidget, args, 1);
1668 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1671 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1672 if (gres != XtGeometryYes && appData.debugMode) {
1674 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1675 programName, gres, w, h, wr, hr);
1679 XawFormDoLayout(formWidget, True);
1682 * Inhibit shell resizing.
1684 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1685 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1686 shellArgs[4].value = shellArgs[2].value = w;
1687 shellArgs[5].value = shellArgs[3].value = h;
1688 XtSetValues(shellWidget, &shellArgs[0], 6);
1690 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1693 for(i=0; i<4; i++) {
1695 for(p=0; p<=(int)WhiteKing; p++)
1696 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1697 if(gameInfo.variant == VariantShogi) {
1698 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1699 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1700 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1701 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1702 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1705 if(gameInfo.variant == VariantGothic) {
1706 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1710 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1711 for(p=0; p<=(int)WhiteKing; p++)
1712 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1713 if(gameInfo.variant == VariantShogi) {
1714 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1715 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1716 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1717 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1718 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1721 if(gameInfo.variant == VariantGothic) {
1722 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1728 for(i=0; i<2; i++) {
1730 for(p=0; p<=(int)WhiteKing; p++)
1731 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1732 if(gameInfo.variant == VariantShogi) {
1733 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1734 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1735 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1736 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1737 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1740 if(gameInfo.variant == VariantGothic) {
1741 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1757 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1758 XSetWindowAttributes window_attributes;
1760 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1761 XrmValue vFrom, vTo;
1762 XtGeometryResult gres;
1765 int forceMono = False;
1767 srandom(time(0)); // [HGM] book: make random truly random
1769 setbuf(stdout, NULL);
1770 setbuf(stderr, NULL);
1773 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1774 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1778 programName = strrchr(argv[0], '/');
1779 if (programName == NULL)
1780 programName = argv[0];
1785 XtSetLanguageProc(NULL, NULL, NULL);
1786 bindtextdomain(PACKAGE, LOCALEDIR);
1787 textdomain(PACKAGE);
1791 XtAppInitialize(&appContext, "XBoard", shellOptions,
1792 XtNumber(shellOptions),
1793 &argc, argv, xboardResources, NULL, 0);
1794 appData.boardSize = "";
1795 InitAppData(ConvertToLine(argc, argv));
1797 if (p == NULL) p = "/tmp";
1798 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1799 gameCopyFilename = (char*) malloc(i);
1800 gamePasteFilename = (char*) malloc(i);
1801 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1802 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1804 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1805 clientResources, XtNumber(clientResources),
1808 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1809 static char buf[MSG_SIZ];
1810 EscapeExpand(buf, appData.initString);
1811 appData.initString = strdup(buf);
1812 EscapeExpand(buf, appData.secondInitString);
1813 appData.secondInitString = strdup(buf);
1814 EscapeExpand(buf, appData.firstComputerString);
1815 appData.firstComputerString = strdup(buf);
1816 EscapeExpand(buf, appData.secondComputerString);
1817 appData.secondComputerString = strdup(buf);
1820 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1823 if (chdir(chessDir) != 0) {
1824 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1830 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1831 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1832 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1833 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1836 setbuf(debugFP, NULL);
1839 /* [HGM,HR] make sure board size is acceptable */
1840 if(appData.NrFiles > BOARD_FILES ||
1841 appData.NrRanks > BOARD_RANKS )
1842 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1845 /* This feature does not work; animation needs a rewrite */
1846 appData.highlightDragging = FALSE;
1850 xDisplay = XtDisplay(shellWidget);
1851 xScreen = DefaultScreen(xDisplay);
1852 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1854 gameInfo.variant = StringToVariant(appData.variant);
1855 InitPosition(FALSE);
1858 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1860 if (isdigit(appData.boardSize[0])) {
1861 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1862 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1863 &fontPxlSize, &smallLayout, &tinyLayout);
1865 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1866 programName, appData.boardSize);
1870 /* Find some defaults; use the nearest known size */
1871 SizeDefaults *szd, *nearest;
1872 int distance = 99999;
1873 nearest = szd = sizeDefaults;
1874 while (szd->name != NULL) {
1875 if (abs(szd->squareSize - squareSize) < distance) {
1877 distance = abs(szd->squareSize - squareSize);
1878 if (distance == 0) break;
1882 if (i < 2) lineGap = nearest->lineGap;
1883 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1884 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1885 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1886 if (i < 6) smallLayout = nearest->smallLayout;
1887 if (i < 7) tinyLayout = nearest->tinyLayout;
1890 SizeDefaults *szd = sizeDefaults;
1891 if (*appData.boardSize == NULLCHAR) {
1892 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1893 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1896 if (szd->name == NULL) szd--;
1897 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1899 while (szd->name != NULL &&
1900 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1901 if (szd->name == NULL) {
1902 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1903 programName, appData.boardSize);
1907 squareSize = szd->squareSize;
1908 lineGap = szd->lineGap;
1909 clockFontPxlSize = szd->clockFontPxlSize;
1910 coordFontPxlSize = szd->coordFontPxlSize;
1911 fontPxlSize = szd->fontPxlSize;
1912 smallLayout = szd->smallLayout;
1913 tinyLayout = szd->tinyLayout;
1914 // [HGM] font: use defaults from settings file if available and not overruled
1916 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1917 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1918 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1919 appData.font = fontTable[MESSAGE_FONT][squareSize];
1920 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1921 appData.coordFont = fontTable[COORD_FONT][squareSize];
1923 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1924 if (strlen(appData.pixmapDirectory) > 0) {
1925 p = ExpandPathName(appData.pixmapDirectory);
1927 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1928 appData.pixmapDirectory);
1931 if (appData.debugMode) {
1932 fprintf(stderr, _("\
1933 XBoard square size (hint): %d\n\
1934 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1936 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1937 if (appData.debugMode) {
1938 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1942 /* [HR] height treated separately (hacked) */
1943 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1944 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1945 if (appData.showJail == 1) {
1946 /* Jail on top and bottom */
1947 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1948 XtSetArg(boardArgs[2], XtNheight,
1949 boardHeight + 2*(lineGap + squareSize));
1950 } else if (appData.showJail == 2) {
1952 XtSetArg(boardArgs[1], XtNwidth,
1953 boardWidth + 2*(lineGap + squareSize));
1954 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1957 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1958 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1962 * Determine what fonts to use.
1964 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1965 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1966 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1967 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1968 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1969 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1970 appData.font = FindFont(appData.font, fontPxlSize);
1971 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1972 countFontStruct = XQueryFont(xDisplay, countFontID);
1973 // appData.font = FindFont(appData.font, fontPxlSize);
1975 xdb = XtDatabase(xDisplay);
1976 XrmPutStringResource(&xdb, "*font", appData.font);
1979 * Detect if there are not enough colors available and adapt.
1981 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1982 appData.monoMode = True;
1985 if (!appData.monoMode) {
1986 vFrom.addr = (caddr_t) appData.lightSquareColor;
1987 vFrom.size = strlen(appData.lightSquareColor);
1988 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1989 if (vTo.addr == NULL) {
1990 appData.monoMode = True;
1993 lightSquareColor = *(Pixel *) vTo.addr;
1996 if (!appData.monoMode) {
1997 vFrom.addr = (caddr_t) appData.darkSquareColor;
1998 vFrom.size = strlen(appData.darkSquareColor);
1999 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2000 if (vTo.addr == NULL) {
2001 appData.monoMode = True;
2004 darkSquareColor = *(Pixel *) vTo.addr;
2007 if (!appData.monoMode) {
2008 vFrom.addr = (caddr_t) appData.whitePieceColor;
2009 vFrom.size = strlen(appData.whitePieceColor);
2010 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2011 if (vTo.addr == NULL) {
2012 appData.monoMode = True;
2015 whitePieceColor = *(Pixel *) vTo.addr;
2018 if (!appData.monoMode) {
2019 vFrom.addr = (caddr_t) appData.blackPieceColor;
2020 vFrom.size = strlen(appData.blackPieceColor);
2021 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2022 if (vTo.addr == NULL) {
2023 appData.monoMode = True;
2026 blackPieceColor = *(Pixel *) vTo.addr;
2030 if (!appData.monoMode) {
2031 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2032 vFrom.size = strlen(appData.highlightSquareColor);
2033 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2034 if (vTo.addr == NULL) {
2035 appData.monoMode = True;
2038 highlightSquareColor = *(Pixel *) vTo.addr;
2042 if (!appData.monoMode) {
2043 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2044 vFrom.size = strlen(appData.premoveHighlightColor);
2045 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2046 if (vTo.addr == NULL) {
2047 appData.monoMode = True;
2050 premoveHighlightColor = *(Pixel *) vTo.addr;
2055 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2058 if (appData.bitmapDirectory == NULL ||
2059 appData.bitmapDirectory[0] == NULLCHAR)
2060 appData.bitmapDirectory = DEF_BITMAP_DIR;
2063 if (appData.lowTimeWarning && !appData.monoMode) {
2064 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2065 vFrom.size = strlen(appData.lowTimeWarningColor);
2066 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2067 if (vTo.addr == NULL)
2068 appData.monoMode = True;
2070 lowTimeWarningColor = *(Pixel *) vTo.addr;
2073 if (appData.monoMode && appData.debugMode) {
2074 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2075 (unsigned long) XWhitePixel(xDisplay, xScreen),
2076 (unsigned long) XBlackPixel(xDisplay, xScreen));
2079 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2080 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2081 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2082 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2083 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2084 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2085 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2086 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2087 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2088 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2090 if (appData.colorize) {
2092 _("%s: can't parse color names; disabling colorization\n"),
2095 appData.colorize = FALSE;
2097 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2098 textColors[ColorNone].attr = 0;
2100 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2106 layoutName = "tinyLayout";
2107 } else if (smallLayout) {
2108 layoutName = "smallLayout";
2110 layoutName = "normalLayout";
2112 /* Outer layoutWidget is there only to provide a name for use in
2113 resources that depend on the layout style */
2115 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2116 layoutArgs, XtNumber(layoutArgs));
2118 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2119 formArgs, XtNumber(formArgs));
2120 XtSetArg(args[0], XtNdefaultDistance, &sep);
2121 XtGetValues(formWidget, args, 1);
2124 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2125 XtSetArg(args[0], XtNtop, XtChainTop);
2126 XtSetArg(args[1], XtNbottom, XtChainTop);
2127 XtSetArg(args[2], XtNright, XtChainLeft);
2128 XtSetValues(menuBarWidget, args, 3);
2130 widgetList[j++] = whiteTimerWidget =
2131 XtCreateWidget("whiteTime", labelWidgetClass,
2132 formWidget, timerArgs, XtNumber(timerArgs));
2133 XtSetArg(args[0], XtNfont, clockFontStruct);
2134 XtSetArg(args[1], XtNtop, XtChainTop);
2135 XtSetArg(args[2], XtNbottom, XtChainTop);
2136 XtSetValues(whiteTimerWidget, args, 3);
2138 widgetList[j++] = blackTimerWidget =
2139 XtCreateWidget("blackTime", labelWidgetClass,
2140 formWidget, timerArgs, XtNumber(timerArgs));
2141 XtSetArg(args[0], XtNfont, clockFontStruct);
2142 XtSetArg(args[1], XtNtop, XtChainTop);
2143 XtSetArg(args[2], XtNbottom, XtChainTop);
2144 XtSetValues(blackTimerWidget, args, 3);
2146 if (appData.titleInWindow) {
2147 widgetList[j++] = titleWidget =
2148 XtCreateWidget("title", labelWidgetClass, formWidget,
2149 titleArgs, XtNumber(titleArgs));
2150 XtSetArg(args[0], XtNtop, XtChainTop);
2151 XtSetArg(args[1], XtNbottom, XtChainTop);
2152 XtSetValues(titleWidget, args, 2);
2155 if (appData.showButtonBar) {
2156 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2157 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2158 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2159 XtSetArg(args[2], XtNtop, XtChainTop);
2160 XtSetArg(args[3], XtNbottom, XtChainTop);
2161 XtSetValues(buttonBarWidget, args, 4);
2164 widgetList[j++] = messageWidget =
2165 XtCreateWidget("message", labelWidgetClass, formWidget,
2166 messageArgs, XtNumber(messageArgs));
2167 XtSetArg(args[0], XtNtop, XtChainTop);
2168 XtSetArg(args[1], XtNbottom, XtChainTop);
2169 XtSetValues(messageWidget, args, 2);
2171 widgetList[j++] = boardWidget =
2172 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2173 XtNumber(boardArgs));
2175 XtManageChildren(widgetList, j);
2177 timerWidth = (boardWidth - sep) / 2;
2178 XtSetArg(args[0], XtNwidth, timerWidth);
2179 XtSetValues(whiteTimerWidget, args, 1);
2180 XtSetValues(blackTimerWidget, args, 1);
2182 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2183 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2184 XtGetValues(whiteTimerWidget, args, 2);
2186 if (appData.showButtonBar) {
2187 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2188 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2189 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2193 * formWidget uses these constraints but they are stored
2197 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2198 XtSetValues(menuBarWidget, args, i);
2199 if (appData.titleInWindow) {
2202 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2203 XtSetValues(whiteTimerWidget, args, i);
2205 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2206 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2207 XtSetValues(blackTimerWidget, args, i);
2209 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2210 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2211 XtSetValues(titleWidget, args, i);
2213 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2214 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2215 XtSetValues(messageWidget, args, i);
2216 if (appData.showButtonBar) {
2218 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2219 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2220 XtSetValues(buttonBarWidget, args, i);
2224 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2225 XtSetValues(whiteTimerWidget, args, i);
2227 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2228 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2229 XtSetValues(blackTimerWidget, args, i);
2231 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2232 XtSetValues(titleWidget, args, i);
2234 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2235 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2236 XtSetValues(messageWidget, args, i);
2237 if (appData.showButtonBar) {
2239 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2240 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2241 XtSetValues(buttonBarWidget, args, i);
2246 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2247 XtSetValues(whiteTimerWidget, args, i);
2249 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2250 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2251 XtSetValues(blackTimerWidget, args, i);
2253 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2254 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2255 XtSetValues(messageWidget, args, i);
2256 if (appData.showButtonBar) {
2258 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2259 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2260 XtSetValues(buttonBarWidget, args, i);
2264 XtSetArg(args[0], XtNfromVert, messageWidget);
2265 XtSetArg(args[1], XtNtop, XtChainTop);
2266 XtSetArg(args[2], XtNbottom, XtChainBottom);
2267 XtSetArg(args[3], XtNleft, XtChainLeft);
2268 XtSetArg(args[4], XtNright, XtChainRight);
2269 XtSetValues(boardWidget, args, 5);
2271 XtRealizeWidget(shellWidget);
2274 XtSetArg(args[0], XtNx, wpMain.x);
2275 XtSetArg(args[1], XtNy, wpMain.y);
2276 XtSetValues(shellWidget, args, 2);
2280 * Correct the width of the message and title widgets.
2281 * It is not known why some systems need the extra fudge term.
2282 * The value "2" is probably larger than needed.
2284 XawFormDoLayout(formWidget, False);
2286 #define WIDTH_FUDGE 2
2288 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2289 XtSetArg(args[i], XtNheight, &h); i++;
2290 XtGetValues(messageWidget, args, i);
2291 if (appData.showButtonBar) {
2293 XtSetArg(args[i], XtNwidth, &w); i++;
2294 XtGetValues(buttonBarWidget, args, i);
2295 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2297 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2300 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2301 if (gres != XtGeometryYes && appData.debugMode) {
2302 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2303 programName, gres, w, h, wr, hr);
2306 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2307 /* The size used for the child widget in layout lags one resize behind
2308 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2310 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2311 if (gres != XtGeometryYes && appData.debugMode) {
2312 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2313 programName, gres, w, h, wr, hr);
2316 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2317 XtSetArg(args[1], XtNright, XtChainRight);
2318 XtSetValues(messageWidget, args, 2);
2320 if (appData.titleInWindow) {
2322 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2323 XtSetArg(args[i], XtNheight, &h); i++;
2324 XtGetValues(titleWidget, args, i);
2326 w = boardWidth - 2*bor;
2328 XtSetArg(args[0], XtNwidth, &w);
2329 XtGetValues(menuBarWidget, args, 1);
2330 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2333 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2334 if (gres != XtGeometryYes && appData.debugMode) {
2336 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2337 programName, gres, w, h, wr, hr);
2340 XawFormDoLayout(formWidget, True);
2342 xBoardWindow = XtWindow(boardWidget);
2344 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2345 // not need to go into InitDrawingSizes().
2349 * Create X checkmark bitmap and initialize option menu checks.
2351 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2352 checkmark_bits, checkmark_width, checkmark_height);
2353 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2354 if (appData.alwaysPromoteToQueen) {
2355 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2358 if (appData.animateDragging) {
2359 XtSetValues(XtNameToWidget(menuBarWidget,
2360 "menuOptions.Animate Dragging"),
2363 if (appData.animate) {
2364 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2367 if (appData.autoComment) {
2368 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2371 if (appData.autoCallFlag) {
2372 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2375 if (appData.autoFlipView) {
2376 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2379 if (appData.autoObserve) {
2380 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2383 if (appData.autoRaiseBoard) {
2384 XtSetValues(XtNameToWidget(menuBarWidget,
2385 "menuOptions.Auto Raise Board"), args, 1);
2387 if (appData.autoSaveGames) {
2388 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2391 if (appData.saveGameFile[0] != NULLCHAR) {
2392 /* Can't turn this off from menu */
2393 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2395 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2399 if (appData.blindfold) {
2400 XtSetValues(XtNameToWidget(menuBarWidget,
2401 "menuOptions.Blindfold"), args, 1);
2403 if (appData.flashCount > 0) {
2404 XtSetValues(XtNameToWidget(menuBarWidget,
2405 "menuOptions.Flash Moves"),
2408 if (appData.getMoveList) {
2409 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2413 if (appData.highlightDragging) {
2414 XtSetValues(XtNameToWidget(menuBarWidget,
2415 "menuOptions.Highlight Dragging"),
2419 if (appData.highlightLastMove) {
2420 XtSetValues(XtNameToWidget(menuBarWidget,
2421 "menuOptions.Highlight Last Move"),
2424 if (appData.icsAlarm) {
2425 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2428 if (appData.ringBellAfterMoves) {
2429 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2432 if (appData.oldSaveStyle) {
2433 XtSetValues(XtNameToWidget(menuBarWidget,
2434 "menuOptions.Old Save Style"), args, 1);
2436 if (appData.periodicUpdates) {
2437 XtSetValues(XtNameToWidget(menuBarWidget,
2438 "menuOptions.Periodic Updates"), args, 1);
2440 if (appData.ponderNextMove) {
2441 XtSetValues(XtNameToWidget(menuBarWidget,
2442 "menuOptions.Ponder Next Move"), args, 1);
2444 if (appData.popupExitMessage) {
2445 XtSetValues(XtNameToWidget(menuBarWidget,
2446 "menuOptions.Popup Exit Message"), args, 1);
2448 if (appData.popupMoveErrors) {
2449 XtSetValues(XtNameToWidget(menuBarWidget,
2450 "menuOptions.Popup Move Errors"), args, 1);
2452 if (appData.premove) {
2453 XtSetValues(XtNameToWidget(menuBarWidget,
2454 "menuOptions.Premove"), args, 1);
2456 if (appData.quietPlay) {
2457 XtSetValues(XtNameToWidget(menuBarWidget,
2458 "menuOptions.Quiet Play"), args, 1);
2460 if (appData.showCoords) {
2461 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2464 if (appData.hideThinkingFromHuman) {
2465 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2468 if (appData.testLegality) {
2469 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2472 if (saveSettingsOnExit) {
2473 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2480 ReadBitmap(&wIconPixmap, "icon_white.bm",
2481 icon_white_bits, icon_white_width, icon_white_height);
2482 ReadBitmap(&bIconPixmap, "icon_black.bm",
2483 icon_black_bits, icon_black_width, icon_black_height);
2484 iconPixmap = wIconPixmap;
2486 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2487 XtSetValues(shellWidget, args, i);
2490 * Create a cursor for the board widget.
2492 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2493 XChangeWindowAttributes(xDisplay, xBoardWindow,
2494 CWCursor, &window_attributes);
2497 * Inhibit shell resizing.
2499 shellArgs[0].value = (XtArgVal) &w;
2500 shellArgs[1].value = (XtArgVal) &h;
2501 XtGetValues(shellWidget, shellArgs, 2);
2502 shellArgs[4].value = shellArgs[2].value = w;
2503 shellArgs[5].value = shellArgs[3].value = h;
2504 XtSetValues(shellWidget, &shellArgs[2], 4);
2505 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2506 marginH = h - boardHeight;
2508 CatchDeleteWindow(shellWidget, "QuitProc");
2513 if (appData.bitmapDirectory[0] != NULLCHAR) {
2520 /* Create regular pieces */
2521 if (!useImages) CreatePieces();
2526 if (appData.animate || appData.animateDragging)
2529 XtAugmentTranslations(formWidget,
2530 XtParseTranslationTable(globalTranslations));
2531 XtAugmentTranslations(boardWidget,
2532 XtParseTranslationTable(boardTranslations));
2533 XtAugmentTranslations(whiteTimerWidget,
2534 XtParseTranslationTable(whiteTranslations));
2535 XtAugmentTranslations(blackTimerWidget,
2536 XtParseTranslationTable(blackTranslations));
2538 /* Why is the following needed on some versions of X instead
2539 * of a translation? */
2540 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2541 (XtEventHandler) EventProc, NULL);
2544 /* [AS] Restore layout */
2545 if( wpMoveHistory.visible ) {
2549 if( wpEvalGraph.visible )
2554 if( wpEngineOutput.visible ) {
2555 EngineOutputPopUp();
2560 if (errorExitStatus == -1) {
2561 if (appData.icsActive) {
2562 /* We now wait until we see "login:" from the ICS before
2563 sending the logon script (problems with timestamp otherwise) */
2564 /*ICSInitScript();*/
2565 if (appData.icsInputBox) ICSInputBoxPopUp();
2569 signal(SIGWINCH, TermSizeSigHandler);
2571 signal(SIGINT, IntSigHandler);
2572 signal(SIGTERM, IntSigHandler);
2573 if (*appData.cmailGameName != NULLCHAR) {
2574 signal(SIGUSR1, CmailSigHandler);
2577 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2579 XtSetKeyboardFocus(shellWidget, formWidget);
2581 XtAppMainLoop(appContext);
2582 if (appData.debugMode) fclose(debugFP); // [DM] debug
2589 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2590 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2592 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2593 unlink(gameCopyFilename);
2594 unlink(gamePasteFilename);
2597 RETSIGTYPE TermSizeSigHandler(int sig)
2610 CmailSigHandler(sig)
2616 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2618 /* Activate call-back function CmailSigHandlerCallBack() */
2619 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2621 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2625 CmailSigHandlerCallBack(isr, closure, message, count, error)
2633 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2635 /**** end signal code ****/
2645 f = fopen(appData.icsLogon, "r");
2649 safeStrCpy(buf, p, sizeof(buf)/sizeof(buf[0]) );
2651 strcat(buf, appData.icsLogon);
2652 f = fopen(buf, "r");
2656 ProcessICSInitScript(f);
2663 EditCommentPopDown();
2678 if (!menuBarWidget) return;
2679 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2681 DisplayError("menuStep.Revert", 0);
2683 XtSetSensitive(w, !grey);
2685 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2687 DisplayError("menuStep.Annotate", 0);
2689 XtSetSensitive(w, !grey);
2694 SetMenuEnables(enab)
2698 if (!menuBarWidget) return;
2699 while (enab->name != NULL) {
2700 w = XtNameToWidget(menuBarWidget, enab->name);
2702 DisplayError(enab->name, 0);
2704 XtSetSensitive(w, enab->value);
2710 Enables icsEnables[] = {
2711 { "menuFile.Mail Move", False },
2712 { "menuFile.Reload CMail Message", False },
2713 { "menuMode.Machine Black", False },
2714 { "menuMode.Machine White", False },
2715 { "menuMode.Analysis Mode", False },
2716 { "menuMode.Analyze File", False },
2717 { "menuMode.Two Machines", False },
2719 { "menuHelp.Hint", False },
2720 { "menuHelp.Book", False },
2721 { "menuStep.Move Now", False },
2722 { "menuOptions.Periodic Updates", False },
2723 { "menuOptions.Hide Thinking", False },
2724 { "menuOptions.Ponder Next Move", False },
2726 { "menuStep.Annotate", False },
2730 Enables ncpEnables[] = {
2731 { "menuFile.Mail Move", False },
2732 { "menuFile.Reload CMail Message", False },
2733 { "menuMode.Machine White", False },
2734 { "menuMode.Machine Black", False },
2735 { "menuMode.Analysis Mode", False },
2736 { "menuMode.Analyze File", False },
2737 { "menuMode.Two Machines", False },
2738 { "menuMode.ICS Client", False },
2739 { "menuMode.ICS Input Box", False },
2740 { "Action", False },
2741 { "menuStep.Revert", False },
2742 { "menuStep.Annotate", False },
2743 { "menuStep.Move Now", False },
2744 { "menuStep.Retract Move", False },
2745 { "menuOptions.Auto Comment", False },
2746 { "menuOptions.Auto Flag", False },
2747 { "menuOptions.Auto Flip View", False },
2748 { "menuOptions.Auto Observe", False },
2749 { "menuOptions.Auto Raise Board", False },
2750 { "menuOptions.Get Move List", False },
2751 { "menuOptions.ICS Alarm", False },
2752 { "menuOptions.Move Sound", False },
2753 { "menuOptions.Quiet Play", False },
2754 { "menuOptions.Hide Thinking", False },
2755 { "menuOptions.Periodic Updates", False },
2756 { "menuOptions.Ponder Next Move", False },
2757 { "menuHelp.Hint", False },
2758 { "menuHelp.Book", False },
2762 Enables gnuEnables[] = {
2763 { "menuMode.ICS Client", False },
2764 { "menuMode.ICS Input Box", False },
2765 { "menuAction.Accept", False },
2766 { "menuAction.Decline", False },
2767 { "menuAction.Rematch", False },
2768 { "menuAction.Adjourn", False },
2769 { "menuAction.Stop Examining", False },
2770 { "menuAction.Stop Observing", False },
2771 { "menuAction.Upload to Examine", False },
2772 { "menuStep.Revert", False },
2773 { "menuStep.Annotate", False },
2774 { "menuOptions.Auto Comment", False },
2775 { "menuOptions.Auto Observe", False },
2776 { "menuOptions.Auto Raise Board", False },
2777 { "menuOptions.Get Move List", False },
2778 { "menuOptions.Premove", False },
2779 { "menuOptions.Quiet Play", False },
2781 /* The next two options rely on SetCmailMode being called *after* */
2782 /* SetGNUMode so that when GNU is being used to give hints these */
2783 /* menu options are still available */
2785 { "menuFile.Mail Move", False },
2786 { "menuFile.Reload CMail Message", False },
2790 Enables cmailEnables[] = {
2792 { "menuAction.Call Flag", False },
2793 { "menuAction.Draw", True },
2794 { "menuAction.Adjourn", False },
2795 { "menuAction.Abort", False },
2796 { "menuAction.Stop Observing", False },
2797 { "menuAction.Stop Examining", False },
2798 { "menuFile.Mail Move", True },
2799 { "menuFile.Reload CMail Message", True },
2803 Enables trainingOnEnables[] = {
2804 { "menuMode.Edit Comment", False },
2805 { "menuMode.Pause", False },
2806 { "menuStep.Forward", False },
2807 { "menuStep.Backward", False },
2808 { "menuStep.Forward to End", False },
2809 { "menuStep.Back to Start", False },
2810 { "menuStep.Move Now", False },
2811 { "menuStep.Truncate Game", False },
2815 Enables trainingOffEnables[] = {
2816 { "menuMode.Edit Comment", True },
2817 { "menuMode.Pause", True },
2818 { "menuStep.Forward", True },
2819 { "menuStep.Backward", True },
2820 { "menuStep.Forward to End", True },
2821 { "menuStep.Back to Start", True },
2822 { "menuStep.Move Now", True },
2823 { "menuStep.Truncate Game", True },
2827 Enables machineThinkingEnables[] = {
2828 { "menuFile.Load Game", False },
2829 { "menuFile.Load Next Game", False },
2830 { "menuFile.Load Previous Game", False },
2831 { "menuFile.Reload Same Game", False },
2832 { "menuFile.Paste Game", False },
2833 { "menuFile.Load Position", False },
2834 { "menuFile.Load Next Position", False },
2835 { "menuFile.Load Previous Position", False },
2836 { "menuFile.Reload Same Position", False },
2837 { "menuFile.Paste Position", False },
2838 { "menuMode.Machine White", False },
2839 { "menuMode.Machine Black", False },
2840 { "menuMode.Two Machines", False },
2841 { "menuStep.Retract Move", False },
2845 Enables userThinkingEnables[] = {
2846 { "menuFile.Load Game", True },
2847 { "menuFile.Load Next Game", True },
2848 { "menuFile.Load Previous Game", True },
2849 { "menuFile.Reload Same Game", True },
2850 { "menuFile.Paste Game", True },
2851 { "menuFile.Load Position", True },
2852 { "menuFile.Load Next Position", True },
2853 { "menuFile.Load Previous Position", True },
2854 { "menuFile.Reload Same Position", True },
2855 { "menuFile.Paste Position", True },
2856 { "menuMode.Machine White", True },
2857 { "menuMode.Machine Black", True },
2858 { "menuMode.Two Machines", True },
2859 { "menuStep.Retract Move", True },
2865 SetMenuEnables(icsEnables);
2868 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2869 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2876 SetMenuEnables(ncpEnables);
2882 SetMenuEnables(gnuEnables);
2888 SetMenuEnables(cmailEnables);
2894 SetMenuEnables(trainingOnEnables);
2895 if (appData.showButtonBar) {
2896 XtSetSensitive(buttonBarWidget, False);
2902 SetTrainingModeOff()
2904 SetMenuEnables(trainingOffEnables);
2905 if (appData.showButtonBar) {
2906 XtSetSensitive(buttonBarWidget, True);
2911 SetUserThinkingEnables()
2913 if (appData.noChessProgram) return;
2914 SetMenuEnables(userThinkingEnables);
2918 SetMachineThinkingEnables()
2920 if (appData.noChessProgram) return;
2921 SetMenuEnables(machineThinkingEnables);
2923 case MachinePlaysBlack:
2924 case MachinePlaysWhite:
2925 case TwoMachinesPlay:
2926 XtSetSensitive(XtNameToWidget(menuBarWidget,
2927 ModeToWidgetName(gameMode)), True);
2934 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2935 #define HISTORY_SIZE 64
\r
2936 static char *history[HISTORY_SIZE];
\r
2937 int histIn = 0, histP = 0;
\r
2940 SaveInHistory(char *cmd)
\r
2942 if (history[histIn] != NULL) {
\r
2943 free(history[histIn]);
\r
2944 history[histIn] = NULL;
\r
2946 if (*cmd == NULLCHAR) return;
\r
2947 history[histIn] = StrSave(cmd);
\r
2948 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2949 if (history[histIn] != NULL) {
\r
2950 free(history[histIn]);
\r
2951 history[histIn] = NULL;
\r
2957 PrevInHistory(char *cmd)
\r
2960 if (histP == histIn) {
\r
2961 if (history[histIn] != NULL) free(history[histIn]);
\r
2962 history[histIn] = StrSave(cmd);
\r
2964 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2965 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2967 return history[histP];
\r
2973 if (histP == histIn) return NULL;
\r
2974 histP = (histP + 1) % HISTORY_SIZE;
\r
2975 return history[histP];
\r
2977 // end of borrowed code
\r
2979 #define Abs(n) ((n)<0 ? -(n) : (n))
2982 * Find a font that matches "pattern" that is as close as
2983 * possible to the targetPxlSize. Prefer fonts that are k
2984 * pixels smaller to fonts that are k pixels larger. The
2985 * pattern must be in the X Consortium standard format,
2986 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2987 * The return value should be freed with XtFree when no
2991 FindFont(pattern, targetPxlSize)
2995 char **fonts, *p, *best, *scalable, *scalableTail;
2996 int i, j, nfonts, minerr, err, pxlSize;
2999 char **missing_list;
3001 char *def_string, *base_fnt_lst, strInt[3];
3003 XFontStruct **fnt_list;
3005 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3006 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3007 p = strstr(pattern, "--");
3008 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3009 strcat(base_fnt_lst, strInt);
3010 strcat(base_fnt_lst, strchr(p + 2, '-'));
3012 if ((fntSet = XCreateFontSet(xDisplay,
3016 &def_string)) == NULL) {
3018 fprintf(stderr, _("Unable to create font set.\n"));
3022 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3024 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3026 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3027 programName, pattern);
3035 for (i=0; i<nfonts; i++) {
3038 if (*p != '-') continue;
3040 if (*p == NULLCHAR) break;
3041 if (*p++ == '-') j++;
3043 if (j < 7) continue;
3046 scalable = fonts[i];
3049 err = pxlSize - targetPxlSize;
3050 if (Abs(err) < Abs(minerr) ||
3051 (minerr > 0 && err < 0 && -err == minerr)) {
3057 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3058 /* If the error is too big and there is a scalable font,
3059 use the scalable font. */
3060 int headlen = scalableTail - scalable;
3061 p = (char *) XtMalloc(strlen(scalable) + 10);
3062 while (isdigit(*scalableTail)) scalableTail++;
3063 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3065 p = (char *) XtMalloc(strlen(best) + 2);
3066 safeStrCpy(p, best, strlen(best)+1 );
3068 if (appData.debugMode) {
3069 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3070 pattern, targetPxlSize, p);
3073 if (missing_count > 0)
3074 XFreeStringList(missing_list);
3075 XFreeFontSet(xDisplay, fntSet);
3077 XFreeFontNames(fonts);
3084 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3085 | GCBackground | GCFunction | GCPlaneMask;
3086 XGCValues gc_values;
3089 gc_values.plane_mask = AllPlanes;
3090 gc_values.line_width = lineGap;
3091 gc_values.line_style = LineSolid;
3092 gc_values.function = GXcopy;
3094 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3095 gc_values.background = XBlackPixel(xDisplay, xScreen);
3096 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3098 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3099 gc_values.background = XWhitePixel(xDisplay, xScreen);
3100 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3101 XSetFont(xDisplay, coordGC, coordFontID);
3103 // [HGM] make font for holdings counts (white on black0
3104 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3105 gc_values.background = XBlackPixel(xDisplay, xScreen);
3106 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3107 XSetFont(xDisplay, countGC, countFontID);
3109 if (appData.monoMode) {
3110 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3111 gc_values.background = XWhitePixel(xDisplay, xScreen);
3112 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3114 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3115 gc_values.background = XBlackPixel(xDisplay, xScreen);
3116 lightSquareGC = wbPieceGC
3117 = XtGetGC(shellWidget, value_mask, &gc_values);
3119 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3120 gc_values.background = XWhitePixel(xDisplay, xScreen);
3121 darkSquareGC = bwPieceGC
3122 = XtGetGC(shellWidget, value_mask, &gc_values);
3124 if (DefaultDepth(xDisplay, xScreen) == 1) {
3125 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3126 gc_values.function = GXcopyInverted;
3127 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3128 gc_values.function = GXcopy;
3129 if (XBlackPixel(xDisplay, xScreen) == 1) {
3130 bwPieceGC = darkSquareGC;
3131 wbPieceGC = copyInvertedGC;
3133 bwPieceGC = copyInvertedGC;
3134 wbPieceGC = lightSquareGC;
3138 gc_values.foreground = highlightSquareColor;
3139 gc_values.background = highlightSquareColor;
3140 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3142 gc_values.foreground = premoveHighlightColor;
3143 gc_values.background = premoveHighlightColor;
3144 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3146 gc_values.foreground = lightSquareColor;
3147 gc_values.background = darkSquareColor;
3148 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3150 gc_values.foreground = darkSquareColor;
3151 gc_values.background = lightSquareColor;
3152 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3154 gc_values.foreground = jailSquareColor;
3155 gc_values.background = jailSquareColor;
3156 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3158 gc_values.foreground = whitePieceColor;
3159 gc_values.background = darkSquareColor;
3160 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3162 gc_values.foreground = whitePieceColor;
3163 gc_values.background = lightSquareColor;
3164 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3166 gc_values.foreground = whitePieceColor;
3167 gc_values.background = jailSquareColor;
3168 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3170 gc_values.foreground = blackPieceColor;
3171 gc_values.background = darkSquareColor;
3172 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3174 gc_values.foreground = blackPieceColor;
3175 gc_values.background = lightSquareColor;
3176 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3178 gc_values.foreground = blackPieceColor;
3179 gc_values.background = jailSquareColor;
3180 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3184 void loadXIM(xim, xmask, filename, dest, mask)
3197 fp = fopen(filename, "rb");
3199 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3206 for (y=0; y<h; ++y) {
3207 for (x=0; x<h; ++x) {
3212 XPutPixel(xim, x, y, blackPieceColor);
3214 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3217 XPutPixel(xim, x, y, darkSquareColor);
3219 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3222 XPutPixel(xim, x, y, whitePieceColor);
3224 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3227 XPutPixel(xim, x, y, lightSquareColor);
3229 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3235 /* create Pixmap of piece */
3236 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3238 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3241 /* create Pixmap of clipmask
3242 Note: We assume the white/black pieces have the same
3243 outline, so we make only 6 masks. This is okay
3244 since the XPM clipmask routines do the same. */
3246 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3248 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3251 /* now create the 1-bit version */
3252 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3255 values.foreground = 1;
3256 values.background = 0;
3258 /* Don't use XtGetGC, not read only */
3259 maskGC = XCreateGC(xDisplay, *mask,
3260 GCForeground | GCBackground, &values);
3261 XCopyPlane(xDisplay, temp, *mask, maskGC,
3262 0, 0, squareSize, squareSize, 0, 0, 1);
3263 XFreePixmap(xDisplay, temp);
3268 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3270 void CreateXIMPieces()
3275 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3280 /* The XSynchronize calls were copied from CreatePieces.
3281 Not sure if needed, but can't hurt */
3282 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3285 /* temp needed by loadXIM() */
3286 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3287 0, 0, ss, ss, AllPlanes, XYPixmap);
3289 if (strlen(appData.pixmapDirectory) == 0) {
3293 if (appData.monoMode) {
3294 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3298 fprintf(stderr, _("\nLoading XIMs...\n"));
3300 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3301 fprintf(stderr, "%d", piece+1);
3302 for (kind=0; kind<4; kind++) {
3303 fprintf(stderr, ".");
3304 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3305 ExpandPathName(appData.pixmapDirectory),
3306 piece <= (int) WhiteKing ? "" : "w",
3307 pieceBitmapNames[piece],
3309 ximPieceBitmap[kind][piece] =
3310 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3311 0, 0, ss, ss, AllPlanes, XYPixmap);
3312 if (appData.debugMode)
3313 fprintf(stderr, _("(File:%s:) "), buf);
3314 loadXIM(ximPieceBitmap[kind][piece],
3316 &(xpmPieceBitmap2[kind][piece]),
3317 &(ximMaskPm2[piece]));
3318 if(piece <= (int)WhiteKing)
3319 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3321 fprintf(stderr," ");
3323 /* Load light and dark squares */
3324 /* If the LSQ and DSQ pieces don't exist, we will
3325 draw them with solid squares. */
3326 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3327 if (access(buf, 0) != 0) {
3331 fprintf(stderr, _("light square "));
3333 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3334 0, 0, ss, ss, AllPlanes, XYPixmap);
3335 if (appData.debugMode)
3336 fprintf(stderr, _("(File:%s:) "), buf);
3338 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3339 fprintf(stderr, _("dark square "));
3340 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3341 ExpandPathName(appData.pixmapDirectory), ss);
3342 if (appData.debugMode)
3343 fprintf(stderr, _("(File:%s:) "), buf);
3345 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3346 0, 0, ss, ss, AllPlanes, XYPixmap);
3347 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3348 xpmJailSquare = xpmLightSquare;
3350 fprintf(stderr, _("Done.\n"));
3352 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3356 void CreateXPMPieces()
3360 u_int ss = squareSize;
3362 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3363 XpmColorSymbol symbols[4];
3365 /* The XSynchronize calls were copied from CreatePieces.
3366 Not sure if needed, but can't hurt */
3367 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3369 /* Setup translations so piece colors match square colors */
3370 symbols[0].name = "light_piece";
3371 symbols[0].value = appData.whitePieceColor;
3372 symbols[1].name = "dark_piece";
3373 symbols[1].value = appData.blackPieceColor;
3374 symbols[2].name = "light_square";
3375 symbols[2].value = appData.lightSquareColor;
3376 symbols[3].name = "dark_square";
3377 symbols[3].value = appData.darkSquareColor;
3379 attr.valuemask = XpmColorSymbols;
3380 attr.colorsymbols = symbols;
3381 attr.numsymbols = 4;
3383 if (appData.monoMode) {
3384 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3388 if (strlen(appData.pixmapDirectory) == 0) {
3389 XpmPieces* pieces = builtInXpms;
3392 while (pieces->size != squareSize && pieces->size) pieces++;
3393 if (!pieces->size) {
3394 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3397 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3398 for (kind=0; kind<4; kind++) {
3400 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3401 pieces->xpm[piece][kind],
3402 &(xpmPieceBitmap2[kind][piece]),
3403 NULL, &attr)) != 0) {
3404 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3408 if(piece <= (int) WhiteKing)
3409 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3413 xpmJailSquare = xpmLightSquare;
3417 fprintf(stderr, _("\nLoading XPMs...\n"));
3420 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3421 fprintf(stderr, "%d ", piece+1);
3422 for (kind=0; kind<4; kind++) {
3423 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3424 ExpandPathName(appData.pixmapDirectory),
3425 piece > (int) WhiteKing ? "w" : "",
3426 pieceBitmapNames[piece],
3428 if (appData.debugMode) {
3429 fprintf(stderr, _("(File:%s:) "), buf);
3431 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3432 &(xpmPieceBitmap2[kind][piece]),
3433 NULL, &attr)) != 0) {
3434 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3435 // [HGM] missing: read of unorthodox piece failed; substitute King.
3436 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3437 ExpandPathName(appData.pixmapDirectory),
3439 if (appData.debugMode) {
3440 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3442 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3443 &(xpmPieceBitmap2[kind][piece]),
3447 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3452 if(piece <= (int) WhiteKing)
3453 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3456 /* Load light and dark squares */
3457 /* If the LSQ and DSQ pieces don't exist, we will
3458 draw them with solid squares. */
3459 fprintf(stderr, _("light square "));
3460 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3461 if (access(buf, 0) != 0) {
3465 if (appData.debugMode)
3466 fprintf(stderr, _("(File:%s:) "), buf);
3468 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3469 &xpmLightSquare, NULL, &attr)) != 0) {
3470 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3473 fprintf(stderr, _("dark square "));
3474 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3475 ExpandPathName(appData.pixmapDirectory), ss);
3476 if (appData.debugMode) {
3477 fprintf(stderr, _("(File:%s:) "), buf);
3479 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3480 &xpmDarkSquare, NULL, &attr)) != 0) {
3481 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3485 xpmJailSquare = xpmLightSquare;
3486 fprintf(stderr, _("Done.\n"));
3488 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3491 #endif /* HAVE_LIBXPM */
3494 /* No built-in bitmaps */
3499 u_int ss = squareSize;
3501 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3504 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3505 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3506 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3507 pieceBitmapNames[piece],
3508 ss, kind == SOLID ? 's' : 'o');
3509 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3510 if(piece <= (int)WhiteKing)
3511 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3515 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3519 /* With built-in bitmaps */
3522 BuiltInBits* bib = builtInBits;
3525 u_int ss = squareSize;
3527 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3530 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3532 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3533 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3534 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3535 pieceBitmapNames[piece],
3536 ss, kind == SOLID ? 's' : 'o');
3537 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3538 bib->bits[kind][piece], ss, ss);
3539 if(piece <= (int)WhiteKing)
3540 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3544 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3549 void ReadBitmap(pm, name, bits, wreq, hreq)
3552 unsigned char bits[];
3558 char msg[MSG_SIZ], fullname[MSG_SIZ];
3560 if (*appData.bitmapDirectory != NULLCHAR) {
3561 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3562 strcat(fullname, "/");
3563 strcat(fullname, name);
3564 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3565 &w, &h, pm, &x_hot, &y_hot);
3566 fprintf(stderr, "load %s\n", name);
3567 if (errcode != BitmapSuccess) {
3569 case BitmapOpenFailed:
3570 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3572 case BitmapFileInvalid:
3573 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3575 case BitmapNoMemory:
3576 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3580 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3584 fprintf(stderr, _("%s: %s...using built-in\n"),
3586 } else if (w != wreq || h != hreq) {
3588 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3589 programName, fullname, w, h, wreq, hreq);
3595 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3604 if (lineGap == 0) return;
3606 /* [HR] Split this into 2 loops for non-square boards. */
3608 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3609 gridSegments[i].x1 = 0;
3610 gridSegments[i].x2 =
3611 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3612 gridSegments[i].y1 = gridSegments[i].y2
3613 = lineGap / 2 + (i * (squareSize + lineGap));
3616 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3617 gridSegments[j + i].y1 = 0;
3618 gridSegments[j + i].y2 =
3619 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3620 gridSegments[j + i].x1 = gridSegments[j + i].x2
3621 = lineGap / 2 + (j * (squareSize + lineGap));
3625 static void MenuBarSelect(w, addr, index)
3630 XtActionProc proc = (XtActionProc) addr;
3632 (proc)(NULL, NULL, NULL, NULL);
3635 void CreateMenuBarPopup(parent, name, mb)
3645 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3648 XtSetArg(args[j], XtNleftMargin, 20); j++;
3649 XtSetArg(args[j], XtNrightMargin, 20); j++;
3651 while (mi->string != NULL) {
3652 if (strcmp(mi->string, "----") == 0) {
3653 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3656 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3657 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3659 XtAddCallback(entry, XtNcallback,
3660 (XtCallbackProc) MenuBarSelect,
3661 (caddr_t) mi->proc);
3667 Widget CreateMenuBar(mb)
3671 Widget anchor, menuBar;
3673 char menuName[MSG_SIZ];
3676 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3677 XtSetArg(args[j], XtNvSpace, 0); j++;
3678 XtSetArg(args[j], XtNborderWidth, 0); j++;
3679 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3680 formWidget, args, j);
3682 while (mb->name != NULL) {
3683 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3684 strcat(menuName, mb->name);
3686 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3689 shortName[0] = _(mb->name)[0];
3690 shortName[1] = NULLCHAR;
3691 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3694 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3697 XtSetArg(args[j], XtNborderWidth, 0); j++;
3698 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3700 CreateMenuBarPopup(menuBar, menuName, mb);
3706 Widget CreateButtonBar(mi)
3710 Widget button, buttonBar;
3714 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3716 XtSetArg(args[j], XtNhSpace, 0); j++;
3718 XtSetArg(args[j], XtNborderWidth, 0); j++;
3719 XtSetArg(args[j], XtNvSpace, 0); j++;
3720 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3721 formWidget, args, j);
3723 while (mi->string != NULL) {
3726 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3727 XtSetArg(args[j], XtNborderWidth, 0); j++;
3729 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3730 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3731 buttonBar, args, j);
3732 XtAddCallback(button, XtNcallback,
3733 (XtCallbackProc) MenuBarSelect,
3734 (caddr_t) mi->proc);
3741 CreatePieceMenu(name, color)
3748 ChessSquare selection;
3750 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3751 boardWidget, args, 0);
3753 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3754 String item = pieceMenuStrings[color][i];
3756 if (strcmp(item, "----") == 0) {
3757 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3760 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3761 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3763 selection = pieceMenuTranslation[color][i];
3764 XtAddCallback(entry, XtNcallback,
3765 (XtCallbackProc) PieceMenuSelect,
3766 (caddr_t) selection);
3767 if (selection == WhitePawn || selection == BlackPawn) {
3768 XtSetArg(args[0], XtNpopupOnEntry, entry);
3769 XtSetValues(menu, args, 1);
3782 ChessSquare selection;
3784 whitePieceMenu = CreatePieceMenu("menuW", 0);
3785 blackPieceMenu = CreatePieceMenu("menuB", 1);
3787 XtRegisterGrabAction(PieceMenuPopup, True,
3788 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3789 GrabModeAsync, GrabModeAsync);
3791 XtSetArg(args[0], XtNlabel, _("Drop"));
3792 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3793 boardWidget, args, 1);
3794 for (i = 0; i < DROP_MENU_SIZE; i++) {
3795 String item = dropMenuStrings[i];
3797 if (strcmp(item, "----") == 0) {
3798 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3801 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3802 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3804 selection = dropMenuTranslation[i];
3805 XtAddCallback(entry, XtNcallback,
3806 (XtCallbackProc) DropMenuSelect,
3807 (caddr_t) selection);
3812 void SetupDropMenu()
3820 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3821 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3822 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3823 dmEnables[i].piece);
3824 XtSetSensitive(entry, p != NULL || !appData.testLegality
3825 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3826 && !appData.icsActive));
3828 while (p && *p++ == dmEnables[i].piece) count++;
3829 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3831 XtSetArg(args[j], XtNlabel, label); j++;
3832 XtSetValues(entry, args, j);
3836 void PieceMenuPopup(w, event, params, num_params)
3840 Cardinal *num_params;
3842 String whichMenu; int menuNr;
3843 if (event->type == ButtonRelease)
3844 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3845 else if (event->type == ButtonPress)
3846 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3848 case 0: whichMenu = params[0]; break;
3849 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3851 case -1: if (errorUp) ErrorPopDown();
3854 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3857 static void PieceMenuSelect(w, piece, junk)
3862 if (pmFromX < 0 || pmFromY < 0) return;
3863 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3866 static void DropMenuSelect(w, piece, junk)
3871 if (pmFromX < 0 || pmFromY < 0) return;
3872 DropMenuEvent(piece, pmFromX, pmFromY);
3875 void WhiteClock(w, event, prms, nprms)
3881 if (gameMode == EditPosition || gameMode == IcsExamining) {
3882 SetWhiteToPlayEvent();
3883 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3888 void BlackClock(w, event, prms, nprms)
3894 if (gameMode == EditPosition || gameMode == IcsExamining) {
3895 SetBlackToPlayEvent();
3896 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3903 * If the user selects on a border boundary, return -1; if off the board,
3904 * return -2. Otherwise map the event coordinate to the square.
3906 int EventToSquare(x, limit)
3914 if ((x % (squareSize + lineGap)) >= squareSize)
3916 x /= (squareSize + lineGap);
3922 static void do_flash_delay(msec)
3928 static void drawHighlight(file, rank, gc)
3934 if (lineGap == 0 || appData.blindfold) return;
3937 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3938 (squareSize + lineGap);
3939 y = lineGap/2 + rank * (squareSize + lineGap);
3941 x = lineGap/2 + file * (squareSize + lineGap);
3942 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3943 (squareSize + lineGap);
3946 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3947 squareSize+lineGap, squareSize+lineGap);
3950 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3951 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3954 SetHighlights(fromX, fromY, toX, toY)
3955 int fromX, fromY, toX, toY;
3957 if (hi1X != fromX || hi1Y != fromY) {
3958 if (hi1X >= 0 && hi1Y >= 0) {
3959 drawHighlight(hi1X, hi1Y, lineGC);
3961 } // [HGM] first erase both, then draw new!
3962 if (hi2X != toX || hi2Y != toY) {
3963 if (hi2X >= 0 && hi2Y >= 0) {
3964 drawHighlight(hi2X, hi2Y, lineGC);
3967 if (hi1X != fromX || hi1Y != fromY) {
3968 if (fromX >= 0 && fromY >= 0) {
3969 drawHighlight(fromX, fromY, highlineGC);
3972 if (hi2X != toX || hi2Y != toY) {
3973 if (toX >= 0 && toY >= 0) {
3974 drawHighlight(toX, toY, highlineGC);
3986 SetHighlights(-1, -1, -1, -1);
3991 SetPremoveHighlights(fromX, fromY, toX, toY)
3992 int fromX, fromY, toX, toY;
3994 if (pm1X != fromX || pm1Y != fromY) {
3995 if (pm1X >= 0 && pm1Y >= 0) {
3996 drawHighlight(pm1X, pm1Y, lineGC);
3998 if (fromX >= 0 && fromY >= 0) {
3999 drawHighlight(fromX, fromY, prelineGC);
4002 if (pm2X != toX || pm2Y != toY) {
4003 if (pm2X >= 0 && pm2Y >= 0) {
4004 drawHighlight(pm2X, pm2Y, lineGC);
4006 if (toX >= 0 && toY >= 0) {
4007 drawHighlight(toX, toY, prelineGC);
4017 ClearPremoveHighlights()
4019 SetPremoveHighlights(-1, -1, -1, -1);
4022 static void BlankSquare(x, y, color, piece, dest)
4027 if (useImages && useImageSqs) {
4031 pm = xpmLightSquare;
4036 case 2: /* neutral */
4041 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4042 squareSize, squareSize, x, y);
4052 case 2: /* neutral */
4057 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4062 I split out the routines to draw a piece so that I could
4063 make a generic flash routine.
4065 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4067 int square_color, x, y;
4070 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4071 switch (square_color) {
4073 case 2: /* neutral */
4075 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4076 ? *pieceToOutline(piece)
4077 : *pieceToSolid(piece),
4078 dest, bwPieceGC, 0, 0,
4079 squareSize, squareSize, x, y);
4082 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4083 ? *pieceToSolid(piece)
4084 : *pieceToOutline(piece),
4085 dest, wbPieceGC, 0, 0,
4086 squareSize, squareSize, x, y);
4091 static void monoDrawPiece(piece, square_color, x, y, dest)
4093 int square_color, x, y;
4096 switch (square_color) {
4098 case 2: /* neutral */
4100 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4101 ? *pieceToOutline(piece)
4102 : *pieceToSolid(piece),
4103 dest, bwPieceGC, 0, 0,
4104 squareSize, squareSize, x, y, 1);
4107 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4108 ? *pieceToSolid(piece)
4109 : *pieceToOutline(piece),
4110 dest, wbPieceGC, 0, 0,
4111 squareSize, squareSize, x, y, 1);
4116 static void colorDrawPiece(piece, square_color, x, y, dest)
4118 int square_color, x, y;
4121 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4122 switch (square_color) {
4124 XCopyPlane(xDisplay, *pieceToSolid(piece),
4125 dest, (int) piece < (int) BlackPawn
4126 ? wlPieceGC : blPieceGC, 0, 0,
4127 squareSize, squareSize, x, y, 1);
4130 XCopyPlane(xDisplay, *pieceToSolid(piece),
4131 dest, (int) piece < (int) BlackPawn
4132 ? wdPieceGC : bdPieceGC, 0, 0,
4133 squareSize, squareSize, x, y, 1);
4135 case 2: /* neutral */
4137 XCopyPlane(xDisplay, *pieceToSolid(piece),
4138 dest, (int) piece < (int) BlackPawn
4139 ? wjPieceGC : bjPieceGC, 0, 0,
4140 squareSize, squareSize, x, y, 1);
4145 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4147 int square_color, x, y;
4152 switch (square_color) {
4154 case 2: /* neutral */
4156 if ((int)piece < (int) BlackPawn) {
4164 if ((int)piece < (int) BlackPawn) {
4172 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4173 dest, wlPieceGC, 0, 0,
4174 squareSize, squareSize, x, y);
4177 typedef void (*DrawFunc)();
4179 DrawFunc ChooseDrawFunc()
4181 if (appData.monoMode) {
4182 if (DefaultDepth(xDisplay, xScreen) == 1) {
4183 return monoDrawPiece_1bit;
4185 return monoDrawPiece;
4189 return colorDrawPieceImage;
4191 return colorDrawPiece;
4195 /* [HR] determine square color depending on chess variant. */
4196 static int SquareColor(row, column)
4201 if (gameInfo.variant == VariantXiangqi) {
4202 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4204 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4206 } else if (row <= 4) {
4212 square_color = ((column + row) % 2) == 1;
4215 /* [hgm] holdings: next line makes all holdings squares light */
4216 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4218 return square_color;
4221 void DrawSquare(row, column, piece, do_flash)
4222 int row, column, do_flash;
4225 int square_color, x, y, direction, font_ascent, font_descent;
4228 XCharStruct overall;
4232 /* Calculate delay in milliseconds (2-delays per complete flash) */
4233 flash_delay = 500 / appData.flashRate;
4236 x = lineGap + ((BOARD_WIDTH-1)-column) *
4237 (squareSize + lineGap);
4238 y = lineGap + row * (squareSize + lineGap);
4240 x = lineGap + column * (squareSize + lineGap);
4241 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4242 (squareSize + lineGap);
4245 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4247 square_color = SquareColor(row, column);
4249 if ( // [HGM] holdings: blank out area between board and holdings
4250 column == BOARD_LEFT-1 || column == BOARD_RGHT
4251 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4252 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4253 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4255 // [HGM] print piece counts next to holdings
4256 string[1] = NULLCHAR;
4257 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4258 string[0] = '0' + piece;
4259 XTextExtents(countFontStruct, string, 1, &direction,
4260 &font_ascent, &font_descent, &overall);
4261 if (appData.monoMode) {
4262 XDrawImageString(xDisplay, xBoardWindow, countGC,
4263 x + squareSize - overall.width - 2,
4264 y + font_ascent + 1, string, 1);
4266 XDrawString(xDisplay, xBoardWindow, countGC,
4267 x + squareSize - overall.width - 2,
4268 y + font_ascent + 1, string, 1);
4271 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4272 string[0] = '0' + piece;
4273 XTextExtents(countFontStruct, string, 1, &direction,
4274 &font_ascent, &font_descent, &overall);
4275 if (appData.monoMode) {
4276 XDrawImageString(xDisplay, xBoardWindow, countGC,
4277 x + 2, y + font_ascent + 1, string, 1);
4279 XDrawString(xDisplay, xBoardWindow, countGC,
4280 x + 2, y + font_ascent + 1, string, 1);
4284 if (piece == EmptySquare || appData.blindfold) {
4285 BlankSquare(x, y, square_color, piece, xBoardWindow);
4287 drawfunc = ChooseDrawFunc();
4288 if (do_flash && appData.flashCount > 0) {
4289 for (i=0; i<appData.flashCount; ++i) {
4291 drawfunc(piece, square_color, x, y, xBoardWindow);
4292 XSync(xDisplay, False);
4293 do_flash_delay(flash_delay);
4295 BlankSquare(x, y, square_color, piece, xBoardWindow);
4296 XSync(xDisplay, False);
4297 do_flash_delay(flash_delay);
4300 drawfunc(piece, square_color, x, y, xBoardWindow);
4304 string[1] = NULLCHAR;
4305 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4306 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4307 string[0] = 'a' + column - BOARD_LEFT;
4308 XTextExtents(coordFontStruct, string, 1, &direction,
4309 &font_ascent, &font_descent, &overall);
4310 if (appData.monoMode) {
4311 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4312 x + squareSize - overall.width - 2,
4313 y + squareSize - font_descent - 1, string, 1);
4315 XDrawString(xDisplay, xBoardWindow, coordGC,
4316 x + squareSize - overall.width - 2,
4317 y + squareSize - font_descent - 1, string, 1);
4320 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4321 string[0] = ONE + row;
4322 XTextExtents(coordFontStruct, string, 1, &direction,
4323 &font_ascent, &font_descent, &overall);
4324 if (appData.monoMode) {
4325 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4326 x + 2, y + font_ascent + 1, string, 1);
4328 XDrawString(xDisplay, xBoardWindow, coordGC,
4329 x + 2, y + font_ascent + 1, string, 1);
4332 if(!partnerUp && marker[row][column]) {
4333 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4334 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4339 /* Why is this needed on some versions of X? */
4340 void EventProc(widget, unused, event)
4345 if (!XtIsRealized(widget))
4348 switch (event->type) {
4350 if (event->xexpose.count > 0) return; /* no clipping is done */
4351 XDrawPosition(widget, True, NULL);
4352 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4353 flipView = !flipView; partnerUp = !partnerUp;
4354 XDrawPosition(widget, True, NULL);
4355 flipView = !flipView; partnerUp = !partnerUp;
4359 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4366 void DrawPosition(fullRedraw, board)
4367 /*Boolean*/int fullRedraw;
4370 XDrawPosition(boardWidget, fullRedraw, board);
4373 /* Returns 1 if there are "too many" differences between b1 and b2
4374 (i.e. more than 1 move was made) */
4375 static int too_many_diffs(b1, b2)
4381 for (i=0; i<BOARD_HEIGHT; ++i) {
4382 for (j=0; j<BOARD_WIDTH; ++j) {
4383 if (b1[i][j] != b2[i][j]) {
4384 if (++c > 4) /* Castling causes 4 diffs */
4393 /* Matrix describing castling maneuvers */
4394 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4395 static int castling_matrix[4][5] = {
4396 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4397 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4398 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4399 { 7, 7, 4, 5, 6 } /* 0-0, black */
4402 /* Checks whether castling occurred. If it did, *rrow and *rcol
4403 are set to the destination (row,col) of the rook that moved.
4405 Returns 1 if castling occurred, 0 if not.
4407 Note: Only handles a max of 1 castling move, so be sure
4408 to call too_many_diffs() first.
4410 static int check_castle_draw(newb, oldb, rrow, rcol)
4417 /* For each type of castling... */
4418 for (i=0; i<4; ++i) {
4419 r = castling_matrix[i];
4421 /* Check the 4 squares involved in the castling move */
4423 for (j=1; j<=4; ++j) {
4424 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4431 /* All 4 changed, so it must be a castling move */
4440 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4441 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4443 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4446 void DrawSeekBackground( int left, int top, int right, int bottom )
4448 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4451 void DrawSeekText(char *buf, int x, int y)
4453 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4456 void DrawSeekDot(int x, int y, int colorNr)
4458 int square = colorNr & 0x80;
4461 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4463 XFillRectangle(xDisplay, xBoardWindow, color,
4464 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4466 XFillArc(xDisplay, xBoardWindow, color,
4467 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4470 static int damage[2][BOARD_RANKS][BOARD_FILES];
4473 * event handler for redrawing the board
4475 void XDrawPosition(w, repaint, board)
4477 /*Boolean*/int repaint;
4481 static int lastFlipView = 0;
4482 static int lastBoardValid[2] = {0, 0};
4483 static Board lastBoard[2];
4486 int nr = twoBoards*partnerUp;
4488 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4490 if (board == NULL) {
4491 if (!lastBoardValid) return;
4492 board = lastBoard[nr];
4494 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4495 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4496 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4501 * It would be simpler to clear the window with XClearWindow()
4502 * but this causes a very distracting flicker.
4505 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4507 /* If too much changes (begin observing new game, etc.), don't
4509 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4511 /* Special check for castling so we don't flash both the king
4512 and the rook (just flash the king). */
4514 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4515 /* Draw rook with NO flashing. King will be drawn flashing later */
4516 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4517 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4521 /* First pass -- Draw (newly) empty squares and repair damage.
4522 This prevents you from having a piece show up twice while it
4523 is flashing on its new square */
4524 for (i = 0; i < BOARD_HEIGHT; i++)
4525 for (j = 0; j < BOARD_WIDTH; j++)
4526 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4527 || damage[nr][i][j]) {
4528 DrawSquare(i, j, board[i][j], 0);
4529 damage[nr][i][j] = False;
4532 /* Second pass -- Draw piece(s) in new position and flash them */
4533 for (i = 0; i < BOARD_HEIGHT; i++)
4534 for (j = 0; j < BOARD_WIDTH; j++)
4535 if (board[i][j] != lastBoard[nr][i][j]) {
4536 DrawSquare(i, j, board[i][j], do_flash);
4540 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4541 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4542 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4544 for (i = 0; i < BOARD_HEIGHT; i++)
4545 for (j = 0; j < BOARD_WIDTH; j++) {
4546 DrawSquare(i, j, board[i][j], 0);
4547 damage[nr][i][j] = False;
4551 CopyBoard(lastBoard[nr], board);
4552 lastBoardValid[nr] = 1;
4553 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4554 lastFlipView = flipView;
4556 /* Draw highlights */
4557 if (pm1X >= 0 && pm1Y >= 0) {
4558 drawHighlight(pm1X, pm1Y, prelineGC);
4560 if (pm2X >= 0 && pm2Y >= 0) {
4561 drawHighlight(pm2X, pm2Y, prelineGC);
4563 if (hi1X >= 0 && hi1Y >= 0) {
4564 drawHighlight(hi1X, hi1Y, highlineGC);
4566 if (hi2X >= 0 && hi2Y >= 0) {
4567 drawHighlight(hi2X, hi2Y, highlineGC);
4570 /* If piece being dragged around board, must redraw that too */
4573 XSync(xDisplay, False);
4578 * event handler for redrawing the board
4580 void DrawPositionProc(w, event, prms, nprms)
4586 XDrawPosition(w, True, NULL);
4591 * event handler for parsing user moves
4593 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4594 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4595 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4596 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4597 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4598 // and at the end FinishMove() to perform the move after optional promotion popups.
4599 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4600 void HandleUserMove(w, event, prms, nprms)
4606 if (w != boardWidget || errorExitStatus != -1) return;
4609 if (event->type == ButtonPress) {
4610 XtPopdown(promotionShell);
4611 XtDestroyWidget(promotionShell);
4612 promotionUp = False;
4620 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4621 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4622 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4625 void AnimateUserMove (Widget w, XEvent * event,
4626 String * params, Cardinal * nParams)
4628 DragPieceMove(event->xmotion.x, event->xmotion.y);
4631 void HandlePV (Widget w, XEvent * event,
4632 String * params, Cardinal * nParams)
4633 { // [HGM] pv: walk PV
4634 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4637 Widget CommentCreate(name, text, mutable, callback, lines)
4639 int /*Boolean*/ mutable;
4640 XtCallbackProc callback;
4644 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4649 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4650 XtGetValues(boardWidget, args, j);
4653 XtSetArg(args[j], XtNresizable, True); j++;
4656 XtCreatePopupShell(name, topLevelShellWidgetClass,
4657 shellWidget, args, j);
4660 XtCreatePopupShell(name, transientShellWidgetClass,
4661 shellWidget, args, j);
4664 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4665 layoutArgs, XtNumber(layoutArgs));
4667 XtCreateManagedWidget("form", formWidgetClass, layout,
4668 formArgs, XtNumber(formArgs));
4672 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4673 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4675 XtSetArg(args[j], XtNstring, text); j++;
4676 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4677 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4678 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4679 XtSetArg(args[j], XtNright, XtChainRight); j++;
4680 XtSetArg(args[j], XtNresizable, True); j++;
4681 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4682 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4683 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4684 XtSetArg(args[j], XtNautoFill, True); j++;
4685 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4687 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4688 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4692 XtSetArg(args[j], XtNfromVert, edit); j++;
4693 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4694 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4695 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4696 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4698 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4699 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4702 XtSetArg(args[j], XtNfromVert, edit); j++;
4703 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4704 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4705 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4706 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4707 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4709 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4710 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4713 XtSetArg(args[j], XtNfromVert, edit); j++;
4714 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4715 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4716 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4717 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4718 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4720 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4721 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4724 XtSetArg(args[j], XtNfromVert, edit); j++;
4725 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4726 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4727 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4728 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4730 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4731 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4734 XtSetArg(args[j], XtNfromVert, edit); j++;
4735 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4736 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4737 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4738 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4739 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4741 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4742 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4745 XtRealizeWidget(shell);
4747 if (commentX == -1) {
4750 Dimension pw_height;
4751 Dimension ew_height;
4754 XtSetArg(args[j], XtNheight, &ew_height); j++;
4755 XtGetValues(edit, args, j);
4758 XtSetArg(args[j], XtNheight, &pw_height); j++;
4759 XtGetValues(shell, args, j);
4760 commentH = pw_height + (lines - 1) * ew_height;
4761 commentW = bw_width - 16;
4763 XSync(xDisplay, False);
4765 /* This code seems to tickle an X bug if it is executed too soon
4766 after xboard starts up. The coordinates get transformed as if
4767 the main window was positioned at (0, 0).
4769 XtTranslateCoords(shellWidget,
4770 (bw_width - commentW) / 2, 0 - commentH / 2,
4771 &commentX, &commentY);
4773 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4774 RootWindowOfScreen(XtScreen(shellWidget)),
4775 (bw_width - commentW) / 2, 0 - commentH / 2,
4780 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4783 if(wpComment.width > 0) {
4784 commentX = wpComment.x;
4785 commentY = wpComment.y;
4786 commentW = wpComment.width;
4787 commentH = wpComment.height;
4791 XtSetArg(args[j], XtNheight, commentH); j++;
4792 XtSetArg(args[j], XtNwidth, commentW); j++;
4793 XtSetArg(args[j], XtNx, commentX); j++;
4794 XtSetArg(args[j], XtNy, commentY); j++;
4795 XtSetValues(shell, args, j);
4796 XtSetKeyboardFocus(shell, edit);
4801 /* Used for analysis window and ICS input window */
4802 Widget MiscCreate(name, text, mutable, callback, lines)
4804 int /*Boolean*/ mutable;
4805 XtCallbackProc callback;
4809 Widget shell, layout, form, edit;
4811 Dimension bw_width, pw_height, ew_height, w, h;
4817 XtSetArg(args[j], XtNresizable, True); j++;
4820 XtCreatePopupShell(name, topLevelShellWidgetClass,
4821 shellWidget, args, j);
4824 XtCreatePopupShell(name, transientShellWidgetClass,
4825 shellWidget, args, j);
4828 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4829 layoutArgs, XtNumber(layoutArgs));
4831 XtCreateManagedWidget("form", formWidgetClass, layout,
4832 formArgs, XtNumber(formArgs));
4836 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4837 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4839 XtSetArg(args[j], XtNstring, text); j++;
4840 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4841 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4842 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4843 XtSetArg(args[j], XtNright, XtChainRight); j++;
4844 XtSetArg(args[j], XtNresizable, True); j++;
4845 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4846 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4847 XtSetArg(args[j], XtNautoFill, True); j++;
4848 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4850 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4852 XtRealizeWidget(shell);
4855 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4856 XtGetValues(boardWidget, args, j);
4859 XtSetArg(args[j], XtNheight, &ew_height); j++;
4860 XtGetValues(edit, args, j);
4863 XtSetArg(args[j], XtNheight, &pw_height); j++;
4864 XtGetValues(shell, args, j);
4865 h = pw_height + (lines - 1) * ew_height;
4868 XSync(xDisplay, False);
4870 /* This code seems to tickle an X bug if it is executed too soon
4871 after xboard starts up. The coordinates get transformed as if
4872 the main window was positioned at (0, 0).
4874 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4876 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4877 RootWindowOfScreen(XtScreen(shellWidget)),
4878 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4882 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4885 XtSetArg(args[j], XtNheight, h); j++;
4886 XtSetArg(args[j], XtNwidth, w); j++;
4887 XtSetArg(args[j], XtNx, x); j++;
4888 XtSetArg(args[j], XtNy, y); j++;
4889 XtSetValues(shell, args, j);
4895 static int savedIndex; /* gross that this is global */
4897 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4900 XawTextPosition index, dummy;
4903 XawTextGetSelectionPos(w, &index, &dummy);
4904 XtSetArg(arg, XtNstring, &val);
4905 XtGetValues(w, &arg, 1);
4906 ReplaceComment(savedIndex, val);
4907 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4908 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4911 void EditCommentPopUp(index, title, text)
4920 if (text == NULL) text = "";
4922 if (editShell == NULL) {
4924 CommentCreate(title, text, True, EditCommentCallback, 4);
4925 XtRealizeWidget(editShell);
4926 CatchDeleteWindow(editShell, "EditCommentPopDown");
4928 edit = XtNameToWidget(editShell, "*form.text");
4930 XtSetArg(args[j], XtNstring, text); j++;
4931 XtSetValues(edit, args, j);
4933 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4934 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4935 XtSetValues(editShell, args, j);
4938 XtPopup(editShell, XtGrabNone);
4942 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4943 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4947 void EditCommentCallback(w, client_data, call_data)
4949 XtPointer client_data, call_data;
4957 XtSetArg(args[j], XtNlabel, &name); j++;
4958 XtGetValues(w, args, j);
4960 if (strcmp(name, _("ok")) == 0) {
4961 edit = XtNameToWidget(editShell, "*form.text");
4963 XtSetArg(args[j], XtNstring, &val); j++;
4964 XtGetValues(edit, args, j);
4965 ReplaceComment(savedIndex, val);
4966 EditCommentPopDown();
4967 } else if (strcmp(name, _("cancel")) == 0) {
4968 EditCommentPopDown();
4969 } else if (strcmp(name, _("clear")) == 0) {
4970 edit = XtNameToWidget(editShell, "*form.text");
4971 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4972 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4976 void EditCommentPopDown()
4981 if (!editUp) return;
4983 XtSetArg(args[j], XtNx, &commentX); j++;
4984 XtSetArg(args[j], XtNy, &commentY); j++;
4985 XtSetArg(args[j], XtNheight, &commentH); j++;
4986 XtSetArg(args[j], XtNwidth, &commentW); j++;
4987 XtGetValues(editShell, args, j);
4988 XtPopdown(editShell);
4991 XtSetArg(args[j], XtNleftBitmap, None); j++;
4992 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4996 void ICSInputBoxPopUp()
5001 char *title = _("ICS Input");
5004 if (ICSInputShell == NULL) {
5005 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5006 tr = XtParseTranslationTable(ICSInputTranslations);
5007 edit = XtNameToWidget(ICSInputShell, "*form.text");
5008 XtOverrideTranslations(edit, tr);
5009 XtRealizeWidget(ICSInputShell);
5010 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5013 edit = XtNameToWidget(ICSInputShell, "*form.text");
5015 XtSetArg(args[j], XtNstring, ""); j++;
5016 XtSetValues(edit, args, j);
5018 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5019 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5020 XtSetValues(ICSInputShell, args, j);
5023 XtPopup(ICSInputShell, XtGrabNone);
5024 XtSetKeyboardFocus(ICSInputShell, edit);
5026 ICSInputBoxUp = True;
5028 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5029 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5033 void ICSInputSendText()
5040 edit = XtNameToWidget(ICSInputShell, "*form.text");
5042 XtSetArg(args[j], XtNstring, &val); j++;
5043 XtGetValues(edit, args, j);
5045 SendMultiLineToICS(val);
5046 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5047 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5050 void ICSInputBoxPopDown()
5055 if (!ICSInputBoxUp) return;
5057 XtPopdown(ICSInputShell);
5058 ICSInputBoxUp = False;
5060 XtSetArg(args[j], XtNleftBitmap, None); j++;
5061 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5065 void CommentPopUp(title, text)
5072 savedIndex = currentMove; // [HGM] vari
5073 if (commentShell == NULL) {
5075 CommentCreate(title, text, False, CommentCallback, 4);
5076 XtRealizeWidget(commentShell);
5077 CatchDeleteWindow(commentShell, "CommentPopDown");
5079 edit = XtNameToWidget(commentShell, "*form.text");
5081 XtSetArg(args[j], XtNstring, text); j++;
5082 XtSetValues(edit, args, j);
5084 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5085 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5086 XtSetValues(commentShell, args, j);
5089 XtPopup(commentShell, XtGrabNone);
5090 XSync(xDisplay, False);
5095 void CommentCallback(w, client_data, call_data)
5097 XtPointer client_data, call_data;
5104 XtSetArg(args[j], XtNlabel, &name); j++;
5105 XtGetValues(w, args, j);
5107 if (strcmp(name, _("close")) == 0) {
5109 } else if (strcmp(name, _("edit")) == 0) {
5116 void CommentPopDown()
5121 if (!commentUp) return;
5123 XtSetArg(args[j], XtNx, &commentX); j++;
5124 XtSetArg(args[j], XtNy, &commentY); j++;
5125 XtSetArg(args[j], XtNwidth, &commentW); j++;
5126 XtSetArg(args[j], XtNheight, &commentH); j++;
5127 XtGetValues(commentShell, args, j);
5128 XtPopdown(commentShell);
5129 XSync(xDisplay, False);
5133 void FileNamePopUp(label, def, proc, openMode)
5140 Widget popup, layout, dialog, edit;
5146 fileProc = proc; /* I can't see a way not */
5147 fileOpenMode = openMode; /* to use globals here */
5148 { // [HGM] use file-selector dialog stolen from Ghostview
5150 int index; // this is not supported yet
5152 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5153 def, openMode, NULL, &name))
5154 (void) (*fileProc)(f, index=0, name);
5158 void FileNamePopDown()
5160 if (!filenameUp) return;
5161 XtPopdown(fileNameShell);
5162 XtDestroyWidget(fileNameShell);
5167 void FileNameCallback(w, client_data, call_data)
5169 XtPointer client_data, call_data;
5174 XtSetArg(args[0], XtNlabel, &name);
5175 XtGetValues(w, args, 1);
5177 if (strcmp(name, _("cancel")) == 0) {
5182 FileNameAction(w, NULL, NULL, NULL);
5185 void FileNameAction(w, event, prms, nprms)
5197 name = XawDialogGetValueString(w = XtParent(w));
5199 if ((name != NULL) && (*name != NULLCHAR)) {
5200 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5201 XtPopdown(w = XtParent(XtParent(w)));
5205 p = strrchr(buf, ' ');
5212 fullname = ExpandPathName(buf);
5214 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5217 f = fopen(fullname, fileOpenMode);
5219 DisplayError(_("Failed to open file"), errno);
5221 (void) (*fileProc)(f, index, buf);
5228 XtPopdown(w = XtParent(XtParent(w)));
5234 void PromotionPopUp()
5237 Widget dialog, layout;
5239 Dimension bw_width, pw_width;
5243 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5244 XtGetValues(boardWidget, args, j);
5247 XtSetArg(args[j], XtNresizable, True); j++;
5248 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5250 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5251 shellWidget, args, j);
5253 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5254 layoutArgs, XtNumber(layoutArgs));
5257 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5258 XtSetArg(args[j], XtNborderWidth, 0); j++;
5259 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5262 if(gameInfo.variant != VariantShogi) {
5263 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5264 (XtPointer) dialog);
5265 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5266 (XtPointer) dialog);
5267 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5268 (XtPointer) dialog);
5269 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5270 (XtPointer) dialog);
5271 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5272 gameInfo.variant == VariantGiveaway) {
5273 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5274 (XtPointer) dialog);
5276 if(gameInfo.variant == VariantCapablanca ||
5277 gameInfo.variant == VariantGothic ||
5278 gameInfo.variant == VariantCapaRandom) {
5279 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5280 (XtPointer) dialog);
5281 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5282 (XtPointer) dialog);
5284 } else // [HGM] shogi
5286 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5287 (XtPointer) dialog);
5288 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5289 (XtPointer) dialog);
5291 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5292 (XtPointer) dialog);
5294 XtRealizeWidget(promotionShell);
5295 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5298 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5299 XtGetValues(promotionShell, args, j);
5301 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5302 lineGap + squareSize/3 +
5303 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5304 0 : 6*(squareSize + lineGap)), &x, &y);
5307 XtSetArg(args[j], XtNx, x); j++;
5308 XtSetArg(args[j], XtNy, y); j++;
5309 XtSetValues(promotionShell, args, j);
5311 XtPopup(promotionShell, XtGrabNone);
5316 void PromotionPopDown()
5318 if (!promotionUp) return;
5319 XtPopdown(promotionShell);
5320 XtDestroyWidget(promotionShell);
5321 promotionUp = False;
5324 void PromotionCallback(w, client_data, call_data)
5326 XtPointer client_data, call_data;
5332 XtSetArg(args[0], XtNlabel, &name);
5333 XtGetValues(w, args, 1);
5337 if (fromX == -1) return;
5339 if (strcmp(name, _("cancel")) == 0) {
5343 } else if (strcmp(name, _("Knight")) == 0) {
5345 } else if (strcmp(name, _("Promote")) == 0) {
5347 } else if (strcmp(name, _("Defer")) == 0) {
5350 promoChar = ToLower(name[0]);
5353 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5355 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5356 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5361 void ErrorCallback(w, client_data, call_data)
5363 XtPointer client_data, call_data;
5366 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5368 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5374 if (!errorUp) return;
5376 XtPopdown(errorShell);
5377 XtDestroyWidget(errorShell);
5378 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5381 void ErrorPopUp(title, label, modal)
5382 char *title, *label;
5386 Widget dialog, layout;
5390 Dimension bw_width, pw_width;
5391 Dimension pw_height;
5395 XtSetArg(args[i], XtNresizable, True); i++;
5396 XtSetArg(args[i], XtNtitle, title); i++;
5398 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5399 shellWidget, args, i);
5401 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5402 layoutArgs, XtNumber(layoutArgs));
5405 XtSetArg(args[i], XtNlabel, label); i++;
5406 XtSetArg(args[i], XtNborderWidth, 0); i++;
5407 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5410 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5412 XtRealizeWidget(errorShell);
5413 CatchDeleteWindow(errorShell, "ErrorPopDown");
5416 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5417 XtGetValues(boardWidget, args, i);
5419 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5420 XtSetArg(args[i], XtNheight, &pw_height); i++;
5421 XtGetValues(errorShell, args, i);
5424 /* This code seems to tickle an X bug if it is executed too soon
5425 after xboard starts up. The coordinates get transformed as if
5426 the main window was positioned at (0, 0).
5428 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5429 0 - pw_height + squareSize / 3, &x, &y);
5431 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5432 RootWindowOfScreen(XtScreen(boardWidget)),
5433 (bw_width - pw_width) / 2,
5434 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5438 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5441 XtSetArg(args[i], XtNx, x); i++;
5442 XtSetArg(args[i], XtNy, y); i++;
5443 XtSetValues(errorShell, args, i);
5446 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5449 /* Disable all user input other than deleting the window */
5450 static int frozen = 0;
5454 /* Grab by a widget that doesn't accept input */
5455 XtAddGrab(messageWidget, TRUE, FALSE);
5459 /* Undo a FreezeUI */
5462 if (!frozen) return;
5463 XtRemoveGrab(messageWidget);
5467 char *ModeToWidgetName(mode)
5471 case BeginningOfGame:
5472 if (appData.icsActive)
5473 return "menuMode.ICS Client";
5474 else if (appData.noChessProgram ||
5475 *appData.cmailGameName != NULLCHAR)
5476 return "menuMode.Edit Game";
5478 return "menuMode.Machine Black";
5479 case MachinePlaysBlack:
5480 return "menuMode.Machine Black";
5481 case MachinePlaysWhite:
5482 return "menuMode.Machine White";
5484 return "menuMode.Analysis Mode";
5486 return "menuMode.Analyze File";
5487 case TwoMachinesPlay:
5488 return "menuMode.Two Machines";
5490 return "menuMode.Edit Game";
5491 case PlayFromGameFile:
5492 return "menuFile.Load Game";
5494 return "menuMode.Edit Position";
5496 return "menuMode.Training";
5497 case IcsPlayingWhite:
5498 case IcsPlayingBlack:
5502 return "menuMode.ICS Client";
5509 void ModeHighlight()
5512 static int oldPausing = FALSE;
5513 static GameMode oldmode = (GameMode) -1;
5516 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5518 if (pausing != oldPausing) {
5519 oldPausing = pausing;
5521 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5523 XtSetArg(args[0], XtNleftBitmap, None);
5525 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5528 if (appData.showButtonBar) {
5529 /* Always toggle, don't set. Previous code messes up when
5530 invoked while the button is pressed, as releasing it
5531 toggles the state again. */
5534 XtSetArg(args[0], XtNbackground, &oldbg);
5535 XtSetArg(args[1], XtNforeground, &oldfg);
5536 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5538 XtSetArg(args[0], XtNbackground, oldfg);
5539 XtSetArg(args[1], XtNforeground, oldbg);
5541 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5545 wname = ModeToWidgetName(oldmode);
5546 if (wname != NULL) {
5547 XtSetArg(args[0], XtNleftBitmap, None);
5548 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5550 wname = ModeToWidgetName(gameMode);
5551 if (wname != NULL) {
5552 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5553 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5557 /* Maybe all the enables should be handled here, not just this one */
5558 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5559 gameMode == Training || gameMode == PlayFromGameFile);
5564 * Button/menu procedures
5566 void ResetProc(w, event, prms, nprms)
5575 int LoadGamePopUp(f, gameNumber, title)
5580 cmailMsgLoaded = FALSE;
5581 if (gameNumber == 0) {
5582 int error = GameListBuild(f);
5584 DisplayError(_("Cannot build game list"), error);
5585 } else if (!ListEmpty(&gameList) &&
5586 ((ListGame *) gameList.tailPred)->number > 1) {
5587 GameListPopUp(f, title);
5593 return LoadGame(f, gameNumber, title, FALSE);
5596 void LoadGameProc(w, event, prms, nprms)
5602 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5605 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5608 void LoadNextGameProc(w, event, prms, nprms)
5617 void LoadPrevGameProc(w, event, prms, nprms)
5626 void ReloadGameProc(w, event, prms, nprms)
5635 void LoadNextPositionProc(w, event, prms, nprms)
5644 void LoadPrevPositionProc(w, event, prms, nprms)
5653 void ReloadPositionProc(w, event, prms, nprms)
5662 void LoadPositionProc(w, event, prms, nprms)
5668 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5671 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5674 void SaveGameProc(w, event, prms, nprms)
5680 FileNamePopUp(_("Save game file name?"),
5681 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5685 void SavePositionProc(w, event, prms, nprms)
5691 FileNamePopUp(_("Save position file name?"),
5692 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5696 void ReloadCmailMsgProc(w, event, prms, nprms)
5702 ReloadCmailMsgEvent(FALSE);
5705 void MailMoveProc(w, event, prms, nprms)
5714 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5715 char *selected_fen_position=NULL;
5718 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5719 Atom *type_return, XtPointer *value_return,
5720 unsigned long *length_return, int *format_return)
5722 char *selection_tmp;
5724 if (!selected_fen_position) return False; /* should never happen */
5725 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5726 /* note: since no XtSelectionDoneProc was registered, Xt will
5727 * automatically call XtFree on the value returned. So have to
5728 * make a copy of it allocated with XtMalloc */
5729 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5730 safeStrCpy(selection_tmp, selected_fen_position, sizeof(selection_tmp)/sizeof(selection_tmp[0]) );
5732 *value_return=selection_tmp;
5733 *length_return=strlen(selection_tmp);
5734 *type_return=*target;
5735 *format_return = 8; /* bits per byte */
5737 } else if (*target == XA_TARGETS(xDisplay)) {
5738 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5739 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5740 targets_tmp[1] = XA_STRING;
5741 *value_return = targets_tmp;
5742 *type_return = XA_ATOM;
5744 *format_return = 8 * sizeof(Atom);
5745 if (*format_return > 32) {
5746 *length_return *= *format_return / 32;
5747 *format_return = 32;
5755 /* note: when called from menu all parameters are NULL, so no clue what the
5756 * Widget which was clicked on was, or what the click event was
5758 void CopyPositionProc(w, event, prms, nprms)
5765 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5766 * have a notion of a position that is selected but not copied.
5767 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5769 if(gameMode == EditPosition) EditPositionDone(TRUE);
5770 if (selected_fen_position) free(selected_fen_position);
5771 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5772 if (!selected_fen_position) return;
5773 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5775 SendPositionSelection,
5776 NULL/* lose_ownership_proc */ ,
5777 NULL/* transfer_done_proc */);
5778 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5780 SendPositionSelection,
5781 NULL/* lose_ownership_proc */ ,
5782 NULL/* transfer_done_proc */);
5785 /* function called when the data to Paste is ready */
5787 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5788 Atom *type, XtPointer value, unsigned long *len, int *format)
5791 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5792 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5793 EditPositionPasteFEN(fenstr);
5797 /* called when Paste Position button is pressed,
5798 * all parameters will be NULL */
5799 void PastePositionProc(w, event, prms, nprms)
5805 XtGetSelectionValue(menuBarWidget,
5806 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5807 /* (XtSelectionCallbackProc) */ PastePositionCB,
5808 NULL, /* client_data passed to PastePositionCB */
5810 /* better to use the time field from the event that triggered the
5811 * call to this function, but that isn't trivial to get
5819 SendGameSelection(Widget w, Atom *selection, Atom *target,
5820 Atom *type_return, XtPointer *value_return,
5821 unsigned long *length_return, int *format_return)
5823 char *selection_tmp;
5825 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5826 FILE* f = fopen(gameCopyFilename, "r");
5829 if (f == NULL) return False;
5833 selection_tmp = XtMalloc(len + 1);
5834 count = fread(selection_tmp, 1, len, f);
5836 XtFree(selection_tmp);
5839 selection_tmp[len] = NULLCHAR;
5840 *value_return = selection_tmp;
5841 *length_return = len;
5842 *type_return = *target;
5843 *format_return = 8; /* bits per byte */
5845 } else if (*target == XA_TARGETS(xDisplay)) {
5846 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5847 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5848 targets_tmp[1] = XA_STRING;
5849 *value_return = targets_tmp;
5850 *type_return = XA_ATOM;
5852 *format_return = 8 * sizeof(Atom);
5853 if (*format_return > 32) {
5854 *length_return *= *format_return / 32;
5855 *format_return = 32;
5863 /* note: when called from menu all parameters are NULL, so no clue what the
5864 * Widget which was clicked on was, or what the click event was
5866 void CopyGameProc(w, event, prms, nprms)
5874 ret = SaveGameToFile(gameCopyFilename, FALSE);
5878 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5879 * have a notion of a game that is selected but not copied.
5880 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5882 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5885 NULL/* lose_ownership_proc */ ,
5886 NULL/* transfer_done_proc */);
5887 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5890 NULL/* lose_ownership_proc */ ,
5891 NULL/* transfer_done_proc */);
5894 /* function called when the data to Paste is ready */
5896 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5897 Atom *type, XtPointer value, unsigned long *len, int *format)
5900 if (value == NULL || *len == 0) {
5901 return; /* nothing had been selected to copy */
5903 f = fopen(gamePasteFilename, "w");
5905 DisplayError(_("Can't open temp file"), errno);
5908 fwrite(value, 1, *len, f);
5911 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5914 /* called when Paste Game button is pressed,
5915 * all parameters will be NULL */
5916 void PasteGameProc(w, event, prms, nprms)
5922 XtGetSelectionValue(menuBarWidget,
5923 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5924 /* (XtSelectionCallbackProc) */ PasteGameCB,
5925 NULL, /* client_data passed to PasteGameCB */
5927 /* better to use the time field from the event that triggered the
5928 * call to this function, but that isn't trivial to get
5938 SaveGameProc(NULL, NULL, NULL, NULL);
5942 void QuitProc(w, event, prms, nprms)
5951 void PauseProc(w, event, prms, nprms)
5961 void MachineBlackProc(w, event, prms, nprms)
5967 MachineBlackEvent();
5970 void MachineWhiteProc(w, event, prms, nprms)
5976 MachineWhiteEvent();
5979 void AnalyzeModeProc(w, event, prms, nprms)
5987 if (!first.analysisSupport) {
5988 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5989 DisplayError(buf, 0);
5992 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5993 if (appData.icsActive) {
5994 if (gameMode != IcsObserving) {
5995 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5996 DisplayError(buf, 0);
5998 if (appData.icsEngineAnalyze) {
5999 if (appData.debugMode)
6000 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6006 /* if enable, use want disable icsEngineAnalyze */
6007 if (appData.icsEngineAnalyze) {
6012 appData.icsEngineAnalyze = TRUE;
6013 if (appData.debugMode)
6014 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6016 if (!appData.showThinking)
6017 ShowThinkingProc(w,event,prms,nprms);
6022 void AnalyzeFileProc(w, event, prms, nprms)
6028 if (!first.analysisSupport) {
6030 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6031 DisplayError(buf, 0);
6036 if (!appData.showThinking)
6037 ShowThinkingProc(w,event,prms,nprms);
6040 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6041 AnalysisPeriodicEvent(1);
6044 void TwoMachinesProc(w, event, prms, nprms)
6053 void IcsClientProc(w, event, prms, nprms)
6062 void EditGameProc(w, event, prms, nprms)
6071 void EditPositionProc(w, event, prms, nprms)
6077 EditPositionEvent();
6080 void TrainingProc(w, event, prms, nprms)
6089 void EditCommentProc(w, event, prms, nprms)
6096 EditCommentPopDown();
6102 void IcsInputBoxProc(w, event, prms, nprms)
6108 if (ICSInputBoxUp) {
6109 ICSInputBoxPopDown();
6115 void AcceptProc(w, event, prms, nprms)
6124 void DeclineProc(w, event, prms, nprms)
6133 void RematchProc(w, event, prms, nprms)
6142 void CallFlagProc(w, event, prms, nprms)
6151 void DrawProc(w, event, prms, nprms)
6160 void AbortProc(w, event, prms, nprms)
6169 void AdjournProc(w, event, prms, nprms)
6178 void ResignProc(w, event, prms, nprms)
6187 void AdjuWhiteProc(w, event, prms, nprms)
6193 UserAdjudicationEvent(+1);
6196 void AdjuBlackProc(w, event, prms, nprms)
6202 UserAdjudicationEvent(-1);
6205 void AdjuDrawProc(w, event, prms, nprms)
6211 UserAdjudicationEvent(0);
6214 void EnterKeyProc(w, event, prms, nprms)
6220 if (ICSInputBoxUp == True)
6224 void UpKeyProc(w, event, prms, nprms)
6229 { // [HGM] input: let up-arrow recall previous line from history
6236 if (!ICSInputBoxUp) return;
6237 edit = XtNameToWidget(ICSInputShell, "*form.text");
6239 XtSetArg(args[j], XtNstring, &val); j++;
6240 XtGetValues(edit, args, j);
6241 val = PrevInHistory(val);
6242 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6243 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6245 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6246 XawTextReplace(edit, 0, 0, &t);
6247 XawTextSetInsertionPoint(edit, 9999);
6251 void DownKeyProc(w, event, prms, nprms)
6256 { // [HGM] input: let down-arrow recall next line from history
6261 if (!ICSInputBoxUp) return;
6262 edit = XtNameToWidget(ICSInputShell, "*form.text");
6263 val = NextInHistory();
6264 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6265 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6267 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6268 XawTextReplace(edit, 0, 0, &t);
6269 XawTextSetInsertionPoint(edit, 9999);
6273 void StopObservingProc(w, event, prms, nprms)
6279 StopObservingEvent();
6282 void StopExaminingProc(w, event, prms, nprms)
6288 StopExaminingEvent();
6291 void UploadProc(w, event, prms, nprms)
6301 void ForwardProc(w, event, prms, nprms)
6311 void BackwardProc(w, event, prms, nprms)
6320 void ToStartProc(w, event, prms, nprms)
6329 void ToEndProc(w, event, prms, nprms)
6338 void RevertProc(w, event, prms, nprms)
6347 void AnnotateProc(w, event, prms, nprms)
6356 void TruncateGameProc(w, event, prms, nprms)
6362 TruncateGameEvent();
6364 void RetractMoveProc(w, event, prms, nprms)
6373 void MoveNowProc(w, event, prms, nprms)
6383 void AlwaysQueenProc(w, event, prms, nprms)
6391 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6393 if (appData.alwaysPromoteToQueen) {
6394 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6396 XtSetArg(args[0], XtNleftBitmap, None);
6398 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6402 void AnimateDraggingProc(w, event, prms, nprms)
6410 appData.animateDragging = !appData.animateDragging;
6412 if (appData.animateDragging) {
6413 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6416 XtSetArg(args[0], XtNleftBitmap, None);
6418 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6422 void AnimateMovingProc(w, event, prms, nprms)
6430 appData.animate = !appData.animate;
6432 if (appData.animate) {
6433 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6436 XtSetArg(args[0], XtNleftBitmap, None);
6438 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6442 void AutocommProc(w, event, prms, nprms)
6450 appData.autoComment = !appData.autoComment;
6452 if (appData.autoComment) {
6453 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6455 XtSetArg(args[0], XtNleftBitmap, None);
6457 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6462 void AutoflagProc(w, event, prms, nprms)
6470 appData.autoCallFlag = !appData.autoCallFlag;
6472 if (appData.autoCallFlag) {
6473 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6475 XtSetArg(args[0], XtNleftBitmap, None);
6477 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6481 void AutoflipProc(w, event, prms, nprms)
6489 appData.autoFlipView = !appData.autoFlipView;
6491 if (appData.autoFlipView) {
6492 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6494 XtSetArg(args[0], XtNleftBitmap, None);
6496 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6500 void AutobsProc(w, event, prms, nprms)
6508 appData.autoObserve = !appData.autoObserve;
6510 if (appData.autoObserve) {
6511 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6513 XtSetArg(args[0], XtNleftBitmap, None);
6515 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6519 void AutoraiseProc(w, event, prms, nprms)
6527 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6529 if (appData.autoRaiseBoard) {
6530 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6532 XtSetArg(args[0], XtNleftBitmap, None);
6534 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6538 void AutosaveProc(w, event, prms, nprms)
6546 appData.autoSaveGames = !appData.autoSaveGames;
6548 if (appData.autoSaveGames) {
6549 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6551 XtSetArg(args[0], XtNleftBitmap, None);
6553 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6557 void BlindfoldProc(w, event, prms, nprms)
6565 appData.blindfold = !appData.blindfold;
6567 if (appData.blindfold) {
6568 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6570 XtSetArg(args[0], XtNleftBitmap, None);
6572 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6575 DrawPosition(True, NULL);
6578 void TestLegalityProc(w, event, prms, nprms)
6586 appData.testLegality = !appData.testLegality;
6588 if (appData.testLegality) {
6589 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6591 XtSetArg(args[0], XtNleftBitmap, None);
6593 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6598 void FlashMovesProc(w, event, prms, nprms)
6606 if (appData.flashCount == 0) {
6607 appData.flashCount = 3;
6609 appData.flashCount = -appData.flashCount;
6612 if (appData.flashCount > 0) {
6613 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6615 XtSetArg(args[0], XtNleftBitmap, None);
6617 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6621 void FlipViewProc(w, event, prms, nprms)
6627 flipView = !flipView;
6628 DrawPosition(True, NULL);
6631 void GetMoveListProc(w, event, prms, nprms)
6639 appData.getMoveList = !appData.getMoveList;
6641 if (appData.getMoveList) {
6642 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6645 XtSetArg(args[0], XtNleftBitmap, None);
6647 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6652 void HighlightDraggingProc(w, event, prms, nprms)
6660 appData.highlightDragging = !appData.highlightDragging;
6662 if (appData.highlightDragging) {
6663 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6665 XtSetArg(args[0], XtNleftBitmap, None);
6667 XtSetValues(XtNameToWidget(menuBarWidget,
6668 "menuOptions.Highlight Dragging"), args, 1);
6672 void HighlightLastMoveProc(w, event, prms, nprms)
6680 appData.highlightLastMove = !appData.highlightLastMove;
6682 if (appData.highlightLastMove) {
6683 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6685 XtSetArg(args[0], XtNleftBitmap, None);
6687 XtSetValues(XtNameToWidget(menuBarWidget,
6688 "menuOptions.Highlight Last Move"), args, 1);
6691 void IcsAlarmProc(w, event, prms, nprms)
6699 appData.icsAlarm = !appData.icsAlarm;
6701 if (appData.icsAlarm) {
6702 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6704 XtSetArg(args[0], XtNleftBitmap, None);
6706 XtSetValues(XtNameToWidget(menuBarWidget,
6707 "menuOptions.ICS Alarm"), args, 1);
6710 void MoveSoundProc(w, event, prms, nprms)
6718 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6720 if (appData.ringBellAfterMoves) {
6721 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6723 XtSetArg(args[0], XtNleftBitmap, None);
6725 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6730 void OldSaveStyleProc(w, event, prms, nprms)
6738 appData.oldSaveStyle = !appData.oldSaveStyle;
6740 if (appData.oldSaveStyle) {
6741 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6743 XtSetArg(args[0], XtNleftBitmap, None);
6745 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6749 void PeriodicUpdatesProc(w, event, prms, nprms)
6757 PeriodicUpdatesEvent(!appData.periodicUpdates);
6759 if (appData.periodicUpdates) {
6760 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6762 XtSetArg(args[0], XtNleftBitmap, None);
6764 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6768 void PonderNextMoveProc(w, event, prms, nprms)
6776 PonderNextMoveEvent(!appData.ponderNextMove);
6778 if (appData.ponderNextMove) {
6779 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6781 XtSetArg(args[0], XtNleftBitmap, None);
6783 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6787 void PopupExitMessageProc(w, event, prms, nprms)
6795 appData.popupExitMessage = !appData.popupExitMessage;
6797 if (appData.popupExitMessage) {
6798 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6800 XtSetArg(args[0], XtNleftBitmap, None);
6802 XtSetValues(XtNameToWidget(menuBarWidget,
6803 "menuOptions.Popup Exit Message"), args, 1);
6806 void PopupMoveErrorsProc(w, event, prms, nprms)
6814 appData.popupMoveErrors = !appData.popupMoveErrors;
6816 if (appData.popupMoveErrors) {
6817 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6819 XtSetArg(args[0], XtNleftBitmap, None);
6821 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6825 void PremoveProc(w, event, prms, nprms)
6833 appData.premove = !appData.premove;
6835 if (appData.premove) {
6836 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6838 XtSetArg(args[0], XtNleftBitmap, None);
6840 XtSetValues(XtNameToWidget(menuBarWidget,
6841 "menuOptions.Premove"), args, 1);
6844 void QuietPlayProc(w, event, prms, nprms)
6852 appData.quietPlay = !appData.quietPlay;
6854 if (appData.quietPlay) {
6855 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6857 XtSetArg(args[0], XtNleftBitmap, None);
6859 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6863 void ShowCoordsProc(w, event, prms, nprms)
6871 appData.showCoords = !appData.showCoords;
6873 if (appData.showCoords) {
6874 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6876 XtSetArg(args[0], XtNleftBitmap, None);
6878 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6881 DrawPosition(True, NULL);
6884 void ShowThinkingProc(w, event, prms, nprms)
6890 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6891 ShowThinkingEvent();
6894 void HideThinkingProc(w, event, prms, nprms)
6902 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6903 ShowThinkingEvent();
6905 if (appData.hideThinkingFromHuman) {
6906 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6908 XtSetArg(args[0], XtNleftBitmap, None);
6910 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6914 void SaveOnExitProc(w, event, prms, nprms)
6922 saveSettingsOnExit = !saveSettingsOnExit;
6924 if (saveSettingsOnExit) {
6925 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6927 XtSetArg(args[0], XtNleftBitmap, None);
6929 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6933 void SaveSettingsProc(w, event, prms, nprms)
6939 SaveSettings(settingsFileName);
6942 void InfoProc(w, event, prms, nprms)
6949 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6954 void ManProc(w, event, prms, nprms)
6962 if (nprms && *nprms > 0)
6966 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6970 void HintProc(w, event, prms, nprms)
6979 void BookProc(w, event, prms, nprms)
6988 void AboutProc(w, event, prms, nprms)
6996 char *zippy = " (with Zippy code)";
7000 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7001 programVersion, zippy,
7002 "Copyright 1991 Digital Equipment Corporation",
7003 "Enhancements Copyright 1992-2009 Free Software Foundation",
7004 "Enhancements Copyright 2005 Alessandro Scotti",
7005 PACKAGE, " is free software and carries NO WARRANTY;",
7006 "see the file COPYING for more information.");
7007 ErrorPopUp(_("About XBoard"), buf, FALSE);
7010 void DebugProc(w, event, prms, nprms)
7016 appData.debugMode = !appData.debugMode;
7019 void AboutGameProc(w, event, prms, nprms)
7028 void NothingProc(w, event, prms, nprms)
7037 void Iconify(w, event, prms, nprms)
7046 XtSetArg(args[0], XtNiconic, True);
7047 XtSetValues(shellWidget, args, 1);
7050 void DisplayMessage(message, extMessage)
7051 char *message, *extMessage;
7053 /* display a message in the message widget */
7062 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7067 message = extMessage;
7071 /* need to test if messageWidget already exists, since this function
7072 can also be called during the startup, if for example a Xresource
7073 is not set up correctly */
7076 XtSetArg(arg, XtNlabel, message);
7077 XtSetValues(messageWidget, &arg, 1);
7083 void DisplayTitle(text)
7088 char title[MSG_SIZ];
7091 if (text == NULL) text = "";
7093 if (appData.titleInWindow) {
7095 XtSetArg(args[i], XtNlabel, text); i++;
7096 XtSetValues(titleWidget, args, i);
7099 if (*text != NULLCHAR) {
7100 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7101 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7102 } else if (appData.icsActive) {
7103 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7104 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7105 } else if (appData.cmailGameName[0] != NULLCHAR) {
7106 snprintf(icon, sizeof(icon), "%s", "CMail");
7107 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7109 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7110 } else if (gameInfo.variant == VariantGothic) {
7111 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7112 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7115 } else if (gameInfo.variant == VariantFalcon) {
7116 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7117 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7119 } else if (appData.noChessProgram) {
7120 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7121 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7123 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7124 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7127 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7128 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7129 XtSetValues(shellWidget, args, i);
7134 DisplayError(message, error)
7141 if (appData.debugMode || appData.matchMode) {
7142 fprintf(stderr, "%s: %s\n", programName, message);
7145 if (appData.debugMode || appData.matchMode) {
7146 fprintf(stderr, "%s: %s: %s\n",
7147 programName, message, strerror(error));
7149 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7152 ErrorPopUp(_("Error"), message, FALSE);
7156 void DisplayMoveError(message)
7161 DrawPosition(FALSE, NULL);
7162 if (appData.debugMode || appData.matchMode) {
7163 fprintf(stderr, "%s: %s\n", programName, message);
7165 if (appData.popupMoveErrors) {
7166 ErrorPopUp(_("Error"), message, FALSE);
7168 DisplayMessage(message, "");
7173 void DisplayFatalError(message, error, status)
7179 errorExitStatus = status;
7181 fprintf(stderr, "%s: %s\n", programName, message);
7183 fprintf(stderr, "%s: %s: %s\n",
7184 programName, message, strerror(error));
7185 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7188 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7189 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7195 void DisplayInformation(message)
7199 ErrorPopUp(_("Information"), message, TRUE);
7202 void DisplayNote(message)
7206 ErrorPopUp(_("Note"), message, FALSE);
7210 NullXErrorCheck(dpy, error_event)
7212 XErrorEvent *error_event;
7217 void DisplayIcsInteractionTitle(message)
7220 if (oldICSInteractionTitle == NULL) {
7221 /* Magic to find the old window title, adapted from vim */
7222 char *wina = getenv("WINDOWID");
7224 Window win = (Window) atoi(wina);
7225 Window root, parent, *children;
7226 unsigned int nchildren;
7227 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7229 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7230 if (!XQueryTree(xDisplay, win, &root, &parent,
7231 &children, &nchildren)) break;
7232 if (children) XFree((void *)children);
7233 if (parent == root || parent == 0) break;
7236 XSetErrorHandler(oldHandler);
7238 if (oldICSInteractionTitle == NULL) {
7239 oldICSInteractionTitle = "xterm";
7242 printf("\033]0;%s\007", message);
7246 char pendingReplyPrefix[MSG_SIZ];
7247 ProcRef pendingReplyPR;
7249 void AskQuestionProc(w, event, prms, nprms)
7256 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7260 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7263 void AskQuestionPopDown()
7265 if (!askQuestionUp) return;
7266 XtPopdown(askQuestionShell);
7267 XtDestroyWidget(askQuestionShell);
7268 askQuestionUp = False;
7271 void AskQuestionReplyAction(w, event, prms, nprms)
7281 reply = XawDialogGetValueString(w = XtParent(w));
7282 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7283 if (*buf) strcat(buf, " ");
7286 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7287 AskQuestionPopDown();
7289 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7292 void AskQuestionCallback(w, client_data, call_data)
7294 XtPointer client_data, call_data;
7299 XtSetArg(args[0], XtNlabel, &name);
7300 XtGetValues(w, args, 1);
7302 if (strcmp(name, _("cancel")) == 0) {
7303 AskQuestionPopDown();
7305 AskQuestionReplyAction(w, NULL, NULL, NULL);
7309 void AskQuestion(title, question, replyPrefix, pr)
7310 char *title, *question, *replyPrefix;
7314 Widget popup, layout, dialog, edit;
7320 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7321 pendingReplyPR = pr;
7324 XtSetArg(args[i], XtNresizable, True); i++;
7325 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7326 askQuestionShell = popup =
7327 XtCreatePopupShell(title, transientShellWidgetClass,
7328 shellWidget, args, i);
7331 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7332 layoutArgs, XtNumber(layoutArgs));
7335 XtSetArg(args[i], XtNlabel, question); i++;
7336 XtSetArg(args[i], XtNvalue, ""); i++;
7337 XtSetArg(args[i], XtNborderWidth, 0); i++;
7338 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7341 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7342 (XtPointer) dialog);
7343 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7344 (XtPointer) dialog);
7346 XtRealizeWidget(popup);
7347 CatchDeleteWindow(popup, "AskQuestionPopDown");
7349 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7350 &x, &y, &win_x, &win_y, &mask);
7352 XtSetArg(args[0], XtNx, x - 10);
7353 XtSetArg(args[1], XtNy, y - 30);
7354 XtSetValues(popup, args, 2);
7356 XtPopup(popup, XtGrabExclusive);
7357 askQuestionUp = True;
7359 edit = XtNameToWidget(dialog, "*value");
7360 XtSetKeyboardFocus(popup, edit);
7368 if (*name == NULLCHAR) {
7370 } else if (strcmp(name, "$") == 0) {
7371 putc(BELLCHAR, stderr);
7374 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7382 PlaySound(appData.soundMove);
7388 PlaySound(appData.soundIcsWin);
7394 PlaySound(appData.soundIcsLoss);
7400 PlaySound(appData.soundIcsDraw);
7404 PlayIcsUnfinishedSound()
7406 PlaySound(appData.soundIcsUnfinished);
7412 PlaySound(appData.soundIcsAlarm);
7418 system("stty echo");
7424 system("stty -echo");
7428 Colorize(cc, continuation)
7433 int count, outCount, error;
7435 if (textColors[(int)cc].bg > 0) {
7436 if (textColors[(int)cc].fg > 0) {
7437 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7438 textColors[(int)cc].fg, textColors[(int)cc].bg);
7440 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7441 textColors[(int)cc].bg);
7444 if (textColors[(int)cc].fg > 0) {
7445 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7446 textColors[(int)cc].fg);
7448 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7451 count = strlen(buf);
7452 outCount = OutputToProcess(NoProc, buf, count, &error);
7453 if (outCount < count) {
7454 DisplayFatalError(_("Error writing to display"), error, 1);
7457 if (continuation) return;
7460 PlaySound(appData.soundShout);
7463 PlaySound(appData.soundSShout);
7466 PlaySound(appData.soundChannel1);
7469 PlaySound(appData.soundChannel);
7472 PlaySound(appData.soundKibitz);
7475 PlaySound(appData.soundTell);
7477 case ColorChallenge:
7478 PlaySound(appData.soundChallenge);
7481 PlaySound(appData.soundRequest);
7484 PlaySound(appData.soundSeek);
7495 return getpwuid(getuid())->pw_name;
7499 ExpandPathName(path)
7502 static char static_buf[4*MSG_SIZ];
7503 char *d, *s, buf[4*MSG_SIZ];
7509 while (*s && isspace(*s))
7518 if (*(s+1) == '/') {
7519 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7523 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7524 *strchr(buf, '/') = 0;
7525 pwd = getpwnam(buf);
7528 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7532 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7533 strcat(d, strchr(s+1, '/'));
7537 safeStrCpy(d, s, 4*MSG_SIZ );
7544 static char host_name[MSG_SIZ];
7546 #if HAVE_GETHOSTNAME
7547 gethostname(host_name, MSG_SIZ);
7549 #else /* not HAVE_GETHOSTNAME */
7550 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7551 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7553 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7555 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7556 #endif /* not HAVE_GETHOSTNAME */
7559 XtIntervalId delayedEventTimerXID = 0;
7560 DelayedEventCallback delayedEventCallback = 0;
7565 delayedEventTimerXID = 0;
7566 delayedEventCallback();
7570 ScheduleDelayedEvent(cb, millisec)
7571 DelayedEventCallback cb; long millisec;
7573 if(delayedEventTimerXID && delayedEventCallback == cb)
7574 // [HGM] alive: replace, rather than add or flush identical event
7575 XtRemoveTimeOut(delayedEventTimerXID);
7576 delayedEventCallback = cb;
7577 delayedEventTimerXID =
7578 XtAppAddTimeOut(appContext, millisec,
7579 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7582 DelayedEventCallback
7585 if (delayedEventTimerXID) {
7586 return delayedEventCallback;
7593 CancelDelayedEvent()
7595 if (delayedEventTimerXID) {
7596 XtRemoveTimeOut(delayedEventTimerXID);
7597 delayedEventTimerXID = 0;
7601 XtIntervalId loadGameTimerXID = 0;
7603 int LoadGameTimerRunning()
7605 return loadGameTimerXID != 0;
7608 int StopLoadGameTimer()
7610 if (loadGameTimerXID != 0) {
7611 XtRemoveTimeOut(loadGameTimerXID);
7612 loadGameTimerXID = 0;
7620 LoadGameTimerCallback(arg, id)
7624 loadGameTimerXID = 0;
7629 StartLoadGameTimer(millisec)
7633 XtAppAddTimeOut(appContext, millisec,
7634 (XtTimerCallbackProc) LoadGameTimerCallback,
7638 XtIntervalId analysisClockXID = 0;
7641 AnalysisClockCallback(arg, id)
7645 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7646 || appData.icsEngineAnalyze) { // [DM]
7647 AnalysisPeriodicEvent(0);
7648 StartAnalysisClock();
7653 StartAnalysisClock()
7656 XtAppAddTimeOut(appContext, 2000,
7657 (XtTimerCallbackProc) AnalysisClockCallback,
7661 XtIntervalId clockTimerXID = 0;
7663 int ClockTimerRunning()
7665 return clockTimerXID != 0;
7668 int StopClockTimer()
7670 if (clockTimerXID != 0) {
7671 XtRemoveTimeOut(clockTimerXID);
7680 ClockTimerCallback(arg, id)
7689 StartClockTimer(millisec)
7693 XtAppAddTimeOut(appContext, millisec,
7694 (XtTimerCallbackProc) ClockTimerCallback,
7699 DisplayTimerLabel(w, color, timer, highlight)
7708 /* check for low time warning */
7709 Pixel foregroundOrWarningColor = timerForegroundPixel;
7712 appData.lowTimeWarning &&
7713 (timer / 1000) < appData.icsAlarmTime)
7714 foregroundOrWarningColor = lowTimeWarningColor;
7716 if (appData.clockMode) {
7717 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7718 XtSetArg(args[0], XtNlabel, buf);
7720 snprintf(buf, MSG_SIZ, "%s ", color);
7721 XtSetArg(args[0], XtNlabel, buf);
7726 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7727 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7729 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7730 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7733 XtSetValues(w, args, 3);
7737 DisplayWhiteClock(timeRemaining, highlight)
7743 if(appData.noGUI) return;
7744 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7745 if (highlight && iconPixmap == bIconPixmap) {
7746 iconPixmap = wIconPixmap;
7747 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7748 XtSetValues(shellWidget, args, 1);
7753 DisplayBlackClock(timeRemaining, highlight)
7759 if(appData.noGUI) return;
7760 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7761 if (highlight && iconPixmap == wIconPixmap) {
7762 iconPixmap = bIconPixmap;
7763 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7764 XtSetValues(shellWidget, args, 1);
7782 int StartChildProcess(cmdLine, dir, pr)
7789 int to_prog[2], from_prog[2];
7793 if (appData.debugMode) {
7794 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7797 /* We do NOT feed the cmdLine to the shell; we just
7798 parse it into blank-separated arguments in the
7799 most simple-minded way possible.
7802 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7805 while(*p == ' ') p++;
7807 if(*p == '"' || *p == '\'')
7808 p = strchr(++argv[i-1], *p);
7809 else p = strchr(p, ' ');
7810 if (p == NULL) break;
7815 SetUpChildIO(to_prog, from_prog);
7817 if ((pid = fork()) == 0) {
7819 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7820 close(to_prog[1]); // first close the unused pipe ends
7821 close(from_prog[0]);
7822 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7823 dup2(from_prog[1], 1);
7824 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7825 close(from_prog[1]); // and closing again loses one of the pipes!
7826 if(fileno(stderr) >= 2) // better safe than sorry...
7827 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7829 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7834 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7836 execvp(argv[0], argv);
7838 /* If we get here, exec failed */
7843 /* Parent process */
7845 close(from_prog[1]);
7847 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7850 cp->fdFrom = from_prog[0];
7851 cp->fdTo = to_prog[1];
7856 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7857 static RETSIGTYPE AlarmCallBack(int n)
7863 DestroyChildProcess(pr, signalType)
7867 ChildProc *cp = (ChildProc *) pr;
7869 if (cp->kind != CPReal) return;
7871 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7872 signal(SIGALRM, AlarmCallBack);
7874 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7875 kill(cp->pid, SIGKILL); // kill it forcefully
7876 wait((int *) 0); // and wait again
7880 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7882 /* Process is exiting either because of the kill or because of
7883 a quit command sent by the backend; either way, wait for it to die.
7892 InterruptChildProcess(pr)
7895 ChildProc *cp = (ChildProc *) pr;
7897 if (cp->kind != CPReal) return;
7898 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7901 int OpenTelnet(host, port, pr)
7906 char cmdLine[MSG_SIZ];
7908 if (port[0] == NULLCHAR) {
7909 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7911 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7913 return StartChildProcess(cmdLine, "", pr);
7916 int OpenTCP(host, port, pr)
7922 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7923 #else /* !OMIT_SOCKETS */
7925 struct sockaddr_in sa;
7927 unsigned short uport;
7930 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7934 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7935 sa.sin_family = AF_INET;
7936 sa.sin_addr.s_addr = INADDR_ANY;
7937 uport = (unsigned short) 0;
7938 sa.sin_port = htons(uport);
7939 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7943 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7944 if (!(hp = gethostbyname(host))) {
7946 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7947 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7948 hp->h_addrtype = AF_INET;
7950 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7951 hp->h_addr_list[0] = (char *) malloc(4);
7952 hp->h_addr_list[0][0] = b0;
7953 hp->h_addr_list[0][1] = b1;
7954 hp->h_addr_list[0][2] = b2;
7955 hp->h_addr_list[0][3] = b3;
7960 sa.sin_family = hp->h_addrtype;
7961 uport = (unsigned short) atoi(port);
7962 sa.sin_port = htons(uport);
7963 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7965 if (connect(s, (struct sockaddr *) &sa,
7966 sizeof(struct sockaddr_in)) < 0) {
7970 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7977 #endif /* !OMIT_SOCKETS */
7982 int OpenCommPort(name, pr)
7989 fd = open(name, 2, 0);
7990 if (fd < 0) return errno;
7992 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8002 int OpenLoopback(pr)
8008 SetUpChildIO(to, from);
8010 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8013 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8020 int OpenRcmd(host, user, cmd, pr)
8021 char *host, *user, *cmd;
8024 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8028 #define INPUT_SOURCE_BUF_SIZE 8192
8037 char buf[INPUT_SOURCE_BUF_SIZE];
8042 DoInputCallback(closure, source, xid)
8047 InputSource *is = (InputSource *) closure;
8052 if (is->lineByLine) {
8053 count = read(is->fd, is->unused,
8054 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8056 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8059 is->unused += count;
8061 while (p < is->unused) {
8062 q = memchr(p, '\n', is->unused - p);
8063 if (q == NULL) break;
8065 (is->func)(is, is->closure, p, q - p, 0);
8069 while (p < is->unused) {
8074 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8079 (is->func)(is, is->closure, is->buf, count, error);
8083 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8090 ChildProc *cp = (ChildProc *) pr;
8092 is = (InputSource *) calloc(1, sizeof(InputSource));
8093 is->lineByLine = lineByLine;
8097 is->fd = fileno(stdin);
8099 is->kind = cp->kind;
8100 is->fd = cp->fdFrom;
8103 is->unused = is->buf;
8106 is->xid = XtAppAddInput(appContext, is->fd,
8107 (XtPointer) (XtInputReadMask),
8108 (XtInputCallbackProc) DoInputCallback,
8110 is->closure = closure;
8111 return (InputSourceRef) is;
8115 RemoveInputSource(isr)
8118 InputSource *is = (InputSource *) isr;
8120 if (is->xid == 0) return;
8121 XtRemoveInput(is->xid);
8125 int OutputToProcess(pr, message, count, outError)
8131 static int line = 0;
8132 ChildProc *cp = (ChildProc *) pr;
8137 if (appData.noJoin || !appData.useInternalWrap)
8138 outCount = fwrite(message, 1, count, stdout);
8141 int width = get_term_width();
8142 int len = wrap(NULL, message, count, width, &line);
8143 char *msg = malloc(len);
8147 outCount = fwrite(message, 1, count, stdout);
8150 dbgchk = wrap(msg, message, count, width, &line);
8151 if (dbgchk != len && appData.debugMode)
8152 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8153 outCount = fwrite(msg, 1, dbgchk, stdout);
8159 outCount = write(cp->fdTo, message, count);
8169 /* Output message to process, with "ms" milliseconds of delay
8170 between each character. This is needed when sending the logon
8171 script to ICC, which for some reason doesn't like the
8172 instantaneous send. */
8173 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8180 ChildProc *cp = (ChildProc *) pr;
8185 r = write(cp->fdTo, message++, 1);
8198 /**** Animation code by Hugh Fisher, DCS, ANU.
8200 Known problem: if a window overlapping the board is
8201 moved away while a piece is being animated underneath,
8202 the newly exposed area won't be updated properly.
8203 I can live with this.
8205 Known problem: if you look carefully at the animation
8206 of pieces in mono mode, they are being drawn as solid
8207 shapes without interior detail while moving. Fixing
8208 this would be a major complication for minimal return.
8211 /* Masks for XPM pieces. Black and white pieces can have
8212 different shapes, but in the interest of retaining my
8213 sanity pieces must have the same outline on both light
8214 and dark squares, and all pieces must use the same
8215 background square colors/images. */
8217 static int xpmDone = 0;
8220 CreateAnimMasks (pieceDepth)
8227 unsigned long plane;
8230 /* Need a bitmap just to get a GC with right depth */
8231 buf = XCreatePixmap(xDisplay, xBoardWindow,
8233 values.foreground = 1;
8234 values.background = 0;
8235 /* Don't use XtGetGC, not read only */
8236 maskGC = XCreateGC(xDisplay, buf,
8237 GCForeground | GCBackground, &values);
8238 XFreePixmap(xDisplay, buf);
8240 buf = XCreatePixmap(xDisplay, xBoardWindow,
8241 squareSize, squareSize, pieceDepth);
8242 values.foreground = XBlackPixel(xDisplay, xScreen);
8243 values.background = XWhitePixel(xDisplay, xScreen);
8244 bufGC = XCreateGC(xDisplay, buf,
8245 GCForeground | GCBackground, &values);
8247 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8248 /* Begin with empty mask */
8249 if(!xpmDone) // [HGM] pieces: keep using existing
8250 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8251 squareSize, squareSize, 1);
8252 XSetFunction(xDisplay, maskGC, GXclear);
8253 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8254 0, 0, squareSize, squareSize);
8256 /* Take a copy of the piece */
8261 XSetFunction(xDisplay, bufGC, GXcopy);
8262 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8264 0, 0, squareSize, squareSize, 0, 0);
8266 /* XOR the background (light) over the piece */
8267 XSetFunction(xDisplay, bufGC, GXxor);
8269 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8270 0, 0, squareSize, squareSize, 0, 0);
8272 XSetForeground(xDisplay, bufGC, lightSquareColor);
8273 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8276 /* We now have an inverted piece image with the background
8277 erased. Construct mask by just selecting all the non-zero
8278 pixels - no need to reconstruct the original image. */
8279 XSetFunction(xDisplay, maskGC, GXor);
8281 /* Might be quicker to download an XImage and create bitmap
8282 data from it rather than this N copies per piece, but it
8283 only takes a fraction of a second and there is a much
8284 longer delay for loading the pieces. */
8285 for (n = 0; n < pieceDepth; n ++) {
8286 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8287 0, 0, squareSize, squareSize,
8293 XFreePixmap(xDisplay, buf);
8294 XFreeGC(xDisplay, bufGC);
8295 XFreeGC(xDisplay, maskGC);
8299 InitAnimState (anim, info)
8301 XWindowAttributes * info;
8306 /* Each buffer is square size, same depth as window */
8307 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8308 squareSize, squareSize, info->depth);
8309 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8310 squareSize, squareSize, info->depth);
8312 /* Create a plain GC for blitting */
8313 mask = GCForeground | GCBackground | GCFunction |
8314 GCPlaneMask | GCGraphicsExposures;
8315 values.foreground = XBlackPixel(xDisplay, xScreen);
8316 values.background = XWhitePixel(xDisplay, xScreen);
8317 values.function = GXcopy;
8318 values.plane_mask = AllPlanes;
8319 values.graphics_exposures = False;
8320 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8322 /* Piece will be copied from an existing context at
8323 the start of each new animation/drag. */
8324 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8326 /* Outline will be a read-only copy of an existing */
8327 anim->outlineGC = None;
8333 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8334 XWindowAttributes info;
8336 if (xpmDone && gameInfo.variant == old) return;
8337 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8338 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8340 InitAnimState(&game, &info);
8341 InitAnimState(&player, &info);
8343 /* For XPM pieces, we need bitmaps to use as masks. */
8345 CreateAnimMasks(info.depth);
8351 static Boolean frameWaiting;
8353 static RETSIGTYPE FrameAlarm (sig)
8356 frameWaiting = False;
8357 /* In case System-V style signals. Needed?? */
8358 signal(SIGALRM, FrameAlarm);
8365 struct itimerval delay;
8367 XSync(xDisplay, False);
8370 frameWaiting = True;
8371 signal(SIGALRM, FrameAlarm);
8372 delay.it_interval.tv_sec =
8373 delay.it_value.tv_sec = time / 1000;
8374 delay.it_interval.tv_usec =
8375 delay.it_value.tv_usec = (time % 1000) * 1000;
8376 setitimer(ITIMER_REAL, &delay, NULL);
8377 while (frameWaiting) pause();
8378 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8379 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8380 setitimer(ITIMER_REAL, &delay, NULL);
8390 XSync(xDisplay, False);
8392 usleep(time * 1000);
8397 /* Convert board position to corner of screen rect and color */
8400 ScreenSquare(column, row, pt, color)
8401 int column; int row; XPoint * pt; int * color;
8404 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8405 pt->y = lineGap + row * (squareSize + lineGap);
8407 pt->x = lineGap + column * (squareSize + lineGap);
8408 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8410 *color = SquareColor(row, column);
8413 /* Convert window coords to square */
8416 BoardSquare(x, y, column, row)
8417 int x; int y; int * column; int * row;
8419 *column = EventToSquare(x, BOARD_WIDTH);
8420 if (flipView && *column >= 0)
8421 *column = BOARD_WIDTH - 1 - *column;
8422 *row = EventToSquare(y, BOARD_HEIGHT);
8423 if (!flipView && *row >= 0)
8424 *row = BOARD_HEIGHT - 1 - *row;
8429 #undef Max /* just in case */
8431 #define Max(a, b) ((a) > (b) ? (a) : (b))
8432 #define Min(a, b) ((a) < (b) ? (a) : (b))
8435 SetRect(rect, x, y, width, height)
8436 XRectangle * rect; int x; int y; int width; int height;
8440 rect->width = width;
8441 rect->height = height;
8444 /* Test if two frames overlap. If they do, return
8445 intersection rect within old and location of
8446 that rect within new. */
8449 Intersect(old, new, size, area, pt)
8450 XPoint * old; XPoint * new;
8451 int size; XRectangle * area; XPoint * pt;
8453 if (old->x > new->x + size || new->x > old->x + size ||
8454 old->y > new->y + size || new->y > old->y + size) {
8457 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8458 size - abs(old->x - new->x), size - abs(old->y - new->y));
8459 pt->x = Max(old->x - new->x, 0);
8460 pt->y = Max(old->y - new->y, 0);
8465 /* For two overlapping frames, return the rect(s)
8466 in the old that do not intersect with the new. */
8469 CalcUpdateRects(old, new, size, update, nUpdates)
8470 XPoint * old; XPoint * new; int size;
8471 XRectangle update[]; int * nUpdates;
8475 /* If old = new (shouldn't happen) then nothing to draw */
8476 if (old->x == new->x && old->y == new->y) {
8480 /* Work out what bits overlap. Since we know the rects
8481 are the same size we don't need a full intersect calc. */
8483 /* Top or bottom edge? */
8484 if (new->y > old->y) {
8485 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8487 } else if (old->y > new->y) {
8488 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8489 size, old->y - new->y);
8492 /* Left or right edge - don't overlap any update calculated above. */
8493 if (new->x > old->x) {
8494 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8495 new->x - old->x, size - abs(new->y - old->y));
8497 } else if (old->x > new->x) {
8498 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8499 old->x - new->x, size - abs(new->y - old->y));
8506 /* Generate a series of frame coords from start->mid->finish.
8507 The movement rate doubles until the half way point is
8508 reached, then halves back down to the final destination,
8509 which gives a nice slow in/out effect. The algorithmn
8510 may seem to generate too many intermediates for short
8511 moves, but remember that the purpose is to attract the
8512 viewers attention to the piece about to be moved and
8513 then to where it ends up. Too few frames would be less
8517 Tween(start, mid, finish, factor, frames, nFrames)
8518 XPoint * start; XPoint * mid;
8519 XPoint * finish; int factor;
8520 XPoint frames[]; int * nFrames;
8522 int fraction, n, count;
8526 /* Slow in, stepping 1/16th, then 1/8th, ... */
8528 for (n = 0; n < factor; n++)
8530 for (n = 0; n < factor; n++) {
8531 frames[count].x = start->x + (mid->x - start->x) / fraction;
8532 frames[count].y = start->y + (mid->y - start->y) / fraction;
8534 fraction = fraction / 2;
8538 frames[count] = *mid;
8541 /* Slow out, stepping 1/2, then 1/4, ... */
8543 for (n = 0; n < factor; n++) {
8544 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8545 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8547 fraction = fraction * 2;
8552 /* Draw a piece on the screen without disturbing what's there */
8555 SelectGCMask(piece, clip, outline, mask)
8556 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8560 /* Bitmap for piece being moved. */
8561 if (appData.monoMode) {
8562 *mask = *pieceToSolid(piece);
8563 } else if (useImages) {
8565 *mask = xpmMask[piece];
8567 *mask = ximMaskPm[piece];
8570 *mask = *pieceToSolid(piece);
8573 /* GC for piece being moved. Square color doesn't matter, but
8574 since it gets modified we make a copy of the original. */
8576 if (appData.monoMode)
8581 if (appData.monoMode)
8586 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8588 /* Outline only used in mono mode and is not modified */
8590 *outline = bwPieceGC;
8592 *outline = wbPieceGC;
8596 OverlayPiece(piece, clip, outline, dest)
8597 ChessSquare piece; GC clip; GC outline; Drawable dest;
8602 /* Draw solid rectangle which will be clipped to shape of piece */
8603 XFillRectangle(xDisplay, dest, clip,
8604 0, 0, squareSize, squareSize);
8605 if (appData.monoMode)
8606 /* Also draw outline in contrasting color for black
8607 on black / white on white cases */
8608 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8609 0, 0, squareSize, squareSize, 0, 0, 1);
8611 /* Copy the piece */
8616 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8618 0, 0, squareSize, squareSize,
8623 /* Animate the movement of a single piece */
8626 BeginAnimation(anim, piece, startColor, start)
8634 /* The old buffer is initialised with the start square (empty) */
8635 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8636 anim->prevFrame = *start;
8638 /* The piece will be drawn using its own bitmap as a matte */
8639 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8640 XSetClipMask(xDisplay, anim->pieceGC, mask);
8644 AnimationFrame(anim, frame, piece)
8649 XRectangle updates[4];
8654 /* Save what we are about to draw into the new buffer */
8655 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8656 frame->x, frame->y, squareSize, squareSize,
8659 /* Erase bits of the previous frame */
8660 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8661 /* Where the new frame overlapped the previous,
8662 the contents in newBuf are wrong. */
8663 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8664 overlap.x, overlap.y,
8665 overlap.width, overlap.height,
8667 /* Repaint the areas in the old that don't overlap new */
8668 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8669 for (i = 0; i < count; i++)
8670 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8671 updates[i].x - anim->prevFrame.x,
8672 updates[i].y - anim->prevFrame.y,
8673 updates[i].width, updates[i].height,
8674 updates[i].x, updates[i].y);
8676 /* Easy when no overlap */
8677 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8678 0, 0, squareSize, squareSize,
8679 anim->prevFrame.x, anim->prevFrame.y);
8682 /* Save this frame for next time round */
8683 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8684 0, 0, squareSize, squareSize,
8686 anim->prevFrame = *frame;
8688 /* Draw piece over original screen contents, not current,
8689 and copy entire rect. Wipes out overlapping piece images. */
8690 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8691 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8692 0, 0, squareSize, squareSize,
8693 frame->x, frame->y);
8697 EndAnimation (anim, finish)
8701 XRectangle updates[4];
8706 /* The main code will redraw the final square, so we
8707 only need to erase the bits that don't overlap. */
8708 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8709 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8710 for (i = 0; i < count; i++)
8711 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8712 updates[i].x - anim->prevFrame.x,
8713 updates[i].y - anim->prevFrame.y,
8714 updates[i].width, updates[i].height,
8715 updates[i].x, updates[i].y);
8717 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8718 0, 0, squareSize, squareSize,
8719 anim->prevFrame.x, anim->prevFrame.y);
8724 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8726 ChessSquare piece; int startColor;
8727 XPoint * start; XPoint * finish;
8728 XPoint frames[]; int nFrames;
8732 BeginAnimation(anim, piece, startColor, start);
8733 for (n = 0; n < nFrames; n++) {
8734 AnimationFrame(anim, &(frames[n]), piece);
8735 FrameDelay(appData.animSpeed);
8737 EndAnimation(anim, finish);
8740 /* Main control logic for deciding what to animate and how */
8743 AnimateMove(board, fromX, fromY, toX, toY)
8752 XPoint start, finish, mid;
8753 XPoint frames[kFactor * 2 + 1];
8754 int nFrames, startColor, endColor;
8756 /* Are we animating? */
8757 if (!appData.animate || appData.blindfold)
8760 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8761 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8762 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8764 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8765 piece = board[fromY][fromX];
8766 if (piece >= EmptySquare) return;
8771 hop = (piece == WhiteKnight || piece == BlackKnight);
8774 if (appData.debugMode) {
8775 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8776 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8777 piece, fromX, fromY, toX, toY); }
8779 ScreenSquare(fromX, fromY, &start, &startColor);
8780 ScreenSquare(toX, toY, &finish, &endColor);
8783 /* Knight: make diagonal movement then straight */
8784 if (abs(toY - fromY) < abs(toX - fromX)) {
8785 mid.x = start.x + (finish.x - start.x) / 2;
8789 mid.y = start.y + (finish.y - start.y) / 2;
8792 mid.x = start.x + (finish.x - start.x) / 2;
8793 mid.y = start.y + (finish.y - start.y) / 2;
8796 /* Don't use as many frames for very short moves */
8797 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8798 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8800 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8801 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8803 /* Be sure end square is redrawn */
8804 damage[0][toY][toX] = True;
8808 DragPieceBegin(x, y)
8811 int boardX, boardY, color;
8814 /* Are we animating? */
8815 if (!appData.animateDragging || appData.blindfold)
8818 /* Figure out which square we start in and the
8819 mouse position relative to top left corner. */
8820 BoardSquare(x, y, &boardX, &boardY);
8821 player.startBoardX = boardX;
8822 player.startBoardY = boardY;
8823 ScreenSquare(boardX, boardY, &corner, &color);
8824 player.startSquare = corner;
8825 player.startColor = color;
8826 /* As soon as we start dragging, the piece will jump slightly to
8827 be centered over the mouse pointer. */
8828 player.mouseDelta.x = squareSize/2;
8829 player.mouseDelta.y = squareSize/2;
8830 /* Initialise animation */
8831 player.dragPiece = PieceForSquare(boardX, boardY);
8833 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8834 player.dragActive = True;
8835 BeginAnimation(&player, player.dragPiece, color, &corner);
8836 /* Mark this square as needing to be redrawn. Note that
8837 we don't remove the piece though, since logically (ie
8838 as seen by opponent) the move hasn't been made yet. */
8839 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8840 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8841 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8842 corner.x, corner.y, squareSize, squareSize,
8843 0, 0); // [HGM] zh: unstack in stead of grab
8844 damage[0][boardY][boardX] = True;
8846 player.dragActive = False;
8856 /* Are we animating? */
8857 if (!appData.animateDragging || appData.blindfold)
8861 if (! player.dragActive)
8863 /* Move piece, maintaining same relative position
8864 of mouse within square */
8865 corner.x = x - player.mouseDelta.x;
8866 corner.y = y - player.mouseDelta.y;
8867 AnimationFrame(&player, &corner, player.dragPiece);
8869 if (appData.highlightDragging) {
8871 BoardSquare(x, y, &boardX, &boardY);
8872 SetHighlights(fromX, fromY, boardX, boardY);
8881 int boardX, boardY, color;
8884 /* Are we animating? */
8885 if (!appData.animateDragging || appData.blindfold)
8889 if (! player.dragActive)
8891 /* Last frame in sequence is square piece is
8892 placed on, which may not match mouse exactly. */
8893 BoardSquare(x, y, &boardX, &boardY);
8894 ScreenSquare(boardX, boardY, &corner, &color);
8895 EndAnimation(&player, &corner);
8897 /* Be sure end square is redrawn */
8898 damage[0][boardY][boardX] = True;
8900 /* This prevents weird things happening with fast successive
8901 clicks which on my Sun at least can cause motion events
8902 without corresponding press/release. */
8903 player.dragActive = False;
8906 /* Handle expose event while piece being dragged */
8911 if (!player.dragActive || appData.blindfold)
8914 /* What we're doing: logically, the move hasn't been made yet,
8915 so the piece is still in it's original square. But visually
8916 it's being dragged around the board. So we erase the square
8917 that the piece is on and draw it at the last known drag point. */
8918 BlankSquare(player.startSquare.x, player.startSquare.y,
8919 player.startColor, EmptySquare, xBoardWindow);
8920 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8921 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8924 #include <sys/ioctl.h>
8925 int get_term_width()
8927 int fd, default_width;
8930 default_width = 79; // this is FICS default anyway...
8932 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8934 if (!ioctl(fd, TIOCGSIZE, &win))
8935 default_width = win.ts_cols;
8936 #elif defined(TIOCGWINSZ)
8938 if (!ioctl(fd, TIOCGWINSZ, &win))
8939 default_width = win.ws_col;
8941 return default_width;
8944 void update_ics_width()
8946 static int old_width = 0;
8947 int new_width = get_term_width();
8949 if (old_width != new_width)
8950 ics_printf("set width %d\n", new_width);
8951 old_width = new_width;
8954 void NotifyFrontendLogin()