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, 2011, 2012 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>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
149 #include <X11/Intrinsic.h>
150 #include <X11/StringDefs.h>
151 #include <X11/Shell.h>
152 #include <X11/cursorfont.h>
153 #include <X11/Xatom.h>
154 #include <X11/Xmu/Atoms.h>
156 #include <X11/Xaw3d/Dialog.h>
157 #include <X11/Xaw3d/Form.h>
158 #include <X11/Xaw3d/List.h>
159 #include <X11/Xaw3d/Label.h>
160 #include <X11/Xaw3d/SimpleMenu.h>
161 #include <X11/Xaw3d/SmeBSB.h>
162 #include <X11/Xaw3d/SmeLine.h>
163 #include <X11/Xaw3d/Box.h>
164 #include <X11/Xaw3d/MenuButton.h>
165 #include <X11/Xaw3d/Text.h>
166 #include <X11/Xaw3d/AsciiText.h>
168 #include <X11/Xaw/Dialog.h>
169 #include <X11/Xaw/Form.h>
170 #include <X11/Xaw/List.h>
171 #include <X11/Xaw/Label.h>
172 #include <X11/Xaw/SimpleMenu.h>
173 #include <X11/Xaw/SmeBSB.h>
174 #include <X11/Xaw/SmeLine.h>
175 #include <X11/Xaw/Box.h>
176 #include <X11/Xaw/MenuButton.h>
177 #include <X11/Xaw/Text.h>
178 #include <X11/Xaw/AsciiText.h>
181 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
186 #include "pixmaps/pixmaps.h"
187 #define IMAGE_EXT "xpm"
189 #define IMAGE_EXT "xim"
190 #include "bitmaps/bitmaps.h"
193 #include "bitmaps/icon_white.bm"
194 #include "bitmaps/icon_black.bm"
195 #include "bitmaps/checkmark.bm"
197 #include "frontend.h"
199 #include "backendz.h"
203 #include "xgamelist.h"
204 #include "xhistory.h"
205 #include "xedittags.h"
208 // must be moved to xengineoutput.h
210 void EngineOutputProc P((Widget w, XEvent *event,
211 String *prms, Cardinal *nprms));
212 void EvalGraphProc P((Widget w, XEvent *event,
213 String *prms, Cardinal *nprms));
220 #define usleep(t) _sleep2(((t)+500)/1000)
224 # define _(s) gettext (s)
225 # define N_(s) gettext_noop (s)
245 int main P((int argc, char **argv));
246 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
247 char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return));
248 RETSIGTYPE CmailSigHandler P((int sig));
249 RETSIGTYPE IntSigHandler P((int sig));
250 RETSIGTYPE TermSizeSigHandler P((int sig));
251 void CreateGCs P((int redo));
252 void CreateAnyPieces P((void));
253 void CreateXIMPieces P((void));
254 void CreateXPMPieces P((void));
255 void CreateXPMBoard P((char *s, int n));
256 void CreatePieces P((void));
257 void CreatePieceMenus P((void));
258 Widget CreateMenuBar P((Menu *mb, int boardWidth));
259 Widget CreateButtonBar P ((MenuItem *mi));
261 char *InsertPxlSize P((char *pattern, int targetPxlSize));
262 XFontSet CreateFontSet P((char *base_fnt_lst));
264 char *FindFont P((char *pattern, int targetPxlSize));
266 void PieceMenuPopup P((Widget w, XEvent *event,
267 String *params, Cardinal *num_params));
268 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
269 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
270 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
271 u_int wreq, u_int hreq));
272 void CreateGrid P((void));
273 int EventToSquare P((int x, int limit));
274 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
275 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
276 void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
277 void HandleUserMove P((Widget w, XEvent *event,
278 String *prms, Cardinal *nprms));
279 void AnimateUserMove P((Widget w, XEvent * event,
280 String * params, Cardinal * nParams));
281 void HandlePV P((Widget w, XEvent * event,
282 String * params, Cardinal * nParams));
283 void SelectPV P((Widget w, XEvent * event,
284 String * params, Cardinal * nParams));
285 void StopPV P((Widget w, XEvent * event,
286 String * params, Cardinal * nParams));
287 void WhiteClock P((Widget w, XEvent *event,
288 String *prms, Cardinal *nprms));
289 void BlackClock P((Widget w, XEvent *event,
290 String *prms, Cardinal *nprms));
291 void DrawPositionProc P((Widget w, XEvent *event,
292 String *prms, Cardinal *nprms));
293 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
295 void CommentClick P((Widget w, XEvent * event,
296 String * params, Cardinal * nParams));
297 void CommentPopUp P((char *title, char *label));
298 void CommentPopDown P((void));
299 void ICSInputBoxPopUp P((void));
300 void ICSInputBoxPopDown P((void));
301 void FileNamePopUp P((char *label, char *def, char *filter,
302 FileProc proc, char *openMode));
303 void FileNamePopDown P((void));
304 void FileNameCallback P((Widget w, XtPointer client_data,
305 XtPointer call_data));
306 void FileNameAction P((Widget w, XEvent *event,
307 String *prms, Cardinal *nprms));
308 void AskQuestionReplyAction P((Widget w, XEvent *event,
309 String *prms, Cardinal *nprms));
310 void AskQuestionProc P((Widget w, XEvent *event,
311 String *prms, Cardinal *nprms));
312 void AskQuestionPopDown P((void));
313 void PromotionPopDown P((void));
314 void PromotionCallback P((Widget w, XtPointer client_data,
315 XtPointer call_data));
316 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
317 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
321 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
323 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
325 void LoadPositionProc P((Widget w, XEvent *event,
326 String *prms, Cardinal *nprms));
327 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
329 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
331 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
333 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
335 void PastePositionProc P((Widget w, XEvent *event, String *prms,
337 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void CopyGameListProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
340 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void SavePositionProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
346 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
350 void MachineWhiteProc P((Widget w, XEvent *event,
351 String *prms, Cardinal *nprms));
352 void AnalyzeModeProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void AnalyzeFileProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
358 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void IcsClientProc P((Widget w, XEvent *event, String *prms,
362 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void EditPositionProc P((Widget w, XEvent *event,
364 String *prms, Cardinal *nprms));
365 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void EditCommentProc P((Widget w, XEvent *event,
367 String *prms, Cardinal *nprms));
368 void IcsInputBoxProc P((Widget w, XEvent *event,
369 String *prms, Cardinal *nprms));
370 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void TypeInProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void StopObservingProc P((Widget w, XEvent *event, String *prms,
387 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
389 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 Boolean TempBackwardActive = False;
395 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
401 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
403 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
406 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
408 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
410 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
412 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
415 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
418 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
420 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
422 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
427 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
429 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
431 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
433 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
436 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
438 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
440 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
442 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void DisplayMove P((int moveNumber));
453 void DisplayTitle P((char *title));
454 void ICSInitScript P((void));
455 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
456 void ErrorPopUp P((char *title, char *text, int modal));
457 void ErrorPopDown P((void));
458 static char *ExpandPathName P((char *path));
459 static void CreateAnimVars P((void));
460 static void DragPieceMove P((int x, int y));
461 static void DrawDragPiece P((void));
462 char *ModeToWidgetName P((GameMode mode));
463 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
468 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
469 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
470 void LoadEngineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
471 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
472 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
473 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
474 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
475 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
476 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
477 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
478 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
479 void EditBookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
480 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
481 void GameListOptionsPopDown P(());
482 void GenericPopDown P(());
483 void update_ics_width P(());
484 int get_term_width P(());
485 int CopyMemoProc P(());
486 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
487 Boolean IsDrawArrowEnabled P(());
490 * XBoard depends on Xt R4 or higher
492 int xtVersion = XtSpecificationRelease;
497 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
498 jailSquareColor, highlightSquareColor, premoveHighlightColor;
499 Pixel lowTimeWarningColor;
500 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
501 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
502 wjPieceGC, bjPieceGC, prelineGC, countGC;
503 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
504 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
505 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
506 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
507 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
508 ICSInputShell, fileNameShell, askQuestionShell;
509 Widget historyShell, evalGraphShell, gameListShell;
510 int hOffset; // [HGM] dual
511 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
512 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
513 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
515 XFontSet fontSet, clockFontSet;
518 XFontStruct *clockFontStruct;
520 Font coordFontID, countFontID;
521 XFontStruct *coordFontStruct, *countFontStruct;
522 XtAppContext appContext;
524 char *oldICSInteractionTitle;
528 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
530 Position commentX = -1, commentY = -1;
531 Dimension commentW, commentH;
532 typedef unsigned int BoardSize;
534 Boolean chessProgram;
536 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
537 int squareSize, smallLayout = 0, tinyLayout = 0,
538 marginW, marginH, // [HGM] for run-time resizing
539 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
540 ICSInputBoxUp = False, askQuestionUp = False,
541 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
542 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
543 Dimension textHeight;
544 Pixel timerForegroundPixel, timerBackgroundPixel;
545 Pixel buttonForegroundPixel, buttonBackgroundPixel;
546 char *chessDir, *programName, *programVersion,
547 *gameCopyFilename, *gamePasteFilename;
548 Boolean alwaysOnTop = False;
549 Boolean saveSettingsOnExit;
550 char *settingsFileName;
551 char *icsTextMenuString;
553 char *firstChessProgramNames;
554 char *secondChessProgramNames;
556 WindowPlacement wpMain;
557 WindowPlacement wpConsole;
558 WindowPlacement wpComment;
559 WindowPlacement wpMoveHistory;
560 WindowPlacement wpEvalGraph;
561 WindowPlacement wpEngineOutput;
562 WindowPlacement wpGameList;
563 WindowPlacement wpTags;
565 extern Widget shells[];
566 extern Boolean shellUp[];
570 Pixmap pieceBitmap[2][(int)BlackPawn];
571 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
572 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
573 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
574 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
575 Pixmap xpmBoardBitmap[2];
576 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
577 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
578 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
579 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
580 XImage *ximLightSquare, *ximDarkSquare;
583 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
584 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
586 #define White(piece) ((int)(piece) < (int)BlackPawn)
588 /* Variables for doing smooth animation. This whole thing
589 would be much easier if the board was double-buffered,
590 but that would require a fairly major rewrite. */
595 GC blitGC, pieceGC, outlineGC;
596 XPoint startSquare, prevFrame, mouseDelta;
600 int startBoardX, startBoardY;
603 /* There can be two pieces being animated at once: a player
604 can begin dragging a piece before the remote opponent has moved. */
606 static AnimState game, player;
608 /* Bitmaps for use as masks when drawing XPM pieces.
609 Need one for each black and white piece. */
610 static Pixmap xpmMask[BlackKing + 1];
612 /* This magic number is the number of intermediate frames used
613 in each half of the animation. For short moves it's reduced
614 by 1. The total number of frames will be factor * 2 + 1. */
617 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
619 MenuItem fileMenu[] = {
620 {N_("New Game Ctrl+N"), "New Game", ResetProc},
621 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
622 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
623 {"----", NULL, NothingProc},
624 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
625 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
626 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
627 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
628 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
629 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
630 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
631 {"----", NULL, NothingProc},
632 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
633 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
634 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
635 {"----", NULL, NothingProc},
636 {N_("Mail Move"), "Mail Move", MailMoveProc},
637 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
638 {"----", NULL, NothingProc},
639 {N_("Quit Ctr+Q"), "Exit", QuitProc},
643 MenuItem editMenu[] = {
644 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
645 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
646 {N_("Copy Game List"), "Copy Game List", CopyGameListProc},
647 {"----", NULL, NothingProc},
648 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
649 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
650 {"----", NULL, NothingProc},
651 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
652 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
653 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
654 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
655 {N_("Edit Book"), "Edit Book", EditBookProc},
656 {"----", NULL, NothingProc},
657 {N_("Revert Home"), "Revert", RevertProc},
658 {N_("Annotate"), "Annotate", AnnotateProc},
659 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
660 {"----", NULL, NothingProc},
661 {N_("Backward Alt+Left"), "Backward", BackwardProc},
662 {N_("Forward Alt+Right"), "Forward", ForwardProc},
663 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
664 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
668 MenuItem viewMenu[] = {
669 {N_("Flip View F2"), "Flip View", FlipViewProc},
670 {"----", NULL, NothingProc},
671 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
672 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
673 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
674 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
675 {N_("ICS text menu"), "ICStex", IcsTextProc},
676 {"----", NULL, NothingProc},
677 {N_("Tags"), "Show Tags", EditTagsProc},
678 {N_("Comments"), "Show Comments", EditCommentProc},
679 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
680 {"----", NULL, NothingProc},
681 {N_("Board..."), "Board Options", BoardOptionsProc},
682 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
686 MenuItem modeMenu[] = {
687 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
688 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
689 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
690 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
691 {N_("Analyze Game Ctrl+G"), "Analyze File", AnalyzeFileProc },
692 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
693 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
694 {N_("Training"), "Training", TrainingProc},
695 {N_("ICS Client"), "ICS Client", IcsClientProc},
696 {"----", NULL, NothingProc},
697 {N_("Machine Match"), "Machine Match", MatchProc},
698 {N_("Pause Pause"), "Pause", PauseProc},
702 MenuItem actionMenu[] = {
703 {N_("Accept F3"), "Accept", AcceptProc},
704 {N_("Decline F4"), "Decline", DeclineProc},
705 {N_("Rematch F12"), "Rematch", RematchProc},
706 {"----", NULL, NothingProc},
707 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
708 {N_("Draw F6"), "Draw", DrawProc},
709 {N_("Adjourn F7"), "Adjourn", AdjournProc},
710 {N_("Abort F8"),"Abort", AbortProc},
711 {N_("Resign F9"), "Resign", ResignProc},
712 {"----", NULL, NothingProc},
713 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
714 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
715 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
716 {"----", NULL, NothingProc},
717 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
718 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
719 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
723 MenuItem engineMenu[] = {
724 {N_("Load New Engine ..."), "Load Engine", LoadEngineProc},
725 {"----", NULL, NothingProc},
726 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
727 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
728 {"----", NULL, NothingProc},
729 {N_("Hint"), "Hint", HintProc},
730 {N_("Book"), "Book", BookProc},
731 {"----", NULL, NothingProc},
732 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
733 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
737 MenuItem optionsMenu[] = {
738 #define OPTIONSDIALOG
740 {N_("General ..."), "General", OptionsProc},
742 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
743 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
744 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
745 {N_("ICS ..."), "ICS", IcsOptionsProc},
746 {N_("Match ..."), "Match", MatchOptionsProc},
747 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
748 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
749 // {N_(" ..."), "", OptionsProc},
750 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
751 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
752 {"----", NULL, NothingProc},
753 #ifndef OPTIONSDIALOG
754 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
755 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
756 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
757 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
758 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
759 {N_("Blindfold"), "Blindfold", BlindfoldProc},
760 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
762 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
764 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
765 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
766 {N_("Move Sound"), "Move Sound", MoveSoundProc},
767 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
768 {N_("One-Click Moving"), "OneClick", OneClickProc},
769 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
770 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
771 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
772 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
773 // {N_("Premove"), "Premove", PremoveProc},
774 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
775 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
776 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
777 {"----", NULL, NothingProc},
779 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
780 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
784 MenuItem helpMenu[] = {
785 {N_("Info XBoard"), "Info XBoard", InfoProc},
786 {N_("Man XBoard F1"), "Man XBoard", ManProc},
787 {"----", NULL, NothingProc},
788 {N_("About XBoard"), "About XBoard", AboutProc},
793 {N_("File"), "File", fileMenu},
794 {N_("Edit"), "Edit", editMenu},
795 {N_("View"), "View", viewMenu},
796 {N_("Mode"), "Mode", modeMenu},
797 {N_("Action"), "Action", actionMenu},
798 {N_("Engine"), "Engine", engineMenu},
799 {N_("Options"), "Options", optionsMenu},
800 {N_("Help"), "Help", helpMenu},
804 #define PAUSE_BUTTON "P"
805 MenuItem buttonBar[] = {
806 {"<<", "<<", ToStartProc},
807 {"<", "<", BackwardProc},
808 {N_(PAUSE_BUTTON), PAUSE_BUTTON, PauseProc},
809 {">", ">", ForwardProc},
810 {">>", ">>", ToEndProc},
814 #define PIECE_MENU_SIZE 18
815 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
816 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
817 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
818 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
819 N_("Empty square"), N_("Clear board") },
820 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
821 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
822 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
823 N_("Empty square"), N_("Clear board") }
825 /* must be in same order as pieceMenuStrings! */
826 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
827 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
828 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
829 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
830 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
831 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
832 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
833 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
834 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
837 #define DROP_MENU_SIZE 6
838 String dropMenuStrings[DROP_MENU_SIZE] = {
839 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
841 /* must be in same order as dropMenuStrings! */
842 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
843 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
844 WhiteRook, WhiteQueen
852 DropMenuEnables dmEnables[] = {
870 { XtNborderWidth, 0 },
871 { XtNdefaultDistance, 0 },
875 { XtNborderWidth, 0 },
876 { XtNresizable, (XtArgVal) True },
880 { XtNborderWidth, 0 },
886 { XtNjustify, (XtArgVal) XtJustifyRight },
887 { XtNlabel, (XtArgVal) "..." },
888 { XtNresizable, (XtArgVal) True },
889 { XtNresize, (XtArgVal) False }
892 Arg messageArgs[] = {
893 { XtNjustify, (XtArgVal) XtJustifyLeft },
894 { XtNlabel, (XtArgVal) "..." },
895 { XtNresizable, (XtArgVal) True },
896 { XtNresize, (XtArgVal) False }
900 { XtNborderWidth, 0 },
901 { XtNjustify, (XtArgVal) XtJustifyLeft }
904 XtResource clientResources[] = {
905 { "flashCount", "flashCount", XtRInt, sizeof(int),
906 XtOffset(AppDataPtr, flashCount), XtRImmediate,
907 (XtPointer) FLASH_COUNT },
910 XrmOptionDescRec shellOptions[] = {
911 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
912 { "-flash", "flashCount", XrmoptionNoArg, "3" },
913 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
916 XtActionsRec boardActions[] = {
917 { "DrawPosition", DrawPositionProc },
918 { "HandleUserMove", HandleUserMove },
919 { "AnimateUserMove", AnimateUserMove },
920 { "HandlePV", HandlePV },
921 { "SelectPV", SelectPV },
922 { "StopPV", StopPV },
923 { "FileNameAction", FileNameAction },
924 { "AskQuestionProc", AskQuestionProc },
925 { "AskQuestionReplyAction", AskQuestionReplyAction },
926 { "PieceMenuPopup", PieceMenuPopup },
927 { "WhiteClock", WhiteClock },
928 { "BlackClock", BlackClock },
929 { "ResetProc", ResetProc },
930 { "NewVariantProc", NewVariantProc },
931 { "LoadGameProc", LoadGameProc },
932 { "LoadNextGameProc", LoadNextGameProc },
933 { "LoadPrevGameProc", LoadPrevGameProc },
934 { "LoadSelectedProc", LoadSelectedProc },
935 { "SetFilterProc", SetFilterProc },
936 { "ReloadGameProc", ReloadGameProc },
937 { "LoadPositionProc", LoadPositionProc },
938 { "LoadNextPositionProc", LoadNextPositionProc },
939 { "LoadPrevPositionProc", LoadPrevPositionProc },
940 { "ReloadPositionProc", ReloadPositionProc },
941 { "CopyPositionProc", CopyPositionProc },
942 { "PastePositionProc", PastePositionProc },
943 { "CopyGameProc", CopyGameProc },
944 { "CopyGameListProc", CopyGameListProc },
945 { "PasteGameProc", PasteGameProc },
946 { "SaveGameProc", SaveGameProc },
947 { "SavePositionProc", SavePositionProc },
948 { "MailMoveProc", MailMoveProc },
949 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
950 { "QuitProc", QuitProc },
951 { "MachineWhiteProc", MachineWhiteProc },
952 { "MachineBlackProc", MachineBlackProc },
953 { "AnalysisModeProc", AnalyzeModeProc },
954 { "AnalyzeFileProc", AnalyzeFileProc },
955 { "TwoMachinesProc", TwoMachinesProc },
956 { "IcsClientProc", IcsClientProc },
957 { "EditGameProc", EditGameProc },
958 { "EditPositionProc", EditPositionProc },
959 { "TrainingProc", EditPositionProc },
960 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
961 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
962 { "ShowGameListProc", ShowGameListProc },
963 { "ShowMoveListProc", HistoryShowProc},
964 { "EditTagsProc", EditTagsProc },
965 { "EditBookProc", EditBookProc },
966 { "EditCommentProc", EditCommentProc },
967 { "IcsInputBoxProc", IcsInputBoxProc },
968 { "PauseProc", PauseProc },
969 { "AcceptProc", AcceptProc },
970 { "DeclineProc", DeclineProc },
971 { "RematchProc", RematchProc },
972 { "CallFlagProc", CallFlagProc },
973 { "DrawProc", DrawProc },
974 { "AdjournProc", AdjournProc },
975 { "AbortProc", AbortProc },
976 { "ResignProc", ResignProc },
977 { "AdjuWhiteProc", AdjuWhiteProc },
978 { "AdjuBlackProc", AdjuBlackProc },
979 { "AdjuDrawProc", AdjuDrawProc },
980 { "TypeInProc", TypeInProc },
981 { "EnterKeyProc", EnterKeyProc },
982 { "UpKeyProc", UpKeyProc },
983 { "DownKeyProc", DownKeyProc },
984 { "StopObservingProc", StopObservingProc },
985 { "StopExaminingProc", StopExaminingProc },
986 { "UploadProc", UploadProc },
987 { "BackwardProc", BackwardProc },
988 { "ForwardProc", ForwardProc },
989 { "TempBackwardProc", TempBackwardProc },
990 { "TempForwardProc", TempForwardProc },
991 { "ToStartProc", ToStartProc },
992 { "ToEndProc", ToEndProc },
993 { "RevertProc", RevertProc },
994 { "AnnotateProc", AnnotateProc },
995 { "TruncateGameProc", TruncateGameProc },
996 { "MoveNowProc", MoveNowProc },
997 { "RetractMoveProc", RetractMoveProc },
998 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
999 { "UciMenuProc", (XtActionProc) UciMenuProc },
1000 { "TimeControlProc", (XtActionProc) TimeControlProc },
1001 { "FlipViewProc", FlipViewProc },
1002 { "PonderNextMoveProc", PonderNextMoveProc },
1003 #ifndef OPTIONSDIALOG
1004 { "AlwaysQueenProc", AlwaysQueenProc },
1005 { "AnimateDraggingProc", AnimateDraggingProc },
1006 { "AnimateMovingProc", AnimateMovingProc },
1007 { "AutoflagProc", AutoflagProc },
1008 { "AutoflipProc", AutoflipProc },
1009 { "BlindfoldProc", BlindfoldProc },
1010 { "FlashMovesProc", FlashMovesProc },
1012 { "HighlightDraggingProc", HighlightDraggingProc },
1014 { "HighlightLastMoveProc", HighlightLastMoveProc },
1015 // { "IcsAlarmProc", IcsAlarmProc },
1016 { "MoveSoundProc", MoveSoundProc },
1017 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1018 { "PopupExitMessageProc", PopupExitMessageProc },
1019 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1020 // { "PremoveProc", PremoveProc },
1021 { "ShowCoordsProc", ShowCoordsProc },
1022 { "ShowThinkingProc", ShowThinkingProc },
1023 { "HideThinkingProc", HideThinkingProc },
1024 { "TestLegalityProc", TestLegalityProc },
1026 { "SaveSettingsProc", SaveSettingsProc },
1027 { "SaveOnExitProc", SaveOnExitProc },
1028 { "InfoProc", InfoProc },
1029 { "ManProc", ManProc },
1030 { "HintProc", HintProc },
1031 { "BookProc", BookProc },
1032 { "AboutGameProc", AboutGameProc },
1033 { "AboutProc", AboutProc },
1034 { "DebugProc", DebugProc },
1035 { "NothingProc", NothingProc },
1036 { "CommentClick", (XtActionProc) CommentClick },
1037 { "CommentPopDown", (XtActionProc) CommentPopDown },
1038 { "TagsPopDown", (XtActionProc) TagsPopDown },
1039 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1040 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1041 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1042 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1043 { "GameListPopDown", (XtActionProc) GameListPopDown },
1044 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1045 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1046 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1047 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1048 { "GenericPopDown", (XtActionProc) GenericPopDown },
1049 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1050 { "SelectMove", (XtActionProc) SelectMove },
1053 char globalTranslations[] =
1054 ":<Key>F9: ResignProc() \n \
1055 :Ctrl<Key>n: ResetProc() \n \
1056 :Meta<Key>V: NewVariantProc() \n \
1057 :Ctrl<Key>o: LoadGameProc() \n \
1058 :Meta<Key>Next: LoadNextGameProc() \n \
1059 :Meta<Key>Prior: LoadPrevGameProc() \n \
1060 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
1061 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
1062 :Ctrl<Key>s: SaveGameProc() \n \
1063 :Ctrl<Key>c: CopyGameProc() \n \
1064 :Ctrl<Key>v: PasteGameProc() \n \
1065 :Ctrl<Key>O: LoadPositionProc() \n \
1066 :Shift<Key>Next: LoadNextPositionProc() \n \
1067 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1068 :Ctrl<Key>S: SavePositionProc() \n \
1069 :Ctrl<Key>C: CopyPositionProc() \n \
1070 :Ctrl<Key>V: PastePositionProc() \n \
1071 :Ctrl<Key>q: QuitProc() \n \
1072 :Ctrl<Key>w: MachineWhiteProc() \n \
1073 :Ctrl<Key>b: MachineBlackProc() \n \
1074 :Ctrl<Key>t: TwoMachinesProc() \n \
1075 :Ctrl<Key>a: AnalysisModeProc() \n \
1076 :Ctrl<Key>g: AnalyzeFileProc() \n \
1077 :Ctrl<Key>e: EditGameProc() \n \
1078 :Ctrl<Key>E: EditPositionProc() \n \
1079 :Meta<Key>O: EngineOutputProc() \n \
1080 :Meta<Key>E: EvalGraphProc() \n \
1081 :Meta<Key>G: ShowGameListProc() \n \
1082 :Meta<Key>H: ShowMoveListProc() \n \
1083 :<Key>Pause: PauseProc() \n \
1084 :<Key>F3: AcceptProc() \n \
1085 :<Key>F4: DeclineProc() \n \
1086 :<Key>F12: RematchProc() \n \
1087 :<Key>F5: CallFlagProc() \n \
1088 :<Key>F6: DrawProc() \n \
1089 :<Key>F7: AdjournProc() \n \
1090 :<Key>F8: AbortProc() \n \
1091 :<Key>F10: StopObservingProc() \n \
1092 :<Key>F11: StopExaminingProc() \n \
1093 :Meta Ctrl<Key>F12: DebugProc() \n \
1094 :Meta<Key>End: ToEndProc() \n \
1095 :Meta<Key>Right: ForwardProc() \n \
1096 :Meta<Key>Home: ToStartProc() \n \
1097 :Meta<Key>Left: BackwardProc() \n \
1098 :<Key>Left: BackwardProc() \n \
1099 :<Key>Right: ForwardProc() \n \
1100 :<Key>Home: RevertProc() \n \
1101 :<Key>End: TruncateGameProc() \n \
1102 :Ctrl<Key>m: MoveNowProc() \n \
1103 :Ctrl<Key>x: RetractMoveProc() \n \
1104 :Meta<Key>J: EngineMenuProc() \n \
1105 :Meta<Key>U: UciMenuProc() \n \
1106 :Meta<Key>T: TimeControlProc() \n \
1107 :Ctrl<Key>P: PonderNextMoveProc() \n "
1108 #ifndef OPTIONSDIALOG
1110 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1111 :Ctrl<Key>F: AutoflagProc() \n \
1112 :Ctrl<Key>A: AnimateMovingProc() \n \
1113 :Ctrl<Key>L: TestLegalityProc() \n \
1114 :Ctrl<Key>H: HideThinkingProc() \n "
1117 :<Key>F1: ManProc() \n \
1118 :<Key>F2: FlipViewProc() \n \
1119 :<KeyDown>Return: TempBackwardProc() \n \
1120 :<KeyUp>Return: TempForwardProc() \n";
1122 char boardTranslations[] =
1123 "<Btn1Down>: HandleUserMove(0) \n \
1124 Shift<Btn1Up>: HandleUserMove(1) \n \
1125 <Btn1Up>: HandleUserMove(0) \n \
1126 <Btn1Motion>: AnimateUserMove() \n \
1127 <Btn3Motion>: HandlePV() \n \
1128 <Btn3Up>: PieceMenuPopup(menuB) \n \
1129 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1130 PieceMenuPopup(menuB) \n \
1131 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1132 PieceMenuPopup(menuW) \n \
1133 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1134 PieceMenuPopup(menuW) \n \
1135 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1136 PieceMenuPopup(menuB) \n";
1138 char whiteTranslations[] =
1139 "Shift<BtnDown>: WhiteClock(1)\n \
1140 <BtnDown>: WhiteClock(0)\n";
1141 char blackTranslations[] =
1142 "Shift<BtnDown>: BlackClock(1)\n \
1143 <BtnDown>: BlackClock(0)\n";
1145 char ICSInputTranslations[] =
1146 "<Key>Up: UpKeyProc() \n "
1147 "<Key>Down: DownKeyProc() \n "
1148 "<Key>Return: EnterKeyProc() \n";
1150 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1151 // as the widget is destroyed before the up-click can call extend-end
1152 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1154 String xboardResources[] = {
1155 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1156 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1157 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1162 /* Max possible square size */
1163 #define MAXSQSIZE 256
1165 static int xpm_avail[MAXSQSIZE];
1167 #ifdef HAVE_DIR_STRUCT
1169 /* Extract piece size from filename */
1171 xpm_getsize (char *name, int len, char *ext)
1179 if ((p=strchr(name, '.')) == NULL ||
1180 StrCaseCmp(p+1, ext) != 0)
1186 while (*p && isdigit(*p))
1193 /* Setup xpm_avail */
1195 xpm_getavail (char *dirname, char *ext)
1201 for (i=0; i<MAXSQSIZE; ++i)
1204 if (appData.debugMode)
1205 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1207 dir = opendir(dirname);
1210 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1211 programName, dirname);
1215 while ((ent=readdir(dir)) != NULL) {
1216 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1217 if (i > 0 && i < MAXSQSIZE)
1227 xpm_print_avail (FILE *fp, char *ext)
1231 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1232 for (i=1; i<MAXSQSIZE; ++i) {
1238 /* Return XPM piecesize closest to size */
1240 xpm_closest_to (char *dirname, int size, char *ext)
1243 int sm_diff = MAXSQSIZE;
1247 xpm_getavail(dirname, ext);
1249 if (appData.debugMode)
1250 xpm_print_avail(stderr, ext);
1252 for (i=1; i<MAXSQSIZE; ++i) {
1255 diff = (diff<0) ? -diff : diff;
1256 if (diff < sm_diff) {
1264 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1270 #else /* !HAVE_DIR_STRUCT */
1271 /* If we are on a system without a DIR struct, we can't
1272 read the directory, so we can't collect a list of
1273 filenames, etc., so we can't do any size-fitting. */
1275 xpm_closest_to (char *dirname, int size, char *ext)
1277 fprintf(stderr, _("\
1278 Warning: No DIR structure found on this system --\n\
1279 Unable to autosize for XPM/XIM pieces.\n\
1280 Please report this error to %s.\n\
1281 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1284 #endif /* HAVE_DIR_STRUCT */
1286 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1287 "magenta", "cyan", "white" };
1291 TextColors textColors[(int)NColorClasses];
1293 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1295 parse_color (char *str, int which)
1297 char *p, buf[100], *d;
1300 if (strlen(str) > 99) /* watch bounds on buf */
1305 for (i=0; i<which; ++i) {
1312 /* Could be looking at something like:
1314 .. in which case we want to stop on a comma also */
1315 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1319 return -1; /* Use default for empty field */
1322 if (which == 2 || isdigit(*p))
1325 while (*p && isalpha(*p))
1330 for (i=0; i<8; ++i) {
1331 if (!StrCaseCmp(buf, cnames[i]))
1332 return which? (i+40) : (i+30);
1334 if (!StrCaseCmp(buf, "default")) return -1;
1336 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1341 parse_cpair (ColorClass cc, char *str)
1343 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1344 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1349 /* bg and attr are optional */
1350 textColors[(int)cc].bg = parse_color(str, 1);
1351 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1352 textColors[(int)cc].attr = 0;
1358 /* Arrange to catch delete-window events */
1359 Atom wm_delete_window;
1361 CatchDeleteWindow (Widget w, String procname)
1364 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1365 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1366 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1373 XtSetArg(args[0], XtNiconic, False);
1374 XtSetValues(shellWidget, args, 1);
1376 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1379 //---------------------------------------------------------------------------------------------------------
1380 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1383 #define CW_USEDEFAULT (1<<31)
1384 #define ICS_TEXT_MENU_SIZE 90
1385 #define DEBUG_FILE "xboard.debug"
1386 #define SetCurrentDirectory chdir
1387 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1391 // these two must some day move to frontend.h, when they are implemented
1392 Boolean GameListIsUp();
1394 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1397 // front-end part of option handling
1399 // [HGM] This platform-dependent table provides the location for storing the color info
1400 extern char *crWhite, * crBlack;
1404 &appData.whitePieceColor,
1405 &appData.blackPieceColor,
1406 &appData.lightSquareColor,
1407 &appData.darkSquareColor,
1408 &appData.highlightSquareColor,
1409 &appData.premoveHighlightColor,
1410 &appData.lowTimeWarningColor,
1421 // [HGM] font: keep a font for each square size, even non-stndard ones
1422 #define NUM_SIZES 18
1423 #define MAX_SIZE 130
1424 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1425 char *fontTable[NUM_FONTS][MAX_SIZE];
1428 ParseFont (char *name, int number)
1429 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1431 if(sscanf(name, "size%d:", &size)) {
1432 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1433 // defer processing it until we know if it matches our board size
1434 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1435 fontTable[number][size] = strdup(strchr(name, ':')+1);
1436 fontValid[number][size] = True;
1441 case 0: // CLOCK_FONT
1442 appData.clockFont = strdup(name);
1444 case 1: // MESSAGE_FONT
1445 appData.font = strdup(name);
1447 case 2: // COORD_FONT
1448 appData.coordFont = strdup(name);
1453 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1458 { // only 2 fonts currently
1459 appData.clockFont = CLOCK_FONT_NAME;
1460 appData.coordFont = COORD_FONT_NAME;
1461 appData.font = DEFAULT_FONT_NAME;
1466 { // no-op, until we identify the code for this already in XBoard and move it here
1470 ParseColor (int n, char *name)
1471 { // in XBoard, just copy the color-name string
1472 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1476 ParseTextAttribs (ColorClass cc, char *s)
1478 (&appData.colorShout)[cc] = strdup(s);
1482 ParseBoardSize (void *addr, char *name)
1484 appData.boardSize = strdup(name);
1489 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1493 SetCommPortDefaults ()
1494 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1497 // [HGM] args: these three cases taken out to stay in front-end
1499 SaveFontArg (FILE *f, ArgDescriptor *ad)
1502 int i, n = (int)(intptr_t)ad->argLoc;
1504 case 0: // CLOCK_FONT
1505 name = appData.clockFont;
1507 case 1: // MESSAGE_FONT
1508 name = appData.font;
1510 case 2: // COORD_FONT
1511 name = appData.coordFont;
1516 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1517 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1518 fontTable[n][squareSize] = strdup(name);
1519 fontValid[n][squareSize] = True;
1522 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1523 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1528 { // nothing to do, as the sounds are at all times represented by their text-string names already
1532 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
1533 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1534 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1538 SaveColor (FILE *f, ArgDescriptor *ad)
1539 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1540 if(colorVariable[(int)(intptr_t)ad->argLoc])
1541 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1545 SaveBoardSize (FILE *f, char *name, void *addr)
1546 { // wrapper to shield back-end from BoardSize & sizeInfo
1547 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1551 ParseCommPortSettings (char *s)
1552 { // no such option in XBoard (yet)
1555 extern Widget engineOutputShell;
1558 GetActualPlacement (Widget wg, WindowPlacement *wp)
1568 XtSetArg(args[i], XtNx, &x); i++;
1569 XtSetArg(args[i], XtNy, &y); i++;
1570 XtSetArg(args[i], XtNwidth, &w); i++;
1571 XtSetArg(args[i], XtNheight, &h); i++;
1572 XtGetValues(wg, args, i);
1581 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1582 // In XBoard this will have to wait until awareness of window parameters is implemented
1583 GetActualPlacement(shellWidget, &wpMain);
1584 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput);
1585 if(MoveHistoryIsUp()) GetActualPlacement(shells[7], &wpMoveHistory);
1586 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1587 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1588 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1589 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1593 PrintCommPortSettings (FILE *f, char *name)
1594 { // This option does not exist in XBoard
1598 MySearchPath (char *installDir, char *name, char *fullname)
1599 { // just append installDir and name. Perhaps ExpandPath should be used here?
1600 name = ExpandPathName(name);
1601 if(name && name[0] == '/')
1602 safeStrCpy(fullname, name, MSG_SIZ );
1604 sprintf(fullname, "%s%c%s", installDir, '/', name);
1610 MyGetFullPathName (char *name, char *fullname)
1611 { // should use ExpandPath?
1612 name = ExpandPathName(name);
1613 safeStrCpy(fullname, name, MSG_SIZ );
1618 EnsureOnScreen (int *x, int *y, int minX, int minY)
1625 { // [HGM] args: allows testing if main window is realized from back-end
1626 return xBoardWindow != 0;
1630 PopUpStartupDialog ()
1631 { // start menu not implemented in XBoard
1635 ConvertToLine (int argc, char **argv)
1637 static char line[128*1024], buf[1024];
1641 for(i=1; i<argc; i++)
1643 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
1644 && argv[i][0] != '{' )
1645 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1647 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1648 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1651 line[strlen(line)-1] = NULLCHAR;
1655 //--------------------------------------------------------------------------------------------
1657 extern Boolean twoBoards, partnerUp;
1660 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1662 #define BoardSize int
1664 InitDrawingSizes (BoardSize boardSize, int flags)
1665 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1666 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1668 XtGeometryResult gres;
1670 static Dimension oldWidth, oldHeight;
1671 static VariantClass oldVariant;
1672 static int oldDual = -1, oldMono = -1;
1674 if(!formWidget) return;
1676 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1677 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1678 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1680 if(boardWidth != oldWidth || boardHeight != oldHeight || oldDual != twoBoards) { // do resizing stuff only if size actually changed
1682 * Enable shell resizing.
1684 shellArgs[0].value = (XtArgVal) &w;
1685 shellArgs[1].value = (XtArgVal) &h;
1686 XtGetValues(shellWidget, shellArgs, 2);
1688 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1689 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1690 XtSetValues(shellWidget, &shellArgs[2], 4);
1692 XtSetArg(args[0], XtNdefaultDistance, &sep);
1693 XtGetValues(formWidget, args, 1);
1695 oldWidth = boardWidth; oldHeight = boardHeight; oldDual = twoBoards;
1697 hOffset = boardWidth + 10;
1698 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1699 secondSegments[i] = gridSegments[i];
1700 secondSegments[i].x1 += hOffset;
1701 secondSegments[i].x2 += hOffset;
1704 XtSetArg(args[0], XtNwidth, boardWidth);
1705 XtSetArg(args[1], XtNheight, boardHeight);
1706 XtSetValues(boardWidget, args, 2);
1708 timerWidth = (boardWidth - sep) / 2;
1709 XtSetArg(args[0], XtNwidth, timerWidth);
1710 XtSetValues(whiteTimerWidget, args, 1);
1711 XtSetValues(blackTimerWidget, args, 1);
1713 XawFormDoLayout(formWidget, False);
1715 if (appData.titleInWindow) {
1717 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1718 XtSetArg(args[i], XtNheight, &h); i++;
1719 XtGetValues(titleWidget, args, i);
1721 w = boardWidth - 2*bor;
1723 XtSetArg(args[0], XtNwidth, &w);
1724 XtGetValues(menuBarWidget, args, 1);
1725 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1728 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1729 if (gres != XtGeometryYes && appData.debugMode) {
1731 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1732 programName, gres, w, h, wr, hr);
1736 XawFormDoLayout(formWidget, True);
1739 * Inhibit shell resizing.
1741 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1742 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1743 shellArgs[4].value = shellArgs[2].value = w;
1744 shellArgs[5].value = shellArgs[3].value = h;
1745 XtSetValues(shellWidget, &shellArgs[0], 6);
1748 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1751 if(gameInfo.variant != oldVariant) { // and only if variant changed
1754 for(i=0; i<4; i++) {
1756 for(p=0; p<=(int)WhiteKing; p++)
1757 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1758 if(gameInfo.variant == VariantShogi) {
1759 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1760 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1761 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1762 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1763 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1766 if(gameInfo.variant == VariantGothic) {
1767 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1770 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1771 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1772 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1775 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1776 for(p=0; p<=(int)WhiteKing; p++)
1777 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1778 if(gameInfo.variant == VariantShogi) {
1779 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1780 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1781 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1782 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1783 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1786 if(gameInfo.variant == VariantGothic) {
1787 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1790 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1791 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1792 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1797 for(i=0; i<2; i++) {
1799 for(p=0; p<=(int)WhiteKing; p++)
1800 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1801 if(gameInfo.variant == VariantShogi) {
1802 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1803 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1804 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1805 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1806 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1809 if(gameInfo.variant == VariantGothic) {
1810 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1813 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1814 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1815 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1821 if(appData.monoMode != oldMono)
1824 oldMono = appData.monoMode;
1829 ParseIcsTextColors ()
1830 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1831 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1832 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1833 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1834 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1835 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1836 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1837 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1838 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1839 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1840 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1842 if (appData.colorize) {
1844 _("%s: can't parse color names; disabling colorization\n"),
1847 appData.colorize = FALSE;
1853 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1854 XrmValue vFrom, vTo;
1855 int forceMono = False;
1857 if (!appData.monoMode) {
1858 vFrom.addr = (caddr_t) appData.lightSquareColor;
1859 vFrom.size = strlen(appData.lightSquareColor);
1860 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1861 if (vTo.addr == NULL) {
1862 appData.monoMode = True;
1865 lightSquareColor = *(Pixel *) vTo.addr;
1868 if (!appData.monoMode) {
1869 vFrom.addr = (caddr_t) appData.darkSquareColor;
1870 vFrom.size = strlen(appData.darkSquareColor);
1871 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1872 if (vTo.addr == NULL) {
1873 appData.monoMode = True;
1876 darkSquareColor = *(Pixel *) vTo.addr;
1879 if (!appData.monoMode) {
1880 vFrom.addr = (caddr_t) appData.whitePieceColor;
1881 vFrom.size = strlen(appData.whitePieceColor);
1882 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1883 if (vTo.addr == NULL) {
1884 appData.monoMode = True;
1887 whitePieceColor = *(Pixel *) vTo.addr;
1890 if (!appData.monoMode) {
1891 vFrom.addr = (caddr_t) appData.blackPieceColor;
1892 vFrom.size = strlen(appData.blackPieceColor);
1893 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1894 if (vTo.addr == NULL) {
1895 appData.monoMode = True;
1898 blackPieceColor = *(Pixel *) vTo.addr;
1902 if (!appData.monoMode) {
1903 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1904 vFrom.size = strlen(appData.highlightSquareColor);
1905 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1906 if (vTo.addr == NULL) {
1907 appData.monoMode = True;
1910 highlightSquareColor = *(Pixel *) vTo.addr;
1914 if (!appData.monoMode) {
1915 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1916 vFrom.size = strlen(appData.premoveHighlightColor);
1917 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1918 if (vTo.addr == NULL) {
1919 appData.monoMode = True;
1922 premoveHighlightColor = *(Pixel *) vTo.addr;
1930 { // [HGM] taken out of main
1932 if (appData.monoMode && // [HGM] no sense to go on to certain doom
1933 (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1934 appData.bitmapDirectory = strdup(DEF_BITMAP_DIR);
1936 if (appData.bitmapDirectory[0] != NULLCHAR) {
1940 CreateXPMBoard(appData.liteBackTextureFile, 1);
1941 CreateXPMBoard(appData.darkBackTextureFile, 0);
1945 /* Create regular pieces */
1946 if (!useImages) CreatePieces();
1951 main (int argc, char **argv)
1953 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1954 XSetWindowAttributes window_attributes;
1956 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1957 XrmValue vFrom, vTo;
1958 XtGeometryResult gres;
1961 int forceMono = False;
1963 srandom(time(0)); // [HGM] book: make random truly random
1965 setbuf(stdout, NULL);
1966 setbuf(stderr, NULL);
1969 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1970 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1974 programName = strrchr(argv[0], '/');
1975 if (programName == NULL)
1976 programName = argv[0];
1981 XtSetLanguageProc(NULL, NULL, NULL);
1982 bindtextdomain(PACKAGE, LOCALEDIR);
1983 textdomain(PACKAGE);
1987 XtAppInitialize(&appContext, "XBoard", shellOptions,
1988 XtNumber(shellOptions),
1989 &argc, argv, xboardResources, NULL, 0);
1990 appData.boardSize = "";
1991 InitAppData(ConvertToLine(argc, argv));
1993 if (p == NULL) p = "/tmp";
1994 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1995 gameCopyFilename = (char*) malloc(i);
1996 gamePasteFilename = (char*) malloc(i);
1997 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1998 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
2000 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2001 clientResources, XtNumber(clientResources),
2004 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
2005 static char buf[MSG_SIZ];
2006 EscapeExpand(buf, appData.firstInitString);
2007 appData.firstInitString = strdup(buf);
2008 EscapeExpand(buf, appData.secondInitString);
2009 appData.secondInitString = strdup(buf);
2010 EscapeExpand(buf, appData.firstComputerString);
2011 appData.firstComputerString = strdup(buf);
2012 EscapeExpand(buf, appData.secondComputerString);
2013 appData.secondComputerString = strdup(buf);
2016 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2019 if (chdir(chessDir) != 0) {
2020 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2026 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2027 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2028 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
2029 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2032 setbuf(debugFP, NULL);
2036 if (appData.debugMode) {
2037 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2041 /* [HGM,HR] make sure board size is acceptable */
2042 if(appData.NrFiles > BOARD_FILES ||
2043 appData.NrRanks > BOARD_RANKS )
2044 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2047 /* This feature does not work; animation needs a rewrite */
2048 appData.highlightDragging = FALSE;
2052 xDisplay = XtDisplay(shellWidget);
2053 xScreen = DefaultScreen(xDisplay);
2054 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2056 gameInfo.variant = StringToVariant(appData.variant);
2057 InitPosition(FALSE);
2060 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2062 if (isdigit(appData.boardSize[0])) {
2063 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2064 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2065 &fontPxlSize, &smallLayout, &tinyLayout);
2067 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2068 programName, appData.boardSize);
2072 /* Find some defaults; use the nearest known size */
2073 SizeDefaults *szd, *nearest;
2074 int distance = 99999;
2075 nearest = szd = sizeDefaults;
2076 while (szd->name != NULL) {
2077 if (abs(szd->squareSize - squareSize) < distance) {
2079 distance = abs(szd->squareSize - squareSize);
2080 if (distance == 0) break;
2084 if (i < 2) lineGap = nearest->lineGap;
2085 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2086 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2087 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2088 if (i < 6) smallLayout = nearest->smallLayout;
2089 if (i < 7) tinyLayout = nearest->tinyLayout;
2092 SizeDefaults *szd = sizeDefaults;
2093 if (*appData.boardSize == NULLCHAR) {
2094 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2095 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2098 if (szd->name == NULL) szd--;
2099 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2101 while (szd->name != NULL &&
2102 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2103 if (szd->name == NULL) {
2104 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2105 programName, appData.boardSize);
2109 squareSize = szd->squareSize;
2110 lineGap = szd->lineGap;
2111 clockFontPxlSize = szd->clockFontPxlSize;
2112 coordFontPxlSize = szd->coordFontPxlSize;
2113 fontPxlSize = szd->fontPxlSize;
2114 smallLayout = szd->smallLayout;
2115 tinyLayout = szd->tinyLayout;
2116 // [HGM] font: use defaults from settings file if available and not overruled
2118 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2119 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2120 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2121 appData.font = fontTable[MESSAGE_FONT][squareSize];
2122 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2123 appData.coordFont = fontTable[COORD_FONT][squareSize];
2125 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2126 if (strlen(appData.pixmapDirectory) > 0) {
2127 p = ExpandPathName(appData.pixmapDirectory);
2129 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2130 appData.pixmapDirectory);
2133 if (appData.debugMode) {
2134 fprintf(stderr, _("\
2135 XBoard square size (hint): %d\n\
2136 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2138 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2139 if (appData.debugMode) {
2140 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2143 defaultLineGap = lineGap;
2144 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2146 /* [HR] height treated separately (hacked) */
2147 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2148 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2149 if (appData.showJail == 1) {
2150 /* Jail on top and bottom */
2151 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2152 XtSetArg(boardArgs[2], XtNheight,
2153 boardHeight + 2*(lineGap + squareSize));
2154 } else if (appData.showJail == 2) {
2156 XtSetArg(boardArgs[1], XtNwidth,
2157 boardWidth + 2*(lineGap + squareSize));
2158 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2161 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2162 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2166 * Determine what fonts to use.
2169 appData.font = InsertPxlSize(appData.font, fontPxlSize);
2170 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2171 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2172 fontSet = CreateFontSet(appData.font);
2173 clockFontSet = CreateFontSet(appData.clockFont);
2175 /* For the coordFont, use the 0th font of the fontset. */
2176 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2177 XFontStruct **font_struct_list;
2178 XFontSetExtents *fontSize;
2179 char **font_name_list;
2180 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2181 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2182 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2183 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
2184 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
2187 appData.font = FindFont(appData.font, fontPxlSize);
2188 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2189 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2190 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2191 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2192 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2193 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2195 countFontID = coordFontID; // [HGM] holdings
2196 countFontStruct = coordFontStruct;
2198 xdb = XtDatabase(xDisplay);
2200 XrmPutLineResource(&xdb, "*international: True");
2201 vTo.size = sizeof(XFontSet);
2202 vTo.addr = (XtPointer) &fontSet;
2203 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2205 XrmPutStringResource(&xdb, "*font", appData.font);
2209 * Detect if there are not enough colors available and adapt.
2211 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2212 appData.monoMode = True;
2215 forceMono = MakeColors();
2218 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2220 appData.monoMode = True;
2223 if (appData.lowTimeWarning && !appData.monoMode) {
2224 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2225 vFrom.size = strlen(appData.lowTimeWarningColor);
2226 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2227 if (vTo.addr == NULL)
2228 appData.monoMode = True;
2230 lowTimeWarningColor = *(Pixel *) vTo.addr;
2233 if (appData.monoMode && appData.debugMode) {
2234 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2235 (unsigned long) XWhitePixel(xDisplay, xScreen),
2236 (unsigned long) XBlackPixel(xDisplay, xScreen));
2239 ParseIcsTextColors();
2240 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2241 textColors[ColorNone].attr = 0;
2243 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2249 layoutName = "tinyLayout";
2250 } else if (smallLayout) {
2251 layoutName = "smallLayout";
2253 layoutName = "normalLayout";
2255 /* Outer layoutWidget is there only to provide a name for use in
2256 resources that depend on the layout style */
2258 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2259 layoutArgs, XtNumber(layoutArgs));
2261 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2262 formArgs, XtNumber(formArgs));
2263 XtSetArg(args[0], XtNdefaultDistance, &sep);
2264 XtGetValues(formWidget, args, 1);
2267 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar, boardWidth);
2268 XtSetArg(args[0], XtNtop, XtChainTop);
2269 XtSetArg(args[1], XtNbottom, XtChainTop);
2270 XtSetArg(args[2], XtNright, XtChainLeft);
2271 XtSetValues(menuBarWidget, args, 3);
2273 widgetList[j++] = whiteTimerWidget =
2274 XtCreateWidget("whiteTime", labelWidgetClass,
2275 formWidget, timerArgs, XtNumber(timerArgs));
2277 XtSetArg(args[0], XtNfontSet, clockFontSet);
2279 XtSetArg(args[0], XtNfont, clockFontStruct);
2281 XtSetArg(args[1], XtNtop, XtChainTop);
2282 XtSetArg(args[2], XtNbottom, XtChainTop);
2283 XtSetValues(whiteTimerWidget, args, 3);
2285 widgetList[j++] = blackTimerWidget =
2286 XtCreateWidget("blackTime", labelWidgetClass,
2287 formWidget, timerArgs, XtNumber(timerArgs));
2289 XtSetArg(args[0], XtNfontSet, clockFontSet);
2291 XtSetArg(args[0], XtNfont, clockFontStruct);
2293 XtSetArg(args[1], XtNtop, XtChainTop);
2294 XtSetArg(args[2], XtNbottom, XtChainTop);
2295 XtSetValues(blackTimerWidget, args, 3);
2297 if (appData.titleInWindow) {
2298 widgetList[j++] = titleWidget =
2299 XtCreateWidget("title", labelWidgetClass, formWidget,
2300 titleArgs, XtNumber(titleArgs));
2301 XtSetArg(args[0], XtNtop, XtChainTop);
2302 XtSetArg(args[1], XtNbottom, XtChainTop);
2303 XtSetValues(titleWidget, args, 2);
2306 if (appData.showButtonBar) {
2307 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2308 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2309 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2310 XtSetArg(args[2], XtNtop, XtChainTop);
2311 XtSetArg(args[3], XtNbottom, XtChainTop);
2312 XtSetValues(buttonBarWidget, args, 4);
2315 widgetList[j++] = messageWidget =
2316 XtCreateWidget("message", labelWidgetClass, formWidget,
2317 messageArgs, XtNumber(messageArgs));
2318 XtSetArg(args[0], XtNtop, XtChainTop);
2319 XtSetArg(args[1], XtNbottom, XtChainTop);
2320 XtSetValues(messageWidget, args, 2);
2322 widgetList[j++] = boardWidget =
2323 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2324 XtNumber(boardArgs));
2326 XtManageChildren(widgetList, j);
2328 timerWidth = (boardWidth - sep) / 2;
2329 XtSetArg(args[0], XtNwidth, timerWidth);
2330 XtSetValues(whiteTimerWidget, args, 1);
2331 XtSetValues(blackTimerWidget, args, 1);
2333 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2334 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2335 XtGetValues(whiteTimerWidget, args, 2);
2337 if (appData.showButtonBar) {
2338 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2339 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2340 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2344 * formWidget uses these constraints but they are stored
2348 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2349 XtSetValues(menuBarWidget, args, i);
2350 if (appData.titleInWindow) {
2353 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2354 XtSetValues(whiteTimerWidget, args, i);
2356 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2357 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2358 XtSetValues(blackTimerWidget, args, i);
2360 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2361 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2362 XtSetValues(titleWidget, args, i);
2364 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2365 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2366 XtSetValues(messageWidget, args, i);
2367 if (appData.showButtonBar) {
2369 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2370 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2371 XtSetValues(buttonBarWidget, args, i);
2375 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2376 XtSetValues(whiteTimerWidget, args, i);
2378 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2379 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2380 XtSetValues(blackTimerWidget, args, i);
2382 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2383 XtSetValues(titleWidget, args, i);
2385 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2386 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2387 XtSetValues(messageWidget, args, i);
2388 if (appData.showButtonBar) {
2390 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2391 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2392 XtSetValues(buttonBarWidget, args, i);
2397 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2398 XtSetValues(whiteTimerWidget, args, i);
2400 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2401 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2402 XtSetValues(blackTimerWidget, args, i);
2404 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2405 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2406 XtSetValues(messageWidget, args, i);
2407 if (appData.showButtonBar) {
2409 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2410 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2411 XtSetValues(buttonBarWidget, args, i);
2415 XtSetArg(args[0], XtNfromVert, messageWidget);
2416 XtSetArg(args[1], XtNtop, XtChainTop);
2417 XtSetArg(args[2], XtNbottom, XtChainBottom);
2418 XtSetArg(args[3], XtNleft, XtChainLeft);
2419 XtSetArg(args[4], XtNright, XtChainRight);
2420 XtSetValues(boardWidget, args, 5);
2422 XtRealizeWidget(shellWidget);
2425 XtSetArg(args[0], XtNx, wpMain.x);
2426 XtSetArg(args[1], XtNy, wpMain.y);
2427 XtSetValues(shellWidget, args, 2);
2431 * Correct the width of the message and title widgets.
2432 * It is not known why some systems need the extra fudge term.
2433 * The value "2" is probably larger than needed.
2435 XawFormDoLayout(formWidget, False);
2437 #define WIDTH_FUDGE 2
2439 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2440 XtSetArg(args[i], XtNheight, &h); i++;
2441 XtGetValues(messageWidget, args, i);
2442 if (appData.showButtonBar) {
2444 XtSetArg(args[i], XtNwidth, &w); i++;
2445 XtGetValues(buttonBarWidget, args, i);
2446 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2448 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2451 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2452 if (gres != XtGeometryYes && appData.debugMode) {
2453 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2454 programName, gres, w, h, wr, hr);
2457 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2458 /* The size used for the child widget in layout lags one resize behind
2459 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2461 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2462 if (gres != XtGeometryYes && appData.debugMode) {
2463 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2464 programName, gres, w, h, wr, hr);
2467 if(!textHeight) textHeight = hr; // [HGM] if !NLS textHeight is still undefined, and we grab it from here
2468 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2469 XtSetArg(args[1], XtNright, XtChainRight);
2470 XtSetValues(messageWidget, args, 2);
2472 if (appData.titleInWindow) {
2474 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2475 XtSetArg(args[i], XtNheight, &h); i++;
2476 XtGetValues(titleWidget, args, i);
2478 w = boardWidth - 2*bor;
2480 XtSetArg(args[0], XtNwidth, &w);
2481 XtGetValues(menuBarWidget, args, 1);
2482 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2485 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2486 if (gres != XtGeometryYes && appData.debugMode) {
2488 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2489 programName, gres, w, h, wr, hr);
2492 XawFormDoLayout(formWidget, True);
2494 xBoardWindow = XtWindow(boardWidget);
2496 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2497 // not need to go into InitDrawingSizes().
2501 * Create X checkmark bitmap and initialize option menu checks.
2503 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2504 checkmark_bits, checkmark_width, checkmark_height);
2505 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2506 #ifndef OPTIONSDIALOG
2507 if (appData.alwaysPromoteToQueen) {
2508 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2511 if (appData.animateDragging) {
2512 XtSetValues(XtNameToWidget(menuBarWidget,
2513 "menuOptions.Animate Dragging"),
2516 if (appData.animate) {
2517 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2520 if (appData.autoCallFlag) {
2521 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2524 if (appData.autoFlipView) {
2525 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2528 if (appData.blindfold) {
2529 XtSetValues(XtNameToWidget(menuBarWidget,
2530 "menuOptions.Blindfold"), args, 1);
2532 if (appData.flashCount > 0) {
2533 XtSetValues(XtNameToWidget(menuBarWidget,
2534 "menuOptions.Flash Moves"),
2538 if (appData.highlightDragging) {
2539 XtSetValues(XtNameToWidget(menuBarWidget,
2540 "menuOptions.Highlight Dragging"),
2544 if (appData.highlightLastMove) {
2545 XtSetValues(XtNameToWidget(menuBarWidget,
2546 "menuOptions.Highlight Last Move"),
2549 if (appData.highlightMoveWithArrow) {
2550 XtSetValues(XtNameToWidget(menuBarWidget,
2551 "menuOptions.Arrow"),
2554 // if (appData.icsAlarm) {
2555 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2558 if (appData.ringBellAfterMoves) {
2559 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2562 if (appData.oneClick) {
2563 XtSetValues(XtNameToWidget(menuBarWidget,
2564 "menuOptions.OneClick"), args, 1);
2566 if (appData.periodicUpdates) {
2567 XtSetValues(XtNameToWidget(menuBarWidget,
2568 "menuOptions.Periodic Updates"), args, 1);
2570 if (appData.ponderNextMove) {
2571 XtSetValues(XtNameToWidget(menuBarWidget,
2572 "menuOptions.Ponder Next Move"), args, 1);
2574 if (appData.popupExitMessage) {
2575 XtSetValues(XtNameToWidget(menuBarWidget,
2576 "menuOptions.Popup Exit Message"), args, 1);
2578 if (appData.popupMoveErrors) {
2579 XtSetValues(XtNameToWidget(menuBarWidget,
2580 "menuOptions.Popup Move Errors"), args, 1);
2582 // if (appData.premove) {
2583 // XtSetValues(XtNameToWidget(menuBarWidget,
2584 // "menuOptions.Premove"), args, 1);
2586 if (appData.showCoords) {
2587 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2590 if (appData.hideThinkingFromHuman) {
2591 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2594 if (appData.testLegality) {
2595 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2599 if (saveSettingsOnExit) {
2600 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2607 ReadBitmap(&wIconPixmap, "icon_white.bm",
2608 icon_white_bits, icon_white_width, icon_white_height);
2609 ReadBitmap(&bIconPixmap, "icon_black.bm",
2610 icon_black_bits, icon_black_width, icon_black_height);
2611 iconPixmap = wIconPixmap;
2613 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2614 XtSetValues(shellWidget, args, i);
2617 * Create a cursor for the board widget.
2619 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2620 XChangeWindowAttributes(xDisplay, xBoardWindow,
2621 CWCursor, &window_attributes);
2624 * Inhibit shell resizing.
2626 shellArgs[0].value = (XtArgVal) &w;
2627 shellArgs[1].value = (XtArgVal) &h;
2628 XtGetValues(shellWidget, shellArgs, 2);
2629 shellArgs[4].value = shellArgs[2].value = w;
2630 shellArgs[5].value = shellArgs[3].value = h;
2631 XtSetValues(shellWidget, &shellArgs[2], 4);
2632 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2633 marginH = h - boardHeight;
2635 CatchDeleteWindow(shellWidget, "QuitProc");
2643 if (appData.animate || appData.animateDragging)
2646 XtAugmentTranslations(formWidget,
2647 XtParseTranslationTable(globalTranslations));
2648 XtAugmentTranslations(boardWidget,
2649 XtParseTranslationTable(boardTranslations));
2650 XtAugmentTranslations(whiteTimerWidget,
2651 XtParseTranslationTable(whiteTranslations));
2652 XtAugmentTranslations(blackTimerWidget,
2653 XtParseTranslationTable(blackTranslations));
2655 /* Why is the following needed on some versions of X instead
2656 * of a translation? */
2657 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2658 (XtEventHandler) EventProc, NULL);
2660 XtAddEventHandler(formWidget, KeyPressMask, False,
2661 (XtEventHandler) MoveTypeInProc, NULL);
2663 /* [AS] Restore layout */
2664 if( wpMoveHistory.visible ) {
2668 if( wpEvalGraph.visible )
2673 if( wpEngineOutput.visible ) {
2674 EngineOutputPopUp();
2679 if (errorExitStatus == -1) {
2680 if (appData.icsActive) {
2681 /* We now wait until we see "login:" from the ICS before
2682 sending the logon script (problems with timestamp otherwise) */
2683 /*ICSInitScript();*/
2684 if (appData.icsInputBox) ICSInputBoxPopUp();
2688 signal(SIGWINCH, TermSizeSigHandler);
2690 signal(SIGINT, IntSigHandler);
2691 signal(SIGTERM, IntSigHandler);
2692 if (*appData.cmailGameName != NULLCHAR) {
2693 signal(SIGUSR1, CmailSigHandler);
2696 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2698 // XtSetKeyboardFocus(shellWidget, formWidget);
2699 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2701 XtAppMainLoop(appContext);
2702 if (appData.debugMode) fclose(debugFP); // [DM] debug
2706 static Boolean noEcho;
2711 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2712 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2714 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2715 unlink(gameCopyFilename);
2716 unlink(gamePasteFilename);
2717 if(noEcho) EchoOn();
2721 TermSizeSigHandler (int sig)
2727 IntSigHandler (int sig)
2733 CmailSigHandler (int sig)
2738 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2740 /* Activate call-back function CmailSigHandlerCallBack() */
2741 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2743 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2747 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
2750 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2752 /**** end signal code ****/
2758 /* try to open the icsLogon script, either in the location given
2759 * or in the users HOME directory
2766 f = fopen(appData.icsLogon, "r");
2769 homedir = getenv("HOME");
2770 if (homedir != NULL)
2772 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2773 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2774 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2775 f = fopen(buf, "r");
2780 ProcessICSInitScript(f);
2782 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2801 GreyRevert (Boolean grey)
2804 if (!menuBarWidget) return;
2805 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2807 DisplayError("menuEdit.Revert", 0);
2809 XtSetSensitive(w, !grey);
2811 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2813 DisplayError("menuEdit.Annotate", 0);
2815 XtSetSensitive(w, !grey);
2820 SetMenuEnables (Enables *enab)
2823 if (!menuBarWidget) return;
2824 while (enab->name != NULL) {
2825 w = XtNameToWidget(menuBarWidget, enab->name);
2827 DisplayError(enab->name, 0);
2829 XtSetSensitive(w, enab->value);
2835 Enables icsEnables[] = {
2836 { "menuFile.Mail Move", False },
2837 { "menuFile.Reload CMail Message", False },
2838 { "menuMode.Machine Black", False },
2839 { "menuMode.Machine White", False },
2840 { "menuMode.Analysis Mode", False },
2841 { "menuMode.Analyze File", False },
2842 { "menuMode.Two Machines", False },
2843 { "menuMode.Machine Match", False },
2845 { "menuEngine.Hint", False },
2846 { "menuEngine.Book", False },
2847 { "menuEngine.Move Now", False },
2848 #ifndef OPTIONSDIALOG
2849 { "menuOptions.Periodic Updates", False },
2850 { "menuOptions.Hide Thinking", False },
2851 { "menuOptions.Ponder Next Move", False },
2854 { "menuEngine.Engine #1 Settings", False },
2855 { "menuEngine.Engine #2 Settings", False },
2856 { "menuEngine.Load Engine", False },
2857 { "menuEdit.Annotate", False },
2858 { "menuOptions.Match", False },
2862 Enables ncpEnables[] = {
2863 { "menuFile.Mail Move", False },
2864 { "menuFile.Reload CMail Message", False },
2865 { "menuMode.Machine White", False },
2866 { "menuMode.Machine Black", False },
2867 { "menuMode.Analysis Mode", False },
2868 { "menuMode.Analyze File", False },
2869 { "menuMode.Two Machines", False },
2870 { "menuMode.Machine Match", False },
2871 { "menuMode.ICS Client", False },
2872 { "menuView.ICStex", False },
2873 { "menuView.ICS Input Box", False },
2874 { "Action", False },
2875 { "menuEdit.Revert", False },
2876 { "menuEdit.Annotate", False },
2877 { "menuEngine.Engine #1 Settings", False },
2878 { "menuEngine.Engine #2 Settings", False },
2879 { "menuEngine.Move Now", False },
2880 { "menuEngine.Retract Move", False },
2881 { "menuOptions.ICS", False },
2882 #ifndef OPTIONSDIALOG
2883 { "menuOptions.Auto Flag", False },
2884 { "menuOptions.Auto Flip View", False },
2885 // { "menuOptions.ICS Alarm", False },
2886 { "menuOptions.Move Sound", False },
2887 { "menuOptions.Hide Thinking", False },
2888 { "menuOptions.Periodic Updates", False },
2889 { "menuOptions.Ponder Next Move", False },
2891 { "menuEngine.Hint", False },
2892 { "menuEngine.Book", False },
2896 Enables gnuEnables[] = {
2897 { "menuMode.ICS Client", False },
2898 { "menuView.ICStex", False },
2899 { "menuView.ICS Input Box", False },
2900 { "menuAction.Accept", False },
2901 { "menuAction.Decline", False },
2902 { "menuAction.Rematch", False },
2903 { "menuAction.Adjourn", False },
2904 { "menuAction.Stop Examining", False },
2905 { "menuAction.Stop Observing", False },
2906 { "menuAction.Upload to Examine", False },
2907 { "menuEdit.Revert", False },
2908 { "menuEdit.Annotate", False },
2909 { "menuOptions.ICS", False },
2911 /* The next two options rely on SetCmailMode being called *after* */
2912 /* SetGNUMode so that when GNU is being used to give hints these */
2913 /* menu options are still available */
2915 { "menuFile.Mail Move", False },
2916 { "menuFile.Reload CMail Message", False },
2917 // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2918 { "menuMode.Machine White", True },
2919 { "menuMode.Machine Black", True },
2920 { "menuMode.Analysis Mode", True },
2921 { "menuMode.Analyze File", True },
2922 { "menuMode.Two Machines", True },
2923 { "menuMode.Machine Match", True },
2924 { "menuEngine.Engine #1 Settings", True },
2925 { "menuEngine.Engine #2 Settings", True },
2926 { "menuEngine.Hint", True },
2927 { "menuEngine.Book", True },
2928 { "menuEngine.Move Now", True },
2929 { "menuEngine.Retract Move", True },
2934 Enables cmailEnables[] = {
2936 { "menuAction.Call Flag", False },
2937 { "menuAction.Draw", True },
2938 { "menuAction.Adjourn", False },
2939 { "menuAction.Abort", False },
2940 { "menuAction.Stop Observing", False },
2941 { "menuAction.Stop Examining", False },
2942 { "menuFile.Mail Move", True },
2943 { "menuFile.Reload CMail Message", True },
2947 Enables trainingOnEnables[] = {
2948 { "menuMode.Edit Comment", False },
2949 { "menuMode.Pause", False },
2950 { "menuEdit.Forward", False },
2951 { "menuEdit.Backward", False },
2952 { "menuEdit.Forward to End", False },
2953 { "menuEdit.Back to Start", False },
2954 { "menuEngine.Move Now", False },
2955 { "menuEdit.Truncate Game", False },
2959 Enables trainingOffEnables[] = {
2960 { "menuMode.Edit Comment", True },
2961 { "menuMode.Pause", True },
2962 { "menuEdit.Forward", True },
2963 { "menuEdit.Backward", True },
2964 { "menuEdit.Forward to End", True },
2965 { "menuEdit.Back to Start", True },
2966 { "menuEngine.Move Now", True },
2967 { "menuEdit.Truncate Game", True },
2971 Enables machineThinkingEnables[] = {
2972 { "menuFile.Load Game", False },
2973 // { "menuFile.Load Next Game", False },
2974 // { "menuFile.Load Previous Game", False },
2975 // { "menuFile.Reload Same Game", False },
2976 { "menuEdit.Paste Game", False },
2977 { "menuFile.Load Position", False },
2978 // { "menuFile.Load Next Position", False },
2979 // { "menuFile.Load Previous Position", False },
2980 // { "menuFile.Reload Same Position", False },
2981 { "menuEdit.Paste Position", False },
2982 { "menuMode.Machine White", False },
2983 { "menuMode.Machine Black", False },
2984 { "menuMode.Two Machines", False },
2985 // { "menuMode.Machine Match", False },
2986 { "menuEngine.Retract Move", False },
2990 Enables userThinkingEnables[] = {
2991 { "menuFile.Load Game", True },
2992 // { "menuFile.Load Next Game", True },
2993 // { "menuFile.Load Previous Game", True },
2994 // { "menuFile.Reload Same Game", True },
2995 { "menuEdit.Paste Game", True },
2996 { "menuFile.Load Position", True },
2997 // { "menuFile.Load Next Position", True },
2998 // { "menuFile.Load Previous Position", True },
2999 // { "menuFile.Reload Same Position", True },
3000 { "menuEdit.Paste Position", True },
3001 { "menuMode.Machine White", True },
3002 { "menuMode.Machine Black", True },
3003 { "menuMode.Two Machines", True },
3004 // { "menuMode.Machine Match", True },
3005 { "menuEngine.Retract Move", True },
3012 SetMenuEnables(icsEnables);
3015 if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3016 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3017 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3025 SetMenuEnables(ncpEnables);
3031 SetMenuEnables(gnuEnables);
3037 SetMenuEnables(cmailEnables);
3041 SetTrainingModeOn ()
3043 SetMenuEnables(trainingOnEnables);
3044 if (appData.showButtonBar) {
3045 XtSetSensitive(buttonBarWidget, False);
3051 SetTrainingModeOff ()
3053 SetMenuEnables(trainingOffEnables);
3054 if (appData.showButtonBar) {
3055 XtSetSensitive(buttonBarWidget, True);
3060 SetUserThinkingEnables ()
3062 if (appData.noChessProgram) return;
3063 SetMenuEnables(userThinkingEnables);
3067 SetMachineThinkingEnables ()
3069 if (appData.noChessProgram) return;
3070 SetMenuEnables(machineThinkingEnables);
3072 case MachinePlaysBlack:
3073 case MachinePlaysWhite:
3074 case TwoMachinesPlay:
3075 XtSetSensitive(XtNameToWidget(menuBarWidget,
3076 ModeToWidgetName(gameMode)), True);
3083 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3084 #define HISTORY_SIZE 64
3085 static char *history[HISTORY_SIZE];
3086 int histIn = 0, histP = 0;
3089 SaveInHistory (char *cmd)
3091 if (history[histIn] != NULL) {
3092 free(history[histIn]);
3093 history[histIn] = NULL;
3095 if (*cmd == NULLCHAR) return;
3096 history[histIn] = StrSave(cmd);
3097 histIn = (histIn + 1) % HISTORY_SIZE;
3098 if (history[histIn] != NULL) {
3099 free(history[histIn]);
3100 history[histIn] = NULL;
3106 PrevInHistory (char *cmd)
3109 if (histP == histIn) {
3110 if (history[histIn] != NULL) free(history[histIn]);
3111 history[histIn] = StrSave(cmd);
3113 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3114 if (newhp == histIn || history[newhp] == NULL) return NULL;
3116 return history[histP];
3122 if (histP == histIn) return NULL;
3123 histP = (histP + 1) % HISTORY_SIZE;
3124 return history[histP];
3126 // end of borrowed code
3128 #define Abs(n) ((n)<0 ? -(n) : (n))
3132 InsertPxlSize (char *pattern, int targetPxlSize)
3134 char *base_fnt_lst, strInt[12], *p, *q;
3135 int alternatives, i, len, strIntLen;
3138 * Replace the "*" (if present) in the pixel-size slot of each
3139 * alternative with the targetPxlSize.
3143 while ((p = strchr(p, ',')) != NULL) {
3147 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3148 strIntLen = strlen(strInt);
3149 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3153 while (alternatives--) {
3154 char *comma = strchr(p, ',');
3155 for (i=0; i<14; i++) {
3156 char *hyphen = strchr(p, '-');
3158 if (comma && hyphen > comma) break;
3159 len = hyphen + 1 - p;
3160 if (i == 7 && *p == '*' && len == 2) {
3162 memcpy(q, strInt, strIntLen);
3172 len = comma + 1 - p;
3179 return base_fnt_lst;
3183 CreateFontSet (char *base_fnt_lst)
3186 char **missing_list;
3190 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3191 &missing_list, &missing_count, &def_string);
3192 if (appData.debugMode) {
3194 XFontStruct **font_struct_list;
3195 char **font_name_list;
3196 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3198 fprintf(debugFP, " got list %s, locale %s\n",
3199 XBaseFontNameListOfFontSet(fntSet),
3200 XLocaleOfFontSet(fntSet));
3201 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3202 for (i = 0; i < count; i++) {
3203 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3206 for (i = 0; i < missing_count; i++) {
3207 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3210 if (fntSet == NULL) {
3211 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3216 #else // not ENABLE_NLS
3218 * Find a font that matches "pattern" that is as close as
3219 * possible to the targetPxlSize. Prefer fonts that are k
3220 * pixels smaller to fonts that are k pixels larger. The
3221 * pattern must be in the X Consortium standard format,
3222 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3223 * The return value should be freed with XtFree when no
3227 FindFont (char *pattern, int targetPxlSize)
3229 char **fonts, *p, *best, *scalable, *scalableTail;
3230 int i, j, nfonts, minerr, err, pxlSize;
3232 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3234 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3235 programName, pattern);
3242 for (i=0; i<nfonts; i++) {
3245 if (*p != '-') continue;
3247 if (*p == NULLCHAR) break;
3248 if (*p++ == '-') j++;
3250 if (j < 7) continue;
3253 scalable = fonts[i];
3256 err = pxlSize - targetPxlSize;
3257 if (Abs(err) < Abs(minerr) ||
3258 (minerr > 0 && err < 0 && -err == minerr)) {
3264 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3265 /* If the error is too big and there is a scalable font,
3266 use the scalable font. */
3267 int headlen = scalableTail - scalable;
3268 p = (char *) XtMalloc(strlen(scalable) + 10);
3269 while (isdigit(*scalableTail)) scalableTail++;
3270 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3272 p = (char *) XtMalloc(strlen(best) + 2);
3273 safeStrCpy(p, best, strlen(best)+1 );
3275 if (appData.debugMode) {
3276 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3277 pattern, targetPxlSize, p);
3279 XFreeFontNames(fonts);
3286 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3287 // must be called before all non-first callse to CreateGCs()
3288 XtReleaseGC(shellWidget, highlineGC);
3289 XtReleaseGC(shellWidget, lightSquareGC);
3290 XtReleaseGC(shellWidget, darkSquareGC);
3291 XtReleaseGC(shellWidget, lineGC);
3292 if (appData.monoMode) {
3293 if (DefaultDepth(xDisplay, xScreen) == 1) {
3294 XtReleaseGC(shellWidget, wbPieceGC);
3296 XtReleaseGC(shellWidget, bwPieceGC);
3299 XtReleaseGC(shellWidget, prelineGC);
3300 XtReleaseGC(shellWidget, jailSquareGC);
3301 XtReleaseGC(shellWidget, wdPieceGC);
3302 XtReleaseGC(shellWidget, wlPieceGC);
3303 XtReleaseGC(shellWidget, wjPieceGC);
3304 XtReleaseGC(shellWidget, bdPieceGC);
3305 XtReleaseGC(shellWidget, blPieceGC);
3306 XtReleaseGC(shellWidget, bjPieceGC);
3311 CreateGCs (int redo)
3313 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3314 | GCBackground | GCFunction | GCPlaneMask;
3315 XGCValues gc_values;
3318 gc_values.plane_mask = AllPlanes;
3319 gc_values.line_width = lineGap;
3320 gc_values.line_style = LineSolid;
3321 gc_values.function = GXcopy;
3324 DeleteGCs(); // called a second time; clean up old GCs first
3325 } else { // [HGM] grid and font GCs created on first call only
3326 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3327 gc_values.background = XWhitePixel(xDisplay, xScreen);
3328 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3329 XSetFont(xDisplay, coordGC, coordFontID);
3331 // [HGM] make font for holdings counts (white on black)
3332 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3333 gc_values.background = XBlackPixel(xDisplay, xScreen);
3334 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3335 XSetFont(xDisplay, countGC, countFontID);
3337 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3338 gc_values.background = XBlackPixel(xDisplay, xScreen);
3339 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3341 if (appData.monoMode) {
3342 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3343 gc_values.background = XWhitePixel(xDisplay, xScreen);
3344 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3346 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3347 gc_values.background = XBlackPixel(xDisplay, xScreen);
3348 lightSquareGC = wbPieceGC
3349 = XtGetGC(shellWidget, value_mask, &gc_values);
3351 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3352 gc_values.background = XWhitePixel(xDisplay, xScreen);
3353 darkSquareGC = bwPieceGC
3354 = XtGetGC(shellWidget, value_mask, &gc_values);
3356 if (DefaultDepth(xDisplay, xScreen) == 1) {
3357 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3358 gc_values.function = GXcopyInverted;
3359 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3360 gc_values.function = GXcopy;
3361 if (XBlackPixel(xDisplay, xScreen) == 1) {
3362 bwPieceGC = darkSquareGC;
3363 wbPieceGC = copyInvertedGC;
3365 bwPieceGC = copyInvertedGC;
3366 wbPieceGC = lightSquareGC;
3370 gc_values.foreground = highlightSquareColor;
3371 gc_values.background = highlightSquareColor;
3372 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3374 gc_values.foreground = premoveHighlightColor;
3375 gc_values.background = premoveHighlightColor;
3376 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3378 gc_values.foreground = lightSquareColor;
3379 gc_values.background = darkSquareColor;
3380 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3382 gc_values.foreground = darkSquareColor;
3383 gc_values.background = lightSquareColor;
3384 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3386 gc_values.foreground = jailSquareColor;
3387 gc_values.background = jailSquareColor;
3388 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3390 gc_values.foreground = whitePieceColor;
3391 gc_values.background = darkSquareColor;
3392 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3394 gc_values.foreground = whitePieceColor;
3395 gc_values.background = lightSquareColor;
3396 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3398 gc_values.foreground = whitePieceColor;
3399 gc_values.background = jailSquareColor;
3400 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3402 gc_values.foreground = blackPieceColor;
3403 gc_values.background = darkSquareColor;
3404 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3406 gc_values.foreground = blackPieceColor;
3407 gc_values.background = lightSquareColor;
3408 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3410 gc_values.foreground = blackPieceColor;
3411 gc_values.background = jailSquareColor;
3412 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3417 loadXIM (XImage *xim, XImage *xmask, char *filename, Pixmap *dest, Pixmap *mask)
3425 fp = fopen(filename, "rb");
3427 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3434 for (y=0; y<h; ++y) {
3435 for (x=0; x<h; ++x) {
3440 XPutPixel(xim, x, y, blackPieceColor);
3442 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3445 XPutPixel(xim, x, y, darkSquareColor);
3447 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3450 XPutPixel(xim, x, y, whitePieceColor);
3452 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3455 XPutPixel(xim, x, y, lightSquareColor);
3457 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3465 /* create Pixmap of piece */
3466 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3468 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3471 /* create Pixmap of clipmask
3472 Note: We assume the white/black pieces have the same
3473 outline, so we make only 6 masks. This is okay
3474 since the XPM clipmask routines do the same. */
3476 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3478 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3481 /* now create the 1-bit version */
3482 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3485 values.foreground = 1;
3486 values.background = 0;
3488 /* Don't use XtGetGC, not read only */
3489 maskGC = XCreateGC(xDisplay, *mask,
3490 GCForeground | GCBackground, &values);
3491 XCopyPlane(xDisplay, temp, *mask, maskGC,
3492 0, 0, squareSize, squareSize, 0, 0, 1);
3493 XFreePixmap(xDisplay, temp);
3498 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3506 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3511 /* The XSynchronize calls were copied from CreatePieces.
3512 Not sure if needed, but can't hurt */
3513 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3516 /* temp needed by loadXIM() */
3517 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3518 0, 0, ss, ss, AllPlanes, XYPixmap);
3520 if (strlen(appData.pixmapDirectory) == 0) {
3524 if (appData.monoMode) {
3525 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3529 fprintf(stderr, _("\nLoading XIMs...\n"));
3531 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3532 fprintf(stderr, "%d", piece+1);
3533 for (kind=0; kind<4; kind++) {
3534 fprintf(stderr, ".");
3535 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3536 ExpandPathName(appData.pixmapDirectory),
3537 piece <= (int) WhiteKing ? "" : "w",
3538 pieceBitmapNames[piece],
3540 ximPieceBitmap[kind][piece] =
3541 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3542 0, 0, ss, ss, AllPlanes, XYPixmap);
3543 if (appData.debugMode)
3544 fprintf(stderr, _("(File:%s:) "), buf);
3545 loadXIM(ximPieceBitmap[kind][piece],
3547 &(xpmPieceBitmap2[kind][piece]),
3548 &(ximMaskPm2[piece]));
3549 if(piece <= (int)WhiteKing)
3550 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3552 fprintf(stderr," ");
3554 /* Load light and dark squares */
3555 /* If the LSQ and DSQ pieces don't exist, we will
3556 draw them with solid squares. */
3557 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3558 if (access(buf, 0) != 0) {
3562 fprintf(stderr, _("light square "));
3564 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3565 0, 0, ss, ss, AllPlanes, XYPixmap);
3566 if (appData.debugMode)
3567 fprintf(stderr, _("(File:%s:) "), buf);
3569 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3570 fprintf(stderr, _("dark square "));
3571 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3572 ExpandPathName(appData.pixmapDirectory), ss);
3573 if (appData.debugMode)
3574 fprintf(stderr, _("(File:%s:) "), buf);
3576 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3577 0, 0, ss, ss, AllPlanes, XYPixmap);
3578 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3579 xpmJailSquare = xpmLightSquare;
3581 fprintf(stderr, _("Done.\n"));
3583 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3586 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3590 CreateXPMBoard (char *s, int kind)
3594 if(!appData.useBitmaps || s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3595 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3596 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3602 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3603 // thisroutine has to be called t free the old piece pixmaps
3605 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3606 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3608 XFreePixmap(xDisplay, xpmLightSquare);
3609 XFreePixmap(xDisplay, xpmDarkSquare);
3618 u_int ss = squareSize;
3620 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3621 XpmColorSymbol symbols[4];
3622 static int redo = False;
3624 if(redo) FreeXPMPieces(); else redo = 1;
3626 /* The XSynchronize calls were copied from CreatePieces.
3627 Not sure if needed, but can't hurt */
3628 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3630 /* Setup translations so piece colors match square colors */
3631 symbols[0].name = "light_piece";
3632 symbols[0].value = appData.whitePieceColor;
3633 symbols[1].name = "dark_piece";
3634 symbols[1].value = appData.blackPieceColor;
3635 symbols[2].name = "light_square";
3636 symbols[2].value = appData.lightSquareColor;
3637 symbols[3].name = "dark_square";
3638 symbols[3].value = appData.darkSquareColor;
3640 attr.valuemask = XpmColorSymbols;
3641 attr.colorsymbols = symbols;
3642 attr.numsymbols = 4;
3644 if (appData.monoMode) {
3645 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3649 if (strlen(appData.pixmapDirectory) == 0) {
3650 XpmPieces* pieces = builtInXpms;
3653 while (pieces->size != squareSize && pieces->size) pieces++;
3654 if (!pieces->size) {
3655 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3658 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3659 for (kind=0; kind<4; kind++) {
3661 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3662 pieces->xpm[piece][kind],
3663 &(xpmPieceBitmap2[kind][piece]),
3664 NULL, &attr)) != 0) {
3665 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3669 if(piece <= (int) WhiteKing)
3670 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3674 xpmJailSquare = xpmLightSquare;
3678 fprintf(stderr, _("\nLoading XPMs...\n"));
3681 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3682 fprintf(stderr, "%d ", piece+1);
3683 for (kind=0; kind<4; kind++) {
3684 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3685 ExpandPathName(appData.pixmapDirectory),
3686 piece > (int) WhiteKing ? "w" : "",
3687 pieceBitmapNames[piece],
3689 if (appData.debugMode) {
3690 fprintf(stderr, _("(File:%s:) "), buf);
3692 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3693 &(xpmPieceBitmap2[kind][piece]),
3694 NULL, &attr)) != 0) {
3695 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3696 // [HGM] missing: read of unorthodox piece failed; substitute King.
3697 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3698 ExpandPathName(appData.pixmapDirectory),
3700 if (appData.debugMode) {
3701 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3703 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3704 &(xpmPieceBitmap2[kind][piece]),
3708 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3713 if(piece <= (int) WhiteKing)
3714 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3717 /* Load light and dark squares */
3718 /* If the LSQ and DSQ pieces don't exist, we will
3719 draw them with solid squares. */
3720 fprintf(stderr, _("light square "));
3721 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3722 if (access(buf, 0) != 0) {
3726 if (appData.debugMode)
3727 fprintf(stderr, _("(File:%s:) "), buf);
3729 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3730 &xpmLightSquare, NULL, &attr)) != 0) {
3731 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3734 fprintf(stderr, _("dark square "));
3735 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3736 ExpandPathName(appData.pixmapDirectory), ss);
3737 if (appData.debugMode) {
3738 fprintf(stderr, _("(File:%s:) "), buf);
3740 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3741 &xpmDarkSquare, NULL, &attr)) != 0) {
3742 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3746 xpmJailSquare = xpmLightSquare;
3747 fprintf(stderr, _("Done.\n"));
3749 oldVariant = -1; // kludge to force re-makig of animation masks
3750 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3753 #endif /* HAVE_LIBXPM */
3756 /* No built-in bitmaps */
3761 u_int ss = squareSize;
3763 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3766 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3767 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3768 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3769 pieceBitmapNames[piece],
3770 ss, kind == SOLID ? 's' : 'o');
3771 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3772 if(piece <= (int)WhiteKing)
3773 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3777 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3781 /* With built-in bitmaps */
3785 BuiltInBits* bib = builtInBits;
3788 u_int ss = squareSize;
3790 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3793 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3795 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3796 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3797 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3798 pieceBitmapNames[piece],
3799 ss, kind == SOLID ? 's' : 'o');
3800 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3801 bib->bits[kind][piece], ss, ss);
3802 if(piece <= (int)WhiteKing)
3803 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3807 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3813 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
3818 char msg[MSG_SIZ], fullname[MSG_SIZ];
3820 if (*appData.bitmapDirectory != NULLCHAR) {
3821 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3822 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3823 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3824 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3825 &w, &h, pm, &x_hot, &y_hot);
3826 fprintf(stderr, "load %s\n", name);
3827 if (errcode != BitmapSuccess) {
3829 case BitmapOpenFailed:
3830 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3832 case BitmapFileInvalid:
3833 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3835 case BitmapNoMemory:
3836 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3840 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3844 fprintf(stderr, _("%s: %s...using built-in\n"),
3846 } else if (w != wreq || h != hreq) {
3848 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3849 programName, fullname, w, h, wreq, hreq);
3855 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3865 if (lineGap == 0) return;
3867 /* [HR] Split this into 2 loops for non-square boards. */
3869 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3870 gridSegments[i].x1 = 0;
3871 gridSegments[i].x2 =
3872 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3873 gridSegments[i].y1 = gridSegments[i].y2
3874 = lineGap / 2 + (i * (squareSize + lineGap));
3877 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3878 gridSegments[j + i].y1 = 0;
3879 gridSegments[j + i].y2 =
3880 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3881 gridSegments[j + i].x1 = gridSegments[j + i].x2
3882 = lineGap / 2 + (j * (squareSize + lineGap));
3887 MenuBarSelect (Widget w, caddr_t addr, caddr_t index)
3889 XtActionProc proc = (XtActionProc) addr;
3891 (proc)(NULL, NULL, NULL, NULL);
3895 CreateMenuBarPopup (Widget parent, String name, Menu *mb)
3902 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3905 XtSetArg(args[j], XtNleftMargin, 20); j++;
3906 XtSetArg(args[j], XtNrightMargin, 20); j++;
3908 while (mi->string != NULL) {
3909 if (strcmp(mi->string, "----") == 0) {
3910 entry = XtCreateManagedWidget(_(mi->string), smeLineObjectClass,
3913 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3914 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3916 XtAddCallback(entry, XtNcallback,
3917 (XtCallbackProc) MenuBarSelect,
3918 (caddr_t) mi->proc);
3925 CreateMenuBar (Menu *mb, int boardWidth)
3927 int i, j, nr = 0, wtot = 0, widths[10];
3930 char menuName[MSG_SIZ];
3935 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3936 XtSetArg(args[j], XtNvSpace, 0); j++;
3937 XtSetArg(args[j], XtNborderWidth, 0); j++;
3938 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3939 formWidget, args, j);
3941 while (mb->name != NULL) {
3942 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3943 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3945 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3946 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3947 XtSetArg(args[j], XtNborderWidth, 0); j++;
3948 mb->subMenu = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3950 CreateMenuBarPopup(menuBar, menuName, mb);
3952 XtSetArg(args[j], XtNwidth, &w); j++;
3953 XtGetValues(mb->subMenu, args, j);
3954 wtot += mb->textWidth = widths[nr++] = w;
3957 while(wtot > boardWidth - 40) {
3959 for(i=0; i<nr; i++) if(widths[i] > wmax) wmax = widths[imax=i];
3963 for(i=0; i<nr; i++) if(widths[i] != ma[i].textWidth) {
3965 XtSetArg(args[j], XtNwidth, widths[i]); j++;
3966 XtSetValues(ma[i].subMenu, args, j);
3972 CreateButtonBar (MenuItem *mi)
3975 Widget button, buttonBar;
3979 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3981 XtSetArg(args[j], XtNhSpace, 0); j++;
3983 XtSetArg(args[j], XtNborderWidth, 0); j++;
3984 XtSetArg(args[j], XtNvSpace, 0); j++;
3985 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3986 formWidget, args, j);
3988 while (mi->string != NULL) {
3991 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3992 XtSetArg(args[j], XtNborderWidth, 0); j++;
3994 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3995 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3996 buttonBar, args, j);
3997 XtAddCallback(button, XtNcallback,
3998 (XtCallbackProc) MenuBarSelect,
3999 (caddr_t) mi->proc);
4006 CreatePieceMenu (char *name, int color)
4011 ChessSquare selection;
4013 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
4014 boardWidget, args, 0);
4016 for (i = 0; i < PIECE_MENU_SIZE; i++) {
4017 String item = pieceMenuStrings[color][i];
4019 if (strcmp(item, "----") == 0) {
4020 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4023 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4024 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4026 selection = pieceMenuTranslation[color][i];
4027 XtAddCallback(entry, XtNcallback,
4028 (XtCallbackProc) PieceMenuSelect,
4029 (caddr_t) selection);
4030 if (selection == WhitePawn || selection == BlackPawn) {
4031 XtSetArg(args[0], XtNpopupOnEntry, entry);
4032 XtSetValues(menu, args, 1);
4045 ChessSquare selection;
4047 whitePieceMenu = CreatePieceMenu("menuW", 0);
4048 blackPieceMenu = CreatePieceMenu("menuB", 1);
4050 XtRegisterGrabAction(PieceMenuPopup, True,
4051 (unsigned)(ButtonPressMask|ButtonReleaseMask),
4052 GrabModeAsync, GrabModeAsync);
4054 XtSetArg(args[0], XtNlabel, _("Drop"));
4055 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
4056 boardWidget, args, 1);
4057 for (i = 0; i < DROP_MENU_SIZE; i++) {
4058 String item = dropMenuStrings[i];
4060 if (strcmp(item, "----") == 0) {
4061 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4064 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4065 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4067 selection = dropMenuTranslation[i];
4068 XtAddCallback(entry, XtNcallback,
4069 (XtCallbackProc) DropMenuSelect,
4070 (caddr_t) selection);
4084 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
4085 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
4086 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
4087 dmEnables[i].piece);
4088 XtSetSensitive(entry, p != NULL || !appData.testLegality
4089 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
4090 && !appData.icsActive));
4092 while (p && *p++ == dmEnables[i].piece) count++;
4093 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
4095 XtSetArg(args[j], XtNlabel, label); j++;
4096 XtSetValues(entry, args, j);
4101 PieceMenuPopup (Widget w, XEvent *event, String *params, Cardinal *num_params)
4103 String whichMenu; int menuNr = -2;
4104 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
4105 if (event->type == ButtonRelease)
4106 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4107 else if (event->type == ButtonPress)
4108 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4110 case 0: whichMenu = params[0]; break;
4111 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
4113 case -1: if (errorUp) ErrorPopDown();
4116 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
4120 PieceMenuSelect (Widget w, ChessSquare piece, caddr_t junk)
4122 if (pmFromX < 0 || pmFromY < 0) return;
4123 EditPositionMenuEvent(piece, pmFromX, pmFromY);
4127 DropMenuSelect (Widget w, ChessSquare piece, caddr_t junk)
4129 if (pmFromX < 0 || pmFromY < 0) return;
4130 DropMenuEvent(piece, pmFromX, pmFromY);
4134 WhiteClock (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4136 shiftKey = prms[0][0] & 1;
4141 BlackClock (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4143 shiftKey = prms[0][0] & 1;
4149 * If the user selects on a border boundary, return -1; if off the board,
4150 * return -2. Otherwise map the event coordinate to the square.
4153 EventToSquare (int x, int limit)
4160 if ((x % (squareSize + lineGap)) >= squareSize)
4162 x /= (squareSize + lineGap);
4169 do_flash_delay (unsigned long msec)
4175 drawHighlight (int file, int rank, GC gc)
4179 if (lineGap == 0) return;
4182 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4183 (squareSize + lineGap);
4184 y = lineGap/2 + rank * (squareSize + lineGap);
4186 x = lineGap/2 + file * (squareSize + lineGap);
4187 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4188 (squareSize + lineGap);
4191 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4192 squareSize+lineGap, squareSize+lineGap);
4195 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4196 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4199 SetHighlights (int fromX, int fromY, int toX, int toY)
4201 if (hi1X != fromX || hi1Y != fromY) {
4202 if (hi1X >= 0 && hi1Y >= 0) {
4203 drawHighlight(hi1X, hi1Y, lineGC);
4205 } // [HGM] first erase both, then draw new!
4206 if (hi2X != toX || hi2Y != toY) {
4207 if (hi2X >= 0 && hi2Y >= 0) {
4208 drawHighlight(hi2X, hi2Y, lineGC);
4211 if (hi1X != fromX || hi1Y != fromY) {
4212 if (fromX >= 0 && fromY >= 0) {
4213 drawHighlight(fromX, fromY, highlineGC);
4216 if (hi2X != toX || hi2Y != toY) {
4217 if (toX >= 0 && toY >= 0) {
4218 drawHighlight(toX, toY, highlineGC);
4221 if(toX<0) // clearing the highlights must have damaged arrow
4222 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y); // for now, redraw it (should really be cleared!)
4232 SetHighlights(-1, -1, -1, -1);
4237 SetPremoveHighlights (int fromX, int fromY, int toX, int toY)
4239 if (pm1X != fromX || pm1Y != fromY) {
4240 if (pm1X >= 0 && pm1Y >= 0) {
4241 drawHighlight(pm1X, pm1Y, lineGC);
4243 if (fromX >= 0 && fromY >= 0) {
4244 drawHighlight(fromX, fromY, prelineGC);
4247 if (pm2X != toX || pm2Y != toY) {
4248 if (pm2X >= 0 && pm2Y >= 0) {
4249 drawHighlight(pm2X, pm2Y, lineGC);
4251 if (toX >= 0 && toY >= 0) {
4252 drawHighlight(toX, toY, prelineGC);
4262 ClearPremoveHighlights ()
4264 SetPremoveHighlights(-1, -1, -1, -1);
4268 CutOutSquare (int x, int y, int *x0, int *y0, int kind)
4270 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4271 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4273 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4274 if(textureW[kind] < W*squareSize)
4275 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4277 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4278 if(textureH[kind] < H*squareSize)
4279 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4281 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4286 BlankSquare (int x, int y, int color, ChessSquare piece, Drawable dest, int fac)
4287 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4289 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4290 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4291 squareSize, squareSize, x*fac, y*fac);
4293 if (useImages && useImageSqs) {
4297 pm = xpmLightSquare;
4302 case 2: /* neutral */
4307 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4308 squareSize, squareSize, x*fac, y*fac);
4318 case 2: /* neutral */
4323 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4328 I split out the routines to draw a piece so that I could
4329 make a generic flash routine.
4332 monoDrawPiece_1bit (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4334 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4335 switch (square_color) {
4337 case 2: /* neutral */
4339 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4340 ? *pieceToOutline(piece)
4341 : *pieceToSolid(piece),
4342 dest, bwPieceGC, 0, 0,
4343 squareSize, squareSize, x, y);
4346 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4347 ? *pieceToSolid(piece)
4348 : *pieceToOutline(piece),
4349 dest, wbPieceGC, 0, 0,
4350 squareSize, squareSize, x, y);
4356 monoDrawPiece (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4358 switch (square_color) {
4360 case 2: /* neutral */
4362 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4363 ? *pieceToOutline(piece)
4364 : *pieceToSolid(piece),
4365 dest, bwPieceGC, 0, 0,
4366 squareSize, squareSize, x, y, 1);
4369 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4370 ? *pieceToSolid(piece)
4371 : *pieceToOutline(piece),
4372 dest, wbPieceGC, 0, 0,
4373 squareSize, squareSize, x, y, 1);
4379 colorDrawPiece (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4381 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4382 switch (square_color) {
4384 XCopyPlane(xDisplay, *pieceToSolid(piece),
4385 dest, (int) piece < (int) BlackPawn
4386 ? wlPieceGC : blPieceGC, 0, 0,
4387 squareSize, squareSize, x, y, 1);
4390 XCopyPlane(xDisplay, *pieceToSolid(piece),
4391 dest, (int) piece < (int) BlackPawn
4392 ? wdPieceGC : bdPieceGC, 0, 0,
4393 squareSize, squareSize, x, y, 1);
4395 case 2: /* neutral */
4397 XCopyPlane(xDisplay, *pieceToSolid(piece),
4398 dest, (int) piece < (int) BlackPawn
4399 ? wjPieceGC : bjPieceGC, 0, 0,
4400 squareSize, squareSize, x, y, 1);
4406 colorDrawPieceImage (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4408 int kind, p = piece;
4410 switch (square_color) {
4412 case 2: /* neutral */
4414 if ((int)piece < (int) BlackPawn) {
4422 if ((int)piece < (int) BlackPawn) {
4430 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4431 if(useTexture & square_color+1) {
4432 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4433 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4434 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4435 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4436 XSetClipMask(xDisplay, wlPieceGC, None);
4437 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4439 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4440 dest, wlPieceGC, 0, 0,
4441 squareSize, squareSize, x, y);
4444 typedef void (*DrawFunc)();
4449 if (appData.monoMode) {
4450 if (DefaultDepth(xDisplay, xScreen) == 1) {
4451 return monoDrawPiece_1bit;
4453 return monoDrawPiece;
4457 return colorDrawPieceImage;
4459 return colorDrawPiece;
4463 /* [HR] determine square color depending on chess variant. */
4465 SquareColor (int row, int column)
4469 if (gameInfo.variant == VariantXiangqi) {
4470 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4472 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4474 } else if (row <= 4) {
4480 square_color = ((column + row) % 2) == 1;
4483 /* [hgm] holdings: next line makes all holdings squares light */
4484 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4486 return square_color;
4490 DrawSquare (int row, int column, ChessSquare piece, int do_flash)
4492 int square_color, x, y, direction, font_ascent, font_descent;
4495 XCharStruct overall;
4499 /* Calculate delay in milliseconds (2-delays per complete flash) */
4500 flash_delay = 500 / appData.flashRate;
4503 x = lineGap + ((BOARD_WIDTH-1)-column) *
4504 (squareSize + lineGap);
4505 y = lineGap + row * (squareSize + lineGap);
4507 x = lineGap + column * (squareSize + lineGap);
4508 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4509 (squareSize + lineGap);
4512 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4514 square_color = SquareColor(row, column);
4516 if ( // [HGM] holdings: blank out area between board and holdings
4517 column == BOARD_LEFT-1 || column == BOARD_RGHT
4518 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4519 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4520 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4522 // [HGM] print piece counts next to holdings
4523 string[1] = NULLCHAR;
4524 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4525 string[0] = '0' + piece;
4526 XTextExtents(countFontStruct, string, 1, &direction,
4527 &font_ascent, &font_descent, &overall);
4528 if (appData.monoMode) {
4529 XDrawImageString(xDisplay, xBoardWindow, countGC,
4530 x + squareSize - overall.width - 2,
4531 y + font_ascent + 1, string, 1);
4533 XDrawString(xDisplay, xBoardWindow, countGC,
4534 x + squareSize - overall.width - 2,
4535 y + font_ascent + 1, string, 1);
4538 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4539 string[0] = '0' + piece;
4540 XTextExtents(countFontStruct, string, 1, &direction,
4541 &font_ascent, &font_descent, &overall);
4542 if (appData.monoMode) {
4543 XDrawImageString(xDisplay, xBoardWindow, countGC,
4544 x + 2, y + font_ascent + 1, string, 1);
4546 XDrawString(xDisplay, xBoardWindow, countGC,
4547 x + 2, y + font_ascent + 1, string, 1);
4551 if (piece == EmptySquare || appData.blindfold) {
4552 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4554 drawfunc = ChooseDrawFunc();
4556 if (do_flash && appData.flashCount > 0) {
4557 for (i=0; i<appData.flashCount; ++i) {
4558 drawfunc(piece, square_color, x, y, xBoardWindow);
4559 XSync(xDisplay, False);
4560 do_flash_delay(flash_delay);
4562 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4563 XSync(xDisplay, False);
4564 do_flash_delay(flash_delay);
4567 drawfunc(piece, square_color, x, y, xBoardWindow);
4571 string[1] = NULLCHAR;
4572 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4573 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4574 string[0] = 'a' + column - BOARD_LEFT;
4575 XTextExtents(coordFontStruct, string, 1, &direction,
4576 &font_ascent, &font_descent, &overall);
4577 if (appData.monoMode) {
4578 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4579 x + squareSize - overall.width - 2,
4580 y + squareSize - font_descent - 1, string, 1);
4582 XDrawString(xDisplay, xBoardWindow, coordGC,
4583 x + squareSize - overall.width - 2,
4584 y + squareSize - font_descent - 1, string, 1);
4587 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4588 string[0] = ONE + row;
4589 XTextExtents(coordFontStruct, string, 1, &direction,
4590 &font_ascent, &font_descent, &overall);
4591 if (appData.monoMode) {
4592 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4593 x + 2, y + font_ascent + 1, string, 1);
4595 XDrawString(xDisplay, xBoardWindow, coordGC,
4596 x + 2, y + font_ascent + 1, string, 1);
4599 if(!partnerUp && marker[row][column]) {
4600 if(appData.monoMode) {
4601 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? darkSquareGC : lightSquareGC,
4602 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4603 XDrawArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? lightSquareGC : darkSquareGC,
4604 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4606 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4607 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4612 /* Why is this needed on some versions of X? */
4614 EventProc (Widget widget, caddr_t unused, XEvent *event)
4616 if (!XtIsRealized(widget))
4619 switch (event->type) {
4621 if (event->xexpose.count > 0) return; /* no clipping is done */
4622 XDrawPosition(widget, True, NULL);
4623 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4624 flipView = !flipView; partnerUp = !partnerUp;
4625 XDrawPosition(widget, True, NULL);
4626 flipView = !flipView; partnerUp = !partnerUp;
4630 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4638 DrawPosition (int fullRedraw, Board board)
4640 XDrawPosition(boardWidget, fullRedraw, board);
4643 /* Returns 1 if there are "too many" differences between b1 and b2
4644 (i.e. more than 1 move was made) */
4646 too_many_diffs (Board b1, Board b2)
4651 for (i=0; i<BOARD_HEIGHT; ++i) {
4652 for (j=0; j<BOARD_WIDTH; ++j) {
4653 if (b1[i][j] != b2[i][j]) {
4654 if (++c > 4) /* Castling causes 4 diffs */
4662 /* Matrix describing castling maneuvers */
4663 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4664 static int castling_matrix[4][5] = {
4665 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4666 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4667 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4668 { 7, 7, 4, 5, 6 } /* 0-0, black */
4671 /* Checks whether castling occurred. If it did, *rrow and *rcol
4672 are set to the destination (row,col) of the rook that moved.
4674 Returns 1 if castling occurred, 0 if not.
4676 Note: Only handles a max of 1 castling move, so be sure
4677 to call too_many_diffs() first.
4680 check_castle_draw (Board newb, Board oldb, int *rrow, int *rcol)
4685 /* For each type of castling... */
4686 for (i=0; i<4; ++i) {
4687 r = castling_matrix[i];
4689 /* Check the 4 squares involved in the castling move */
4691 for (j=1; j<=4; ++j) {
4692 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4699 /* All 4 changed, so it must be a castling move */
4708 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4710 DrawSeekAxis (int x, int y, int xTo, int yTo)
4712 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4716 DrawSeekBackground (int left, int top, int right, int bottom)
4718 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4722 DrawSeekText (char *buf, int x, int y)
4724 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4728 DrawSeekDot (int x, int y, int colorNr)
4730 int square = colorNr & 0x80;
4733 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4735 XFillRectangle(xDisplay, xBoardWindow, color,
4736 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4738 XFillArc(xDisplay, xBoardWindow, color,
4739 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4742 static int damage[2][BOARD_RANKS][BOARD_FILES];
4745 * event handler for redrawing the board
4748 XDrawPosition (Widget w, int repaint, Board board)
4751 static int lastFlipView = 0;
4752 static int lastBoardValid[2] = {0, 0};
4753 static Board lastBoard[2];
4756 int nr = twoBoards*partnerUp;
4758 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4760 if (board == NULL) {
4761 if (!lastBoardValid[nr]) return;
4762 board = lastBoard[nr];
4764 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4765 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4766 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4771 * It would be simpler to clear the window with XClearWindow()
4772 * but this causes a very distracting flicker.
4775 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4777 if ( lineGap && IsDrawArrowEnabled())
4778 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4779 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4781 /* If too much changes (begin observing new game, etc.), don't
4783 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4785 /* Special check for castling so we don't flash both the king
4786 and the rook (just flash the king). */
4788 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4789 /* Draw rook with NO flashing. King will be drawn flashing later */
4790 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4791 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4795 /* First pass -- Draw (newly) empty squares and repair damage.
4796 This prevents you from having a piece show up twice while it
4797 is flashing on its new square */
4798 for (i = 0; i < BOARD_HEIGHT; i++)
4799 for (j = 0; j < BOARD_WIDTH; j++)
4800 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4801 || damage[nr][i][j]) {
4802 DrawSquare(i, j, board[i][j], 0);
4803 damage[nr][i][j] = False;
4806 /* Second pass -- Draw piece(s) in new position and flash them */
4807 for (i = 0; i < BOARD_HEIGHT; i++)
4808 for (j = 0; j < BOARD_WIDTH; j++)
4809 if (board[i][j] != lastBoard[nr][i][j]) {
4810 DrawSquare(i, j, board[i][j], do_flash);
4814 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4815 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4816 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4818 for (i = 0; i < BOARD_HEIGHT; i++)
4819 for (j = 0; j < BOARD_WIDTH; j++) {
4820 DrawSquare(i, j, board[i][j], 0);
4821 damage[nr][i][j] = False;
4825 CopyBoard(lastBoard[nr], board);
4826 lastBoardValid[nr] = 1;
4827 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4828 lastFlipView = flipView;
4830 /* Draw highlights */
4831 if (pm1X >= 0 && pm1Y >= 0) {
4832 drawHighlight(pm1X, pm1Y, prelineGC);
4834 if (pm2X >= 0 && pm2Y >= 0) {
4835 drawHighlight(pm2X, pm2Y, prelineGC);
4837 if (hi1X >= 0 && hi1Y >= 0) {
4838 drawHighlight(hi1X, hi1Y, highlineGC);
4840 if (hi2X >= 0 && hi2Y >= 0) {
4841 drawHighlight(hi2X, hi2Y, highlineGC);
4843 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4845 /* If piece being dragged around board, must redraw that too */
4848 XSync(xDisplay, False);
4853 * event handler for redrawing the board
4856 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4858 XDrawPosition(w, True, NULL);
4863 * event handler for parsing user moves
4865 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4866 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4867 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4868 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4869 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4870 // and at the end FinishMove() to perform the move after optional promotion popups.
4871 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4873 HandleUserMove (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4875 if (w != boardWidget || errorExitStatus != -1) return;
4876 if(nprms) shiftKey = !strcmp(prms[0], "1");
4879 if (event->type == ButtonPress) {
4880 XtPopdown(promotionShell);
4881 XtDestroyWidget(promotionShell);
4882 promotionUp = False;
4890 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4891 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4892 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4896 AnimateUserMove (Widget w, XEvent *event, String *params, Cardinal *nParams)
4898 if(!PromoScroll(event->xmotion.x, event->xmotion.y))
4899 DragPieceMove(event->xmotion.x, event->xmotion.y);
4903 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
4904 { // [HGM] pv: walk PV
4905 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4908 static int savedIndex; /* gross that this is global */
4911 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4914 XawTextPosition index, dummy;
4917 XawTextGetSelectionPos(w, &index, &dummy);
4918 XtSetArg(arg, XtNstring, &val);
4919 XtGetValues(w, &arg, 1);
4920 ReplaceComment(savedIndex, val);
4921 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4922 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4926 EditCommentPopUp (int index, char *title, char *text)
4929 if (text == NULL) text = "";
4930 NewCommentPopup(title, text, index);
4939 extern Option boxOptions[];
4949 edit = boxOptions[0].handle;
4951 XtSetArg(args[j], XtNstring, &val); j++;
4952 XtGetValues(edit, args, j);
4954 SendMultiLineToICS(val);
4955 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4956 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4960 ICSInputBoxPopDown ()
4966 CommentPopUp (char *title, char *text)
4968 savedIndex = currentMove; // [HGM] vari
4969 NewCommentPopup(title, text, currentMove);
4978 static char *openName;
4984 (void) (*fileProc)(openFP, 0, openName);
4988 FileNamePopUp (char *label, char *def, char *filter, FileProc proc, char *openMode)
4990 fileProc = proc; /* I can't see a way not */
4991 fileOpenMode = openMode; /* to use globals here */
4992 { // [HGM] use file-selector dialog stolen from Ghostview
4993 int index; // this is not supported yet
4994 if(openFP = XsraSelFile(shellWidget, label, NULL, NULL, _("could not open: "),
4995 (def[0] ? def : NULL), filter, openMode, NULL, &openName))
4996 // [HGM] delay to give expose event opportunity to redraw board after browser-dialog popdown before lengthy load starts
4997 ScheduleDelayedEvent(&DelayedLoad, 50);
5004 if (!filenameUp) return;
5005 XtPopdown(fileNameShell);
5006 XtDestroyWidget(fileNameShell);
5012 FileNameCallback (Widget w, XtPointer client_data, XtPointer call_data)
5017 XtSetArg(args[0], XtNlabel, &name);
5018 XtGetValues(w, args, 1);
5020 if (strcmp(name, _("cancel")) == 0) {
5025 FileNameAction(w, NULL, NULL, NULL);
5029 FileNameAction (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5037 name = XawDialogGetValueString(w = XtParent(w));
5039 if ((name != NULL) && (*name != NULLCHAR)) {
5040 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5041 XtPopdown(w = XtParent(XtParent(w)));
5045 p = strrchr(buf, ' ');
5052 fullname = ExpandPathName(buf);
5054 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5057 f = fopen(fullname, fileOpenMode);
5059 DisplayError(_("Failed to open file"), errno);
5061 (void) (*fileProc)(f, index, buf);
5068 XtPopdown(w = XtParent(XtParent(w)));
5078 Widget dialog, layout;
5080 Dimension bw_width, pw_width;
5082 char *PromoChars = "wglcqrbnkac+=\0";
5085 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5086 XtGetValues(boardWidget, args, j);
5089 XtSetArg(args[j], XtNresizable, True); j++;
5090 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5092 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5093 shellWidget, args, j);
5095 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5096 layoutArgs, XtNumber(layoutArgs));
5099 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5100 XtSetArg(args[j], XtNborderWidth, 0); j++;
5101 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5104 if(gameInfo.variant != VariantShogi) {
5105 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5106 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback, PromoChars + 0);
5107 XawDialogAddButton(dialog, _("General"), PromotionCallback, PromoChars + 1);
5108 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback, PromoChars + 2);
5109 XawDialogAddButton(dialog, _("Captain"), PromotionCallback, PromoChars + 3);
5111 XawDialogAddButton(dialog, _("Queen"), PromotionCallback, PromoChars + 4);
5112 XawDialogAddButton(dialog, _("Rook"), PromotionCallback, PromoChars + 5);
5113 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback, PromoChars + 6);
5114 XawDialogAddButton(dialog, _("Knight"), PromotionCallback, PromoChars + 7);
5116 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5117 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
5118 gameInfo.variant == VariantGiveaway) {
5119 XawDialogAddButton(dialog, _("King"), PromotionCallback, PromoChars + 8);
5121 if(gameInfo.variant == VariantCapablanca ||
5122 gameInfo.variant == VariantGothic ||
5123 gameInfo.variant == VariantCapaRandom) {
5124 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback, PromoChars + 9);
5125 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback, PromoChars + 10);
5127 } else // [HGM] shogi
5129 XawDialogAddButton(dialog, _("Promote"), PromotionCallback, PromoChars + 11);
5130 XawDialogAddButton(dialog, _("Defer"), PromotionCallback, PromoChars + 12);
5132 XawDialogAddButton(dialog, _("cancel"), PromotionCallback, PromoChars + 13);
5134 XtRealizeWidget(promotionShell);
5135 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5138 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5139 XtGetValues(promotionShell, args, j);
5141 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5142 lineGap + squareSize/3 +
5143 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5144 0 : 6*(squareSize + lineGap)), &x, &y);
5147 XtSetArg(args[j], XtNx, x); j++;
5148 XtSetArg(args[j], XtNy, y); j++;
5149 XtSetValues(promotionShell, args, j);
5151 XtPopup(promotionShell, XtGrabNone);
5159 if (!promotionUp) return;
5160 XtPopdown(promotionShell);
5161 XtDestroyWidget(promotionShell);
5162 promotionUp = False;
5166 PromotionCallback (Widget w, XtPointer client_data, XtPointer call_data)
5168 int promoChar = * (const char *) client_data;
5172 if (fromX == -1) return;
5179 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5181 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5182 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5188 ErrorCallback (Widget w, XtPointer client_data, XtPointer call_data)
5191 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5193 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5200 if (!errorUp) return;
5202 XtPopdown(errorShell);
5203 XtDestroyWidget(errorShell);
5204 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5208 ErrorPopUp (char *title, char *label, int modal)
5211 Widget dialog, layout;
5215 Dimension bw_width, pw_width;
5216 Dimension pw_height;
5220 XtSetArg(args[i], XtNresizable, True); i++;
5221 XtSetArg(args[i], XtNtitle, title); i++;
5223 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5224 shellWidget, args, i);
5226 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5227 layoutArgs, XtNumber(layoutArgs));
5230 XtSetArg(args[i], XtNlabel, label); i++;
5231 XtSetArg(args[i], XtNborderWidth, 0); i++;
5232 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5235 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5237 XtRealizeWidget(errorShell);
5238 CatchDeleteWindow(errorShell, "ErrorPopDown");
5241 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5242 XtGetValues(boardWidget, args, i);
5244 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5245 XtSetArg(args[i], XtNheight, &pw_height); i++;
5246 XtGetValues(errorShell, args, i);
5249 /* This code seems to tickle an X bug if it is executed too soon
5250 after xboard starts up. The coordinates get transformed as if
5251 the main window was positioned at (0, 0).
5253 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5254 0 - pw_height + squareSize / 3, &x, &y);
5256 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5257 RootWindowOfScreen(XtScreen(boardWidget)),
5258 (bw_width - pw_width) / 2,
5259 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5263 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5266 XtSetArg(args[i], XtNx, x); i++;
5267 XtSetArg(args[i], XtNy, y); i++;
5268 XtSetValues(errorShell, args, i);
5271 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5274 /* Disable all user input other than deleting the window */
5275 static int frozen = 0;
5281 /* Grab by a widget that doesn't accept input */
5282 XtAddGrab(messageWidget, TRUE, FALSE);
5286 /* Undo a FreezeUI */
5290 if (!frozen) return;
5291 XtRemoveGrab(messageWidget);
5296 ModeToWidgetName (GameMode mode)
5299 case BeginningOfGame:
5300 if (appData.icsActive)
5301 return "menuMode.ICS Client";
5302 else if (appData.noChessProgram ||
5303 *appData.cmailGameName != NULLCHAR)
5304 return "menuMode.Edit Game";
5306 return "menuMode.Machine Black";
5307 case MachinePlaysBlack:
5308 return "menuMode.Machine Black";
5309 case MachinePlaysWhite:
5310 return "menuMode.Machine White";
5312 return "menuMode.Analysis Mode";
5314 return "menuMode.Analyze File";
5315 case TwoMachinesPlay:
5316 return "menuMode.Two Machines";
5318 return "menuMode.Edit Game";
5319 case PlayFromGameFile:
5320 return "menuFile.Load Game";
5322 return "menuMode.Edit Position";
5324 return "menuMode.Training";
5325 case IcsPlayingWhite:
5326 case IcsPlayingBlack:
5330 return "menuMode.ICS Client";
5341 static int oldPausing = FALSE;
5342 static GameMode oldmode = (GameMode) -1;
5345 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5347 if (pausing != oldPausing) {
5348 oldPausing = pausing;
5350 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5352 XtSetArg(args[0], XtNleftBitmap, None);
5354 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5357 if (appData.showButtonBar) {
5358 /* Always toggle, don't set. Previous code messes up when
5359 invoked while the button is pressed, as releasing it
5360 toggles the state again. */
5363 XtSetArg(args[0], XtNbackground, &oldbg);
5364 XtSetArg(args[1], XtNforeground, &oldfg);
5365 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5367 XtSetArg(args[0], XtNbackground, oldfg);
5368 XtSetArg(args[1], XtNforeground, oldbg);
5370 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5374 wname = ModeToWidgetName(oldmode);
5375 if (wname != NULL) {
5376 XtSetArg(args[0], XtNleftBitmap, None);
5377 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5379 wname = ModeToWidgetName(gameMode);
5380 if (wname != NULL) {
5381 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5382 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5385 XtSetArg(args[0], XtNleftBitmap, matchMode && matchGame < appData.matchGames ? xMarkPixmap : None);
5386 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Machine Match"), args, 1);
5388 /* Maybe all the enables should be handled here, not just this one */
5389 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5390 gameMode == Training || gameMode == PlayFromGameFile);
5395 * Button/menu procedures
5398 ResetProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5404 LoadGamePopUp (FILE *f, int gameNumber, char *title)
5406 cmailMsgLoaded = FALSE;
5407 if (gameNumber == 0) {
5408 int error = GameListBuild(f);
5410 DisplayError(_("Cannot build game list"), error);
5411 } else if (!ListEmpty(&gameList) &&
5412 ((ListGame *) gameList.tailPred)->number > 1) {
5413 GameListPopUp(f, title);
5419 return LoadGame(f, gameNumber, title, FALSE);
5423 LoadGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5425 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5428 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5432 LoadNextGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5438 LoadPrevGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5444 ReloadGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5450 LoadNextPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5456 LoadPrevPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5462 ReloadPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5468 LoadPositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5470 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5473 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5477 SaveGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5479 FileNamePopUp(_("Save game file name?"),
5480 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5481 appData.oldSaveStyle ? ".game" : ".pgn",
5486 SavePositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5488 FileNamePopUp(_("Save position file name?"),
5489 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5490 appData.oldSaveStyle ? ".pos" : ".fen",
5495 ReloadCmailMsgProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5497 ReloadCmailMsgEvent(FALSE);
5501 MailMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5506 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5507 char *selected_fen_position=NULL;
5510 SendPositionSelection (Widget w, Atom *selection, Atom *target,
5511 Atom *type_return, XtPointer *value_return,
5512 unsigned long *length_return, int *format_return)
5514 char *selection_tmp;
5516 if (!selected_fen_position) return False; /* should never happen */
5517 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5518 /* note: since no XtSelectionDoneProc was registered, Xt will
5519 * automatically call XtFree on the value returned. So have to
5520 * make a copy of it allocated with XtMalloc */
5521 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5522 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5524 *value_return=selection_tmp;
5525 *length_return=strlen(selection_tmp);
5526 *type_return=*target;
5527 *format_return = 8; /* bits per byte */
5529 } else if (*target == XA_TARGETS(xDisplay)) {
5530 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5531 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5532 targets_tmp[1] = XA_STRING;
5533 *value_return = targets_tmp;
5534 *type_return = XA_ATOM;
5537 // This code leads to a read of value_return out of bounds on 64-bit systems.
5538 // Other code which I have seen always sets *format_return to 32 independent of
5539 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
5540 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
5541 *format_return = 8 * sizeof(Atom);
5542 if (*format_return > 32) {
5543 *length_return *= *format_return / 32;
5544 *format_return = 32;
5547 *format_return = 32;
5555 /* note: when called from menu all parameters are NULL, so no clue what the
5556 * Widget which was clicked on was, or what the click event was
5559 CopyPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5562 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5563 * have a notion of a position that is selected but not copied.
5564 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5566 if(gameMode == EditPosition) EditPositionDone(TRUE);
5567 if (selected_fen_position) free(selected_fen_position);
5568 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5569 if (!selected_fen_position) return;
5570 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5572 SendPositionSelection,
5573 NULL/* lose_ownership_proc */ ,
5574 NULL/* transfer_done_proc */);
5575 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5577 SendPositionSelection,
5578 NULL/* lose_ownership_proc */ ,
5579 NULL/* transfer_done_proc */);
5582 /* function called when the data to Paste is ready */
5584 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
5585 Atom *type, XtPointer value, unsigned long *len, int *format)
5588 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5589 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5590 EditPositionPasteFEN(fenstr);
5594 /* called when Paste Position button is pressed,
5595 * all parameters will be NULL */
5596 void PastePositionProc(w, event, prms, nprms)
5602 XtGetSelectionValue(menuBarWidget,
5603 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5604 /* (XtSelectionCallbackProc) */ PastePositionCB,
5605 NULL, /* client_data passed to PastePositionCB */
5607 /* better to use the time field from the event that triggered the
5608 * call to this function, but that isn't trivial to get
5616 SendGameSelection (Widget w, Atom *selection, Atom *target,
5617 Atom *type_return, XtPointer *value_return,
5618 unsigned long *length_return, int *format_return)
5620 char *selection_tmp;
5622 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5623 FILE* f = fopen(gameCopyFilename, "r");
5626 if (f == NULL) return False;
5630 selection_tmp = XtMalloc(len + 1);
5631 count = fread(selection_tmp, 1, len, f);
5634 XtFree(selection_tmp);
5637 selection_tmp[len] = NULLCHAR;
5638 *value_return = selection_tmp;
5639 *length_return = len;
5640 *type_return = *target;
5641 *format_return = 8; /* bits per byte */
5643 } else if (*target == XA_TARGETS(xDisplay)) {
5644 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5645 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5646 targets_tmp[1] = XA_STRING;
5647 *value_return = targets_tmp;
5648 *type_return = XA_ATOM;
5651 // This code leads to a read of value_return out of bounds on 64-bit systems.
5652 // Other code which I have seen always sets *format_return to 32 independent of
5653 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
5654 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
5655 *format_return = 8 * sizeof(Atom);
5656 if (*format_return > 32) {
5657 *length_return *= *format_return / 32;
5658 *format_return = 32;
5661 *format_return = 32;
5673 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5674 * have a notion of a game that is selected but not copied.
5675 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5677 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5680 NULL/* lose_ownership_proc */ ,
5681 NULL/* transfer_done_proc */);
5682 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5685 NULL/* lose_ownership_proc */ ,
5686 NULL/* transfer_done_proc */);
5689 /* note: when called from menu all parameters are NULL, so no clue what the
5690 * Widget which was clicked on was, or what the click event was
5693 CopyGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5697 ret = SaveGameToFile(gameCopyFilename, FALSE);
5704 CopyGameListProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5706 if(!SaveGameListAsText(fopen(gameCopyFilename, "w"))) return;
5710 /* function called when the data to Paste is ready */
5712 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
5713 Atom *type, XtPointer value, unsigned long *len, int *format)
5716 if (value == NULL || *len == 0) {
5717 return; /* nothing had been selected to copy */
5719 f = fopen(gamePasteFilename, "w");
5721 DisplayError(_("Can't open temp file"), errno);
5724 fwrite(value, 1, *len, f);
5727 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5730 /* called when Paste Game button is pressed,
5731 * all parameters will be NULL */
5733 PasteGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5735 XtGetSelectionValue(menuBarWidget,
5736 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5737 /* (XtSelectionCallbackProc) */ PasteGameCB,
5738 NULL, /* client_data passed to PasteGameCB */
5740 /* better to use the time field from the event that triggered the
5741 * call to this function, but that isn't trivial to get
5752 SaveGameProc(NULL, NULL, NULL, NULL);
5757 QuitProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5763 PauseProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5769 MachineBlackProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5771 MachineBlackEvent();
5775 MachineWhiteProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5777 MachineWhiteEvent();
5781 AnalyzeModeProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5785 if (!first.analysisSupport) {
5786 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5787 DisplayError(buf, 0);
5790 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5791 if (appData.icsActive) {
5792 if (gameMode != IcsObserving) {
5793 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5794 DisplayError(buf, 0);
5796 if (appData.icsEngineAnalyze) {
5797 if (appData.debugMode)
5798 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5804 /* if enable, use want disable icsEngineAnalyze */
5805 if (appData.icsEngineAnalyze) {
5810 appData.icsEngineAnalyze = TRUE;
5811 if (appData.debugMode)
5812 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5814 #ifndef OPTIONSDIALOG
5815 if (!appData.showThinking)
5816 ShowThinkingProc(w,event,prms,nprms);
5823 AnalyzeFileProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5825 if (!first.analysisSupport) {
5827 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5828 DisplayError(buf, 0);
5831 // Reset(FALSE, TRUE);
5832 #ifndef OPTIONSDIALOG
5833 if (!appData.showThinking)
5834 ShowThinkingProc(w,event,prms,nprms);
5837 // FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5838 AnalysisPeriodicEvent(1);
5842 TwoMachinesProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5848 MatchProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5854 IcsClientProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5860 EditGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5866 EditPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5868 EditPositionEvent();
5872 TrainingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5878 EditCommentProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5882 if (PopDown(1)) { // popdown succesful
5884 XtSetArg(args[j], XtNleftBitmap, None); j++;
5885 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
5886 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
5887 } else // was not up
5892 IcsInputBoxProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5894 if (!PopDown(4)) ICSInputBoxPopUp();
5898 AcceptProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5904 DeclineProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5910 RematchProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5916 CallFlagProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5922 DrawProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5928 AbortProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5934 AdjournProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5940 ResignProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5946 AdjuWhiteProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5948 UserAdjudicationEvent(+1);
5952 AdjuBlackProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5954 UserAdjudicationEvent(-1);
5958 AdjuDrawProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5960 UserAdjudicationEvent(0);
5964 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5966 if (shellUp[4] == True)
5971 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5972 { // [HGM] input: let up-arrow recall previous line from history
5979 if (!shellUp[4]) return;
5980 edit = boxOptions[0].handle;
5982 XtSetArg(args[j], XtNstring, &val); j++;
5983 XtGetValues(edit, args, j);
5984 val = PrevInHistory(val);
5985 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5986 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5988 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
5989 XawTextReplace(edit, 0, 0, &t);
5990 XawTextSetInsertionPoint(edit, 9999);
5995 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5996 { // [HGM] input: let down-arrow recall next line from history
6001 if (!shellUp[4]) return;
6002 edit = boxOptions[0].handle;
6003 val = NextInHistory();
6004 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6005 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6007 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6008 XawTextReplace(edit, 0, 0, &t);
6009 XawTextSetInsertionPoint(edit, 9999);
6014 StopObservingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6016 StopObservingEvent();
6020 StopExaminingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6022 StopExaminingEvent();
6026 UploadProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6033 ForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6040 BackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6046 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6048 if (!TempBackwardActive) {
6049 TempBackwardActive = True;
6055 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6057 /* Check to see if triggered by a key release event for a repeating key.
6058 * If so the next queued event will be a key press of the same key at the same time */
6059 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
6061 XPeekEvent(xDisplay, &next);
6062 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
6063 next.xkey.keycode == event->xkey.keycode)
6067 TempBackwardActive = False;
6071 ToStartProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6077 ToEndProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6083 RevertProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6089 AnnotateProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6095 TruncateGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6097 TruncateGameEvent();
6101 RetractMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6107 MoveNowProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6113 FlipViewProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6115 flipView = !flipView;
6116 DrawPosition(True, NULL);
6120 PonderNextMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6124 PonderNextMoveEvent(!appData.ponderNextMove);
6125 #ifndef OPTIONSDIALOG
6126 if (appData.ponderNextMove) {
6127 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6129 XtSetArg(args[0], XtNleftBitmap, None);
6131 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6136 #ifndef OPTIONSDIALOG
6138 AlwaysQueenProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6142 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6144 if (appData.alwaysPromoteToQueen) {
6145 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6147 XtSetArg(args[0], XtNleftBitmap, None);
6149 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6154 AnimateDraggingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6158 appData.animateDragging = !appData.animateDragging;
6160 if (appData.animateDragging) {
6161 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6164 XtSetArg(args[0], XtNleftBitmap, None);
6166 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6171 AnimateMovingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6175 appData.animate = !appData.animate;
6177 if (appData.animate) {
6178 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6181 XtSetArg(args[0], XtNleftBitmap, None);
6183 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6188 AutoflagProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6192 appData.autoCallFlag = !appData.autoCallFlag;
6194 if (appData.autoCallFlag) {
6195 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6197 XtSetArg(args[0], XtNleftBitmap, None);
6199 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6204 AutoflipProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6208 appData.autoFlipView = !appData.autoFlipView;
6210 if (appData.autoFlipView) {
6211 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6213 XtSetArg(args[0], XtNleftBitmap, None);
6215 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6220 BlindfoldProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6224 appData.blindfold = !appData.blindfold;
6226 if (appData.blindfold) {
6227 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6229 XtSetArg(args[0], XtNleftBitmap, None);
6231 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6234 DrawPosition(True, NULL);
6238 TestLegalityProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6242 appData.testLegality = !appData.testLegality;
6244 if (appData.testLegality) {
6245 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6247 XtSetArg(args[0], XtNleftBitmap, None);
6249 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6255 FlashMovesProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6259 if (appData.flashCount == 0) {
6260 appData.flashCount = 3;
6262 appData.flashCount = -appData.flashCount;
6265 if (appData.flashCount > 0) {
6266 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6268 XtSetArg(args[0], XtNleftBitmap, None);
6270 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6276 HighlightDraggingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6280 appData.highlightDragging = !appData.highlightDragging;
6282 if (appData.highlightDragging) {
6283 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6285 XtSetArg(args[0], XtNleftBitmap, None);
6287 XtSetValues(XtNameToWidget(menuBarWidget,
6288 "menuOptions.Highlight Dragging"), args, 1);
6293 HighlightLastMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6297 appData.highlightLastMove = !appData.highlightLastMove;
6299 if (appData.highlightLastMove) {
6300 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6302 XtSetArg(args[0], XtNleftBitmap, None);
6304 XtSetValues(XtNameToWidget(menuBarWidget,
6305 "menuOptions.Highlight Last Move"), args, 1);
6309 HighlightArrowProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6313 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6315 if (appData.highlightMoveWithArrow) {
6316 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6318 XtSetArg(args[0], XtNleftBitmap, None);
6320 XtSetValues(XtNameToWidget(menuBarWidget,
6321 "menuOptions.Arrow"), args, 1);
6326 IcsAlarmProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6330 appData.icsAlarm = !appData.icsAlarm;
6332 if (appData.icsAlarm) {
6333 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6335 XtSetArg(args[0], XtNleftBitmap, None);
6337 XtSetValues(XtNameToWidget(menuBarWidget,
6338 "menuOptions.ICS Alarm"), args, 1);
6343 MoveSoundProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6347 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6349 if (appData.ringBellAfterMoves) {
6350 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6352 XtSetArg(args[0], XtNleftBitmap, None);
6354 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6359 OneClickProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6363 appData.oneClick = !appData.oneClick;
6365 if (appData.oneClick) {
6366 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6368 XtSetArg(args[0], XtNleftBitmap, None);
6370 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6375 PeriodicUpdatesProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6379 PeriodicUpdatesEvent(!appData.periodicUpdates);
6381 if (appData.periodicUpdates) {
6382 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6384 XtSetArg(args[0], XtNleftBitmap, None);
6386 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6391 PopupExitMessageProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6395 appData.popupExitMessage = !appData.popupExitMessage;
6397 if (appData.popupExitMessage) {
6398 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6400 XtSetArg(args[0], XtNleftBitmap, None);
6402 XtSetValues(XtNameToWidget(menuBarWidget,
6403 "menuOptions.Popup Exit Message"), args, 1);
6407 PopupMoveErrorsProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6411 appData.popupMoveErrors = !appData.popupMoveErrors;
6413 if (appData.popupMoveErrors) {
6414 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6416 XtSetArg(args[0], XtNleftBitmap, None);
6418 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6424 PremoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6428 appData.premove = !appData.premove;
6430 if (appData.premove) {
6431 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6433 XtSetArg(args[0], XtNleftBitmap, None);
6435 XtSetValues(XtNameToWidget(menuBarWidget,
6436 "menuOptions.Premove"), args, 1);
6441 ShowCoordsProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6445 appData.showCoords = !appData.showCoords;
6447 if (appData.showCoords) {
6448 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6450 XtSetArg(args[0], XtNleftBitmap, None);
6452 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6455 DrawPosition(True, NULL);
6459 ShowThinkingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6461 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6462 ShowThinkingEvent();
6466 HideThinkingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6470 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6471 ShowThinkingEvent();
6473 if (appData.hideThinkingFromHuman) {
6474 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6476 XtSetArg(args[0], XtNleftBitmap, None);
6478 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6484 SaveOnExitProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6488 saveSettingsOnExit = !saveSettingsOnExit;
6490 if (saveSettingsOnExit) {
6491 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6493 XtSetArg(args[0], XtNleftBitmap, None);
6495 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6500 SaveSettingsProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6502 SaveSettings(settingsFileName);
6506 InfoProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6509 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6515 ManProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6519 if (nprms && *nprms > 0)
6523 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6528 HintProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6534 BookProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6540 AboutProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6544 char *zippy = _(" (with Zippy code)");
6548 snprintf(buf, sizeof(buf),
6550 "Copyright 1991 Digital Equipment Corporation\n"
6551 "Enhancements Copyright 1992-2009 Free Software Foundation\n"
6552 "Enhancements Copyright 2005 Alessandro Scotti\n\n"
6553 "%s is free software and carries NO WARRANTY;"
6554 "see the file COPYING for more information."),
6555 programVersion, zippy, PACKAGE);
6556 ErrorPopUp(_("About XBoard"), buf, FALSE);
6560 DebugProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6562 appData.debugMode = !appData.debugMode;
6566 AboutGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6572 NothingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6578 DisplayMessage (char *message, char *extMessage)
6580 /* display a message in the message widget */
6589 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6594 message = extMessage;
6598 safeStrCpy(lastMsg, message, MSG_SIZ); // [HGM] make available
6600 /* need to test if messageWidget already exists, since this function
6601 can also be called during the startup, if for example a Xresource
6602 is not set up correctly */
6605 XtSetArg(arg, XtNlabel, message);
6606 XtSetValues(messageWidget, &arg, 1);
6613 DisplayTitle (char *text)
6617 char title[MSG_SIZ];
6620 if (text == NULL) text = "";
6622 if (appData.titleInWindow) {
6624 XtSetArg(args[i], XtNlabel, text); i++;
6625 XtSetValues(titleWidget, args, i);
6628 if (*text != NULLCHAR) {
6629 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6630 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6631 } else if (appData.icsActive) {
6632 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6633 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6634 } else if (appData.cmailGameName[0] != NULLCHAR) {
6635 snprintf(icon, sizeof(icon), "%s", "CMail");
6636 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6638 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6639 } else if (gameInfo.variant == VariantGothic) {
6640 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6641 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6644 } else if (gameInfo.variant == VariantFalcon) {
6645 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6646 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6648 } else if (appData.noChessProgram) {
6649 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6650 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6652 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6653 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6656 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6657 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6658 XtSetValues(shellWidget, args, i);
6659 XSync(xDisplay, False);
6664 DisplayError (String message, int error)
6669 if (appData.debugMode || appData.matchMode) {
6670 fprintf(stderr, "%s: %s\n", programName, message);
6673 if (appData.debugMode || appData.matchMode) {
6674 fprintf(stderr, "%s: %s: %s\n",
6675 programName, message, strerror(error));
6677 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6680 ErrorPopUp(_("Error"), message, FALSE);
6685 DisplayMoveError (String message)
6689 DrawPosition(FALSE, NULL);
6690 if (appData.debugMode || appData.matchMode) {
6691 fprintf(stderr, "%s: %s\n", programName, message);
6693 if (appData.popupMoveErrors) {
6694 ErrorPopUp(_("Error"), message, FALSE);
6696 DisplayMessage(message, "");
6702 DisplayFatalError (String message, int error, int status)
6706 errorExitStatus = status;
6708 fprintf(stderr, "%s: %s\n", programName, message);
6710 fprintf(stderr, "%s: %s: %s\n",
6711 programName, message, strerror(error));
6712 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6715 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6716 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6723 DisplayInformation (String message)
6726 ErrorPopUp(_("Information"), message, TRUE);
6730 DisplayNote (String message)
6733 ErrorPopUp(_("Note"), message, FALSE);
6737 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
6743 DisplayIcsInteractionTitle (String message)
6745 if (oldICSInteractionTitle == NULL) {
6746 /* Magic to find the old window title, adapted from vim */
6747 char *wina = getenv("WINDOWID");
6749 Window win = (Window) atoi(wina);
6750 Window root, parent, *children;
6751 unsigned int nchildren;
6752 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6754 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6755 if (!XQueryTree(xDisplay, win, &root, &parent,
6756 &children, &nchildren)) break;
6757 if (children) XFree((void *)children);
6758 if (parent == root || parent == 0) break;
6761 XSetErrorHandler(oldHandler);
6763 if (oldICSInteractionTitle == NULL) {
6764 oldICSInteractionTitle = "xterm";
6767 printf("\033]0;%s\007", message);
6771 char pendingReplyPrefix[MSG_SIZ];
6772 ProcRef pendingReplyPR;
6775 AskQuestionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6778 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6782 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6786 AskQuestionPopDown ()
6788 if (!askQuestionUp) return;
6789 XtPopdown(askQuestionShell);
6790 XtDestroyWidget(askQuestionShell);
6791 askQuestionUp = False;
6795 AskQuestionReplyAction (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6801 reply = XawDialogGetValueString(w = XtParent(w));
6802 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
6803 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
6804 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
6805 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
6806 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
6807 AskQuestionPopDown();
6809 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
6813 AskQuestionCallback (Widget w, XtPointer client_data, XtPointer call_data)
6818 XtSetArg(args[0], XtNlabel, &name);
6819 XtGetValues(w, args, 1);
6821 if (strcmp(name, _("cancel")) == 0) {
6822 AskQuestionPopDown();
6824 AskQuestionReplyAction(w, NULL, NULL, NULL);
6829 AskQuestion (char *title, char *question, char *replyPrefix, ProcRef pr)
6832 Widget popup, layout, dialog, edit;
6838 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
6839 pendingReplyPR = pr;
6842 XtSetArg(args[i], XtNresizable, True); i++;
6843 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
6844 askQuestionShell = popup =
6845 XtCreatePopupShell(title, transientShellWidgetClass,
6846 shellWidget, args, i);
6849 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
6850 layoutArgs, XtNumber(layoutArgs));
6853 XtSetArg(args[i], XtNlabel, question); i++;
6854 XtSetArg(args[i], XtNvalue, ""); i++;
6855 XtSetArg(args[i], XtNborderWidth, 0); i++;
6856 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
6859 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
6860 (XtPointer) dialog);
6861 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
6862 (XtPointer) dialog);
6864 XtRealizeWidget(popup);
6865 CatchDeleteWindow(popup, "AskQuestionPopDown");
6867 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
6868 &x, &y, &win_x, &win_y, &mask);
6870 XtSetArg(args[0], XtNx, x - 10);
6871 XtSetArg(args[1], XtNy, y - 30);
6872 XtSetValues(popup, args, 2);
6874 XtPopup(popup, XtGrabExclusive);
6875 askQuestionUp = True;
6877 edit = XtNameToWidget(dialog, "*value");
6878 XtSetKeyboardFocus(popup, edit);
6883 PlaySound (char *name)
6885 if (*name == NULLCHAR) {
6887 } else if (strcmp(name, "$") == 0) {
6888 putc(BELLCHAR, stderr);
6891 char *prefix = "", *sep = "";
6892 if(appData.soundProgram[0] == NULLCHAR) return;
6893 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
6894 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
6902 PlaySound(appData.soundMove);
6908 PlaySound(appData.soundIcsWin);
6914 PlaySound(appData.soundIcsLoss);
6920 PlaySound(appData.soundIcsDraw);
6924 PlayIcsUnfinishedSound ()
6926 PlaySound(appData.soundIcsUnfinished);
6932 PlaySound(appData.soundIcsAlarm);
6938 PlaySound(appData.soundTell);
6944 system("stty echo");
6951 system("stty -echo");
6956 RunCommand (char *buf)
6962 Colorize (ColorClass cc, int continuation)
6965 int count, outCount, error;
6967 if (textColors[(int)cc].bg > 0) {
6968 if (textColors[(int)cc].fg > 0) {
6969 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
6970 textColors[(int)cc].fg, textColors[(int)cc].bg);
6972 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
6973 textColors[(int)cc].bg);
6976 if (textColors[(int)cc].fg > 0) {
6977 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
6978 textColors[(int)cc].fg);
6980 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
6983 count = strlen(buf);
6984 outCount = OutputToProcess(NoProc, buf, count, &error);
6985 if (outCount < count) {
6986 DisplayFatalError(_("Error writing to display"), error, 1);
6989 if (continuation) return;
6992 PlaySound(appData.soundShout);
6995 PlaySound(appData.soundSShout);
6998 PlaySound(appData.soundChannel1);
7001 PlaySound(appData.soundChannel);
7004 PlaySound(appData.soundKibitz);
7007 PlaySound(appData.soundTell);
7009 case ColorChallenge:
7010 PlaySound(appData.soundChallenge);
7013 PlaySound(appData.soundRequest);
7016 PlaySound(appData.soundSeek);
7028 return getpwuid(getuid())->pw_name;
7032 ExpandPathName (char *path)
7034 static char static_buf[4*MSG_SIZ];
7035 char *d, *s, buf[4*MSG_SIZ];
7041 while (*s && isspace(*s))
7050 if (*(s+1) == '/') {
7051 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7055 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7056 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7057 pwd = getpwnam(buf);
7060 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7064 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7065 strcat(d, strchr(s+1, '/'));
7069 safeStrCpy(d, s, 4*MSG_SIZ );
7077 static char host_name[MSG_SIZ];
7079 #if HAVE_GETHOSTNAME
7080 gethostname(host_name, MSG_SIZ);
7082 #else /* not HAVE_GETHOSTNAME */
7083 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7084 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7086 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7088 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7089 #endif /* not HAVE_GETHOSTNAME */
7092 XtIntervalId delayedEventTimerXID = 0;
7093 DelayedEventCallback delayedEventCallback = 0;
7098 delayedEventTimerXID = 0;
7099 delayedEventCallback();
7103 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
7105 if(delayedEventTimerXID && delayedEventCallback == cb)
7106 // [HGM] alive: replace, rather than add or flush identical event
7107 XtRemoveTimeOut(delayedEventTimerXID);
7108 delayedEventCallback = cb;
7109 delayedEventTimerXID =
7110 XtAppAddTimeOut(appContext, millisec,
7111 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7114 DelayedEventCallback
7117 if (delayedEventTimerXID) {
7118 return delayedEventCallback;
7125 CancelDelayedEvent ()
7127 if (delayedEventTimerXID) {
7128 XtRemoveTimeOut(delayedEventTimerXID);
7129 delayedEventTimerXID = 0;
7133 XtIntervalId loadGameTimerXID = 0;
7136 LoadGameTimerRunning ()
7138 return loadGameTimerXID != 0;
7142 StopLoadGameTimer ()
7144 if (loadGameTimerXID != 0) {
7145 XtRemoveTimeOut(loadGameTimerXID);
7146 loadGameTimerXID = 0;
7154 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
7156 loadGameTimerXID = 0;
7161 StartLoadGameTimer (long millisec)
7164 XtAppAddTimeOut(appContext, millisec,
7165 (XtTimerCallbackProc) LoadGameTimerCallback,
7169 XtIntervalId analysisClockXID = 0;
7172 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
7174 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7175 || appData.icsEngineAnalyze) { // [DM]
7176 AnalysisPeriodicEvent(0);
7177 StartAnalysisClock();
7182 StartAnalysisClock ()
7185 XtAppAddTimeOut(appContext, 2000,
7186 (XtTimerCallbackProc) AnalysisClockCallback,
7190 XtIntervalId clockTimerXID = 0;
7193 ClockTimerRunning ()
7195 return clockTimerXID != 0;
7201 if (clockTimerXID != 0) {
7202 XtRemoveTimeOut(clockTimerXID);
7211 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
7218 StartClockTimer (long millisec)
7221 XtAppAddTimeOut(appContext, millisec,
7222 (XtTimerCallbackProc) ClockTimerCallback,
7227 DisplayTimerLabel (Widget w, char *color, long timer, int highlight)
7232 /* check for low time warning */
7233 Pixel foregroundOrWarningColor = timerForegroundPixel;
7236 appData.lowTimeWarning &&
7237 (timer / 1000) < appData.icsAlarmTime)
7238 foregroundOrWarningColor = lowTimeWarningColor;
7240 if (appData.clockMode) {
7241 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7242 XtSetArg(args[0], XtNlabel, buf);
7244 snprintf(buf, MSG_SIZ, "%s ", color);
7245 XtSetArg(args[0], XtNlabel, buf);
7250 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7251 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7253 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7254 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7257 XtSetValues(w, args, 3);
7261 DisplayWhiteClock (long timeRemaining, int highlight)
7265 if(appData.noGUI) return;
7266 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7267 if (highlight && iconPixmap == bIconPixmap) {
7268 iconPixmap = wIconPixmap;
7269 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7270 XtSetValues(shellWidget, args, 1);
7275 DisplayBlackClock (long timeRemaining, int highlight)
7279 if(appData.noGUI) return;
7280 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7281 if (highlight && iconPixmap == wIconPixmap) {
7282 iconPixmap = bIconPixmap;
7283 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7284 XtSetValues(shellWidget, args, 1);
7303 StartChildProcess (char *cmdLine, char *dir, ProcRef *pr)
7307 int to_prog[2], from_prog[2];
7311 if (appData.debugMode) {
7312 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7315 /* We do NOT feed the cmdLine to the shell; we just
7316 parse it into blank-separated arguments in the
7317 most simple-minded way possible.
7320 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7323 while(*p == ' ') p++;
7325 if(*p == '"' || *p == '\'')
7326 p = strchr(++argv[i-1], *p);
7327 else p = strchr(p, ' ');
7328 if (p == NULL) break;
7333 SetUpChildIO(to_prog, from_prog);
7335 if ((pid = fork()) == 0) {
7337 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7338 close(to_prog[1]); // first close the unused pipe ends
7339 close(from_prog[0]);
7340 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7341 dup2(from_prog[1], 1);
7342 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7343 close(from_prog[1]); // and closing again loses one of the pipes!
7344 if(fileno(stderr) >= 2) // better safe than sorry...
7345 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7347 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7352 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7354 execvp(argv[0], argv);
7356 /* If we get here, exec failed */
7361 /* Parent process */
7363 close(from_prog[1]);
7365 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7368 cp->fdFrom = from_prog[0];
7369 cp->fdTo = to_prog[1];
7374 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7376 AlarmCallBack (int n)
7382 DestroyChildProcess (ProcRef pr, int signalType)
7384 ChildProc *cp = (ChildProc *) pr;
7386 if (cp->kind != CPReal) return;
7388 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7389 signal(SIGALRM, AlarmCallBack);
7391 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7392 kill(cp->pid, SIGKILL); // kill it forcefully
7393 wait((int *) 0); // and wait again
7397 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7399 /* Process is exiting either because of the kill or because of
7400 a quit command sent by the backend; either way, wait for it to die.
7409 InterruptChildProcess (ProcRef pr)
7411 ChildProc *cp = (ChildProc *) pr;
7413 if (cp->kind != CPReal) return;
7414 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7418 OpenTelnet (char *host, char *port, ProcRef *pr)
7420 char cmdLine[MSG_SIZ];
7422 if (port[0] == NULLCHAR) {
7423 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7425 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7427 return StartChildProcess(cmdLine, "", pr);
7431 OpenTCP (char *host, char *port, ProcRef *pr)
7434 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7435 #else /* !OMIT_SOCKETS */
7436 struct addrinfo hints;
7437 struct addrinfo *ais, *ai;
7442 memset(&hints, 0, sizeof(hints));
7443 hints.ai_family = AF_UNSPEC;
7444 hints.ai_socktype = SOCK_STREAM;
7446 error = getaddrinfo(host, port, &hints, &ais);
7448 /* a getaddrinfo error is not an errno, so can't return it */
7449 fprintf(debugFP, "getaddrinfo(%s, %s): %s\n",
7450 host, port, gai_strerror(error));
7454 for (ai = ais; ai != NULL; ai = ai->ai_next) {
7455 if ((s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
7459 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
7472 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7478 #endif /* !OMIT_SOCKETS */
7484 OpenCommPort (char *name, ProcRef *pr)
7489 fd = open(name, 2, 0);
7490 if (fd < 0) return errno;
7492 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7503 OpenLoopback (ProcRef *pr)
7508 SetUpChildIO(to, from);
7510 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7513 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7521 OpenRcmd (char *host, char *user, char *cmd, ProcRef *pr)
7523 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7527 #define INPUT_SOURCE_BUF_SIZE 8192
7536 char buf[INPUT_SOURCE_BUF_SIZE];
7541 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
7543 InputSource *is = (InputSource *) closure;
7548 if (is->lineByLine) {
7549 count = read(is->fd, is->unused,
7550 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7552 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7555 is->unused += count;
7557 while (p < is->unused) {
7558 q = memchr(p, '\n', is->unused - p);
7559 if (q == NULL) break;
7561 (is->func)(is, is->closure, p, q - p, 0);
7565 while (p < is->unused) {
7570 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7575 (is->func)(is, is->closure, is->buf, count, error);
7580 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
7583 ChildProc *cp = (ChildProc *) pr;
7585 is = (InputSource *) calloc(1, sizeof(InputSource));
7586 is->lineByLine = lineByLine;
7590 is->fd = fileno(stdin);
7592 is->kind = cp->kind;
7593 is->fd = cp->fdFrom;
7596 is->unused = is->buf;
7599 is->xid = XtAppAddInput(appContext, is->fd,
7600 (XtPointer) (XtInputReadMask),
7601 (XtInputCallbackProc) DoInputCallback,
7603 is->closure = closure;
7604 return (InputSourceRef) is;
7608 RemoveInputSource (InputSourceRef isr)
7610 InputSource *is = (InputSource *) isr;
7612 if (is->xid == 0) return;
7613 XtRemoveInput(is->xid);
7618 OutputToProcess (ProcRef pr, char *message, int count, int *outError)
7620 static int line = 0;
7621 ChildProc *cp = (ChildProc *) pr;
7626 if (appData.noJoin || !appData.useInternalWrap)
7627 outCount = fwrite(message, 1, count, stdout);
7630 int width = get_term_width();
7631 int len = wrap(NULL, message, count, width, &line);
7632 char *msg = malloc(len);
7636 outCount = fwrite(message, 1, count, stdout);
7639 dbgchk = wrap(msg, message, count, width, &line);
7640 if (dbgchk != len && appData.debugMode)
7641 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7642 outCount = fwrite(msg, 1, dbgchk, stdout);
7648 outCount = write(cp->fdTo, message, count);
7658 /* Output message to process, with "ms" milliseconds of delay
7659 between each character. This is needed when sending the logon
7660 script to ICC, which for some reason doesn't like the
7661 instantaneous send. */
7663 OutputToProcessDelayed (ProcRef pr, char *message, int count, int *outError, long msdelay)
7665 ChildProc *cp = (ChildProc *) pr;
7670 r = write(cp->fdTo, message++, 1);
7683 /**** Animation code by Hugh Fisher, DCS, ANU.
7685 Known problem: if a window overlapping the board is
7686 moved away while a piece is being animated underneath,
7687 the newly exposed area won't be updated properly.
7688 I can live with this.
7690 Known problem: if you look carefully at the animation
7691 of pieces in mono mode, they are being drawn as solid
7692 shapes without interior detail while moving. Fixing
7693 this would be a major complication for minimal return.
7696 /* Masks for XPM pieces. Black and white pieces can have
7697 different shapes, but in the interest of retaining my
7698 sanity pieces must have the same outline on both light
7699 and dark squares, and all pieces must use the same
7700 background square colors/images. */
7702 static int xpmDone = 0;
7705 CreateAnimMasks (int pieceDepth)
7711 unsigned long plane;
7714 /* Need a bitmap just to get a GC with right depth */
7715 buf = XCreatePixmap(xDisplay, xBoardWindow,
7717 values.foreground = 1;
7718 values.background = 0;
7719 /* Don't use XtGetGC, not read only */
7720 maskGC = XCreateGC(xDisplay, buf,
7721 GCForeground | GCBackground, &values);
7722 XFreePixmap(xDisplay, buf);
7724 buf = XCreatePixmap(xDisplay, xBoardWindow,
7725 squareSize, squareSize, pieceDepth);
7726 values.foreground = XBlackPixel(xDisplay, xScreen);
7727 values.background = XWhitePixel(xDisplay, xScreen);
7728 bufGC = XCreateGC(xDisplay, buf,
7729 GCForeground | GCBackground, &values);
7731 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7732 /* Begin with empty mask */
7733 if(!xpmDone) // [HGM] pieces: keep using existing
7734 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7735 squareSize, squareSize, 1);
7736 XSetFunction(xDisplay, maskGC, GXclear);
7737 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7738 0, 0, squareSize, squareSize);
7740 /* Take a copy of the piece */
7745 XSetFunction(xDisplay, bufGC, GXcopy);
7746 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7748 0, 0, squareSize, squareSize, 0, 0);
7750 /* XOR the background (light) over the piece */
7751 XSetFunction(xDisplay, bufGC, GXxor);
7753 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7754 0, 0, squareSize, squareSize, 0, 0);
7756 XSetForeground(xDisplay, bufGC, lightSquareColor);
7757 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7760 /* We now have an inverted piece image with the background
7761 erased. Construct mask by just selecting all the non-zero
7762 pixels - no need to reconstruct the original image. */
7763 XSetFunction(xDisplay, maskGC, GXor);
7765 /* Might be quicker to download an XImage and create bitmap
7766 data from it rather than this N copies per piece, but it
7767 only takes a fraction of a second and there is a much
7768 longer delay for loading the pieces. */
7769 for (n = 0; n < pieceDepth; n ++) {
7770 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7771 0, 0, squareSize, squareSize,
7777 XFreePixmap(xDisplay, buf);
7778 XFreeGC(xDisplay, bufGC);
7779 XFreeGC(xDisplay, maskGC);
7783 InitAnimState (AnimState *anim, XWindowAttributes *info)
7788 /* Each buffer is square size, same depth as window */
7789 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
7790 squareSize, squareSize, info->depth);
7791 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
7792 squareSize, squareSize, info->depth);
7794 /* Create a plain GC for blitting */
7795 mask = GCForeground | GCBackground | GCFunction |
7796 GCPlaneMask | GCGraphicsExposures;
7797 values.foreground = XBlackPixel(xDisplay, xScreen);
7798 values.background = XWhitePixel(xDisplay, xScreen);
7799 values.function = GXcopy;
7800 values.plane_mask = AllPlanes;
7801 values.graphics_exposures = False;
7802 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
7804 /* Piece will be copied from an existing context at
7805 the start of each new animation/drag. */
7806 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
7808 /* Outline will be a read-only copy of an existing */
7809 anim->outlineGC = None;
7815 XWindowAttributes info;
7817 if (xpmDone && gameInfo.variant == oldVariant) return;
7818 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
7819 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
7821 InitAnimState(&game, &info);
7822 InitAnimState(&player, &info);
7824 /* For XPM pieces, we need bitmaps to use as masks. */
7826 CreateAnimMasks(info.depth), xpmDone = 1;
7831 static Boolean frameWaiting;
7834 FrameAlarm (int sig)
7836 frameWaiting = False;
7837 /* In case System-V style signals. Needed?? */
7838 signal(SIGALRM, FrameAlarm);
7842 FrameDelay (int time)
7844 struct itimerval delay;
7846 XSync(xDisplay, False);
7849 frameWaiting = True;
7850 signal(SIGALRM, FrameAlarm);
7851 delay.it_interval.tv_sec =
7852 delay.it_value.tv_sec = time / 1000;
7853 delay.it_interval.tv_usec =
7854 delay.it_value.tv_usec = (time % 1000) * 1000;
7855 setitimer(ITIMER_REAL, &delay, NULL);
7856 while (frameWaiting) pause();
7857 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
7858 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
7859 setitimer(ITIMER_REAL, &delay, NULL);
7866 FrameDelay (int time)
7868 XSync(xDisplay, False);
7870 usleep(time * 1000);
7881 /* Convert board position to corner of screen rect and color */
7884 ScreenSquare (int column, int row, XPoint *pt, int *color)
7887 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
7888 pt->y = lineGap + row * (squareSize + lineGap);
7890 pt->x = lineGap + column * (squareSize + lineGap);
7891 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
7893 *color = SquareColor(row, column);
7896 /* Convert window coords to square */
7899 BoardSquare (int x, int y, int *column, int *row)
7901 *column = EventToSquare(x, BOARD_WIDTH);
7902 if (flipView && *column >= 0)
7903 *column = BOARD_WIDTH - 1 - *column;
7904 *row = EventToSquare(y, BOARD_HEIGHT);
7905 if (!flipView && *row >= 0)
7906 *row = BOARD_HEIGHT - 1 - *row;
7911 #undef Max /* just in case */
7913 #define Max(a, b) ((a) > (b) ? (a) : (b))
7914 #define Min(a, b) ((a) < (b) ? (a) : (b))
7917 SetRect (XRectangle *rect, int x, int y, int width, int height)
7921 rect->width = width;
7922 rect->height = height;
7925 /* Test if two frames overlap. If they do, return
7926 intersection rect within old and location of
7927 that rect within new. */
7930 Intersect ( XPoint *old, XPoint *new, int size, XRectangle *area, XPoint *pt)
7932 if (old->x > new->x + size || new->x > old->x + size ||
7933 old->y > new->y + size || new->y > old->y + size) {
7936 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
7937 size - abs(old->x - new->x), size - abs(old->y - new->y));
7938 pt->x = Max(old->x - new->x, 0);
7939 pt->y = Max(old->y - new->y, 0);
7944 /* For two overlapping frames, return the rect(s)
7945 in the old that do not intersect with the new. */
7948 CalcUpdateRects (XPoint *old, XPoint *new, int size, XRectangle update[], int *nUpdates)
7952 /* If old = new (shouldn't happen) then nothing to draw */
7953 if (old->x == new->x && old->y == new->y) {
7957 /* Work out what bits overlap. Since we know the rects
7958 are the same size we don't need a full intersect calc. */
7960 /* Top or bottom edge? */
7961 if (new->y > old->y) {
7962 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
7964 } else if (old->y > new->y) {
7965 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
7966 size, old->y - new->y);
7969 /* Left or right edge - don't overlap any update calculated above. */
7970 if (new->x > old->x) {
7971 SetRect(&(update[count]), old->x, Max(new->y, old->y),
7972 new->x - old->x, size - abs(new->y - old->y));
7974 } else if (old->x > new->x) {
7975 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
7976 old->x - new->x, size - abs(new->y - old->y));
7983 /* Generate a series of frame coords from start->mid->finish.
7984 The movement rate doubles until the half way point is
7985 reached, then halves back down to the final destination,
7986 which gives a nice slow in/out effect. The algorithmn
7987 may seem to generate too many intermediates for short
7988 moves, but remember that the purpose is to attract the
7989 viewers attention to the piece about to be moved and
7990 then to where it ends up. Too few frames would be less
7994 Tween (XPoint *start, XPoint *mid, XPoint *finish, int factor, XPoint frames[], int *nFrames)
7996 int fraction, n, count;
8000 /* Slow in, stepping 1/16th, then 1/8th, ... */
8002 for (n = 0; n < factor; n++)
8004 for (n = 0; n < factor; n++) {
8005 frames[count].x = start->x + (mid->x - start->x) / fraction;
8006 frames[count].y = start->y + (mid->y - start->y) / fraction;
8008 fraction = fraction / 2;
8012 frames[count] = *mid;
8015 /* Slow out, stepping 1/2, then 1/4, ... */
8017 for (n = 0; n < factor; n++) {
8018 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8019 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8021 fraction = fraction * 2;
8026 /* Draw a piece on the screen without disturbing what's there */
8029 SelectGCMask (ChessSquare piece, GC *clip, GC *outline, Pixmap *mask)
8033 /* Bitmap for piece being moved. */
8034 if (appData.monoMode) {
8035 *mask = *pieceToSolid(piece);
8036 } else if (useImages) {
8038 *mask = xpmMask[piece];
8040 *mask = ximMaskPm[piece];
8043 *mask = *pieceToSolid(piece);
8046 /* GC for piece being moved. Square color doesn't matter, but
8047 since it gets modified we make a copy of the original. */
8049 if (appData.monoMode)
8054 if (appData.monoMode)
8059 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8061 /* Outline only used in mono mode and is not modified */
8063 *outline = bwPieceGC;
8065 *outline = wbPieceGC;
8069 OverlayPiece (ChessSquare piece, GC clip, GC outline, Drawable dest)
8074 /* Draw solid rectangle which will be clipped to shape of piece */
8075 XFillRectangle(xDisplay, dest, clip,
8076 0, 0, squareSize, squareSize);
8077 if (appData.monoMode)
8078 /* Also draw outline in contrasting color for black
8079 on black / white on white cases */
8080 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8081 0, 0, squareSize, squareSize, 0, 0, 1);
8083 /* Copy the piece */
8088 if(appData.upsideDown && flipView) kind ^= 2;
8089 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8091 0, 0, squareSize, squareSize,
8096 /* Animate the movement of a single piece */
8099 BeginAnimation (AnimState *anim, ChessSquare piece, int startColor, XPoint *start)
8103 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8104 /* The old buffer is initialised with the start square (empty) */
8105 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8106 anim->prevFrame = *start;
8108 /* The piece will be drawn using its own bitmap as a matte */
8109 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8110 XSetClipMask(xDisplay, anim->pieceGC, mask);
8114 AnimationFrame (AnimState *anim, XPoint *frame, ChessSquare piece)
8116 XRectangle updates[4];
8121 /* Save what we are about to draw into the new buffer */
8122 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8123 frame->x, frame->y, squareSize, squareSize,
8126 /* Erase bits of the previous frame */
8127 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8128 /* Where the new frame overlapped the previous,
8129 the contents in newBuf are wrong. */
8130 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8131 overlap.x, overlap.y,
8132 overlap.width, overlap.height,
8134 /* Repaint the areas in the old that don't overlap new */
8135 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8136 for (i = 0; i < count; i++)
8137 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8138 updates[i].x - anim->prevFrame.x,
8139 updates[i].y - anim->prevFrame.y,
8140 updates[i].width, updates[i].height,
8141 updates[i].x, updates[i].y);
8143 /* Easy when no overlap */
8144 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8145 0, 0, squareSize, squareSize,
8146 anim->prevFrame.x, anim->prevFrame.y);
8149 /* Save this frame for next time round */
8150 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8151 0, 0, squareSize, squareSize,
8153 anim->prevFrame = *frame;
8155 /* Draw piece over original screen contents, not current,
8156 and copy entire rect. Wipes out overlapping piece images. */
8157 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8158 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8159 0, 0, squareSize, squareSize,
8160 frame->x, frame->y);
8164 EndAnimation (AnimState *anim, XPoint *finish)
8166 XRectangle updates[4];
8171 /* The main code will redraw the final square, so we
8172 only need to erase the bits that don't overlap. */
8173 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8174 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8175 for (i = 0; i < count; i++)
8176 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8177 updates[i].x - anim->prevFrame.x,
8178 updates[i].y - anim->prevFrame.y,
8179 updates[i].width, updates[i].height,
8180 updates[i].x, updates[i].y);
8182 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8183 0, 0, squareSize, squareSize,
8184 anim->prevFrame.x, anim->prevFrame.y);
8189 FrameSequence (AnimState *anim, ChessSquare piece, int startColor, XPoint *start, XPoint *finish, XPoint frames[], int nFrames)
8193 BeginAnimation(anim, piece, startColor, start);
8194 for (n = 0; n < nFrames; n++) {
8195 AnimationFrame(anim, &(frames[n]), piece);
8196 FrameDelay(appData.animSpeed);
8198 EndAnimation(anim, finish);
8202 AnimateAtomicCapture (Board board, int fromX, int fromY, int toX, int toY)
8205 ChessSquare piece = board[fromY][toY];
8206 board[fromY][toY] = EmptySquare;
8207 DrawPosition(FALSE, board);
8209 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8210 y = lineGap + toY * (squareSize + lineGap);
8212 x = lineGap + toX * (squareSize + lineGap);
8213 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8215 for(i=1; i<4*kFactor; i++) {
8216 int r = squareSize * 9 * i/(20*kFactor - 5);
8217 XFillArc(xDisplay, xBoardWindow, highlineGC,
8218 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8219 FrameDelay(appData.animSpeed);
8221 board[fromY][toY] = piece;
8224 /* Main control logic for deciding what to animate and how */
8227 AnimateMove (Board board, int fromX, int fromY, int toX, int toY)
8231 XPoint start, finish, mid;
8232 XPoint frames[kFactor * 2 + 1];
8233 int nFrames, startColor, endColor;
8235 /* Are we animating? */
8236 if (!appData.animate || appData.blindfold)
8239 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8240 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8241 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8243 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8244 piece = board[fromY][fromX];
8245 if (piece >= EmptySquare) return;
8250 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8253 ScreenSquare(fromX, fromY, &start, &startColor);
8254 ScreenSquare(toX, toY, &finish, &endColor);
8257 /* Knight: make straight movement then diagonal */
8258 if (abs(toY - fromY) < abs(toX - fromX)) {
8259 mid.x = start.x + (finish.x - start.x) / 2;
8263 mid.y = start.y + (finish.y - start.y) / 2;
8266 mid.x = start.x + (finish.x - start.x) / 2;
8267 mid.y = start.y + (finish.y - start.y) / 2;
8270 /* Don't use as many frames for very short moves */
8271 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8272 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8274 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8275 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8276 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8278 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8279 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8282 /* Be sure end square is redrawn */
8283 damage[0][toY][toX] = True;
8287 DragPieceBegin (int x, int y, Boolean instantly)
8289 int boardX, boardY, color;
8292 /* Are we animating? */
8293 if (!appData.animateDragging || appData.blindfold)
8296 /* Figure out which square we start in and the
8297 mouse position relative to top left corner. */
8298 BoardSquare(x, y, &boardX, &boardY);
8299 player.startBoardX = boardX;
8300 player.startBoardY = boardY;
8301 ScreenSquare(boardX, boardY, &corner, &color);
8302 player.startSquare = corner;
8303 player.startColor = color;
8304 /* As soon as we start dragging, the piece will jump slightly to
8305 be centered over the mouse pointer. */
8306 player.mouseDelta.x = squareSize/2;
8307 player.mouseDelta.y = squareSize/2;
8308 /* Initialise animation */
8309 player.dragPiece = PieceForSquare(boardX, boardY);
8311 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8312 player.dragActive = True;
8313 BeginAnimation(&player, player.dragPiece, color, &corner);
8314 /* Mark this square as needing to be redrawn. Note that
8315 we don't remove the piece though, since logically (ie
8316 as seen by opponent) the move hasn't been made yet. */
8317 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8318 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8319 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8320 corner.x, corner.y, squareSize, squareSize,
8321 0, 0); // [HGM] zh: unstack in stead of grab
8322 if(gatingPiece != EmptySquare) {
8323 /* Kludge alert: When gating we want the introduced
8324 piece to appear on the from square. To generate an
8325 image of it, we draw it on the board, copy the image,
8326 and draw the original piece again. */
8327 ChessSquare piece = boards[currentMove][boardY][boardX];
8328 DrawSquare(boardY, boardX, gatingPiece, 0);
8329 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8330 corner.x, corner.y, squareSize, squareSize, 0, 0);
8331 DrawSquare(boardY, boardX, piece, 0);
8333 damage[0][boardY][boardX] = True;
8335 player.dragActive = False;
8340 ChangeDragPiece (ChessSquare piece)
8343 player.dragPiece = piece;
8344 /* The piece will be drawn using its own bitmap as a matte */
8345 SelectGCMask(piece, &player.pieceGC, &player.outlineGC, &mask);
8346 XSetClipMask(xDisplay, player.pieceGC, mask);
8350 DragPieceMove (int x, int y)
8354 /* Are we animating? */
8355 if (!appData.animateDragging || appData.blindfold)
8359 if (! player.dragActive)
8361 /* Move piece, maintaining same relative position
8362 of mouse within square */
8363 corner.x = x - player.mouseDelta.x;
8364 corner.y = y - player.mouseDelta.y;
8365 AnimationFrame(&player, &corner, player.dragPiece);
8367 if (appData.highlightDragging) {
8369 BoardSquare(x, y, &boardX, &boardY);
8370 SetHighlights(fromX, fromY, boardX, boardY);
8376 DragPieceEnd (int x, int y)
8378 int boardX, boardY, color;
8381 /* Are we animating? */
8382 if (!appData.animateDragging || appData.blindfold)
8386 if (! player.dragActive)
8388 /* Last frame in sequence is square piece is
8389 placed on, which may not match mouse exactly. */
8390 BoardSquare(x, y, &boardX, &boardY);
8391 ScreenSquare(boardX, boardY, &corner, &color);
8392 EndAnimation(&player, &corner);
8394 /* Be sure end square is redrawn */
8395 damage[0][boardY][boardX] = True;
8397 /* This prevents weird things happening with fast successive
8398 clicks which on my Sun at least can cause motion events
8399 without corresponding press/release. */
8400 player.dragActive = False;
8403 /* Handle expose event while piece being dragged */
8408 if (!player.dragActive || appData.blindfold)
8411 /* What we're doing: logically, the move hasn't been made yet,
8412 so the piece is still in it's original square. But visually
8413 it's being dragged around the board. So we erase the square
8414 that the piece is on and draw it at the last known drag point. */
8415 BlankSquare(player.startSquare.x, player.startSquare.y,
8416 player.startColor, EmptySquare, xBoardWindow, 1);
8417 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8418 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8421 #include <sys/ioctl.h>
8425 int fd, default_width;
8428 default_width = 79; // this is FICS default anyway...
8430 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8432 if (!ioctl(fd, TIOCGSIZE, &win))
8433 default_width = win.ts_cols;
8434 #elif defined(TIOCGWINSZ)
8436 if (!ioctl(fd, TIOCGWINSZ, &win))
8437 default_width = win.ws_col;
8439 return default_width;
8445 static int old_width = 0;
8446 int new_width = get_term_width();
8448 if (old_width != new_width)
8449 ics_printf("set width %d\n", new_width);
8450 old_width = new_width;
8454 NotifyFrontendLogin ()
8459 /* [AS] Arrow highlighting support */
8461 static double A_WIDTH = 5; /* Width of arrow body */
8463 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8464 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8475 return (int) (x + 0.5);
8479 SquareToPos (int rank, int file, int *x, int *y)
8482 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8483 *y = lineGap + rank * (squareSize + lineGap);
8485 *x = lineGap + file * (squareSize + lineGap);
8486 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8490 /* Draw an arrow between two points using current settings */
8492 DrawArrowBetweenPoints (int s_x, int s_y, int d_x, int d_y)
8495 double dx, dy, j, k, x, y;
8498 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8500 arrow[0].x = s_x + A_WIDTH + 0.5;
8503 arrow[1].x = s_x + A_WIDTH + 0.5;
8504 arrow[1].y = d_y - h;
8506 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8507 arrow[2].y = d_y - h;
8512 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8513 arrow[5].y = d_y - h;
8515 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8516 arrow[4].y = d_y - h;
8518 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8521 else if( d_y == s_y ) {
8522 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8525 arrow[0].y = s_y + A_WIDTH + 0.5;
8527 arrow[1].x = d_x - w;
8528 arrow[1].y = s_y + A_WIDTH + 0.5;
8530 arrow[2].x = d_x - w;
8531 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8536 arrow[5].x = d_x - w;
8537 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8539 arrow[4].x = d_x - w;
8540 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8543 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8546 /* [AS] Needed a lot of paper for this! :-) */
8547 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8548 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8550 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8552 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8557 arrow[0].x = Round(x - j);
8558 arrow[0].y = Round(y + j*dx);
8560 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8561 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8564 x = (double) d_x - k;
8565 y = (double) d_y - k*dy;
8568 x = (double) d_x + k;
8569 y = (double) d_y + k*dy;
8572 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8574 arrow[6].x = Round(x - j);
8575 arrow[6].y = Round(y + j*dx);
8577 arrow[2].x = Round(arrow[6].x + 2*j);
8578 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8580 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8581 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8586 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8587 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8590 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8591 if(appData.monoMode) arrow[7] = arrow[0], XDrawLines(xDisplay, xBoardWindow, darkSquareGC, arrow, 8, CoordModeOrigin);
8592 // Polygon( hdc, arrow, 7 );
8596 ArrowDamage (int s_col, int s_row, int d_col, int d_row)
8599 hor = 64*s_col + 32; vert = 64*s_row + 32;
8600 for(i=0; i<= 64; i++) {
8601 damage[0][vert+6>>6][hor+6>>6] = True;
8602 damage[0][vert-6>>6][hor+6>>6] = True;
8603 damage[0][vert+6>>6][hor-6>>6] = True;
8604 damage[0][vert-6>>6][hor-6>>6] = True;
8605 hor += d_col - s_col; vert += d_row - s_row;
8609 /* [AS] Draw an arrow between two squares */
8611 DrawArrowBetweenSquares (int s_col, int s_row, int d_col, int d_row)
8613 int s_x, s_y, d_x, d_y;
8615 if( s_col == d_col && s_row == d_row ) {
8619 /* Get source and destination points */
8620 SquareToPos( s_row, s_col, &s_x, &s_y);
8621 SquareToPos( d_row, d_col, &d_x, &d_y);
8624 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8626 else if( d_y < s_y ) {
8627 d_y += squareSize / 2 + squareSize / 4;
8630 d_y += squareSize / 2;
8634 d_x += squareSize / 2 - squareSize / 4;
8636 else if( d_x < s_x ) {
8637 d_x += squareSize / 2 + squareSize / 4;
8640 d_x += squareSize / 2;
8643 s_x += squareSize / 2;
8644 s_y += squareSize / 2;
8647 A_WIDTH = squareSize / 14.; //[HGM] make float
8649 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
8650 ArrowDamage(s_col, s_row, d_col, d_row);
8654 IsDrawArrowEnabled ()
8656 return appData.highlightMoveWithArrow && squareSize >= 32;
8660 DrawArrowHighlight (int fromX, int fromY, int toX,int toY)
8662 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
8663 DrawArrowBetweenSquares(fromX, fromY, toX, toY);
8667 UpdateLogos (int displ)
8669 return; // no logos in XBoard yet