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 sprintf(buf, "{%s} ", argv[i]);
1598 else sprintf(buf, "%s ", argv[i]);
1601 line[strlen(line)-1] = NULLCHAR;
1605 //--------------------------------------------------------------------------------------------
1607 extern Boolean twoBoards, partnerUp;
1610 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1612 #define BoardSize int
1613 void InitDrawingSizes(BoardSize boardSize, int flags)
1614 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1615 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1617 XtGeometryResult gres;
1620 if(!formWidget) return;
1623 * Enable shell resizing.
1625 shellArgs[0].value = (XtArgVal) &w;
1626 shellArgs[1].value = (XtArgVal) &h;
1627 XtGetValues(shellWidget, shellArgs, 2);
1629 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1630 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1631 XtSetValues(shellWidget, &shellArgs[2], 4);
1633 XtSetArg(args[0], XtNdefaultDistance, &sep);
1634 XtGetValues(formWidget, args, 1);
1636 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1637 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1639 hOffset = boardWidth + 10;
1640 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1641 secondSegments[i] = gridSegments[i];
1642 secondSegments[i].x1 += hOffset;
1643 secondSegments[i].x2 += hOffset;
1646 XtSetArg(args[0], XtNwidth, boardWidth);
1647 XtSetArg(args[1], XtNheight, boardHeight);
1648 XtSetValues(boardWidget, args, 2);
1650 timerWidth = (boardWidth - sep) / 2;
1651 XtSetArg(args[0], XtNwidth, timerWidth);
1652 XtSetValues(whiteTimerWidget, args, 1);
1653 XtSetValues(blackTimerWidget, args, 1);
1655 XawFormDoLayout(formWidget, False);
1657 if (appData.titleInWindow) {
1659 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1660 XtSetArg(args[i], XtNheight, &h); i++;
1661 XtGetValues(titleWidget, args, i);
1663 w = boardWidth - 2*bor;
1665 XtSetArg(args[0], XtNwidth, &w);
1666 XtGetValues(menuBarWidget, args, 1);
1667 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1670 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1671 if (gres != XtGeometryYes && appData.debugMode) {
1673 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1674 programName, gres, w, h, wr, hr);
1678 XawFormDoLayout(formWidget, True);
1681 * Inhibit shell resizing.
1683 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1684 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1685 shellArgs[4].value = shellArgs[2].value = w;
1686 shellArgs[5].value = shellArgs[3].value = h;
1687 XtSetValues(shellWidget, &shellArgs[0], 6);
1689 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1692 for(i=0; i<4; i++) {
1694 for(p=0; p<=(int)WhiteKing; p++)
1695 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1696 if(gameInfo.variant == VariantShogi) {
1697 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1698 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1699 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1700 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1701 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1704 if(gameInfo.variant == VariantGothic) {
1705 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1709 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1710 for(p=0; p<=(int)WhiteKing; p++)
1711 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1712 if(gameInfo.variant == VariantShogi) {
1713 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1714 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1715 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1716 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1717 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1720 if(gameInfo.variant == VariantGothic) {
1721 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1727 for(i=0; i<2; i++) {
1729 for(p=0; p<=(int)WhiteKing; p++)
1730 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1731 if(gameInfo.variant == VariantShogi) {
1732 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1733 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1734 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1735 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1736 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1739 if(gameInfo.variant == VariantGothic) {
1740 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1756 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1757 XSetWindowAttributes window_attributes;
1759 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1760 XrmValue vFrom, vTo;
1761 XtGeometryResult gres;
1764 int forceMono = False;
1766 srandom(time(0)); // [HGM] book: make random truly random
1768 setbuf(stdout, NULL);
1769 setbuf(stderr, NULL);
1772 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1773 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1777 programName = strrchr(argv[0], '/');
1778 if (programName == NULL)
1779 programName = argv[0];
1784 XtSetLanguageProc(NULL, NULL, NULL);
1785 bindtextdomain(PACKAGE, LOCALEDIR);
1786 textdomain(PACKAGE);
1790 XtAppInitialize(&appContext, "XBoard", shellOptions,
1791 XtNumber(shellOptions),
1792 &argc, argv, xboardResources, NULL, 0);
1793 appData.boardSize = "";
1794 InitAppData(ConvertToLine(argc, argv));
1796 if (p == NULL) p = "/tmp";
1797 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1798 gameCopyFilename = (char*) malloc(i);
1799 gamePasteFilename = (char*) malloc(i);
1800 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1801 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1803 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1804 clientResources, XtNumber(clientResources),
1807 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1808 static char buf[MSG_SIZ];
1809 EscapeExpand(buf, appData.initString);
1810 appData.initString = strdup(buf);
1811 EscapeExpand(buf, appData.secondInitString);
1812 appData.secondInitString = strdup(buf);
1813 EscapeExpand(buf, appData.firstComputerString);
1814 appData.firstComputerString = strdup(buf);
1815 EscapeExpand(buf, appData.secondComputerString);
1816 appData.secondComputerString = strdup(buf);
1819 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1822 if (chdir(chessDir) != 0) {
1823 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1829 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1830 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1831 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1832 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1835 setbuf(debugFP, NULL);
1838 /* [HGM,HR] make sure board size is acceptable */
1839 if(appData.NrFiles > BOARD_FILES ||
1840 appData.NrRanks > BOARD_RANKS )
1841 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1844 /* This feature does not work; animation needs a rewrite */
1845 appData.highlightDragging = FALSE;
1849 xDisplay = XtDisplay(shellWidget);
1850 xScreen = DefaultScreen(xDisplay);
1851 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1853 gameInfo.variant = StringToVariant(appData.variant);
1854 InitPosition(FALSE);
1857 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1859 if (isdigit(appData.boardSize[0])) {
1860 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1861 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1862 &fontPxlSize, &smallLayout, &tinyLayout);
1864 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1865 programName, appData.boardSize);
1869 /* Find some defaults; use the nearest known size */
1870 SizeDefaults *szd, *nearest;
1871 int distance = 99999;
1872 nearest = szd = sizeDefaults;
1873 while (szd->name != NULL) {
1874 if (abs(szd->squareSize - squareSize) < distance) {
1876 distance = abs(szd->squareSize - squareSize);
1877 if (distance == 0) break;
1881 if (i < 2) lineGap = nearest->lineGap;
1882 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1883 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1884 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1885 if (i < 6) smallLayout = nearest->smallLayout;
1886 if (i < 7) tinyLayout = nearest->tinyLayout;
1889 SizeDefaults *szd = sizeDefaults;
1890 if (*appData.boardSize == NULLCHAR) {
1891 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1892 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1895 if (szd->name == NULL) szd--;
1896 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1898 while (szd->name != NULL &&
1899 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1900 if (szd->name == NULL) {
1901 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1902 programName, appData.boardSize);
1906 squareSize = szd->squareSize;
1907 lineGap = szd->lineGap;
1908 clockFontPxlSize = szd->clockFontPxlSize;
1909 coordFontPxlSize = szd->coordFontPxlSize;
1910 fontPxlSize = szd->fontPxlSize;
1911 smallLayout = szd->smallLayout;
1912 tinyLayout = szd->tinyLayout;
1913 // [HGM] font: use defaults from settings file if available and not overruled
1915 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1916 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1917 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1918 appData.font = fontTable[MESSAGE_FONT][squareSize];
1919 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1920 appData.coordFont = fontTable[COORD_FONT][squareSize];
1922 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1923 if (strlen(appData.pixmapDirectory) > 0) {
1924 p = ExpandPathName(appData.pixmapDirectory);
1926 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1927 appData.pixmapDirectory);
1930 if (appData.debugMode) {
1931 fprintf(stderr, _("\
1932 XBoard square size (hint): %d\n\
1933 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1935 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1936 if (appData.debugMode) {
1937 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1941 /* [HR] height treated separately (hacked) */
1942 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1943 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1944 if (appData.showJail == 1) {
1945 /* Jail on top and bottom */
1946 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1947 XtSetArg(boardArgs[2], XtNheight,
1948 boardHeight + 2*(lineGap + squareSize));
1949 } else if (appData.showJail == 2) {
1951 XtSetArg(boardArgs[1], XtNwidth,
1952 boardWidth + 2*(lineGap + squareSize));
1953 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1956 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1957 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1961 * Determine what fonts to use.
1963 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1964 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1965 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1966 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1967 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1968 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1969 appData.font = FindFont(appData.font, fontPxlSize);
1970 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1971 countFontStruct = XQueryFont(xDisplay, countFontID);
1972 // appData.font = FindFont(appData.font, fontPxlSize);
1974 xdb = XtDatabase(xDisplay);
1975 XrmPutStringResource(&xdb, "*font", appData.font);
1978 * Detect if there are not enough colors available and adapt.
1980 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1981 appData.monoMode = True;
1984 if (!appData.monoMode) {
1985 vFrom.addr = (caddr_t) appData.lightSquareColor;
1986 vFrom.size = strlen(appData.lightSquareColor);
1987 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1988 if (vTo.addr == NULL) {
1989 appData.monoMode = True;
1992 lightSquareColor = *(Pixel *) vTo.addr;
1995 if (!appData.monoMode) {
1996 vFrom.addr = (caddr_t) appData.darkSquareColor;
1997 vFrom.size = strlen(appData.darkSquareColor);
1998 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1999 if (vTo.addr == NULL) {
2000 appData.monoMode = True;
2003 darkSquareColor = *(Pixel *) vTo.addr;
2006 if (!appData.monoMode) {
2007 vFrom.addr = (caddr_t) appData.whitePieceColor;
2008 vFrom.size = strlen(appData.whitePieceColor);
2009 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2010 if (vTo.addr == NULL) {
2011 appData.monoMode = True;
2014 whitePieceColor = *(Pixel *) vTo.addr;
2017 if (!appData.monoMode) {
2018 vFrom.addr = (caddr_t) appData.blackPieceColor;
2019 vFrom.size = strlen(appData.blackPieceColor);
2020 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2021 if (vTo.addr == NULL) {
2022 appData.monoMode = True;
2025 blackPieceColor = *(Pixel *) vTo.addr;
2029 if (!appData.monoMode) {
2030 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2031 vFrom.size = strlen(appData.highlightSquareColor);
2032 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2033 if (vTo.addr == NULL) {
2034 appData.monoMode = True;
2037 highlightSquareColor = *(Pixel *) vTo.addr;
2041 if (!appData.monoMode) {
2042 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2043 vFrom.size = strlen(appData.premoveHighlightColor);
2044 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2045 if (vTo.addr == NULL) {
2046 appData.monoMode = True;
2049 premoveHighlightColor = *(Pixel *) vTo.addr;
2054 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2057 if (appData.bitmapDirectory == NULL ||
2058 appData.bitmapDirectory[0] == NULLCHAR)
2059 appData.bitmapDirectory = DEF_BITMAP_DIR;
2062 if (appData.lowTimeWarning && !appData.monoMode) {
2063 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2064 vFrom.size = strlen(appData.lowTimeWarningColor);
2065 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2066 if (vTo.addr == NULL)
2067 appData.monoMode = True;
2069 lowTimeWarningColor = *(Pixel *) vTo.addr;
2072 if (appData.monoMode && appData.debugMode) {
2073 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2074 (unsigned long) XWhitePixel(xDisplay, xScreen),
2075 (unsigned long) XBlackPixel(xDisplay, xScreen));
2078 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2079 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2080 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2081 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2082 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2083 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2084 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2085 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2086 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2087 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2089 if (appData.colorize) {
2091 _("%s: can't parse color names; disabling colorization\n"),
2094 appData.colorize = FALSE;
2096 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2097 textColors[ColorNone].attr = 0;
2099 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2105 layoutName = "tinyLayout";
2106 } else if (smallLayout) {
2107 layoutName = "smallLayout";
2109 layoutName = "normalLayout";
2111 /* Outer layoutWidget is there only to provide a name for use in
2112 resources that depend on the layout style */
2114 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2115 layoutArgs, XtNumber(layoutArgs));
2117 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2118 formArgs, XtNumber(formArgs));
2119 XtSetArg(args[0], XtNdefaultDistance, &sep);
2120 XtGetValues(formWidget, args, 1);
2123 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2124 XtSetArg(args[0], XtNtop, XtChainTop);
2125 XtSetArg(args[1], XtNbottom, XtChainTop);
2126 XtSetArg(args[2], XtNright, XtChainLeft);
2127 XtSetValues(menuBarWidget, args, 3);
2129 widgetList[j++] = whiteTimerWidget =
2130 XtCreateWidget("whiteTime", labelWidgetClass,
2131 formWidget, timerArgs, XtNumber(timerArgs));
2132 XtSetArg(args[0], XtNfont, clockFontStruct);
2133 XtSetArg(args[1], XtNtop, XtChainTop);
2134 XtSetArg(args[2], XtNbottom, XtChainTop);
2135 XtSetValues(whiteTimerWidget, args, 3);
2137 widgetList[j++] = blackTimerWidget =
2138 XtCreateWidget("blackTime", labelWidgetClass,
2139 formWidget, timerArgs, XtNumber(timerArgs));
2140 XtSetArg(args[0], XtNfont, clockFontStruct);
2141 XtSetArg(args[1], XtNtop, XtChainTop);
2142 XtSetArg(args[2], XtNbottom, XtChainTop);
2143 XtSetValues(blackTimerWidget, args, 3);
2145 if (appData.titleInWindow) {
2146 widgetList[j++] = titleWidget =
2147 XtCreateWidget("title", labelWidgetClass, formWidget,
2148 titleArgs, XtNumber(titleArgs));
2149 XtSetArg(args[0], XtNtop, XtChainTop);
2150 XtSetArg(args[1], XtNbottom, XtChainTop);
2151 XtSetValues(titleWidget, args, 2);
2154 if (appData.showButtonBar) {
2155 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2156 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2157 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2158 XtSetArg(args[2], XtNtop, XtChainTop);
2159 XtSetArg(args[3], XtNbottom, XtChainTop);
2160 XtSetValues(buttonBarWidget, args, 4);
2163 widgetList[j++] = messageWidget =
2164 XtCreateWidget("message", labelWidgetClass, formWidget,
2165 messageArgs, XtNumber(messageArgs));
2166 XtSetArg(args[0], XtNtop, XtChainTop);
2167 XtSetArg(args[1], XtNbottom, XtChainTop);
2168 XtSetValues(messageWidget, args, 2);
2170 widgetList[j++] = boardWidget =
2171 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2172 XtNumber(boardArgs));
2174 XtManageChildren(widgetList, j);
2176 timerWidth = (boardWidth - sep) / 2;
2177 XtSetArg(args[0], XtNwidth, timerWidth);
2178 XtSetValues(whiteTimerWidget, args, 1);
2179 XtSetValues(blackTimerWidget, args, 1);
2181 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2182 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2183 XtGetValues(whiteTimerWidget, args, 2);
2185 if (appData.showButtonBar) {
2186 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2187 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2188 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2192 * formWidget uses these constraints but they are stored
2196 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2197 XtSetValues(menuBarWidget, args, i);
2198 if (appData.titleInWindow) {
2201 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2202 XtSetValues(whiteTimerWidget, args, i);
2204 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2205 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2206 XtSetValues(blackTimerWidget, args, i);
2208 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2209 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2210 XtSetValues(titleWidget, args, i);
2212 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2213 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2214 XtSetValues(messageWidget, args, i);
2215 if (appData.showButtonBar) {
2217 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2218 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2219 XtSetValues(buttonBarWidget, args, i);
2223 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2224 XtSetValues(whiteTimerWidget, args, i);
2226 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2227 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2228 XtSetValues(blackTimerWidget, args, i);
2230 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2231 XtSetValues(titleWidget, args, i);
2233 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2234 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2235 XtSetValues(messageWidget, args, i);
2236 if (appData.showButtonBar) {
2238 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2239 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2240 XtSetValues(buttonBarWidget, args, i);
2245 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2246 XtSetValues(whiteTimerWidget, args, i);
2248 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2249 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2250 XtSetValues(blackTimerWidget, args, i);
2252 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2253 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2254 XtSetValues(messageWidget, args, i);
2255 if (appData.showButtonBar) {
2257 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2258 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2259 XtSetValues(buttonBarWidget, args, i);
2263 XtSetArg(args[0], XtNfromVert, messageWidget);
2264 XtSetArg(args[1], XtNtop, XtChainTop);
2265 XtSetArg(args[2], XtNbottom, XtChainBottom);
2266 XtSetArg(args[3], XtNleft, XtChainLeft);
2267 XtSetArg(args[4], XtNright, XtChainRight);
2268 XtSetValues(boardWidget, args, 5);
2270 XtRealizeWidget(shellWidget);
2273 XtSetArg(args[0], XtNx, wpMain.x);
2274 XtSetArg(args[1], XtNy, wpMain.y);
2275 XtSetValues(shellWidget, args, 2);
2279 * Correct the width of the message and title widgets.
2280 * It is not known why some systems need the extra fudge term.
2281 * The value "2" is probably larger than needed.
2283 XawFormDoLayout(formWidget, False);
2285 #define WIDTH_FUDGE 2
2287 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2288 XtSetArg(args[i], XtNheight, &h); i++;
2289 XtGetValues(messageWidget, args, i);
2290 if (appData.showButtonBar) {
2292 XtSetArg(args[i], XtNwidth, &w); i++;
2293 XtGetValues(buttonBarWidget, args, i);
2294 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2296 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2299 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2300 if (gres != XtGeometryYes && appData.debugMode) {
2301 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2302 programName, gres, w, h, wr, hr);
2305 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2306 /* The size used for the child widget in layout lags one resize behind
2307 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2309 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2310 if (gres != XtGeometryYes && appData.debugMode) {
2311 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2312 programName, gres, w, h, wr, hr);
2315 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2316 XtSetArg(args[1], XtNright, XtChainRight);
2317 XtSetValues(messageWidget, args, 2);
2319 if (appData.titleInWindow) {
2321 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2322 XtSetArg(args[i], XtNheight, &h); i++;
2323 XtGetValues(titleWidget, args, i);
2325 w = boardWidth - 2*bor;
2327 XtSetArg(args[0], XtNwidth, &w);
2328 XtGetValues(menuBarWidget, args, 1);
2329 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2332 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2333 if (gres != XtGeometryYes && appData.debugMode) {
2335 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2336 programName, gres, w, h, wr, hr);
2339 XawFormDoLayout(formWidget, True);
2341 xBoardWindow = XtWindow(boardWidget);
2343 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2344 // not need to go into InitDrawingSizes().
2348 * Create X checkmark bitmap and initialize option menu checks.
2350 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2351 checkmark_bits, checkmark_width, checkmark_height);
2352 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2353 if (appData.alwaysPromoteToQueen) {
2354 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2357 if (appData.animateDragging) {
2358 XtSetValues(XtNameToWidget(menuBarWidget,
2359 "menuOptions.Animate Dragging"),
2362 if (appData.animate) {
2363 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2366 if (appData.autoComment) {
2367 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2370 if (appData.autoCallFlag) {
2371 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2374 if (appData.autoFlipView) {
2375 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2378 if (appData.autoObserve) {
2379 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2382 if (appData.autoRaiseBoard) {
2383 XtSetValues(XtNameToWidget(menuBarWidget,
2384 "menuOptions.Auto Raise Board"), args, 1);
2386 if (appData.autoSaveGames) {
2387 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2390 if (appData.saveGameFile[0] != NULLCHAR) {
2391 /* Can't turn this off from menu */
2392 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2394 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2398 if (appData.blindfold) {
2399 XtSetValues(XtNameToWidget(menuBarWidget,
2400 "menuOptions.Blindfold"), args, 1);
2402 if (appData.flashCount > 0) {
2403 XtSetValues(XtNameToWidget(menuBarWidget,
2404 "menuOptions.Flash Moves"),
2407 if (appData.getMoveList) {
2408 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2412 if (appData.highlightDragging) {
2413 XtSetValues(XtNameToWidget(menuBarWidget,
2414 "menuOptions.Highlight Dragging"),
2418 if (appData.highlightLastMove) {
2419 XtSetValues(XtNameToWidget(menuBarWidget,
2420 "menuOptions.Highlight Last Move"),
2423 if (appData.icsAlarm) {
2424 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2427 if (appData.ringBellAfterMoves) {
2428 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2431 if (appData.oldSaveStyle) {
2432 XtSetValues(XtNameToWidget(menuBarWidget,
2433 "menuOptions.Old Save Style"), args, 1);
2435 if (appData.periodicUpdates) {
2436 XtSetValues(XtNameToWidget(menuBarWidget,
2437 "menuOptions.Periodic Updates"), args, 1);
2439 if (appData.ponderNextMove) {
2440 XtSetValues(XtNameToWidget(menuBarWidget,
2441 "menuOptions.Ponder Next Move"), args, 1);
2443 if (appData.popupExitMessage) {
2444 XtSetValues(XtNameToWidget(menuBarWidget,
2445 "menuOptions.Popup Exit Message"), args, 1);
2447 if (appData.popupMoveErrors) {
2448 XtSetValues(XtNameToWidget(menuBarWidget,
2449 "menuOptions.Popup Move Errors"), args, 1);
2451 if (appData.premove) {
2452 XtSetValues(XtNameToWidget(menuBarWidget,
2453 "menuOptions.Premove"), args, 1);
2455 if (appData.quietPlay) {
2456 XtSetValues(XtNameToWidget(menuBarWidget,
2457 "menuOptions.Quiet Play"), args, 1);
2459 if (appData.showCoords) {
2460 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2463 if (appData.hideThinkingFromHuman) {
2464 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2467 if (appData.testLegality) {
2468 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2471 if (saveSettingsOnExit) {
2472 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2479 ReadBitmap(&wIconPixmap, "icon_white.bm",
2480 icon_white_bits, icon_white_width, icon_white_height);
2481 ReadBitmap(&bIconPixmap, "icon_black.bm",
2482 icon_black_bits, icon_black_width, icon_black_height);
2483 iconPixmap = wIconPixmap;
2485 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2486 XtSetValues(shellWidget, args, i);
2489 * Create a cursor for the board widget.
2491 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2492 XChangeWindowAttributes(xDisplay, xBoardWindow,
2493 CWCursor, &window_attributes);
2496 * Inhibit shell resizing.
2498 shellArgs[0].value = (XtArgVal) &w;
2499 shellArgs[1].value = (XtArgVal) &h;
2500 XtGetValues(shellWidget, shellArgs, 2);
2501 shellArgs[4].value = shellArgs[2].value = w;
2502 shellArgs[5].value = shellArgs[3].value = h;
2503 XtSetValues(shellWidget, &shellArgs[2], 4);
2504 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2505 marginH = h - boardHeight;
2507 CatchDeleteWindow(shellWidget, "QuitProc");
2512 if (appData.bitmapDirectory[0] != NULLCHAR) {
2519 /* Create regular pieces */
2520 if (!useImages) CreatePieces();
2525 if (appData.animate || appData.animateDragging)
2528 XtAugmentTranslations(formWidget,
2529 XtParseTranslationTable(globalTranslations));
2530 XtAugmentTranslations(boardWidget,
2531 XtParseTranslationTable(boardTranslations));
2532 XtAugmentTranslations(whiteTimerWidget,
2533 XtParseTranslationTable(whiteTranslations));
2534 XtAugmentTranslations(blackTimerWidget,
2535 XtParseTranslationTable(blackTranslations));
2537 /* Why is the following needed on some versions of X instead
2538 * of a translation? */
2539 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2540 (XtEventHandler) EventProc, NULL);
2543 /* [AS] Restore layout */
2544 if( wpMoveHistory.visible ) {
2548 if( wpEvalGraph.visible )
2553 if( wpEngineOutput.visible ) {
2554 EngineOutputPopUp();
2559 if (errorExitStatus == -1) {
2560 if (appData.icsActive) {
2561 /* We now wait until we see "login:" from the ICS before
2562 sending the logon script (problems with timestamp otherwise) */
2563 /*ICSInitScript();*/
2564 if (appData.icsInputBox) ICSInputBoxPopUp();
2568 signal(SIGWINCH, TermSizeSigHandler);
2570 signal(SIGINT, IntSigHandler);
2571 signal(SIGTERM, IntSigHandler);
2572 if (*appData.cmailGameName != NULLCHAR) {
2573 signal(SIGUSR1, CmailSigHandler);
2576 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2578 XtSetKeyboardFocus(shellWidget, formWidget);
2580 XtAppMainLoop(appContext);
2581 if (appData.debugMode) fclose(debugFP); // [DM] debug
2588 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2589 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2591 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2592 unlink(gameCopyFilename);
2593 unlink(gamePasteFilename);
2596 RETSIGTYPE TermSizeSigHandler(int sig)
2609 CmailSigHandler(sig)
2615 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2617 /* Activate call-back function CmailSigHandlerCallBack() */
2618 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2620 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2624 CmailSigHandlerCallBack(isr, closure, message, count, error)
2632 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2634 /**** end signal code ****/
2644 f = fopen(appData.icsLogon, "r");
2648 safeStrCpy(buf, p, sizeof(buf)/sizeof(buf[0]) );
2650 strcat(buf, appData.icsLogon);
2651 f = fopen(buf, "r");
2655 ProcessICSInitScript(f);
2662 EditCommentPopDown();
2677 if (!menuBarWidget) return;
2678 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2680 DisplayError("menuStep.Revert", 0);
2682 XtSetSensitive(w, !grey);
2684 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2686 DisplayError("menuStep.Annotate", 0);
2688 XtSetSensitive(w, !grey);
2693 SetMenuEnables(enab)
2697 if (!menuBarWidget) return;
2698 while (enab->name != NULL) {
2699 w = XtNameToWidget(menuBarWidget, enab->name);
2701 DisplayError(enab->name, 0);
2703 XtSetSensitive(w, enab->value);
2709 Enables icsEnables[] = {
2710 { "menuFile.Mail Move", False },
2711 { "menuFile.Reload CMail Message", False },
2712 { "menuMode.Machine Black", False },
2713 { "menuMode.Machine White", False },
2714 { "menuMode.Analysis Mode", False },
2715 { "menuMode.Analyze File", False },
2716 { "menuMode.Two Machines", False },
2718 { "menuHelp.Hint", False },
2719 { "menuHelp.Book", False },
2720 { "menuStep.Move Now", False },
2721 { "menuOptions.Periodic Updates", False },
2722 { "menuOptions.Hide Thinking", False },
2723 { "menuOptions.Ponder Next Move", False },
2725 { "menuStep.Annotate", False },
2729 Enables ncpEnables[] = {
2730 { "menuFile.Mail Move", False },
2731 { "menuFile.Reload CMail Message", False },
2732 { "menuMode.Machine White", False },
2733 { "menuMode.Machine Black", False },
2734 { "menuMode.Analysis Mode", False },
2735 { "menuMode.Analyze File", False },
2736 { "menuMode.Two Machines", False },
2737 { "menuMode.ICS Client", False },
2738 { "menuMode.ICS Input Box", False },
2739 { "Action", False },
2740 { "menuStep.Revert", False },
2741 { "menuStep.Annotate", False },
2742 { "menuStep.Move Now", False },
2743 { "menuStep.Retract Move", False },
2744 { "menuOptions.Auto Comment", False },
2745 { "menuOptions.Auto Flag", False },
2746 { "menuOptions.Auto Flip View", False },
2747 { "menuOptions.Auto Observe", False },
2748 { "menuOptions.Auto Raise Board", False },
2749 { "menuOptions.Get Move List", False },
2750 { "menuOptions.ICS Alarm", False },
2751 { "menuOptions.Move Sound", False },
2752 { "menuOptions.Quiet Play", False },
2753 { "menuOptions.Hide Thinking", False },
2754 { "menuOptions.Periodic Updates", False },
2755 { "menuOptions.Ponder Next Move", False },
2756 { "menuHelp.Hint", False },
2757 { "menuHelp.Book", False },
2761 Enables gnuEnables[] = {
2762 { "menuMode.ICS Client", False },
2763 { "menuMode.ICS Input Box", False },
2764 { "menuAction.Accept", False },
2765 { "menuAction.Decline", False },
2766 { "menuAction.Rematch", False },
2767 { "menuAction.Adjourn", False },
2768 { "menuAction.Stop Examining", False },
2769 { "menuAction.Stop Observing", False },
2770 { "menuAction.Upload to Examine", False },
2771 { "menuStep.Revert", False },
2772 { "menuStep.Annotate", False },
2773 { "menuOptions.Auto Comment", False },
2774 { "menuOptions.Auto Observe", False },
2775 { "menuOptions.Auto Raise Board", False },
2776 { "menuOptions.Get Move List", False },
2777 { "menuOptions.Premove", False },
2778 { "menuOptions.Quiet Play", False },
2780 /* The next two options rely on SetCmailMode being called *after* */
2781 /* SetGNUMode so that when GNU is being used to give hints these */
2782 /* menu options are still available */
2784 { "menuFile.Mail Move", False },
2785 { "menuFile.Reload CMail Message", False },
2789 Enables cmailEnables[] = {
2791 { "menuAction.Call Flag", False },
2792 { "menuAction.Draw", True },
2793 { "menuAction.Adjourn", False },
2794 { "menuAction.Abort", False },
2795 { "menuAction.Stop Observing", False },
2796 { "menuAction.Stop Examining", False },
2797 { "menuFile.Mail Move", True },
2798 { "menuFile.Reload CMail Message", True },
2802 Enables trainingOnEnables[] = {
2803 { "menuMode.Edit Comment", False },
2804 { "menuMode.Pause", False },
2805 { "menuStep.Forward", False },
2806 { "menuStep.Backward", False },
2807 { "menuStep.Forward to End", False },
2808 { "menuStep.Back to Start", False },
2809 { "menuStep.Move Now", False },
2810 { "menuStep.Truncate Game", False },
2814 Enables trainingOffEnables[] = {
2815 { "menuMode.Edit Comment", True },
2816 { "menuMode.Pause", True },
2817 { "menuStep.Forward", True },
2818 { "menuStep.Backward", True },
2819 { "menuStep.Forward to End", True },
2820 { "menuStep.Back to Start", True },
2821 { "menuStep.Move Now", True },
2822 { "menuStep.Truncate Game", True },
2826 Enables machineThinkingEnables[] = {
2827 { "menuFile.Load Game", False },
2828 { "menuFile.Load Next Game", False },
2829 { "menuFile.Load Previous Game", False },
2830 { "menuFile.Reload Same Game", False },
2831 { "menuFile.Paste Game", False },
2832 { "menuFile.Load Position", False },
2833 { "menuFile.Load Next Position", False },
2834 { "menuFile.Load Previous Position", False },
2835 { "menuFile.Reload Same Position", False },
2836 { "menuFile.Paste Position", False },
2837 { "menuMode.Machine White", False },
2838 { "menuMode.Machine Black", False },
2839 { "menuMode.Two Machines", False },
2840 { "menuStep.Retract Move", False },
2844 Enables userThinkingEnables[] = {
2845 { "menuFile.Load Game", True },
2846 { "menuFile.Load Next Game", True },
2847 { "menuFile.Load Previous Game", True },
2848 { "menuFile.Reload Same Game", True },
2849 { "menuFile.Paste Game", True },
2850 { "menuFile.Load Position", True },
2851 { "menuFile.Load Next Position", True },
2852 { "menuFile.Load Previous Position", True },
2853 { "menuFile.Reload Same Position", True },
2854 { "menuFile.Paste Position", True },
2855 { "menuMode.Machine White", True },
2856 { "menuMode.Machine Black", True },
2857 { "menuMode.Two Machines", True },
2858 { "menuStep.Retract Move", True },
2864 SetMenuEnables(icsEnables);
2867 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2868 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2875 SetMenuEnables(ncpEnables);
2881 SetMenuEnables(gnuEnables);
2887 SetMenuEnables(cmailEnables);
2893 SetMenuEnables(trainingOnEnables);
2894 if (appData.showButtonBar) {
2895 XtSetSensitive(buttonBarWidget, False);
2901 SetTrainingModeOff()
2903 SetMenuEnables(trainingOffEnables);
2904 if (appData.showButtonBar) {
2905 XtSetSensitive(buttonBarWidget, True);
2910 SetUserThinkingEnables()
2912 if (appData.noChessProgram) return;
2913 SetMenuEnables(userThinkingEnables);
2917 SetMachineThinkingEnables()
2919 if (appData.noChessProgram) return;
2920 SetMenuEnables(machineThinkingEnables);
2922 case MachinePlaysBlack:
2923 case MachinePlaysWhite:
2924 case TwoMachinesPlay:
2925 XtSetSensitive(XtNameToWidget(menuBarWidget,
2926 ModeToWidgetName(gameMode)), True);
2933 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2934 #define HISTORY_SIZE 64
\r
2935 static char *history[HISTORY_SIZE];
\r
2936 int histIn = 0, histP = 0;
\r
2939 SaveInHistory(char *cmd)
\r
2941 if (history[histIn] != NULL) {
\r
2942 free(history[histIn]);
\r
2943 history[histIn] = NULL;
\r
2945 if (*cmd == NULLCHAR) return;
\r
2946 history[histIn] = StrSave(cmd);
\r
2947 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2948 if (history[histIn] != NULL) {
\r
2949 free(history[histIn]);
\r
2950 history[histIn] = NULL;
\r
2956 PrevInHistory(char *cmd)
\r
2959 if (histP == histIn) {
\r
2960 if (history[histIn] != NULL) free(history[histIn]);
\r
2961 history[histIn] = StrSave(cmd);
\r
2963 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2964 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2966 return history[histP];
\r
2972 if (histP == histIn) return NULL;
\r
2973 histP = (histP + 1) % HISTORY_SIZE;
\r
2974 return history[histP];
\r
2976 // end of borrowed code
\r
2978 #define Abs(n) ((n)<0 ? -(n) : (n))
2981 * Find a font that matches "pattern" that is as close as
2982 * possible to the targetPxlSize. Prefer fonts that are k
2983 * pixels smaller to fonts that are k pixels larger. The
2984 * pattern must be in the X Consortium standard format,
2985 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2986 * The return value should be freed with XtFree when no
2990 FindFont(pattern, targetPxlSize)
2994 char **fonts, *p, *best, *scalable, *scalableTail;
2995 int i, j, nfonts, minerr, err, pxlSize;
2998 char **missing_list;
3000 char *def_string, *base_fnt_lst, strInt[3];
3002 XFontStruct **fnt_list;
3004 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3005 sprintf(strInt, "%d", targetPxlSize);
3006 p = strstr(pattern, "--");
3007 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3008 strcat(base_fnt_lst, strInt);
3009 strcat(base_fnt_lst, strchr(p + 2, '-'));
3011 if ((fntSet = XCreateFontSet(xDisplay,
3015 &def_string)) == NULL) {
3017 fprintf(stderr, _("Unable to create font set.\n"));
3021 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3023 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3025 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3026 programName, pattern);
3034 for (i=0; i<nfonts; i++) {
3037 if (*p != '-') continue;
3039 if (*p == NULLCHAR) break;
3040 if (*p++ == '-') j++;
3042 if (j < 7) continue;
3045 scalable = fonts[i];
3048 err = pxlSize - targetPxlSize;
3049 if (Abs(err) < Abs(minerr) ||
3050 (minerr > 0 && err < 0 && -err == minerr)) {
3056 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3057 /* If the error is too big and there is a scalable font,
3058 use the scalable font. */
3059 int headlen = scalableTail - scalable;
3060 p = (char *) XtMalloc(strlen(scalable) + 10);
3061 while (isdigit(*scalableTail)) scalableTail++;
3062 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3064 p = (char *) XtMalloc(strlen(best) + 2);
3065 safeStrCpy(p, best, strlen(best)+1 );
3067 if (appData.debugMode) {
3068 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3069 pattern, targetPxlSize, p);
3072 if (missing_count > 0)
3073 XFreeStringList(missing_list);
3074 XFreeFontSet(xDisplay, fntSet);
3076 XFreeFontNames(fonts);
3083 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3084 | GCBackground | GCFunction | GCPlaneMask;
3085 XGCValues gc_values;
3088 gc_values.plane_mask = AllPlanes;
3089 gc_values.line_width = lineGap;
3090 gc_values.line_style = LineSolid;
3091 gc_values.function = GXcopy;
3093 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3094 gc_values.background = XBlackPixel(xDisplay, xScreen);
3095 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3097 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3098 gc_values.background = XWhitePixel(xDisplay, xScreen);
3099 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3100 XSetFont(xDisplay, coordGC, coordFontID);
3102 // [HGM] make font for holdings counts (white on black0
3103 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3104 gc_values.background = XBlackPixel(xDisplay, xScreen);
3105 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3106 XSetFont(xDisplay, countGC, countFontID);
3108 if (appData.monoMode) {
3109 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3110 gc_values.background = XWhitePixel(xDisplay, xScreen);
3111 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3113 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3114 gc_values.background = XBlackPixel(xDisplay, xScreen);
3115 lightSquareGC = wbPieceGC
3116 = XtGetGC(shellWidget, value_mask, &gc_values);
3118 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3119 gc_values.background = XWhitePixel(xDisplay, xScreen);
3120 darkSquareGC = bwPieceGC
3121 = XtGetGC(shellWidget, value_mask, &gc_values);
3123 if (DefaultDepth(xDisplay, xScreen) == 1) {
3124 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3125 gc_values.function = GXcopyInverted;
3126 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3127 gc_values.function = GXcopy;
3128 if (XBlackPixel(xDisplay, xScreen) == 1) {
3129 bwPieceGC = darkSquareGC;
3130 wbPieceGC = copyInvertedGC;
3132 bwPieceGC = copyInvertedGC;
3133 wbPieceGC = lightSquareGC;
3137 gc_values.foreground = highlightSquareColor;
3138 gc_values.background = highlightSquareColor;
3139 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3141 gc_values.foreground = premoveHighlightColor;
3142 gc_values.background = premoveHighlightColor;
3143 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3145 gc_values.foreground = lightSquareColor;
3146 gc_values.background = darkSquareColor;
3147 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3149 gc_values.foreground = darkSquareColor;
3150 gc_values.background = lightSquareColor;
3151 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3153 gc_values.foreground = jailSquareColor;
3154 gc_values.background = jailSquareColor;
3155 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3157 gc_values.foreground = whitePieceColor;
3158 gc_values.background = darkSquareColor;
3159 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3161 gc_values.foreground = whitePieceColor;
3162 gc_values.background = lightSquareColor;
3163 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3165 gc_values.foreground = whitePieceColor;
3166 gc_values.background = jailSquareColor;
3167 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3169 gc_values.foreground = blackPieceColor;
3170 gc_values.background = darkSquareColor;
3171 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3173 gc_values.foreground = blackPieceColor;
3174 gc_values.background = lightSquareColor;
3175 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3177 gc_values.foreground = blackPieceColor;
3178 gc_values.background = jailSquareColor;
3179 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3183 void loadXIM(xim, xmask, filename, dest, mask)
3196 fp = fopen(filename, "rb");
3198 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3205 for (y=0; y<h; ++y) {
3206 for (x=0; x<h; ++x) {
3211 XPutPixel(xim, x, y, blackPieceColor);
3213 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3216 XPutPixel(xim, x, y, darkSquareColor);
3218 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3221 XPutPixel(xim, x, y, whitePieceColor);
3223 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3226 XPutPixel(xim, x, y, lightSquareColor);
3228 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3234 /* create Pixmap of piece */
3235 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3237 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3240 /* create Pixmap of clipmask
3241 Note: We assume the white/black pieces have the same
3242 outline, so we make only 6 masks. This is okay
3243 since the XPM clipmask routines do the same. */
3245 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3247 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3250 /* now create the 1-bit version */
3251 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3254 values.foreground = 1;
3255 values.background = 0;
3257 /* Don't use XtGetGC, not read only */
3258 maskGC = XCreateGC(xDisplay, *mask,
3259 GCForeground | GCBackground, &values);
3260 XCopyPlane(xDisplay, temp, *mask, maskGC,
3261 0, 0, squareSize, squareSize, 0, 0, 1);
3262 XFreePixmap(xDisplay, temp);
3267 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3269 void CreateXIMPieces()
3274 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3279 /* The XSynchronize calls were copied from CreatePieces.
3280 Not sure if needed, but can't hurt */
3281 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3284 /* temp needed by loadXIM() */
3285 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3286 0, 0, ss, ss, AllPlanes, XYPixmap);
3288 if (strlen(appData.pixmapDirectory) == 0) {
3292 if (appData.monoMode) {
3293 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3297 fprintf(stderr, _("\nLoading XIMs...\n"));
3299 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3300 fprintf(stderr, "%d", piece+1);
3301 for (kind=0; kind<4; kind++) {
3302 fprintf(stderr, ".");
3303 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3304 ExpandPathName(appData.pixmapDirectory),
3305 piece <= (int) WhiteKing ? "" : "w",
3306 pieceBitmapNames[piece],
3308 ximPieceBitmap[kind][piece] =
3309 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3310 0, 0, ss, ss, AllPlanes, XYPixmap);
3311 if (appData.debugMode)
3312 fprintf(stderr, _("(File:%s:) "), buf);
3313 loadXIM(ximPieceBitmap[kind][piece],
3315 &(xpmPieceBitmap2[kind][piece]),
3316 &(ximMaskPm2[piece]));
3317 if(piece <= (int)WhiteKing)
3318 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3320 fprintf(stderr," ");
3322 /* Load light and dark squares */
3323 /* If the LSQ and DSQ pieces don't exist, we will
3324 draw them with solid squares. */
3325 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3326 if (access(buf, 0) != 0) {
3330 fprintf(stderr, _("light square "));
3332 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3333 0, 0, ss, ss, AllPlanes, XYPixmap);
3334 if (appData.debugMode)
3335 fprintf(stderr, _("(File:%s:) "), buf);
3337 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3338 fprintf(stderr, _("dark square "));
3339 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3340 ExpandPathName(appData.pixmapDirectory), ss);
3341 if (appData.debugMode)
3342 fprintf(stderr, _("(File:%s:) "), buf);
3344 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3345 0, 0, ss, ss, AllPlanes, XYPixmap);
3346 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3347 xpmJailSquare = xpmLightSquare;
3349 fprintf(stderr, _("Done.\n"));
3351 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3355 void CreateXPMPieces()
3359 u_int ss = squareSize;
3361 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3362 XpmColorSymbol symbols[4];
3364 /* The XSynchronize calls were copied from CreatePieces.
3365 Not sure if needed, but can't hurt */
3366 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3368 /* Setup translations so piece colors match square colors */
3369 symbols[0].name = "light_piece";
3370 symbols[0].value = appData.whitePieceColor;
3371 symbols[1].name = "dark_piece";
3372 symbols[1].value = appData.blackPieceColor;
3373 symbols[2].name = "light_square";
3374 symbols[2].value = appData.lightSquareColor;
3375 symbols[3].name = "dark_square";
3376 symbols[3].value = appData.darkSquareColor;
3378 attr.valuemask = XpmColorSymbols;
3379 attr.colorsymbols = symbols;
3380 attr.numsymbols = 4;
3382 if (appData.monoMode) {
3383 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3387 if (strlen(appData.pixmapDirectory) == 0) {
3388 XpmPieces* pieces = builtInXpms;
3391 while (pieces->size != squareSize && pieces->size) pieces++;
3392 if (!pieces->size) {
3393 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3396 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3397 for (kind=0; kind<4; kind++) {
3399 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3400 pieces->xpm[piece][kind],
3401 &(xpmPieceBitmap2[kind][piece]),
3402 NULL, &attr)) != 0) {
3403 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3407 if(piece <= (int) WhiteKing)
3408 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3412 xpmJailSquare = xpmLightSquare;
3416 fprintf(stderr, _("\nLoading XPMs...\n"));
3419 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3420 fprintf(stderr, "%d ", piece+1);
3421 for (kind=0; kind<4; kind++) {
3422 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3423 ExpandPathName(appData.pixmapDirectory),
3424 piece > (int) WhiteKing ? "w" : "",
3425 pieceBitmapNames[piece],
3427 if (appData.debugMode) {
3428 fprintf(stderr, _("(File:%s:) "), buf);
3430 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3431 &(xpmPieceBitmap2[kind][piece]),
3432 NULL, &attr)) != 0) {
3433 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3434 // [HGM] missing: read of unorthodox piece failed; substitute King.
3435 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3436 ExpandPathName(appData.pixmapDirectory),
3438 if (appData.debugMode) {
3439 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3441 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3442 &(xpmPieceBitmap2[kind][piece]),
3446 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3451 if(piece <= (int) WhiteKing)
3452 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3455 /* Load light and dark squares */
3456 /* If the LSQ and DSQ pieces don't exist, we will
3457 draw them with solid squares. */
3458 fprintf(stderr, _("light square "));
3459 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3460 if (access(buf, 0) != 0) {
3464 if (appData.debugMode)
3465 fprintf(stderr, _("(File:%s:) "), buf);
3467 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3468 &xpmLightSquare, NULL, &attr)) != 0) {
3469 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3472 fprintf(stderr, _("dark square "));
3473 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3474 ExpandPathName(appData.pixmapDirectory), ss);
3475 if (appData.debugMode) {
3476 fprintf(stderr, _("(File:%s:) "), buf);
3478 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3479 &xpmDarkSquare, NULL, &attr)) != 0) {
3480 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3484 xpmJailSquare = xpmLightSquare;
3485 fprintf(stderr, _("Done.\n"));
3487 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3490 #endif /* HAVE_LIBXPM */
3493 /* No built-in bitmaps */
3498 u_int ss = squareSize;
3500 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3503 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3504 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3505 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3506 pieceBitmapNames[piece],
3507 ss, kind == SOLID ? 's' : 'o');
3508 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3509 if(piece <= (int)WhiteKing)
3510 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3514 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3518 /* With built-in bitmaps */
3521 BuiltInBits* bib = builtInBits;
3524 u_int ss = squareSize;
3526 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3529 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3531 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3532 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3533 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3534 pieceBitmapNames[piece],
3535 ss, kind == SOLID ? 's' : 'o');
3536 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3537 bib->bits[kind][piece], ss, ss);
3538 if(piece <= (int)WhiteKing)
3539 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3543 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3548 void ReadBitmap(pm, name, bits, wreq, hreq)
3551 unsigned char bits[];
3557 char msg[MSG_SIZ], fullname[MSG_SIZ];
3559 if (*appData.bitmapDirectory != NULLCHAR) {
3560 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3561 strcat(fullname, "/");
3562 strcat(fullname, name);
3563 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3564 &w, &h, pm, &x_hot, &y_hot);
3565 fprintf(stderr, "load %s\n", name);
3566 if (errcode != BitmapSuccess) {
3568 case BitmapOpenFailed:
3569 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3571 case BitmapFileInvalid:
3572 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3574 case BitmapNoMemory:
3575 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3579 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3583 fprintf(stderr, _("%s: %s...using built-in\n"),
3585 } else if (w != wreq || h != hreq) {
3587 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3588 programName, fullname, w, h, wreq, hreq);
3594 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3603 if (lineGap == 0) return;
3605 /* [HR] Split this into 2 loops for non-square boards. */
3607 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3608 gridSegments[i].x1 = 0;
3609 gridSegments[i].x2 =
3610 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3611 gridSegments[i].y1 = gridSegments[i].y2
3612 = lineGap / 2 + (i * (squareSize + lineGap));
3615 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3616 gridSegments[j + i].y1 = 0;
3617 gridSegments[j + i].y2 =
3618 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3619 gridSegments[j + i].x1 = gridSegments[j + i].x2
3620 = lineGap / 2 + (j * (squareSize + lineGap));
3624 static void MenuBarSelect(w, addr, index)
3629 XtActionProc proc = (XtActionProc) addr;
3631 (proc)(NULL, NULL, NULL, NULL);
3634 void CreateMenuBarPopup(parent, name, mb)
3644 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3647 XtSetArg(args[j], XtNleftMargin, 20); j++;
3648 XtSetArg(args[j], XtNrightMargin, 20); j++;
3650 while (mi->string != NULL) {
3651 if (strcmp(mi->string, "----") == 0) {
3652 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3655 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3656 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3658 XtAddCallback(entry, XtNcallback,
3659 (XtCallbackProc) MenuBarSelect,
3660 (caddr_t) mi->proc);
3666 Widget CreateMenuBar(mb)
3670 Widget anchor, menuBar;
3672 char menuName[MSG_SIZ];
3675 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3676 XtSetArg(args[j], XtNvSpace, 0); j++;
3677 XtSetArg(args[j], XtNborderWidth, 0); j++;
3678 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3679 formWidget, args, j);
3681 while (mb->name != NULL) {
3682 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3683 strcat(menuName, mb->name);
3685 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3688 shortName[0] = _(mb->name)[0];
3689 shortName[1] = NULLCHAR;
3690 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3693 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3696 XtSetArg(args[j], XtNborderWidth, 0); j++;
3697 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3699 CreateMenuBarPopup(menuBar, menuName, mb);
3705 Widget CreateButtonBar(mi)
3709 Widget button, buttonBar;
3713 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3715 XtSetArg(args[j], XtNhSpace, 0); j++;
3717 XtSetArg(args[j], XtNborderWidth, 0); j++;
3718 XtSetArg(args[j], XtNvSpace, 0); j++;
3719 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3720 formWidget, args, j);
3722 while (mi->string != NULL) {
3725 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3726 XtSetArg(args[j], XtNborderWidth, 0); j++;
3728 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3729 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3730 buttonBar, args, j);
3731 XtAddCallback(button, XtNcallback,
3732 (XtCallbackProc) MenuBarSelect,
3733 (caddr_t) mi->proc);
3740 CreatePieceMenu(name, color)
3747 ChessSquare selection;
3749 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3750 boardWidget, args, 0);
3752 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3753 String item = pieceMenuStrings[color][i];
3755 if (strcmp(item, "----") == 0) {
3756 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3759 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3760 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3762 selection = pieceMenuTranslation[color][i];
3763 XtAddCallback(entry, XtNcallback,
3764 (XtCallbackProc) PieceMenuSelect,
3765 (caddr_t) selection);
3766 if (selection == WhitePawn || selection == BlackPawn) {
3767 XtSetArg(args[0], XtNpopupOnEntry, entry);
3768 XtSetValues(menu, args, 1);
3781 ChessSquare selection;
3783 whitePieceMenu = CreatePieceMenu("menuW", 0);
3784 blackPieceMenu = CreatePieceMenu("menuB", 1);
3786 XtRegisterGrabAction(PieceMenuPopup, True,
3787 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3788 GrabModeAsync, GrabModeAsync);
3790 XtSetArg(args[0], XtNlabel, _("Drop"));
3791 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3792 boardWidget, args, 1);
3793 for (i = 0; i < DROP_MENU_SIZE; i++) {
3794 String item = dropMenuStrings[i];
3796 if (strcmp(item, "----") == 0) {
3797 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3800 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3801 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3803 selection = dropMenuTranslation[i];
3804 XtAddCallback(entry, XtNcallback,
3805 (XtCallbackProc) DropMenuSelect,
3806 (caddr_t) selection);
3811 void SetupDropMenu()
3819 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3820 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3821 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3822 dmEnables[i].piece);
3823 XtSetSensitive(entry, p != NULL || !appData.testLegality
3824 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3825 && !appData.icsActive));
3827 while (p && *p++ == dmEnables[i].piece) count++;
3828 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3830 XtSetArg(args[j], XtNlabel, label); j++;
3831 XtSetValues(entry, args, j);
3835 void PieceMenuPopup(w, event, params, num_params)
3839 Cardinal *num_params;
3841 String whichMenu; int menuNr;
3842 if (event->type == ButtonRelease)
3843 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3844 else if (event->type == ButtonPress)
3845 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3847 case 0: whichMenu = params[0]; break;
3848 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3850 case -1: if (errorUp) ErrorPopDown();
3853 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3856 static void PieceMenuSelect(w, piece, junk)
3861 if (pmFromX < 0 || pmFromY < 0) return;
3862 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3865 static void DropMenuSelect(w, piece, junk)
3870 if (pmFromX < 0 || pmFromY < 0) return;
3871 DropMenuEvent(piece, pmFromX, pmFromY);
3874 void WhiteClock(w, event, prms, nprms)
3880 if (gameMode == EditPosition || gameMode == IcsExamining) {
3881 SetWhiteToPlayEvent();
3882 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3887 void BlackClock(w, event, prms, nprms)
3893 if (gameMode == EditPosition || gameMode == IcsExamining) {
3894 SetBlackToPlayEvent();
3895 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3902 * If the user selects on a border boundary, return -1; if off the board,
3903 * return -2. Otherwise map the event coordinate to the square.
3905 int EventToSquare(x, limit)
3913 if ((x % (squareSize + lineGap)) >= squareSize)
3915 x /= (squareSize + lineGap);
3921 static void do_flash_delay(msec)
3927 static void drawHighlight(file, rank, gc)
3933 if (lineGap == 0 || appData.blindfold) return;
3936 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3937 (squareSize + lineGap);
3938 y = lineGap/2 + rank * (squareSize + lineGap);
3940 x = lineGap/2 + file * (squareSize + lineGap);
3941 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3942 (squareSize + lineGap);
3945 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3946 squareSize+lineGap, squareSize+lineGap);
3949 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3950 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3953 SetHighlights(fromX, fromY, toX, toY)
3954 int fromX, fromY, toX, toY;
3956 if (hi1X != fromX || hi1Y != fromY) {
3957 if (hi1X >= 0 && hi1Y >= 0) {
3958 drawHighlight(hi1X, hi1Y, lineGC);
3960 } // [HGM] first erase both, then draw new!
3961 if (hi2X != toX || hi2Y != toY) {
3962 if (hi2X >= 0 && hi2Y >= 0) {
3963 drawHighlight(hi2X, hi2Y, lineGC);
3966 if (hi1X != fromX || hi1Y != fromY) {
3967 if (fromX >= 0 && fromY >= 0) {
3968 drawHighlight(fromX, fromY, highlineGC);
3971 if (hi2X != toX || hi2Y != toY) {
3972 if (toX >= 0 && toY >= 0) {
3973 drawHighlight(toX, toY, highlineGC);
3985 SetHighlights(-1, -1, -1, -1);
3990 SetPremoveHighlights(fromX, fromY, toX, toY)
3991 int fromX, fromY, toX, toY;
3993 if (pm1X != fromX || pm1Y != fromY) {
3994 if (pm1X >= 0 && pm1Y >= 0) {
3995 drawHighlight(pm1X, pm1Y, lineGC);
3997 if (fromX >= 0 && fromY >= 0) {
3998 drawHighlight(fromX, fromY, prelineGC);
4001 if (pm2X != toX || pm2Y != toY) {
4002 if (pm2X >= 0 && pm2Y >= 0) {
4003 drawHighlight(pm2X, pm2Y, lineGC);
4005 if (toX >= 0 && toY >= 0) {
4006 drawHighlight(toX, toY, prelineGC);
4016 ClearPremoveHighlights()
4018 SetPremoveHighlights(-1, -1, -1, -1);
4021 static void BlankSquare(x, y, color, piece, dest)
4026 if (useImages && useImageSqs) {
4030 pm = xpmLightSquare;
4035 case 2: /* neutral */
4040 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4041 squareSize, squareSize, x, y);
4051 case 2: /* neutral */
4056 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4061 I split out the routines to draw a piece so that I could
4062 make a generic flash routine.
4064 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4066 int square_color, x, y;
4069 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4070 switch (square_color) {
4072 case 2: /* neutral */
4074 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4075 ? *pieceToOutline(piece)
4076 : *pieceToSolid(piece),
4077 dest, bwPieceGC, 0, 0,
4078 squareSize, squareSize, x, y);
4081 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4082 ? *pieceToSolid(piece)
4083 : *pieceToOutline(piece),
4084 dest, wbPieceGC, 0, 0,
4085 squareSize, squareSize, x, y);
4090 static void monoDrawPiece(piece, square_color, x, y, dest)
4092 int square_color, x, y;
4095 switch (square_color) {
4097 case 2: /* neutral */
4099 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4100 ? *pieceToOutline(piece)
4101 : *pieceToSolid(piece),
4102 dest, bwPieceGC, 0, 0,
4103 squareSize, squareSize, x, y, 1);
4106 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4107 ? *pieceToSolid(piece)
4108 : *pieceToOutline(piece),
4109 dest, wbPieceGC, 0, 0,
4110 squareSize, squareSize, x, y, 1);
4115 static void colorDrawPiece(piece, square_color, x, y, dest)
4117 int square_color, x, y;
4120 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4121 switch (square_color) {
4123 XCopyPlane(xDisplay, *pieceToSolid(piece),
4124 dest, (int) piece < (int) BlackPawn
4125 ? wlPieceGC : blPieceGC, 0, 0,
4126 squareSize, squareSize, x, y, 1);
4129 XCopyPlane(xDisplay, *pieceToSolid(piece),
4130 dest, (int) piece < (int) BlackPawn
4131 ? wdPieceGC : bdPieceGC, 0, 0,
4132 squareSize, squareSize, x, y, 1);
4134 case 2: /* neutral */
4136 XCopyPlane(xDisplay, *pieceToSolid(piece),
4137 dest, (int) piece < (int) BlackPawn
4138 ? wjPieceGC : bjPieceGC, 0, 0,
4139 squareSize, squareSize, x, y, 1);
4144 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4146 int square_color, x, y;
4151 switch (square_color) {
4153 case 2: /* neutral */
4155 if ((int)piece < (int) BlackPawn) {
4163 if ((int)piece < (int) BlackPawn) {
4171 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4172 dest, wlPieceGC, 0, 0,
4173 squareSize, squareSize, x, y);
4176 typedef void (*DrawFunc)();
4178 DrawFunc ChooseDrawFunc()
4180 if (appData.monoMode) {
4181 if (DefaultDepth(xDisplay, xScreen) == 1) {
4182 return monoDrawPiece_1bit;
4184 return monoDrawPiece;
4188 return colorDrawPieceImage;
4190 return colorDrawPiece;
4194 /* [HR] determine square color depending on chess variant. */
4195 static int SquareColor(row, column)
4200 if (gameInfo.variant == VariantXiangqi) {
4201 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4203 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4205 } else if (row <= 4) {
4211 square_color = ((column + row) % 2) == 1;
4214 /* [hgm] holdings: next line makes all holdings squares light */
4215 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4217 return square_color;
4220 void DrawSquare(row, column, piece, do_flash)
4221 int row, column, do_flash;
4224 int square_color, x, y, direction, font_ascent, font_descent;
4227 XCharStruct overall;
4231 /* Calculate delay in milliseconds (2-delays per complete flash) */
4232 flash_delay = 500 / appData.flashRate;
4235 x = lineGap + ((BOARD_WIDTH-1)-column) *
4236 (squareSize + lineGap);
4237 y = lineGap + row * (squareSize + lineGap);
4239 x = lineGap + column * (squareSize + lineGap);
4240 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4241 (squareSize + lineGap);
4244 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4246 square_color = SquareColor(row, column);
4248 if ( // [HGM] holdings: blank out area between board and holdings
4249 column == BOARD_LEFT-1 || column == BOARD_RGHT
4250 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4251 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4252 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4254 // [HGM] print piece counts next to holdings
4255 string[1] = NULLCHAR;
4256 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4257 string[0] = '0' + piece;
4258 XTextExtents(countFontStruct, string, 1, &direction,
4259 &font_ascent, &font_descent, &overall);
4260 if (appData.monoMode) {
4261 XDrawImageString(xDisplay, xBoardWindow, countGC,
4262 x + squareSize - overall.width - 2,
4263 y + font_ascent + 1, string, 1);
4265 XDrawString(xDisplay, xBoardWindow, countGC,
4266 x + squareSize - overall.width - 2,
4267 y + font_ascent + 1, string, 1);
4270 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4271 string[0] = '0' + piece;
4272 XTextExtents(countFontStruct, string, 1, &direction,
4273 &font_ascent, &font_descent, &overall);
4274 if (appData.monoMode) {
4275 XDrawImageString(xDisplay, xBoardWindow, countGC,
4276 x + 2, y + font_ascent + 1, string, 1);
4278 XDrawString(xDisplay, xBoardWindow, countGC,
4279 x + 2, y + font_ascent + 1, string, 1);
4283 if (piece == EmptySquare || appData.blindfold) {
4284 BlankSquare(x, y, square_color, piece, xBoardWindow);
4286 drawfunc = ChooseDrawFunc();
4287 if (do_flash && appData.flashCount > 0) {
4288 for (i=0; i<appData.flashCount; ++i) {
4290 drawfunc(piece, square_color, x, y, xBoardWindow);
4291 XSync(xDisplay, False);
4292 do_flash_delay(flash_delay);
4294 BlankSquare(x, y, square_color, piece, xBoardWindow);
4295 XSync(xDisplay, False);
4296 do_flash_delay(flash_delay);
4299 drawfunc(piece, square_color, x, y, xBoardWindow);
4303 string[1] = NULLCHAR;
4304 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4305 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4306 string[0] = 'a' + column - BOARD_LEFT;
4307 XTextExtents(coordFontStruct, string, 1, &direction,
4308 &font_ascent, &font_descent, &overall);
4309 if (appData.monoMode) {
4310 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4311 x + squareSize - overall.width - 2,
4312 y + squareSize - font_descent - 1, string, 1);
4314 XDrawString(xDisplay, xBoardWindow, coordGC,
4315 x + squareSize - overall.width - 2,
4316 y + squareSize - font_descent - 1, string, 1);
4319 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4320 string[0] = ONE + row;
4321 XTextExtents(coordFontStruct, string, 1, &direction,
4322 &font_ascent, &font_descent, &overall);
4323 if (appData.monoMode) {
4324 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4325 x + 2, y + font_ascent + 1, string, 1);
4327 XDrawString(xDisplay, xBoardWindow, coordGC,
4328 x + 2, y + font_ascent + 1, string, 1);
4331 if(!partnerUp && marker[row][column]) {
4332 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4333 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4338 /* Why is this needed on some versions of X? */
4339 void EventProc(widget, unused, event)
4344 if (!XtIsRealized(widget))
4347 switch (event->type) {
4349 if (event->xexpose.count > 0) return; /* no clipping is done */
4350 XDrawPosition(widget, True, NULL);
4351 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4352 flipView = !flipView; partnerUp = !partnerUp;
4353 XDrawPosition(widget, True, NULL);
4354 flipView = !flipView; partnerUp = !partnerUp;
4358 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4365 void DrawPosition(fullRedraw, board)
4366 /*Boolean*/int fullRedraw;
4369 XDrawPosition(boardWidget, fullRedraw, board);
4372 /* Returns 1 if there are "too many" differences between b1 and b2
4373 (i.e. more than 1 move was made) */
4374 static int too_many_diffs(b1, b2)
4380 for (i=0; i<BOARD_HEIGHT; ++i) {
4381 for (j=0; j<BOARD_WIDTH; ++j) {
4382 if (b1[i][j] != b2[i][j]) {
4383 if (++c > 4) /* Castling causes 4 diffs */
4392 /* Matrix describing castling maneuvers */
4393 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4394 static int castling_matrix[4][5] = {
4395 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4396 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4397 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4398 { 7, 7, 4, 5, 6 } /* 0-0, black */
4401 /* Checks whether castling occurred. If it did, *rrow and *rcol
4402 are set to the destination (row,col) of the rook that moved.
4404 Returns 1 if castling occurred, 0 if not.
4406 Note: Only handles a max of 1 castling move, so be sure
4407 to call too_many_diffs() first.
4409 static int check_castle_draw(newb, oldb, rrow, rcol)
4416 /* For each type of castling... */
4417 for (i=0; i<4; ++i) {
4418 r = castling_matrix[i];
4420 /* Check the 4 squares involved in the castling move */
4422 for (j=1; j<=4; ++j) {
4423 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4430 /* All 4 changed, so it must be a castling move */
4439 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4440 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4442 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4445 void DrawSeekBackground( int left, int top, int right, int bottom )
4447 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4450 void DrawSeekText(char *buf, int x, int y)
4452 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4455 void DrawSeekDot(int x, int y, int colorNr)
4457 int square = colorNr & 0x80;
4460 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4462 XFillRectangle(xDisplay, xBoardWindow, color,
4463 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4465 XFillArc(xDisplay, xBoardWindow, color,
4466 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4469 static int damage[2][BOARD_RANKS][BOARD_FILES];
4472 * event handler for redrawing the board
4474 void XDrawPosition(w, repaint, board)
4476 /*Boolean*/int repaint;
4480 static int lastFlipView = 0;
4481 static int lastBoardValid[2] = {0, 0};
4482 static Board lastBoard[2];
4485 int nr = twoBoards*partnerUp;
4487 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4489 if (board == NULL) {
4490 if (!lastBoardValid) return;
4491 board = lastBoard[nr];
4493 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4494 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4495 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4500 * It would be simpler to clear the window with XClearWindow()
4501 * but this causes a very distracting flicker.
4504 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4506 /* If too much changes (begin observing new game, etc.), don't
4508 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4510 /* Special check for castling so we don't flash both the king
4511 and the rook (just flash the king). */
4513 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4514 /* Draw rook with NO flashing. King will be drawn flashing later */
4515 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4516 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4520 /* First pass -- Draw (newly) empty squares and repair damage.
4521 This prevents you from having a piece show up twice while it
4522 is flashing on its new square */
4523 for (i = 0; i < BOARD_HEIGHT; i++)
4524 for (j = 0; j < BOARD_WIDTH; j++)
4525 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4526 || damage[nr][i][j]) {
4527 DrawSquare(i, j, board[i][j], 0);
4528 damage[nr][i][j] = False;
4531 /* Second pass -- Draw piece(s) in new position and flash them */
4532 for (i = 0; i < BOARD_HEIGHT; i++)
4533 for (j = 0; j < BOARD_WIDTH; j++)
4534 if (board[i][j] != lastBoard[nr][i][j]) {
4535 DrawSquare(i, j, board[i][j], do_flash);
4539 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4540 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4541 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4543 for (i = 0; i < BOARD_HEIGHT; i++)
4544 for (j = 0; j < BOARD_WIDTH; j++) {
4545 DrawSquare(i, j, board[i][j], 0);
4546 damage[nr][i][j] = False;
4550 CopyBoard(lastBoard[nr], board);
4551 lastBoardValid[nr] = 1;
4552 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4553 lastFlipView = flipView;
4555 /* Draw highlights */
4556 if (pm1X >= 0 && pm1Y >= 0) {
4557 drawHighlight(pm1X, pm1Y, prelineGC);
4559 if (pm2X >= 0 && pm2Y >= 0) {
4560 drawHighlight(pm2X, pm2Y, prelineGC);
4562 if (hi1X >= 0 && hi1Y >= 0) {
4563 drawHighlight(hi1X, hi1Y, highlineGC);
4565 if (hi2X >= 0 && hi2Y >= 0) {
4566 drawHighlight(hi2X, hi2Y, highlineGC);
4569 /* If piece being dragged around board, must redraw that too */
4572 XSync(xDisplay, False);
4577 * event handler for redrawing the board
4579 void DrawPositionProc(w, event, prms, nprms)
4585 XDrawPosition(w, True, NULL);
4590 * event handler for parsing user moves
4592 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4593 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4594 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4595 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4596 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4597 // and at the end FinishMove() to perform the move after optional promotion popups.
4598 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4599 void HandleUserMove(w, event, prms, nprms)
4605 if (w != boardWidget || errorExitStatus != -1) return;
4608 if (event->type == ButtonPress) {
4609 XtPopdown(promotionShell);
4610 XtDestroyWidget(promotionShell);
4611 promotionUp = False;
4619 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4620 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4621 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4624 void AnimateUserMove (Widget w, XEvent * event,
4625 String * params, Cardinal * nParams)
4627 DragPieceMove(event->xmotion.x, event->xmotion.y);
4630 void HandlePV (Widget w, XEvent * event,
4631 String * params, Cardinal * nParams)
4632 { // [HGM] pv: walk PV
4633 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4636 Widget CommentCreate(name, text, mutable, callback, lines)
4638 int /*Boolean*/ mutable;
4639 XtCallbackProc callback;
4643 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4648 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4649 XtGetValues(boardWidget, args, j);
4652 XtSetArg(args[j], XtNresizable, True); j++;
4655 XtCreatePopupShell(name, topLevelShellWidgetClass,
4656 shellWidget, args, j);
4659 XtCreatePopupShell(name, transientShellWidgetClass,
4660 shellWidget, args, j);
4663 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4664 layoutArgs, XtNumber(layoutArgs));
4666 XtCreateManagedWidget("form", formWidgetClass, layout,
4667 formArgs, XtNumber(formArgs));
4671 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4672 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4674 XtSetArg(args[j], XtNstring, text); j++;
4675 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4676 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4677 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4678 XtSetArg(args[j], XtNright, XtChainRight); j++;
4679 XtSetArg(args[j], XtNresizable, True); j++;
4680 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4681 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4682 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4683 XtSetArg(args[j], XtNautoFill, True); j++;
4684 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4686 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4687 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4691 XtSetArg(args[j], XtNfromVert, edit); j++;
4692 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4693 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4694 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4695 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4697 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4698 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4701 XtSetArg(args[j], XtNfromVert, edit); j++;
4702 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4703 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4704 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4705 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4706 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4708 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4709 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4712 XtSetArg(args[j], XtNfromVert, edit); j++;
4713 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4714 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4715 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4716 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4717 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4719 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4720 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4723 XtSetArg(args[j], XtNfromVert, edit); j++;
4724 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4725 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4726 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4727 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4729 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4730 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4733 XtSetArg(args[j], XtNfromVert, edit); j++;
4734 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4735 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4736 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4737 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4738 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4740 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4741 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4744 XtRealizeWidget(shell);
4746 if (commentX == -1) {
4749 Dimension pw_height;
4750 Dimension ew_height;
4753 XtSetArg(args[j], XtNheight, &ew_height); j++;
4754 XtGetValues(edit, args, j);
4757 XtSetArg(args[j], XtNheight, &pw_height); j++;
4758 XtGetValues(shell, args, j);
4759 commentH = pw_height + (lines - 1) * ew_height;
4760 commentW = bw_width - 16;
4762 XSync(xDisplay, False);
4764 /* This code seems to tickle an X bug if it is executed too soon
4765 after xboard starts up. The coordinates get transformed as if
4766 the main window was positioned at (0, 0).
4768 XtTranslateCoords(shellWidget,
4769 (bw_width - commentW) / 2, 0 - commentH / 2,
4770 &commentX, &commentY);
4772 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4773 RootWindowOfScreen(XtScreen(shellWidget)),
4774 (bw_width - commentW) / 2, 0 - commentH / 2,
4779 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4782 if(wpComment.width > 0) {
4783 commentX = wpComment.x;
4784 commentY = wpComment.y;
4785 commentW = wpComment.width;
4786 commentH = wpComment.height;
4790 XtSetArg(args[j], XtNheight, commentH); j++;
4791 XtSetArg(args[j], XtNwidth, commentW); j++;
4792 XtSetArg(args[j], XtNx, commentX); j++;
4793 XtSetArg(args[j], XtNy, commentY); j++;
4794 XtSetValues(shell, args, j);
4795 XtSetKeyboardFocus(shell, edit);
4800 /* Used for analysis window and ICS input window */
4801 Widget MiscCreate(name, text, mutable, callback, lines)
4803 int /*Boolean*/ mutable;
4804 XtCallbackProc callback;
4808 Widget shell, layout, form, edit;
4810 Dimension bw_width, pw_height, ew_height, w, h;
4816 XtSetArg(args[j], XtNresizable, True); j++;
4819 XtCreatePopupShell(name, topLevelShellWidgetClass,
4820 shellWidget, args, j);
4823 XtCreatePopupShell(name, transientShellWidgetClass,
4824 shellWidget, args, j);
4827 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4828 layoutArgs, XtNumber(layoutArgs));
4830 XtCreateManagedWidget("form", formWidgetClass, layout,
4831 formArgs, XtNumber(formArgs));
4835 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4836 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4838 XtSetArg(args[j], XtNstring, text); j++;
4839 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4840 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4841 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4842 XtSetArg(args[j], XtNright, XtChainRight); j++;
4843 XtSetArg(args[j], XtNresizable, True); j++;
4844 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4845 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4846 XtSetArg(args[j], XtNautoFill, True); j++;
4847 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4849 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4851 XtRealizeWidget(shell);
4854 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4855 XtGetValues(boardWidget, args, j);
4858 XtSetArg(args[j], XtNheight, &ew_height); j++;
4859 XtGetValues(edit, args, j);
4862 XtSetArg(args[j], XtNheight, &pw_height); j++;
4863 XtGetValues(shell, args, j);
4864 h = pw_height + (lines - 1) * ew_height;
4867 XSync(xDisplay, False);
4869 /* This code seems to tickle an X bug if it is executed too soon
4870 after xboard starts up. The coordinates get transformed as if
4871 the main window was positioned at (0, 0).
4873 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4875 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4876 RootWindowOfScreen(XtScreen(shellWidget)),
4877 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4881 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4884 XtSetArg(args[j], XtNheight, h); j++;
4885 XtSetArg(args[j], XtNwidth, w); j++;
4886 XtSetArg(args[j], XtNx, x); j++;
4887 XtSetArg(args[j], XtNy, y); j++;
4888 XtSetValues(shell, args, j);
4894 static int savedIndex; /* gross that this is global */
4896 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4899 XawTextPosition index, dummy;
4902 XawTextGetSelectionPos(w, &index, &dummy);
4903 XtSetArg(arg, XtNstring, &val);
4904 XtGetValues(w, &arg, 1);
4905 ReplaceComment(savedIndex, val);
4906 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4907 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4910 void EditCommentPopUp(index, title, text)
4919 if (text == NULL) text = "";
4921 if (editShell == NULL) {
4923 CommentCreate(title, text, True, EditCommentCallback, 4);
4924 XtRealizeWidget(editShell);
4925 CatchDeleteWindow(editShell, "EditCommentPopDown");
4927 edit = XtNameToWidget(editShell, "*form.text");
4929 XtSetArg(args[j], XtNstring, text); j++;
4930 XtSetValues(edit, args, j);
4932 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4933 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4934 XtSetValues(editShell, args, j);
4937 XtPopup(editShell, XtGrabNone);
4941 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4942 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4946 void EditCommentCallback(w, client_data, call_data)
4948 XtPointer client_data, call_data;
4956 XtSetArg(args[j], XtNlabel, &name); j++;
4957 XtGetValues(w, args, j);
4959 if (strcmp(name, _("ok")) == 0) {
4960 edit = XtNameToWidget(editShell, "*form.text");
4962 XtSetArg(args[j], XtNstring, &val); j++;
4963 XtGetValues(edit, args, j);
4964 ReplaceComment(savedIndex, val);
4965 EditCommentPopDown();
4966 } else if (strcmp(name, _("cancel")) == 0) {
4967 EditCommentPopDown();
4968 } else if (strcmp(name, _("clear")) == 0) {
4969 edit = XtNameToWidget(editShell, "*form.text");
4970 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4971 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4975 void EditCommentPopDown()
4980 if (!editUp) return;
4982 XtSetArg(args[j], XtNx, &commentX); j++;
4983 XtSetArg(args[j], XtNy, &commentY); j++;
4984 XtSetArg(args[j], XtNheight, &commentH); j++;
4985 XtSetArg(args[j], XtNwidth, &commentW); j++;
4986 XtGetValues(editShell, args, j);
4987 XtPopdown(editShell);
4990 XtSetArg(args[j], XtNleftBitmap, None); j++;
4991 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4995 void ICSInputBoxPopUp()
5000 char *title = _("ICS Input");
5003 if (ICSInputShell == NULL) {
5004 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5005 tr = XtParseTranslationTable(ICSInputTranslations);
5006 edit = XtNameToWidget(ICSInputShell, "*form.text");
5007 XtOverrideTranslations(edit, tr);
5008 XtRealizeWidget(ICSInputShell);
5009 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5012 edit = XtNameToWidget(ICSInputShell, "*form.text");
5014 XtSetArg(args[j], XtNstring, ""); j++;
5015 XtSetValues(edit, args, j);
5017 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5018 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5019 XtSetValues(ICSInputShell, args, j);
5022 XtPopup(ICSInputShell, XtGrabNone);
5023 XtSetKeyboardFocus(ICSInputShell, edit);
5025 ICSInputBoxUp = True;
5027 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5028 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5032 void ICSInputSendText()
5039 edit = XtNameToWidget(ICSInputShell, "*form.text");
5041 XtSetArg(args[j], XtNstring, &val); j++;
5042 XtGetValues(edit, args, j);
5044 SendMultiLineToICS(val);
5045 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5046 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5049 void ICSInputBoxPopDown()
5054 if (!ICSInputBoxUp) return;
5056 XtPopdown(ICSInputShell);
5057 ICSInputBoxUp = False;
5059 XtSetArg(args[j], XtNleftBitmap, None); j++;
5060 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5064 void CommentPopUp(title, text)
5071 savedIndex = currentMove; // [HGM] vari
5072 if (commentShell == NULL) {
5074 CommentCreate(title, text, False, CommentCallback, 4);
5075 XtRealizeWidget(commentShell);
5076 CatchDeleteWindow(commentShell, "CommentPopDown");
5078 edit = XtNameToWidget(commentShell, "*form.text");
5080 XtSetArg(args[j], XtNstring, text); j++;
5081 XtSetValues(edit, args, j);
5083 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5084 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5085 XtSetValues(commentShell, args, j);
5088 XtPopup(commentShell, XtGrabNone);
5089 XSync(xDisplay, False);
5094 void CommentCallback(w, client_data, call_data)
5096 XtPointer client_data, call_data;
5103 XtSetArg(args[j], XtNlabel, &name); j++;
5104 XtGetValues(w, args, j);
5106 if (strcmp(name, _("close")) == 0) {
5108 } else if (strcmp(name, _("edit")) == 0) {
5115 void CommentPopDown()
5120 if (!commentUp) return;
5122 XtSetArg(args[j], XtNx, &commentX); j++;
5123 XtSetArg(args[j], XtNy, &commentY); j++;
5124 XtSetArg(args[j], XtNwidth, &commentW); j++;
5125 XtSetArg(args[j], XtNheight, &commentH); j++;
5126 XtGetValues(commentShell, args, j);
5127 XtPopdown(commentShell);
5128 XSync(xDisplay, False);
5132 void FileNamePopUp(label, def, proc, openMode)
5139 Widget popup, layout, dialog, edit;
5145 fileProc = proc; /* I can't see a way not */
5146 fileOpenMode = openMode; /* to use globals here */
5147 { // [HGM] use file-selector dialog stolen from Ghostview
5149 int index; // this is not supported yet
5151 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5152 def, openMode, NULL, &name))
5153 (void) (*fileProc)(f, index=0, name);
5157 void FileNamePopDown()
5159 if (!filenameUp) return;
5160 XtPopdown(fileNameShell);
5161 XtDestroyWidget(fileNameShell);
5166 void FileNameCallback(w, client_data, call_data)
5168 XtPointer client_data, call_data;
5173 XtSetArg(args[0], XtNlabel, &name);
5174 XtGetValues(w, args, 1);
5176 if (strcmp(name, _("cancel")) == 0) {
5181 FileNameAction(w, NULL, NULL, NULL);
5184 void FileNameAction(w, event, prms, nprms)
5196 name = XawDialogGetValueString(w = XtParent(w));
5198 if ((name != NULL) && (*name != NULLCHAR)) {
5199 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5200 XtPopdown(w = XtParent(XtParent(w)));
5204 p = strrchr(buf, ' ');
5211 fullname = ExpandPathName(buf);
5213 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5216 f = fopen(fullname, fileOpenMode);
5218 DisplayError(_("Failed to open file"), errno);
5220 (void) (*fileProc)(f, index, buf);
5227 XtPopdown(w = XtParent(XtParent(w)));
5233 void PromotionPopUp()
5236 Widget dialog, layout;
5238 Dimension bw_width, pw_width;
5242 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5243 XtGetValues(boardWidget, args, j);
5246 XtSetArg(args[j], XtNresizable, True); j++;
5247 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5249 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5250 shellWidget, args, j);
5252 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5253 layoutArgs, XtNumber(layoutArgs));
5256 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5257 XtSetArg(args[j], XtNborderWidth, 0); j++;
5258 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5261 if(gameInfo.variant != VariantShogi) {
5262 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5263 (XtPointer) dialog);
5264 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5265 (XtPointer) dialog);
5266 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5267 (XtPointer) dialog);
5268 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5269 (XtPointer) dialog);
5270 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5271 gameInfo.variant == VariantGiveaway) {
5272 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5273 (XtPointer) dialog);
5275 if(gameInfo.variant == VariantCapablanca ||
5276 gameInfo.variant == VariantGothic ||
5277 gameInfo.variant == VariantCapaRandom) {
5278 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5279 (XtPointer) dialog);
5280 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5281 (XtPointer) dialog);
5283 } else // [HGM] shogi
5285 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5286 (XtPointer) dialog);
5287 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5288 (XtPointer) dialog);
5290 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5291 (XtPointer) dialog);
5293 XtRealizeWidget(promotionShell);
5294 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5297 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5298 XtGetValues(promotionShell, args, j);
5300 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5301 lineGap + squareSize/3 +
5302 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5303 0 : 6*(squareSize + lineGap)), &x, &y);
5306 XtSetArg(args[j], XtNx, x); j++;
5307 XtSetArg(args[j], XtNy, y); j++;
5308 XtSetValues(promotionShell, args, j);
5310 XtPopup(promotionShell, XtGrabNone);
5315 void PromotionPopDown()
5317 if (!promotionUp) return;
5318 XtPopdown(promotionShell);
5319 XtDestroyWidget(promotionShell);
5320 promotionUp = False;
5323 void PromotionCallback(w, client_data, call_data)
5325 XtPointer client_data, call_data;
5331 XtSetArg(args[0], XtNlabel, &name);
5332 XtGetValues(w, args, 1);
5336 if (fromX == -1) return;
5338 if (strcmp(name, _("cancel")) == 0) {
5342 } else if (strcmp(name, _("Knight")) == 0) {
5344 } else if (strcmp(name, _("Promote")) == 0) {
5346 } else if (strcmp(name, _("Defer")) == 0) {
5349 promoChar = ToLower(name[0]);
5352 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5354 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5355 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5360 void ErrorCallback(w, client_data, call_data)
5362 XtPointer client_data, call_data;
5365 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5367 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5373 if (!errorUp) return;
5375 XtPopdown(errorShell);
5376 XtDestroyWidget(errorShell);
5377 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5380 void ErrorPopUp(title, label, modal)
5381 char *title, *label;
5385 Widget dialog, layout;
5389 Dimension bw_width, pw_width;
5390 Dimension pw_height;
5394 XtSetArg(args[i], XtNresizable, True); i++;
5395 XtSetArg(args[i], XtNtitle, title); i++;
5397 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5398 shellWidget, args, i);
5400 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5401 layoutArgs, XtNumber(layoutArgs));
5404 XtSetArg(args[i], XtNlabel, label); i++;
5405 XtSetArg(args[i], XtNborderWidth, 0); i++;
5406 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5409 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5411 XtRealizeWidget(errorShell);
5412 CatchDeleteWindow(errorShell, "ErrorPopDown");
5415 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5416 XtGetValues(boardWidget, args, i);
5418 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5419 XtSetArg(args[i], XtNheight, &pw_height); i++;
5420 XtGetValues(errorShell, args, i);
5423 /* This code seems to tickle an X bug if it is executed too soon
5424 after xboard starts up. The coordinates get transformed as if
5425 the main window was positioned at (0, 0).
5427 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5428 0 - pw_height + squareSize / 3, &x, &y);
5430 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5431 RootWindowOfScreen(XtScreen(boardWidget)),
5432 (bw_width - pw_width) / 2,
5433 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5437 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5440 XtSetArg(args[i], XtNx, x); i++;
5441 XtSetArg(args[i], XtNy, y); i++;
5442 XtSetValues(errorShell, args, i);
5445 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5448 /* Disable all user input other than deleting the window */
5449 static int frozen = 0;
5453 /* Grab by a widget that doesn't accept input */
5454 XtAddGrab(messageWidget, TRUE, FALSE);
5458 /* Undo a FreezeUI */
5461 if (!frozen) return;
5462 XtRemoveGrab(messageWidget);
5466 char *ModeToWidgetName(mode)
5470 case BeginningOfGame:
5471 if (appData.icsActive)
5472 return "menuMode.ICS Client";
5473 else if (appData.noChessProgram ||
5474 *appData.cmailGameName != NULLCHAR)
5475 return "menuMode.Edit Game";
5477 return "menuMode.Machine Black";
5478 case MachinePlaysBlack:
5479 return "menuMode.Machine Black";
5480 case MachinePlaysWhite:
5481 return "menuMode.Machine White";
5483 return "menuMode.Analysis Mode";
5485 return "menuMode.Analyze File";
5486 case TwoMachinesPlay:
5487 return "menuMode.Two Machines";
5489 return "menuMode.Edit Game";
5490 case PlayFromGameFile:
5491 return "menuFile.Load Game";
5493 return "menuMode.Edit Position";
5495 return "menuMode.Training";
5496 case IcsPlayingWhite:
5497 case IcsPlayingBlack:
5501 return "menuMode.ICS Client";
5508 void ModeHighlight()
5511 static int oldPausing = FALSE;
5512 static GameMode oldmode = (GameMode) -1;
5515 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5517 if (pausing != oldPausing) {
5518 oldPausing = pausing;
5520 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5522 XtSetArg(args[0], XtNleftBitmap, None);
5524 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5527 if (appData.showButtonBar) {
5528 /* Always toggle, don't set. Previous code messes up when
5529 invoked while the button is pressed, as releasing it
5530 toggles the state again. */
5533 XtSetArg(args[0], XtNbackground, &oldbg);
5534 XtSetArg(args[1], XtNforeground, &oldfg);
5535 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5537 XtSetArg(args[0], XtNbackground, oldfg);
5538 XtSetArg(args[1], XtNforeground, oldbg);
5540 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5544 wname = ModeToWidgetName(oldmode);
5545 if (wname != NULL) {
5546 XtSetArg(args[0], XtNleftBitmap, None);
5547 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5549 wname = ModeToWidgetName(gameMode);
5550 if (wname != NULL) {
5551 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5552 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5556 /* Maybe all the enables should be handled here, not just this one */
5557 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5558 gameMode == Training || gameMode == PlayFromGameFile);
5563 * Button/menu procedures
5565 void ResetProc(w, event, prms, nprms)
5574 int LoadGamePopUp(f, gameNumber, title)
5579 cmailMsgLoaded = FALSE;
5580 if (gameNumber == 0) {
5581 int error = GameListBuild(f);
5583 DisplayError(_("Cannot build game list"), error);
5584 } else if (!ListEmpty(&gameList) &&
5585 ((ListGame *) gameList.tailPred)->number > 1) {
5586 GameListPopUp(f, title);
5592 return LoadGame(f, gameNumber, title, FALSE);
5595 void LoadGameProc(w, event, prms, nprms)
5601 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5604 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5607 void LoadNextGameProc(w, event, prms, nprms)
5616 void LoadPrevGameProc(w, event, prms, nprms)
5625 void ReloadGameProc(w, event, prms, nprms)
5634 void LoadNextPositionProc(w, event, prms, nprms)
5643 void LoadPrevPositionProc(w, event, prms, nprms)
5652 void ReloadPositionProc(w, event, prms, nprms)
5661 void LoadPositionProc(w, event, prms, nprms)
5667 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5670 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5673 void SaveGameProc(w, event, prms, nprms)
5679 FileNamePopUp(_("Save game file name?"),
5680 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5684 void SavePositionProc(w, event, prms, nprms)
5690 FileNamePopUp(_("Save position file name?"),
5691 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5695 void ReloadCmailMsgProc(w, event, prms, nprms)
5701 ReloadCmailMsgEvent(FALSE);
5704 void MailMoveProc(w, event, prms, nprms)
5713 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5714 char *selected_fen_position=NULL;
5717 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5718 Atom *type_return, XtPointer *value_return,
5719 unsigned long *length_return, int *format_return)
5721 char *selection_tmp;
5723 if (!selected_fen_position) return False; /* should never happen */
5724 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5725 /* note: since no XtSelectionDoneProc was registered, Xt will
5726 * automatically call XtFree on the value returned. So have to
5727 * make a copy of it allocated with XtMalloc */
5728 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5729 safeStrCpy(selection_tmp, selected_fen_position, sizeof(selection_tmp)/sizeof(selection_tmp[0]) );
5731 *value_return=selection_tmp;
5732 *length_return=strlen(selection_tmp);
5733 *type_return=*target;
5734 *format_return = 8; /* bits per byte */
5736 } else if (*target == XA_TARGETS(xDisplay)) {
5737 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5738 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5739 targets_tmp[1] = XA_STRING;
5740 *value_return = targets_tmp;
5741 *type_return = XA_ATOM;
5743 *format_return = 8 * sizeof(Atom);
5744 if (*format_return > 32) {
5745 *length_return *= *format_return / 32;
5746 *format_return = 32;
5754 /* note: when called from menu all parameters are NULL, so no clue what the
5755 * Widget which was clicked on was, or what the click event was
5757 void CopyPositionProc(w, event, prms, nprms)
5764 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5765 * have a notion of a position that is selected but not copied.
5766 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5768 if(gameMode == EditPosition) EditPositionDone(TRUE);
5769 if (selected_fen_position) free(selected_fen_position);
5770 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5771 if (!selected_fen_position) return;
5772 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5774 SendPositionSelection,
5775 NULL/* lose_ownership_proc */ ,
5776 NULL/* transfer_done_proc */);
5777 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5779 SendPositionSelection,
5780 NULL/* lose_ownership_proc */ ,
5781 NULL/* transfer_done_proc */);
5784 /* function called when the data to Paste is ready */
5786 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5787 Atom *type, XtPointer value, unsigned long *len, int *format)
5790 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5791 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5792 EditPositionPasteFEN(fenstr);
5796 /* called when Paste Position button is pressed,
5797 * all parameters will be NULL */
5798 void PastePositionProc(w, event, prms, nprms)
5804 XtGetSelectionValue(menuBarWidget,
5805 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5806 /* (XtSelectionCallbackProc) */ PastePositionCB,
5807 NULL, /* client_data passed to PastePositionCB */
5809 /* better to use the time field from the event that triggered the
5810 * call to this function, but that isn't trivial to get
5818 SendGameSelection(Widget w, Atom *selection, Atom *target,
5819 Atom *type_return, XtPointer *value_return,
5820 unsigned long *length_return, int *format_return)
5822 char *selection_tmp;
5824 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5825 FILE* f = fopen(gameCopyFilename, "r");
5828 if (f == NULL) return False;
5832 selection_tmp = XtMalloc(len + 1);
5833 count = fread(selection_tmp, 1, len, f);
5835 XtFree(selection_tmp);
5838 selection_tmp[len] = NULLCHAR;
5839 *value_return = selection_tmp;
5840 *length_return = len;
5841 *type_return = *target;
5842 *format_return = 8; /* bits per byte */
5844 } else if (*target == XA_TARGETS(xDisplay)) {
5845 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5846 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5847 targets_tmp[1] = XA_STRING;
5848 *value_return = targets_tmp;
5849 *type_return = XA_ATOM;
5851 *format_return = 8 * sizeof(Atom);
5852 if (*format_return > 32) {
5853 *length_return *= *format_return / 32;
5854 *format_return = 32;
5862 /* note: when called from menu all parameters are NULL, so no clue what the
5863 * Widget which was clicked on was, or what the click event was
5865 void CopyGameProc(w, event, prms, nprms)
5873 ret = SaveGameToFile(gameCopyFilename, FALSE);
5877 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5878 * have a notion of a game that is selected but not copied.
5879 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5881 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5884 NULL/* lose_ownership_proc */ ,
5885 NULL/* transfer_done_proc */);
5886 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5889 NULL/* lose_ownership_proc */ ,
5890 NULL/* transfer_done_proc */);
5893 /* function called when the data to Paste is ready */
5895 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5896 Atom *type, XtPointer value, unsigned long *len, int *format)
5899 if (value == NULL || *len == 0) {
5900 return; /* nothing had been selected to copy */
5902 f = fopen(gamePasteFilename, "w");
5904 DisplayError(_("Can't open temp file"), errno);
5907 fwrite(value, 1, *len, f);
5910 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5913 /* called when Paste Game button is pressed,
5914 * all parameters will be NULL */
5915 void PasteGameProc(w, event, prms, nprms)
5921 XtGetSelectionValue(menuBarWidget,
5922 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5923 /* (XtSelectionCallbackProc) */ PasteGameCB,
5924 NULL, /* client_data passed to PasteGameCB */
5926 /* better to use the time field from the event that triggered the
5927 * call to this function, but that isn't trivial to get
5937 SaveGameProc(NULL, NULL, NULL, NULL);
5941 void QuitProc(w, event, prms, nprms)
5950 void PauseProc(w, event, prms, nprms)
5960 void MachineBlackProc(w, event, prms, nprms)
5966 MachineBlackEvent();
5969 void MachineWhiteProc(w, event, prms, nprms)
5975 MachineWhiteEvent();
5978 void AnalyzeModeProc(w, event, prms, nprms)
5986 if (!first.analysisSupport) {
5987 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5988 DisplayError(buf, 0);
5991 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5992 if (appData.icsActive) {
5993 if (gameMode != IcsObserving) {
5994 sprintf(buf,_("You are not observing a game"));
5995 DisplayError(buf, 0);
5997 if (appData.icsEngineAnalyze) {
5998 if (appData.debugMode)
5999 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6005 /* if enable, use want disable icsEngineAnalyze */
6006 if (appData.icsEngineAnalyze) {
6011 appData.icsEngineAnalyze = TRUE;
6012 if (appData.debugMode)
6013 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6015 if (!appData.showThinking)
6016 ShowThinkingProc(w,event,prms,nprms);
6021 void AnalyzeFileProc(w, event, prms, nprms)
6027 if (!first.analysisSupport) {
6029 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6030 DisplayError(buf, 0);
6035 if (!appData.showThinking)
6036 ShowThinkingProc(w,event,prms,nprms);
6039 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6040 AnalysisPeriodicEvent(1);
6043 void TwoMachinesProc(w, event, prms, nprms)
6052 void IcsClientProc(w, event, prms, nprms)
6061 void EditGameProc(w, event, prms, nprms)
6070 void EditPositionProc(w, event, prms, nprms)
6076 EditPositionEvent();
6079 void TrainingProc(w, event, prms, nprms)
6088 void EditCommentProc(w, event, prms, nprms)
6095 EditCommentPopDown();
6101 void IcsInputBoxProc(w, event, prms, nprms)
6107 if (ICSInputBoxUp) {
6108 ICSInputBoxPopDown();
6114 void AcceptProc(w, event, prms, nprms)
6123 void DeclineProc(w, event, prms, nprms)
6132 void RematchProc(w, event, prms, nprms)
6141 void CallFlagProc(w, event, prms, nprms)
6150 void DrawProc(w, event, prms, nprms)
6159 void AbortProc(w, event, prms, nprms)
6168 void AdjournProc(w, event, prms, nprms)
6177 void ResignProc(w, event, prms, nprms)
6186 void AdjuWhiteProc(w, event, prms, nprms)
6192 UserAdjudicationEvent(+1);
6195 void AdjuBlackProc(w, event, prms, nprms)
6201 UserAdjudicationEvent(-1);
6204 void AdjuDrawProc(w, event, prms, nprms)
6210 UserAdjudicationEvent(0);
6213 void EnterKeyProc(w, event, prms, nprms)
6219 if (ICSInputBoxUp == True)
6223 void UpKeyProc(w, event, prms, nprms)
6228 { // [HGM] input: let up-arrow recall previous line from history
6235 if (!ICSInputBoxUp) return;
6236 edit = XtNameToWidget(ICSInputShell, "*form.text");
6238 XtSetArg(args[j], XtNstring, &val); j++;
6239 XtGetValues(edit, args, j);
6240 val = PrevInHistory(val);
6241 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6242 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6244 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6245 XawTextReplace(edit, 0, 0, &t);
6246 XawTextSetInsertionPoint(edit, 9999);
6250 void DownKeyProc(w, event, prms, nprms)
6255 { // [HGM] input: let down-arrow recall next line from history
6260 if (!ICSInputBoxUp) return;
6261 edit = XtNameToWidget(ICSInputShell, "*form.text");
6262 val = NextInHistory();
6263 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6264 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6266 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6267 XawTextReplace(edit, 0, 0, &t);
6268 XawTextSetInsertionPoint(edit, 9999);
6272 void StopObservingProc(w, event, prms, nprms)
6278 StopObservingEvent();
6281 void StopExaminingProc(w, event, prms, nprms)
6287 StopExaminingEvent();
6290 void UploadProc(w, event, prms, nprms)
6300 void ForwardProc(w, event, prms, nprms)
6310 void BackwardProc(w, event, prms, nprms)
6319 void ToStartProc(w, event, prms, nprms)
6328 void ToEndProc(w, event, prms, nprms)
6337 void RevertProc(w, event, prms, nprms)
6346 void AnnotateProc(w, event, prms, nprms)
6355 void TruncateGameProc(w, event, prms, nprms)
6361 TruncateGameEvent();
6363 void RetractMoveProc(w, event, prms, nprms)
6372 void MoveNowProc(w, event, prms, nprms)
6382 void AlwaysQueenProc(w, event, prms, nprms)
6390 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6392 if (appData.alwaysPromoteToQueen) {
6393 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6395 XtSetArg(args[0], XtNleftBitmap, None);
6397 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6401 void AnimateDraggingProc(w, event, prms, nprms)
6409 appData.animateDragging = !appData.animateDragging;
6411 if (appData.animateDragging) {
6412 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6415 XtSetArg(args[0], XtNleftBitmap, None);
6417 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6421 void AnimateMovingProc(w, event, prms, nprms)
6429 appData.animate = !appData.animate;
6431 if (appData.animate) {
6432 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6435 XtSetArg(args[0], XtNleftBitmap, None);
6437 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6441 void AutocommProc(w, event, prms, nprms)
6449 appData.autoComment = !appData.autoComment;
6451 if (appData.autoComment) {
6452 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6454 XtSetArg(args[0], XtNleftBitmap, None);
6456 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6461 void AutoflagProc(w, event, prms, nprms)
6469 appData.autoCallFlag = !appData.autoCallFlag;
6471 if (appData.autoCallFlag) {
6472 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6474 XtSetArg(args[0], XtNleftBitmap, None);
6476 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6480 void AutoflipProc(w, event, prms, nprms)
6488 appData.autoFlipView = !appData.autoFlipView;
6490 if (appData.autoFlipView) {
6491 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6493 XtSetArg(args[0], XtNleftBitmap, None);
6495 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6499 void AutobsProc(w, event, prms, nprms)
6507 appData.autoObserve = !appData.autoObserve;
6509 if (appData.autoObserve) {
6510 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6512 XtSetArg(args[0], XtNleftBitmap, None);
6514 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6518 void AutoraiseProc(w, event, prms, nprms)
6526 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6528 if (appData.autoRaiseBoard) {
6529 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6531 XtSetArg(args[0], XtNleftBitmap, None);
6533 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6537 void AutosaveProc(w, event, prms, nprms)
6545 appData.autoSaveGames = !appData.autoSaveGames;
6547 if (appData.autoSaveGames) {
6548 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6550 XtSetArg(args[0], XtNleftBitmap, None);
6552 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6556 void BlindfoldProc(w, event, prms, nprms)
6564 appData.blindfold = !appData.blindfold;
6566 if (appData.blindfold) {
6567 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6569 XtSetArg(args[0], XtNleftBitmap, None);
6571 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6574 DrawPosition(True, NULL);
6577 void TestLegalityProc(w, event, prms, nprms)
6585 appData.testLegality = !appData.testLegality;
6587 if (appData.testLegality) {
6588 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6590 XtSetArg(args[0], XtNleftBitmap, None);
6592 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6597 void FlashMovesProc(w, event, prms, nprms)
6605 if (appData.flashCount == 0) {
6606 appData.flashCount = 3;
6608 appData.flashCount = -appData.flashCount;
6611 if (appData.flashCount > 0) {
6612 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6614 XtSetArg(args[0], XtNleftBitmap, None);
6616 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6620 void FlipViewProc(w, event, prms, nprms)
6626 flipView = !flipView;
6627 DrawPosition(True, NULL);
6630 void GetMoveListProc(w, event, prms, nprms)
6638 appData.getMoveList = !appData.getMoveList;
6640 if (appData.getMoveList) {
6641 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6644 XtSetArg(args[0], XtNleftBitmap, None);
6646 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6651 void HighlightDraggingProc(w, event, prms, nprms)
6659 appData.highlightDragging = !appData.highlightDragging;
6661 if (appData.highlightDragging) {
6662 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6664 XtSetArg(args[0], XtNleftBitmap, None);
6666 XtSetValues(XtNameToWidget(menuBarWidget,
6667 "menuOptions.Highlight Dragging"), args, 1);
6671 void HighlightLastMoveProc(w, event, prms, nprms)
6679 appData.highlightLastMove = !appData.highlightLastMove;
6681 if (appData.highlightLastMove) {
6682 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6684 XtSetArg(args[0], XtNleftBitmap, None);
6686 XtSetValues(XtNameToWidget(menuBarWidget,
6687 "menuOptions.Highlight Last Move"), args, 1);
6690 void IcsAlarmProc(w, event, prms, nprms)
6698 appData.icsAlarm = !appData.icsAlarm;
6700 if (appData.icsAlarm) {
6701 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6703 XtSetArg(args[0], XtNleftBitmap, None);
6705 XtSetValues(XtNameToWidget(menuBarWidget,
6706 "menuOptions.ICS Alarm"), args, 1);
6709 void MoveSoundProc(w, event, prms, nprms)
6717 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6719 if (appData.ringBellAfterMoves) {
6720 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6722 XtSetArg(args[0], XtNleftBitmap, None);
6724 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6729 void OldSaveStyleProc(w, event, prms, nprms)
6737 appData.oldSaveStyle = !appData.oldSaveStyle;
6739 if (appData.oldSaveStyle) {
6740 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6742 XtSetArg(args[0], XtNleftBitmap, None);
6744 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6748 void PeriodicUpdatesProc(w, event, prms, nprms)
6756 PeriodicUpdatesEvent(!appData.periodicUpdates);
6758 if (appData.periodicUpdates) {
6759 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6761 XtSetArg(args[0], XtNleftBitmap, None);
6763 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6767 void PonderNextMoveProc(w, event, prms, nprms)
6775 PonderNextMoveEvent(!appData.ponderNextMove);
6777 if (appData.ponderNextMove) {
6778 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6780 XtSetArg(args[0], XtNleftBitmap, None);
6782 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6786 void PopupExitMessageProc(w, event, prms, nprms)
6794 appData.popupExitMessage = !appData.popupExitMessage;
6796 if (appData.popupExitMessage) {
6797 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6799 XtSetArg(args[0], XtNleftBitmap, None);
6801 XtSetValues(XtNameToWidget(menuBarWidget,
6802 "menuOptions.Popup Exit Message"), args, 1);
6805 void PopupMoveErrorsProc(w, event, prms, nprms)
6813 appData.popupMoveErrors = !appData.popupMoveErrors;
6815 if (appData.popupMoveErrors) {
6816 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6818 XtSetArg(args[0], XtNleftBitmap, None);
6820 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6824 void PremoveProc(w, event, prms, nprms)
6832 appData.premove = !appData.premove;
6834 if (appData.premove) {
6835 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6837 XtSetArg(args[0], XtNleftBitmap, None);
6839 XtSetValues(XtNameToWidget(menuBarWidget,
6840 "menuOptions.Premove"), args, 1);
6843 void QuietPlayProc(w, event, prms, nprms)
6851 appData.quietPlay = !appData.quietPlay;
6853 if (appData.quietPlay) {
6854 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6856 XtSetArg(args[0], XtNleftBitmap, None);
6858 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6862 void ShowCoordsProc(w, event, prms, nprms)
6870 appData.showCoords = !appData.showCoords;
6872 if (appData.showCoords) {
6873 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6875 XtSetArg(args[0], XtNleftBitmap, None);
6877 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6880 DrawPosition(True, NULL);
6883 void ShowThinkingProc(w, event, prms, nprms)
6889 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6890 ShowThinkingEvent();
6893 void HideThinkingProc(w, event, prms, nprms)
6901 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6902 ShowThinkingEvent();
6904 if (appData.hideThinkingFromHuman) {
6905 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6907 XtSetArg(args[0], XtNleftBitmap, None);
6909 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6913 void SaveOnExitProc(w, event, prms, nprms)
6921 saveSettingsOnExit = !saveSettingsOnExit;
6923 if (saveSettingsOnExit) {
6924 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6926 XtSetArg(args[0], XtNleftBitmap, None);
6928 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6932 void SaveSettingsProc(w, event, prms, nprms)
6938 SaveSettings(settingsFileName);
6941 void InfoProc(w, event, prms, nprms)
6948 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6953 void ManProc(w, event, prms, nprms)
6961 if (nprms && *nprms > 0)
6965 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6969 void HintProc(w, event, prms, nprms)
6978 void BookProc(w, event, prms, nprms)
6987 void AboutProc(w, event, prms, nprms)
6995 char *zippy = " (with Zippy code)";
6999 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7000 programVersion, zippy,
7001 "Copyright 1991 Digital Equipment Corporation",
7002 "Enhancements Copyright 1992-2009 Free Software Foundation",
7003 "Enhancements Copyright 2005 Alessandro Scotti",
7004 PACKAGE, " is free software and carries NO WARRANTY;",
7005 "see the file COPYING for more information.");
7006 ErrorPopUp(_("About XBoard"), buf, FALSE);
7009 void DebugProc(w, event, prms, nprms)
7015 appData.debugMode = !appData.debugMode;
7018 void AboutGameProc(w, event, prms, nprms)
7027 void NothingProc(w, event, prms, nprms)
7036 void Iconify(w, event, prms, nprms)
7045 XtSetArg(args[0], XtNiconic, True);
7046 XtSetValues(shellWidget, args, 1);
7049 void DisplayMessage(message, extMessage)
7050 char *message, *extMessage;
7052 /* display a message in the message widget */
7061 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7066 message = extMessage;
7070 /* need to test if messageWidget already exists, since this function
7071 can also be called during the startup, if for example a Xresource
7072 is not set up correctly */
7075 XtSetArg(arg, XtNlabel, message);
7076 XtSetValues(messageWidget, &arg, 1);
7082 void DisplayTitle(text)
7087 char title[MSG_SIZ];
7090 if (text == NULL) text = "";
7092 if (appData.titleInWindow) {
7094 XtSetArg(args[i], XtNlabel, text); i++;
7095 XtSetValues(titleWidget, args, i);
7098 if (*text != NULLCHAR) {
7099 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7100 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7101 } else if (appData.icsActive) {
7102 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7103 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7104 } else if (appData.cmailGameName[0] != NULLCHAR) {
7105 snprintf(icon, sizeof(icon), "%s", "CMail");
7106 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7108 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7109 } else if (gameInfo.variant == VariantGothic) {
7110 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7111 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7114 } else if (gameInfo.variant == VariantFalcon) {
7115 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7116 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7118 } else if (appData.noChessProgram) {
7119 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7120 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7122 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7123 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7126 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7127 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7128 XtSetValues(shellWidget, args, i);
7133 DisplayError(message, error)
7140 if (appData.debugMode || appData.matchMode) {
7141 fprintf(stderr, "%s: %s\n", programName, message);
7144 if (appData.debugMode || appData.matchMode) {
7145 fprintf(stderr, "%s: %s: %s\n",
7146 programName, message, strerror(error));
7148 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7151 ErrorPopUp(_("Error"), message, FALSE);
7155 void DisplayMoveError(message)
7160 DrawPosition(FALSE, NULL);
7161 if (appData.debugMode || appData.matchMode) {
7162 fprintf(stderr, "%s: %s\n", programName, message);
7164 if (appData.popupMoveErrors) {
7165 ErrorPopUp(_("Error"), message, FALSE);
7167 DisplayMessage(message, "");
7172 void DisplayFatalError(message, error, status)
7178 errorExitStatus = status;
7180 fprintf(stderr, "%s: %s\n", programName, message);
7182 fprintf(stderr, "%s: %s: %s\n",
7183 programName, message, strerror(error));
7184 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7187 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7188 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7194 void DisplayInformation(message)
7198 ErrorPopUp(_("Information"), message, TRUE);
7201 void DisplayNote(message)
7205 ErrorPopUp(_("Note"), message, FALSE);
7209 NullXErrorCheck(dpy, error_event)
7211 XErrorEvent *error_event;
7216 void DisplayIcsInteractionTitle(message)
7219 if (oldICSInteractionTitle == NULL) {
7220 /* Magic to find the old window title, adapted from vim */
7221 char *wina = getenv("WINDOWID");
7223 Window win = (Window) atoi(wina);
7224 Window root, parent, *children;
7225 unsigned int nchildren;
7226 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7228 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7229 if (!XQueryTree(xDisplay, win, &root, &parent,
7230 &children, &nchildren)) break;
7231 if (children) XFree((void *)children);
7232 if (parent == root || parent == 0) break;
7235 XSetErrorHandler(oldHandler);
7237 if (oldICSInteractionTitle == NULL) {
7238 oldICSInteractionTitle = "xterm";
7241 printf("\033]0;%s\007", message);
7245 char pendingReplyPrefix[MSG_SIZ];
7246 ProcRef pendingReplyPR;
7248 void AskQuestionProc(w, event, prms, nprms)
7255 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7259 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7262 void AskQuestionPopDown()
7264 if (!askQuestionUp) return;
7265 XtPopdown(askQuestionShell);
7266 XtDestroyWidget(askQuestionShell);
7267 askQuestionUp = False;
7270 void AskQuestionReplyAction(w, event, prms, nprms)
7280 reply = XawDialogGetValueString(w = XtParent(w));
7281 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7282 if (*buf) strcat(buf, " ");
7285 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7286 AskQuestionPopDown();
7288 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7291 void AskQuestionCallback(w, client_data, call_data)
7293 XtPointer client_data, call_data;
7298 XtSetArg(args[0], XtNlabel, &name);
7299 XtGetValues(w, args, 1);
7301 if (strcmp(name, _("cancel")) == 0) {
7302 AskQuestionPopDown();
7304 AskQuestionReplyAction(w, NULL, NULL, NULL);
7308 void AskQuestion(title, question, replyPrefix, pr)
7309 char *title, *question, *replyPrefix;
7313 Widget popup, layout, dialog, edit;
7319 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7320 pendingReplyPR = pr;
7323 XtSetArg(args[i], XtNresizable, True); i++;
7324 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7325 askQuestionShell = popup =
7326 XtCreatePopupShell(title, transientShellWidgetClass,
7327 shellWidget, args, i);
7330 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7331 layoutArgs, XtNumber(layoutArgs));
7334 XtSetArg(args[i], XtNlabel, question); i++;
7335 XtSetArg(args[i], XtNvalue, ""); i++;
7336 XtSetArg(args[i], XtNborderWidth, 0); i++;
7337 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7340 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7341 (XtPointer) dialog);
7342 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7343 (XtPointer) dialog);
7345 XtRealizeWidget(popup);
7346 CatchDeleteWindow(popup, "AskQuestionPopDown");
7348 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7349 &x, &y, &win_x, &win_y, &mask);
7351 XtSetArg(args[0], XtNx, x - 10);
7352 XtSetArg(args[1], XtNy, y - 30);
7353 XtSetValues(popup, args, 2);
7355 XtPopup(popup, XtGrabExclusive);
7356 askQuestionUp = True;
7358 edit = XtNameToWidget(dialog, "*value");
7359 XtSetKeyboardFocus(popup, edit);
7367 if (*name == NULLCHAR) {
7369 } else if (strcmp(name, "$") == 0) {
7370 putc(BELLCHAR, stderr);
7373 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7381 PlaySound(appData.soundMove);
7387 PlaySound(appData.soundIcsWin);
7393 PlaySound(appData.soundIcsLoss);
7399 PlaySound(appData.soundIcsDraw);
7403 PlayIcsUnfinishedSound()
7405 PlaySound(appData.soundIcsUnfinished);
7411 PlaySound(appData.soundIcsAlarm);
7417 system("stty echo");
7423 system("stty -echo");
7427 Colorize(cc, continuation)
7432 int count, outCount, error;
7434 if (textColors[(int)cc].bg > 0) {
7435 if (textColors[(int)cc].fg > 0) {
7436 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7437 textColors[(int)cc].fg, textColors[(int)cc].bg);
7439 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7440 textColors[(int)cc].bg);
7443 if (textColors[(int)cc].fg > 0) {
7444 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7445 textColors[(int)cc].fg);
7447 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7450 count = strlen(buf);
7451 outCount = OutputToProcess(NoProc, buf, count, &error);
7452 if (outCount < count) {
7453 DisplayFatalError(_("Error writing to display"), error, 1);
7456 if (continuation) return;
7459 PlaySound(appData.soundShout);
7462 PlaySound(appData.soundSShout);
7465 PlaySound(appData.soundChannel1);
7468 PlaySound(appData.soundChannel);
7471 PlaySound(appData.soundKibitz);
7474 PlaySound(appData.soundTell);
7476 case ColorChallenge:
7477 PlaySound(appData.soundChallenge);
7480 PlaySound(appData.soundRequest);
7483 PlaySound(appData.soundSeek);
7494 return getpwuid(getuid())->pw_name;
7498 ExpandPathName(path)
7501 static char static_buf[4*MSG_SIZ];
7502 char *d, *s, buf[4*MSG_SIZ];
7508 while (*s && isspace(*s))
7517 if (*(s+1) == '/') {
7518 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7522 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7523 *strchr(buf, '/') = 0;
7524 pwd = getpwnam(buf);
7527 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7531 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7532 strcat(d, strchr(s+1, '/'));
7536 safeStrCpy(d, s, 4*MSG_SIZ );
7543 static char host_name[MSG_SIZ];
7545 #if HAVE_GETHOSTNAME
7546 gethostname(host_name, MSG_SIZ);
7548 #else /* not HAVE_GETHOSTNAME */
7549 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7550 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7552 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7554 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7555 #endif /* not HAVE_GETHOSTNAME */
7558 XtIntervalId delayedEventTimerXID = 0;
7559 DelayedEventCallback delayedEventCallback = 0;
7564 delayedEventTimerXID = 0;
7565 delayedEventCallback();
7569 ScheduleDelayedEvent(cb, millisec)
7570 DelayedEventCallback cb; long millisec;
7572 if(delayedEventTimerXID && delayedEventCallback == cb)
7573 // [HGM] alive: replace, rather than add or flush identical event
7574 XtRemoveTimeOut(delayedEventTimerXID);
7575 delayedEventCallback = cb;
7576 delayedEventTimerXID =
7577 XtAppAddTimeOut(appContext, millisec,
7578 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7581 DelayedEventCallback
7584 if (delayedEventTimerXID) {
7585 return delayedEventCallback;
7592 CancelDelayedEvent()
7594 if (delayedEventTimerXID) {
7595 XtRemoveTimeOut(delayedEventTimerXID);
7596 delayedEventTimerXID = 0;
7600 XtIntervalId loadGameTimerXID = 0;
7602 int LoadGameTimerRunning()
7604 return loadGameTimerXID != 0;
7607 int StopLoadGameTimer()
7609 if (loadGameTimerXID != 0) {
7610 XtRemoveTimeOut(loadGameTimerXID);
7611 loadGameTimerXID = 0;
7619 LoadGameTimerCallback(arg, id)
7623 loadGameTimerXID = 0;
7628 StartLoadGameTimer(millisec)
7632 XtAppAddTimeOut(appContext, millisec,
7633 (XtTimerCallbackProc) LoadGameTimerCallback,
7637 XtIntervalId analysisClockXID = 0;
7640 AnalysisClockCallback(arg, id)
7644 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7645 || appData.icsEngineAnalyze) { // [DM]
7646 AnalysisPeriodicEvent(0);
7647 StartAnalysisClock();
7652 StartAnalysisClock()
7655 XtAppAddTimeOut(appContext, 2000,
7656 (XtTimerCallbackProc) AnalysisClockCallback,
7660 XtIntervalId clockTimerXID = 0;
7662 int ClockTimerRunning()
7664 return clockTimerXID != 0;
7667 int StopClockTimer()
7669 if (clockTimerXID != 0) {
7670 XtRemoveTimeOut(clockTimerXID);
7679 ClockTimerCallback(arg, id)
7688 StartClockTimer(millisec)
7692 XtAppAddTimeOut(appContext, millisec,
7693 (XtTimerCallbackProc) ClockTimerCallback,
7698 DisplayTimerLabel(w, color, timer, highlight)
7707 /* check for low time warning */
7708 Pixel foregroundOrWarningColor = timerForegroundPixel;
7711 appData.lowTimeWarning &&
7712 (timer / 1000) < appData.icsAlarmTime)
7713 foregroundOrWarningColor = lowTimeWarningColor;
7715 if (appData.clockMode) {
7716 sprintf(buf, "%s: %s", color, TimeString(timer));
7717 XtSetArg(args[0], XtNlabel, buf);
7719 sprintf(buf, "%s ", color);
7720 XtSetArg(args[0], XtNlabel, buf);
7725 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7726 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7728 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7729 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7732 XtSetValues(w, args, 3);
7736 DisplayWhiteClock(timeRemaining, highlight)
7742 if(appData.noGUI) return;
7743 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7744 if (highlight && iconPixmap == bIconPixmap) {
7745 iconPixmap = wIconPixmap;
7746 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7747 XtSetValues(shellWidget, args, 1);
7752 DisplayBlackClock(timeRemaining, highlight)
7758 if(appData.noGUI) return;
7759 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7760 if (highlight && iconPixmap == wIconPixmap) {
7761 iconPixmap = bIconPixmap;
7762 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7763 XtSetValues(shellWidget, args, 1);
7781 int StartChildProcess(cmdLine, dir, pr)
7788 int to_prog[2], from_prog[2];
7792 if (appData.debugMode) {
7793 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7796 /* We do NOT feed the cmdLine to the shell; we just
7797 parse it into blank-separated arguments in the
7798 most simple-minded way possible.
7801 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7804 while(*p == ' ') p++;
7806 if(*p == '"' || *p == '\'')
7807 p = strchr(++argv[i-1], *p);
7808 else p = strchr(p, ' ');
7809 if (p == NULL) break;
7814 SetUpChildIO(to_prog, from_prog);
7816 if ((pid = fork()) == 0) {
7818 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7819 close(to_prog[1]); // first close the unused pipe ends
7820 close(from_prog[0]);
7821 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7822 dup2(from_prog[1], 1);
7823 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7824 close(from_prog[1]); // and closing again loses one of the pipes!
7825 if(fileno(stderr) >= 2) // better safe than sorry...
7826 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7828 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7833 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7835 execvp(argv[0], argv);
7837 /* If we get here, exec failed */
7842 /* Parent process */
7844 close(from_prog[1]);
7846 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7849 cp->fdFrom = from_prog[0];
7850 cp->fdTo = to_prog[1];
7855 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7856 static RETSIGTYPE AlarmCallBack(int n)
7862 DestroyChildProcess(pr, signalType)
7866 ChildProc *cp = (ChildProc *) pr;
7868 if (cp->kind != CPReal) return;
7870 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7871 signal(SIGALRM, AlarmCallBack);
7873 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7874 kill(cp->pid, SIGKILL); // kill it forcefully
7875 wait((int *) 0); // and wait again
7879 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7881 /* Process is exiting either because of the kill or because of
7882 a quit command sent by the backend; either way, wait for it to die.
7891 InterruptChildProcess(pr)
7894 ChildProc *cp = (ChildProc *) pr;
7896 if (cp->kind != CPReal) return;
7897 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7900 int OpenTelnet(host, port, pr)
7905 char cmdLine[MSG_SIZ];
7907 if (port[0] == NULLCHAR) {
7908 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7910 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7912 return StartChildProcess(cmdLine, "", pr);
7915 int OpenTCP(host, port, pr)
7921 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7922 #else /* !OMIT_SOCKETS */
7924 struct sockaddr_in sa;
7926 unsigned short uport;
7929 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7933 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7934 sa.sin_family = AF_INET;
7935 sa.sin_addr.s_addr = INADDR_ANY;
7936 uport = (unsigned short) 0;
7937 sa.sin_port = htons(uport);
7938 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7942 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7943 if (!(hp = gethostbyname(host))) {
7945 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7946 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7947 hp->h_addrtype = AF_INET;
7949 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7950 hp->h_addr_list[0] = (char *) malloc(4);
7951 hp->h_addr_list[0][0] = b0;
7952 hp->h_addr_list[0][1] = b1;
7953 hp->h_addr_list[0][2] = b2;
7954 hp->h_addr_list[0][3] = b3;
7959 sa.sin_family = hp->h_addrtype;
7960 uport = (unsigned short) atoi(port);
7961 sa.sin_port = htons(uport);
7962 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7964 if (connect(s, (struct sockaddr *) &sa,
7965 sizeof(struct sockaddr_in)) < 0) {
7969 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7976 #endif /* !OMIT_SOCKETS */
7981 int OpenCommPort(name, pr)
7988 fd = open(name, 2, 0);
7989 if (fd < 0) return errno;
7991 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8001 int OpenLoopback(pr)
8007 SetUpChildIO(to, from);
8009 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8012 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8019 int OpenRcmd(host, user, cmd, pr)
8020 char *host, *user, *cmd;
8023 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8027 #define INPUT_SOURCE_BUF_SIZE 8192
8036 char buf[INPUT_SOURCE_BUF_SIZE];
8041 DoInputCallback(closure, source, xid)
8046 InputSource *is = (InputSource *) closure;
8051 if (is->lineByLine) {
8052 count = read(is->fd, is->unused,
8053 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8055 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8058 is->unused += count;
8060 while (p < is->unused) {
8061 q = memchr(p, '\n', is->unused - p);
8062 if (q == NULL) break;
8064 (is->func)(is, is->closure, p, q - p, 0);
8068 while (p < is->unused) {
8073 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8078 (is->func)(is, is->closure, is->buf, count, error);
8082 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8089 ChildProc *cp = (ChildProc *) pr;
8091 is = (InputSource *) calloc(1, sizeof(InputSource));
8092 is->lineByLine = lineByLine;
8096 is->fd = fileno(stdin);
8098 is->kind = cp->kind;
8099 is->fd = cp->fdFrom;
8102 is->unused = is->buf;
8105 is->xid = XtAppAddInput(appContext, is->fd,
8106 (XtPointer) (XtInputReadMask),
8107 (XtInputCallbackProc) DoInputCallback,
8109 is->closure = closure;
8110 return (InputSourceRef) is;
8114 RemoveInputSource(isr)
8117 InputSource *is = (InputSource *) isr;
8119 if (is->xid == 0) return;
8120 XtRemoveInput(is->xid);
8124 int OutputToProcess(pr, message, count, outError)
8130 static int line = 0;
8131 ChildProc *cp = (ChildProc *) pr;
8136 if (appData.noJoin || !appData.useInternalWrap)
8137 outCount = fwrite(message, 1, count, stdout);
8140 int width = get_term_width();
8141 int len = wrap(NULL, message, count, width, &line);
8142 char *msg = malloc(len);
8146 outCount = fwrite(message, 1, count, stdout);
8149 dbgchk = wrap(msg, message, count, width, &line);
8150 if (dbgchk != len && appData.debugMode)
8151 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8152 outCount = fwrite(msg, 1, dbgchk, stdout);
8158 outCount = write(cp->fdTo, message, count);
8168 /* Output message to process, with "ms" milliseconds of delay
8169 between each character. This is needed when sending the logon
8170 script to ICC, which for some reason doesn't like the
8171 instantaneous send. */
8172 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8179 ChildProc *cp = (ChildProc *) pr;
8184 r = write(cp->fdTo, message++, 1);
8197 /**** Animation code by Hugh Fisher, DCS, ANU.
8199 Known problem: if a window overlapping the board is
8200 moved away while a piece is being animated underneath,
8201 the newly exposed area won't be updated properly.
8202 I can live with this.
8204 Known problem: if you look carefully at the animation
8205 of pieces in mono mode, they are being drawn as solid
8206 shapes without interior detail while moving. Fixing
8207 this would be a major complication for minimal return.
8210 /* Masks for XPM pieces. Black and white pieces can have
8211 different shapes, but in the interest of retaining my
8212 sanity pieces must have the same outline on both light
8213 and dark squares, and all pieces must use the same
8214 background square colors/images. */
8216 static int xpmDone = 0;
8219 CreateAnimMasks (pieceDepth)
8226 unsigned long plane;
8229 /* Need a bitmap just to get a GC with right depth */
8230 buf = XCreatePixmap(xDisplay, xBoardWindow,
8232 values.foreground = 1;
8233 values.background = 0;
8234 /* Don't use XtGetGC, not read only */
8235 maskGC = XCreateGC(xDisplay, buf,
8236 GCForeground | GCBackground, &values);
8237 XFreePixmap(xDisplay, buf);
8239 buf = XCreatePixmap(xDisplay, xBoardWindow,
8240 squareSize, squareSize, pieceDepth);
8241 values.foreground = XBlackPixel(xDisplay, xScreen);
8242 values.background = XWhitePixel(xDisplay, xScreen);
8243 bufGC = XCreateGC(xDisplay, buf,
8244 GCForeground | GCBackground, &values);
8246 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8247 /* Begin with empty mask */
8248 if(!xpmDone) // [HGM] pieces: keep using existing
8249 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8250 squareSize, squareSize, 1);
8251 XSetFunction(xDisplay, maskGC, GXclear);
8252 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8253 0, 0, squareSize, squareSize);
8255 /* Take a copy of the piece */
8260 XSetFunction(xDisplay, bufGC, GXcopy);
8261 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8263 0, 0, squareSize, squareSize, 0, 0);
8265 /* XOR the background (light) over the piece */
8266 XSetFunction(xDisplay, bufGC, GXxor);
8268 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8269 0, 0, squareSize, squareSize, 0, 0);
8271 XSetForeground(xDisplay, bufGC, lightSquareColor);
8272 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8275 /* We now have an inverted piece image with the background
8276 erased. Construct mask by just selecting all the non-zero
8277 pixels - no need to reconstruct the original image. */
8278 XSetFunction(xDisplay, maskGC, GXor);
8280 /* Might be quicker to download an XImage and create bitmap
8281 data from it rather than this N copies per piece, but it
8282 only takes a fraction of a second and there is a much
8283 longer delay for loading the pieces. */
8284 for (n = 0; n < pieceDepth; n ++) {
8285 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8286 0, 0, squareSize, squareSize,
8292 XFreePixmap(xDisplay, buf);
8293 XFreeGC(xDisplay, bufGC);
8294 XFreeGC(xDisplay, maskGC);
8298 InitAnimState (anim, info)
8300 XWindowAttributes * info;
8305 /* Each buffer is square size, same depth as window */
8306 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8307 squareSize, squareSize, info->depth);
8308 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8309 squareSize, squareSize, info->depth);
8311 /* Create a plain GC for blitting */
8312 mask = GCForeground | GCBackground | GCFunction |
8313 GCPlaneMask | GCGraphicsExposures;
8314 values.foreground = XBlackPixel(xDisplay, xScreen);
8315 values.background = XWhitePixel(xDisplay, xScreen);
8316 values.function = GXcopy;
8317 values.plane_mask = AllPlanes;
8318 values.graphics_exposures = False;
8319 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8321 /* Piece will be copied from an existing context at
8322 the start of each new animation/drag. */
8323 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8325 /* Outline will be a read-only copy of an existing */
8326 anim->outlineGC = None;
8332 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8333 XWindowAttributes info;
8335 if (xpmDone && gameInfo.variant == old) return;
8336 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8337 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8339 InitAnimState(&game, &info);
8340 InitAnimState(&player, &info);
8342 /* For XPM pieces, we need bitmaps to use as masks. */
8344 CreateAnimMasks(info.depth);
8350 static Boolean frameWaiting;
8352 static RETSIGTYPE FrameAlarm (sig)
8355 frameWaiting = False;
8356 /* In case System-V style signals. Needed?? */
8357 signal(SIGALRM, FrameAlarm);
8364 struct itimerval delay;
8366 XSync(xDisplay, False);
8369 frameWaiting = True;
8370 signal(SIGALRM, FrameAlarm);
8371 delay.it_interval.tv_sec =
8372 delay.it_value.tv_sec = time / 1000;
8373 delay.it_interval.tv_usec =
8374 delay.it_value.tv_usec = (time % 1000) * 1000;
8375 setitimer(ITIMER_REAL, &delay, NULL);
8376 while (frameWaiting) pause();
8377 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8378 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8379 setitimer(ITIMER_REAL, &delay, NULL);
8389 XSync(xDisplay, False);
8391 usleep(time * 1000);
8396 /* Convert board position to corner of screen rect and color */
8399 ScreenSquare(column, row, pt, color)
8400 int column; int row; XPoint * pt; int * color;
8403 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8404 pt->y = lineGap + row * (squareSize + lineGap);
8406 pt->x = lineGap + column * (squareSize + lineGap);
8407 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8409 *color = SquareColor(row, column);
8412 /* Convert window coords to square */
8415 BoardSquare(x, y, column, row)
8416 int x; int y; int * column; int * row;
8418 *column = EventToSquare(x, BOARD_WIDTH);
8419 if (flipView && *column >= 0)
8420 *column = BOARD_WIDTH - 1 - *column;
8421 *row = EventToSquare(y, BOARD_HEIGHT);
8422 if (!flipView && *row >= 0)
8423 *row = BOARD_HEIGHT - 1 - *row;
8428 #undef Max /* just in case */
8430 #define Max(a, b) ((a) > (b) ? (a) : (b))
8431 #define Min(a, b) ((a) < (b) ? (a) : (b))
8434 SetRect(rect, x, y, width, height)
8435 XRectangle * rect; int x; int y; int width; int height;
8439 rect->width = width;
8440 rect->height = height;
8443 /* Test if two frames overlap. If they do, return
8444 intersection rect within old and location of
8445 that rect within new. */
8448 Intersect(old, new, size, area, pt)
8449 XPoint * old; XPoint * new;
8450 int size; XRectangle * area; XPoint * pt;
8452 if (old->x > new->x + size || new->x > old->x + size ||
8453 old->y > new->y + size || new->y > old->y + size) {
8456 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8457 size - abs(old->x - new->x), size - abs(old->y - new->y));
8458 pt->x = Max(old->x - new->x, 0);
8459 pt->y = Max(old->y - new->y, 0);
8464 /* For two overlapping frames, return the rect(s)
8465 in the old that do not intersect with the new. */
8468 CalcUpdateRects(old, new, size, update, nUpdates)
8469 XPoint * old; XPoint * new; int size;
8470 XRectangle update[]; int * nUpdates;
8474 /* If old = new (shouldn't happen) then nothing to draw */
8475 if (old->x == new->x && old->y == new->y) {
8479 /* Work out what bits overlap. Since we know the rects
8480 are the same size we don't need a full intersect calc. */
8482 /* Top or bottom edge? */
8483 if (new->y > old->y) {
8484 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8486 } else if (old->y > new->y) {
8487 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8488 size, old->y - new->y);
8491 /* Left or right edge - don't overlap any update calculated above. */
8492 if (new->x > old->x) {
8493 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8494 new->x - old->x, size - abs(new->y - old->y));
8496 } else if (old->x > new->x) {
8497 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8498 old->x - new->x, size - abs(new->y - old->y));
8505 /* Generate a series of frame coords from start->mid->finish.
8506 The movement rate doubles until the half way point is
8507 reached, then halves back down to the final destination,
8508 which gives a nice slow in/out effect. The algorithmn
8509 may seem to generate too many intermediates for short
8510 moves, but remember that the purpose is to attract the
8511 viewers attention to the piece about to be moved and
8512 then to where it ends up. Too few frames would be less
8516 Tween(start, mid, finish, factor, frames, nFrames)
8517 XPoint * start; XPoint * mid;
8518 XPoint * finish; int factor;
8519 XPoint frames[]; int * nFrames;
8521 int fraction, n, count;
8525 /* Slow in, stepping 1/16th, then 1/8th, ... */
8527 for (n = 0; n < factor; n++)
8529 for (n = 0; n < factor; n++) {
8530 frames[count].x = start->x + (mid->x - start->x) / fraction;
8531 frames[count].y = start->y + (mid->y - start->y) / fraction;
8533 fraction = fraction / 2;
8537 frames[count] = *mid;
8540 /* Slow out, stepping 1/2, then 1/4, ... */
8542 for (n = 0; n < factor; n++) {
8543 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8544 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8546 fraction = fraction * 2;
8551 /* Draw a piece on the screen without disturbing what's there */
8554 SelectGCMask(piece, clip, outline, mask)
8555 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8559 /* Bitmap for piece being moved. */
8560 if (appData.monoMode) {
8561 *mask = *pieceToSolid(piece);
8562 } else if (useImages) {
8564 *mask = xpmMask[piece];
8566 *mask = ximMaskPm[piece];
8569 *mask = *pieceToSolid(piece);
8572 /* GC for piece being moved. Square color doesn't matter, but
8573 since it gets modified we make a copy of the original. */
8575 if (appData.monoMode)
8580 if (appData.monoMode)
8585 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8587 /* Outline only used in mono mode and is not modified */
8589 *outline = bwPieceGC;
8591 *outline = wbPieceGC;
8595 OverlayPiece(piece, clip, outline, dest)
8596 ChessSquare piece; GC clip; GC outline; Drawable dest;
8601 /* Draw solid rectangle which will be clipped to shape of piece */
8602 XFillRectangle(xDisplay, dest, clip,
8603 0, 0, squareSize, squareSize);
8604 if (appData.monoMode)
8605 /* Also draw outline in contrasting color for black
8606 on black / white on white cases */
8607 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8608 0, 0, squareSize, squareSize, 0, 0, 1);
8610 /* Copy the piece */
8615 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8617 0, 0, squareSize, squareSize,
8622 /* Animate the movement of a single piece */
8625 BeginAnimation(anim, piece, startColor, start)
8633 /* The old buffer is initialised with the start square (empty) */
8634 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8635 anim->prevFrame = *start;
8637 /* The piece will be drawn using its own bitmap as a matte */
8638 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8639 XSetClipMask(xDisplay, anim->pieceGC, mask);
8643 AnimationFrame(anim, frame, piece)
8648 XRectangle updates[4];
8653 /* Save what we are about to draw into the new buffer */
8654 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8655 frame->x, frame->y, squareSize, squareSize,
8658 /* Erase bits of the previous frame */
8659 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8660 /* Where the new frame overlapped the previous,
8661 the contents in newBuf are wrong. */
8662 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8663 overlap.x, overlap.y,
8664 overlap.width, overlap.height,
8666 /* Repaint the areas in the old that don't overlap new */
8667 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8668 for (i = 0; i < count; i++)
8669 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8670 updates[i].x - anim->prevFrame.x,
8671 updates[i].y - anim->prevFrame.y,
8672 updates[i].width, updates[i].height,
8673 updates[i].x, updates[i].y);
8675 /* Easy when no overlap */
8676 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8677 0, 0, squareSize, squareSize,
8678 anim->prevFrame.x, anim->prevFrame.y);
8681 /* Save this frame for next time round */
8682 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8683 0, 0, squareSize, squareSize,
8685 anim->prevFrame = *frame;
8687 /* Draw piece over original screen contents, not current,
8688 and copy entire rect. Wipes out overlapping piece images. */
8689 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8690 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8691 0, 0, squareSize, squareSize,
8692 frame->x, frame->y);
8696 EndAnimation (anim, finish)
8700 XRectangle updates[4];
8705 /* The main code will redraw the final square, so we
8706 only need to erase the bits that don't overlap. */
8707 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8708 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8709 for (i = 0; i < count; i++)
8710 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8711 updates[i].x - anim->prevFrame.x,
8712 updates[i].y - anim->prevFrame.y,
8713 updates[i].width, updates[i].height,
8714 updates[i].x, updates[i].y);
8716 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8717 0, 0, squareSize, squareSize,
8718 anim->prevFrame.x, anim->prevFrame.y);
8723 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8725 ChessSquare piece; int startColor;
8726 XPoint * start; XPoint * finish;
8727 XPoint frames[]; int nFrames;
8731 BeginAnimation(anim, piece, startColor, start);
8732 for (n = 0; n < nFrames; n++) {
8733 AnimationFrame(anim, &(frames[n]), piece);
8734 FrameDelay(appData.animSpeed);
8736 EndAnimation(anim, finish);
8739 /* Main control logic for deciding what to animate and how */
8742 AnimateMove(board, fromX, fromY, toX, toY)
8751 XPoint start, finish, mid;
8752 XPoint frames[kFactor * 2 + 1];
8753 int nFrames, startColor, endColor;
8755 /* Are we animating? */
8756 if (!appData.animate || appData.blindfold)
8759 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8760 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8761 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8763 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8764 piece = board[fromY][fromX];
8765 if (piece >= EmptySquare) return;
8770 hop = (piece == WhiteKnight || piece == BlackKnight);
8773 if (appData.debugMode) {
8774 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8775 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8776 piece, fromX, fromY, toX, toY); }
8778 ScreenSquare(fromX, fromY, &start, &startColor);
8779 ScreenSquare(toX, toY, &finish, &endColor);
8782 /* Knight: make diagonal movement then straight */
8783 if (abs(toY - fromY) < abs(toX - fromX)) {
8784 mid.x = start.x + (finish.x - start.x) / 2;
8788 mid.y = start.y + (finish.y - start.y) / 2;
8791 mid.x = start.x + (finish.x - start.x) / 2;
8792 mid.y = start.y + (finish.y - start.y) / 2;
8795 /* Don't use as many frames for very short moves */
8796 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8797 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8799 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8800 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8802 /* Be sure end square is redrawn */
8803 damage[0][toY][toX] = True;
8807 DragPieceBegin(x, y)
8810 int boardX, boardY, color;
8813 /* Are we animating? */
8814 if (!appData.animateDragging || appData.blindfold)
8817 /* Figure out which square we start in and the
8818 mouse position relative to top left corner. */
8819 BoardSquare(x, y, &boardX, &boardY);
8820 player.startBoardX = boardX;
8821 player.startBoardY = boardY;
8822 ScreenSquare(boardX, boardY, &corner, &color);
8823 player.startSquare = corner;
8824 player.startColor = color;
8825 /* As soon as we start dragging, the piece will jump slightly to
8826 be centered over the mouse pointer. */
8827 player.mouseDelta.x = squareSize/2;
8828 player.mouseDelta.y = squareSize/2;
8829 /* Initialise animation */
8830 player.dragPiece = PieceForSquare(boardX, boardY);
8832 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8833 player.dragActive = True;
8834 BeginAnimation(&player, player.dragPiece, color, &corner);
8835 /* Mark this square as needing to be redrawn. Note that
8836 we don't remove the piece though, since logically (ie
8837 as seen by opponent) the move hasn't been made yet. */
8838 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8839 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8840 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8841 corner.x, corner.y, squareSize, squareSize,
8842 0, 0); // [HGM] zh: unstack in stead of grab
8843 damage[0][boardY][boardX] = True;
8845 player.dragActive = False;
8855 /* Are we animating? */
8856 if (!appData.animateDragging || appData.blindfold)
8860 if (! player.dragActive)
8862 /* Move piece, maintaining same relative position
8863 of mouse within square */
8864 corner.x = x - player.mouseDelta.x;
8865 corner.y = y - player.mouseDelta.y;
8866 AnimationFrame(&player, &corner, player.dragPiece);
8868 if (appData.highlightDragging) {
8870 BoardSquare(x, y, &boardX, &boardY);
8871 SetHighlights(fromX, fromY, boardX, boardY);
8880 int boardX, boardY, color;
8883 /* Are we animating? */
8884 if (!appData.animateDragging || appData.blindfold)
8888 if (! player.dragActive)
8890 /* Last frame in sequence is square piece is
8891 placed on, which may not match mouse exactly. */
8892 BoardSquare(x, y, &boardX, &boardY);
8893 ScreenSquare(boardX, boardY, &corner, &color);
8894 EndAnimation(&player, &corner);
8896 /* Be sure end square is redrawn */
8897 damage[0][boardY][boardX] = True;
8899 /* This prevents weird things happening with fast successive
8900 clicks which on my Sun at least can cause motion events
8901 without corresponding press/release. */
8902 player.dragActive = False;
8905 /* Handle expose event while piece being dragged */
8910 if (!player.dragActive || appData.blindfold)
8913 /* What we're doing: logically, the move hasn't been made yet,
8914 so the piece is still in it's original square. But visually
8915 it's being dragged around the board. So we erase the square
8916 that the piece is on and draw it at the last known drag point. */
8917 BlankSquare(player.startSquare.x, player.startSquare.y,
8918 player.startColor, EmptySquare, xBoardWindow);
8919 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8920 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8923 #include <sys/ioctl.h>
8924 int get_term_width()
8926 int fd, default_width;
8929 default_width = 79; // this is FICS default anyway...
8931 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8933 if (!ioctl(fd, TIOCGSIZE, &win))
8934 default_width = win.ts_cols;
8935 #elif defined(TIOCGWINSZ)
8937 if (!ioctl(fd, TIOCGWINSZ, &win))
8938 default_width = win.ws_col;
8940 return default_width;
8943 void update_ics_width()
8945 static int old_width = 0;
8946 int new_width = get_term_width();
8948 if (old_width != new_width)
8949 ics_printf("set width %d\n", new_width);
8950 old_width = new_width;
8953 void NotifyFrontendLogin()