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 Pixel timerForegroundPixel, timerBackgroundPixel;
544 Pixel buttonForegroundPixel, buttonBackgroundPixel;
545 char *chessDir, *programName, *programVersion,
546 *gameCopyFilename, *gamePasteFilename;
547 Boolean alwaysOnTop = False;
548 Boolean saveSettingsOnExit;
549 char *settingsFileName;
550 char *icsTextMenuString;
552 char *firstChessProgramNames;
553 char *secondChessProgramNames;
555 WindowPlacement wpMain;
556 WindowPlacement wpConsole;
557 WindowPlacement wpComment;
558 WindowPlacement wpMoveHistory;
559 WindowPlacement wpEvalGraph;
560 WindowPlacement wpEngineOutput;
561 WindowPlacement wpGameList;
562 WindowPlacement wpTags;
564 extern Widget shells[];
565 extern Boolean shellUp[];
569 Pixmap pieceBitmap[2][(int)BlackPawn];
570 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
571 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
572 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
573 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
574 Pixmap xpmBoardBitmap[2];
575 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
576 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
577 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
578 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
579 XImage *ximLightSquare, *ximDarkSquare;
582 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
583 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
585 #define White(piece) ((int)(piece) < (int)BlackPawn)
587 /* Variables for doing smooth animation. This whole thing
588 would be much easier if the board was double-buffered,
589 but that would require a fairly major rewrite. */
594 GC blitGC, pieceGC, outlineGC;
595 XPoint startSquare, prevFrame, mouseDelta;
599 int startBoardX, startBoardY;
602 /* There can be two pieces being animated at once: a player
603 can begin dragging a piece before the remote opponent has moved. */
605 static AnimState game, player;
607 /* Bitmaps for use as masks when drawing XPM pieces.
608 Need one for each black and white piece. */
609 static Pixmap xpmMask[BlackKing + 1];
611 /* This magic number is the number of intermediate frames used
612 in each half of the animation. For short moves it's reduced
613 by 1. The total number of frames will be factor * 2 + 1. */
616 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
618 MenuItem fileMenu[] = {
619 {N_("New Game Ctrl+N"), "New Game", ResetProc},
620 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
621 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
622 {"----", NULL, NothingProc},
623 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
624 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
625 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
626 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
627 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
628 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
629 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
630 {"----", NULL, NothingProc},
631 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
632 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
633 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
634 {"----", NULL, NothingProc},
635 {N_("Mail Move"), "Mail Move", MailMoveProc},
636 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
637 {"----", NULL, NothingProc},
638 {N_("Quit Ctr+Q"), "Exit", QuitProc},
642 MenuItem editMenu[] = {
643 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
644 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
645 {N_("Copy Game List"), "Copy Game List", CopyGameListProc},
646 {"----", NULL, NothingProc},
647 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
648 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
649 {"----", NULL, NothingProc},
650 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
651 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
652 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
653 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
654 {N_("Edit Book"), "Edit Book", EditBookProc},
655 {"----", NULL, NothingProc},
656 {N_("Revert Home"), "Revert", RevertProc},
657 {N_("Annotate"), "Annotate", AnnotateProc},
658 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
659 {"----", NULL, NothingProc},
660 {N_("Backward Alt+Left"), "Backward", BackwardProc},
661 {N_("Forward Alt+Right"), "Forward", ForwardProc},
662 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
663 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
667 MenuItem viewMenu[] = {
668 {N_("Flip View F2"), "Flip View", FlipViewProc},
669 {"----", NULL, NothingProc},
670 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
671 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
672 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
673 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
674 {N_("ICS text menu"), "ICStex", IcsTextProc},
675 {"----", NULL, NothingProc},
676 {N_("Tags"), "Show Tags", EditTagsProc},
677 {N_("Comments"), "Show Comments", EditCommentProc},
678 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
679 {"----", NULL, NothingProc},
680 {N_("Board..."), "Board Options", BoardOptionsProc},
681 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
685 MenuItem modeMenu[] = {
686 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
687 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
688 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
689 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
690 {N_("Analyze Game Ctrl+G"), "Analyze File", AnalyzeFileProc },
691 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
692 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
693 {N_("Training"), "Training", TrainingProc},
694 {N_("ICS Client"), "ICS Client", IcsClientProc},
695 {"----", NULL, NothingProc},
696 {N_("Machine Match"), "Machine Match", MatchProc},
697 {N_("Pause Pause"), "Pause", PauseProc},
701 MenuItem actionMenu[] = {
702 {N_("Accept F3"), "Accept", AcceptProc},
703 {N_("Decline F4"), "Decline", DeclineProc},
704 {N_("Rematch F12"), "Rematch", RematchProc},
705 {"----", NULL, NothingProc},
706 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
707 {N_("Draw F6"), "Draw", DrawProc},
708 {N_("Adjourn F7"), "Adjourn", AdjournProc},
709 {N_("Abort F8"),"Abort", AbortProc},
710 {N_("Resign F9"), "Resign", ResignProc},
711 {"----", NULL, NothingProc},
712 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
713 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
714 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
715 {"----", NULL, NothingProc},
716 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
717 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
718 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
722 MenuItem engineMenu[] = {
723 {N_("Load New Engine ..."), "Load Engine", LoadEngineProc},
724 {"----", NULL, NothingProc},
725 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
726 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
727 {"----", NULL, NothingProc},
728 {N_("Hint"), "Hint", HintProc},
729 {N_("Book"), "Book", BookProc},
730 {"----", NULL, NothingProc},
731 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
732 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
736 MenuItem optionsMenu[] = {
737 #define OPTIONSDIALOG
739 {N_("General ..."), "General", OptionsProc},
741 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
742 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
743 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
744 {N_("ICS ..."), "ICS", IcsOptionsProc},
745 {N_("Match ..."), "Match", MatchOptionsProc},
746 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
747 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
748 // {N_(" ..."), "", OptionsProc},
749 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
750 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
751 {"----", NULL, NothingProc},
752 #ifndef OPTIONSDIALOG
753 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
754 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
755 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
756 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
757 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
758 {N_("Blindfold"), "Blindfold", BlindfoldProc},
759 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
761 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
763 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
764 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
765 {N_("Move Sound"), "Move Sound", MoveSoundProc},
766 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
767 {N_("One-Click Moving"), "OneClick", OneClickProc},
768 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
769 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
770 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
771 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
772 // {N_("Premove"), "Premove", PremoveProc},
773 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
774 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
775 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
776 {"----", NULL, NothingProc},
778 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
779 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
783 MenuItem helpMenu[] = {
784 {N_("Info XBoard"), "Info XBoard", InfoProc},
785 {N_("Man XBoard F1"), "Man XBoard", ManProc},
786 {"----", NULL, NothingProc},
787 {N_("About XBoard"), "About XBoard", AboutProc},
792 {N_("File"), "File", fileMenu},
793 {N_("Edit"), "Edit", editMenu},
794 {N_("View"), "View", viewMenu},
795 {N_("Mode"), "Mode", modeMenu},
796 {N_("Action"), "Action", actionMenu},
797 {N_("Engine"), "Engine", engineMenu},
798 {N_("Options"), "Options", optionsMenu},
799 {N_("Help"), "Help", helpMenu},
803 #define PAUSE_BUTTON "P"
804 MenuItem buttonBar[] = {
805 {"<<", "<<", ToStartProc},
806 {"<", "<", BackwardProc},
807 {N_(PAUSE_BUTTON), PAUSE_BUTTON, PauseProc},
808 {">", ">", ForwardProc},
809 {">>", ">>", ToEndProc},
813 #define PIECE_MENU_SIZE 18
814 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
815 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
816 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
817 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
818 N_("Empty square"), N_("Clear board") },
819 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
820 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
821 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
822 N_("Empty square"), N_("Clear board") }
824 /* must be in same order as pieceMenuStrings! */
825 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
826 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
827 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
828 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
829 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
830 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
831 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
832 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
833 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
836 #define DROP_MENU_SIZE 6
837 String dropMenuStrings[DROP_MENU_SIZE] = {
838 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
840 /* must be in same order as dropMenuStrings! */
841 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
842 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
843 WhiteRook, WhiteQueen
851 DropMenuEnables dmEnables[] = {
869 { XtNborderWidth, 0 },
870 { XtNdefaultDistance, 0 },
874 { XtNborderWidth, 0 },
875 { XtNresizable, (XtArgVal) True },
879 { XtNborderWidth, 0 },
885 { XtNjustify, (XtArgVal) XtJustifyRight },
886 { XtNlabel, (XtArgVal) "..." },
887 { XtNresizable, (XtArgVal) True },
888 { XtNresize, (XtArgVal) False }
891 Arg messageArgs[] = {
892 { XtNjustify, (XtArgVal) XtJustifyLeft },
893 { XtNlabel, (XtArgVal) "..." },
894 { XtNresizable, (XtArgVal) True },
895 { XtNresize, (XtArgVal) False }
899 { XtNborderWidth, 0 },
900 { XtNjustify, (XtArgVal) XtJustifyLeft }
903 XtResource clientResources[] = {
904 { "flashCount", "flashCount", XtRInt, sizeof(int),
905 XtOffset(AppDataPtr, flashCount), XtRImmediate,
906 (XtPointer) FLASH_COUNT },
909 XrmOptionDescRec shellOptions[] = {
910 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
911 { "-flash", "flashCount", XrmoptionNoArg, "3" },
912 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
915 XtActionsRec boardActions[] = {
916 { "DrawPosition", DrawPositionProc },
917 { "HandleUserMove", HandleUserMove },
918 { "AnimateUserMove", AnimateUserMove },
919 { "HandlePV", HandlePV },
920 { "SelectPV", SelectPV },
921 { "StopPV", StopPV },
922 { "FileNameAction", FileNameAction },
923 { "AskQuestionProc", AskQuestionProc },
924 { "AskQuestionReplyAction", AskQuestionReplyAction },
925 { "PieceMenuPopup", PieceMenuPopup },
926 { "WhiteClock", WhiteClock },
927 { "BlackClock", BlackClock },
928 { "ResetProc", ResetProc },
929 { "NewVariantProc", NewVariantProc },
930 { "LoadGameProc", LoadGameProc },
931 { "LoadNextGameProc", LoadNextGameProc },
932 { "LoadPrevGameProc", LoadPrevGameProc },
933 { "LoadSelectedProc", LoadSelectedProc },
934 { "SetFilterProc", SetFilterProc },
935 { "ReloadGameProc", ReloadGameProc },
936 { "LoadPositionProc", LoadPositionProc },
937 { "LoadNextPositionProc", LoadNextPositionProc },
938 { "LoadPrevPositionProc", LoadPrevPositionProc },
939 { "ReloadPositionProc", ReloadPositionProc },
940 { "CopyPositionProc", CopyPositionProc },
941 { "PastePositionProc", PastePositionProc },
942 { "CopyGameProc", CopyGameProc },
943 { "CopyGameListProc", CopyGameListProc },
944 { "PasteGameProc", PasteGameProc },
945 { "SaveGameProc", SaveGameProc },
946 { "SavePositionProc", SavePositionProc },
947 { "MailMoveProc", MailMoveProc },
948 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
949 { "QuitProc", QuitProc },
950 { "MachineWhiteProc", MachineWhiteProc },
951 { "MachineBlackProc", MachineBlackProc },
952 { "AnalysisModeProc", AnalyzeModeProc },
953 { "AnalyzeFileProc", AnalyzeFileProc },
954 { "TwoMachinesProc", TwoMachinesProc },
955 { "IcsClientProc", IcsClientProc },
956 { "EditGameProc", EditGameProc },
957 { "EditPositionProc", EditPositionProc },
958 { "TrainingProc", EditPositionProc },
959 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
960 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
961 { "ShowGameListProc", ShowGameListProc },
962 { "ShowMoveListProc", HistoryShowProc},
963 { "EditTagsProc", EditCommentProc },
964 { "EditBookProc", EditBookProc },
965 { "EditCommentProc", EditCommentProc },
966 { "IcsInputBoxProc", IcsInputBoxProc },
967 { "PauseProc", PauseProc },
968 { "AcceptProc", AcceptProc },
969 { "DeclineProc", DeclineProc },
970 { "RematchProc", RematchProc },
971 { "CallFlagProc", CallFlagProc },
972 { "DrawProc", DrawProc },
973 { "AdjournProc", AdjournProc },
974 { "AbortProc", AbortProc },
975 { "ResignProc", ResignProc },
976 { "AdjuWhiteProc", AdjuWhiteProc },
977 { "AdjuBlackProc", AdjuBlackProc },
978 { "AdjuDrawProc", AdjuDrawProc },
979 { "TypeInProc", TypeInProc },
980 { "EnterKeyProc", EnterKeyProc },
981 { "UpKeyProc", UpKeyProc },
982 { "DownKeyProc", DownKeyProc },
983 { "StopObservingProc", StopObservingProc },
984 { "StopExaminingProc", StopExaminingProc },
985 { "UploadProc", UploadProc },
986 { "BackwardProc", BackwardProc },
987 { "ForwardProc", ForwardProc },
988 { "TempBackwardProc", TempBackwardProc },
989 { "TempForwardProc", TempForwardProc },
990 { "ToStartProc", ToStartProc },
991 { "ToEndProc", ToEndProc },
992 { "RevertProc", RevertProc },
993 { "AnnotateProc", AnnotateProc },
994 { "TruncateGameProc", TruncateGameProc },
995 { "MoveNowProc", MoveNowProc },
996 { "RetractMoveProc", RetractMoveProc },
997 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
998 { "UciMenuProc", (XtActionProc) UciMenuProc },
999 { "TimeControlProc", (XtActionProc) TimeControlProc },
1000 { "FlipViewProc", FlipViewProc },
1001 { "PonderNextMoveProc", PonderNextMoveProc },
1002 #ifndef OPTIONSDIALOG
1003 { "AlwaysQueenProc", AlwaysQueenProc },
1004 { "AnimateDraggingProc", AnimateDraggingProc },
1005 { "AnimateMovingProc", AnimateMovingProc },
1006 { "AutoflagProc", AutoflagProc },
1007 { "AutoflipProc", AutoflipProc },
1008 { "BlindfoldProc", BlindfoldProc },
1009 { "FlashMovesProc", FlashMovesProc },
1011 { "HighlightDraggingProc", HighlightDraggingProc },
1013 { "HighlightLastMoveProc", HighlightLastMoveProc },
1014 // { "IcsAlarmProc", IcsAlarmProc },
1015 { "MoveSoundProc", MoveSoundProc },
1016 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1017 { "PopupExitMessageProc", PopupExitMessageProc },
1018 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1019 // { "PremoveProc", PremoveProc },
1020 { "ShowCoordsProc", ShowCoordsProc },
1021 { "ShowThinkingProc", ShowThinkingProc },
1022 { "HideThinkingProc", HideThinkingProc },
1023 { "TestLegalityProc", TestLegalityProc },
1025 { "SaveSettingsProc", SaveSettingsProc },
1026 { "SaveOnExitProc", SaveOnExitProc },
1027 { "InfoProc", InfoProc },
1028 { "ManProc", ManProc },
1029 { "HintProc", HintProc },
1030 { "BookProc", BookProc },
1031 { "AboutGameProc", AboutGameProc },
1032 { "AboutProc", AboutProc },
1033 { "DebugProc", DebugProc },
1034 { "NothingProc", NothingProc },
1035 { "CommentClick", (XtActionProc) CommentClick },
1036 { "CommentPopDown", (XtActionProc) CommentPopDown },
1037 { "TagsPopDown", (XtActionProc) TagsPopDown },
1038 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1039 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1040 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1041 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1042 { "GameListPopDown", (XtActionProc) GameListPopDown },
1043 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1044 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1045 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1046 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1047 { "GenericPopDown", (XtActionProc) GenericPopDown },
1048 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1049 { "SelectMove", (XtActionProc) SelectMove },
1052 char globalTranslations[] =
1053 ":<Key>F9: ResignProc() \n \
1054 :Ctrl<Key>n: ResetProc() \n \
1055 :Meta<Key>V: NewVariantProc() \n \
1056 :Ctrl<Key>o: LoadGameProc() \n \
1057 :Meta<Key>Next: LoadNextGameProc() \n \
1058 :Meta<Key>Prior: LoadPrevGameProc() \n \
1059 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
1060 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
1061 :Ctrl<Key>s: SaveGameProc() \n \
1062 :Ctrl<Key>c: CopyGameProc() \n \
1063 :Ctrl<Key>v: PasteGameProc() \n \
1064 :Ctrl<Key>O: LoadPositionProc() \n \
1065 :Shift<Key>Next: LoadNextPositionProc() \n \
1066 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1067 :Ctrl<Key>S: SavePositionProc() \n \
1068 :Ctrl<Key>C: CopyPositionProc() \n \
1069 :Ctrl<Key>V: PastePositionProc() \n \
1070 :Ctrl<Key>q: QuitProc() \n \
1071 :Ctrl<Key>w: MachineWhiteProc() \n \
1072 :Ctrl<Key>b: MachineBlackProc() \n \
1073 :Ctrl<Key>t: TwoMachinesProc() \n \
1074 :Ctrl<Key>a: AnalysisModeProc() \n \
1075 :Ctrl<Key>g: AnalyzeFileProc() \n \
1076 :Ctrl<Key>e: EditGameProc() \n \
1077 :Ctrl<Key>E: EditPositionProc() \n \
1078 :Meta<Key>O: EngineOutputProc() \n \
1079 :Meta<Key>E: EvalGraphProc() \n \
1080 :Meta<Key>G: ShowGameListProc() \n \
1081 :Meta<Key>H: ShowMoveListProc() \n \
1082 :<Key>Pause: PauseProc() \n \
1083 :<Key>F3: AcceptProc() \n \
1084 :<Key>F4: DeclineProc() \n \
1085 :<Key>F12: RematchProc() \n \
1086 :<Key>F5: CallFlagProc() \n \
1087 :<Key>F6: DrawProc() \n \
1088 :<Key>F7: AdjournProc() \n \
1089 :<Key>F8: AbortProc() \n \
1090 :<Key>F10: StopObservingProc() \n \
1091 :<Key>F11: StopExaminingProc() \n \
1092 :Meta Ctrl<Key>F12: DebugProc() \n \
1093 :Meta<Key>End: ToEndProc() \n \
1094 :Meta<Key>Right: ForwardProc() \n \
1095 :Meta<Key>Home: ToStartProc() \n \
1096 :Meta<Key>Left: BackwardProc() \n \
1097 :<Key>Left: BackwardProc() \n \
1098 :<Key>Right: ForwardProc() \n \
1099 :<Key>Home: RevertProc() \n \
1100 :<Key>End: TruncateGameProc() \n \
1101 :Ctrl<Key>m: MoveNowProc() \n \
1102 :Ctrl<Key>x: RetractMoveProc() \n \
1103 :Meta<Key>J: EngineMenuProc() \n \
1104 :Meta<Key>U: UciMenuProc() \n \
1105 :Meta<Key>T: TimeControlProc() \n \
1106 :Ctrl<Key>P: PonderNextMoveProc() \n "
1107 #ifndef OPTIONSDIALOG
1109 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1110 :Ctrl<Key>F: AutoflagProc() \n \
1111 :Ctrl<Key>A: AnimateMovingProc() \n \
1112 :Ctrl<Key>L: TestLegalityProc() \n \
1113 :Ctrl<Key>H: HideThinkingProc() \n "
1116 :<Key>F1: ManProc() \n \
1117 :<Key>F2: FlipViewProc() \n \
1118 :<KeyDown>Return: TempBackwardProc() \n \
1119 :<KeyUp>Return: TempForwardProc() \n \
1120 :Ctrl<Key>1: AskQuestionProc(\"Direct command\",\
1121 \"Send to chess program:\",,1) \n \
1122 :Ctrl<Key>2: AskQuestionProc(\"Direct command\",\
1123 \"Send to second chess program:\",,2) \n";
1125 char boardTranslations[] =
1126 "<Btn1Down>: HandleUserMove(0) \n \
1127 Shift<Btn1Up>: HandleUserMove(1) \n \
1128 <Btn1Up>: HandleUserMove(0) \n \
1129 <Btn1Motion>: AnimateUserMove() \n \
1130 <Btn3Motion>: HandlePV() \n \
1131 <Btn3Up>: PieceMenuPopup(menuB) \n \
1132 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1133 PieceMenuPopup(menuB) \n \
1134 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1135 PieceMenuPopup(menuW) \n \
1136 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1137 PieceMenuPopup(menuW) \n \
1138 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1139 PieceMenuPopup(menuB) \n";
1141 char whiteTranslations[] =
1142 "Shift<BtnDown>: WhiteClock(1)\n \
1143 <BtnDown>: WhiteClock(0)\n";
1144 char blackTranslations[] =
1145 "Shift<BtnDown>: BlackClock(1)\n \
1146 <BtnDown>: BlackClock(0)\n";
1148 char ICSInputTranslations[] =
1149 "<Key>Up: UpKeyProc() \n "
1150 "<Key>Down: DownKeyProc() \n "
1151 "<Key>Return: EnterKeyProc() \n";
1153 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1154 // as the widget is destroyed before the up-click can call extend-end
1155 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1157 String xboardResources[] = {
1158 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1159 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1160 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1165 /* Max possible square size */
1166 #define MAXSQSIZE 256
1168 static int xpm_avail[MAXSQSIZE];
1170 #ifdef HAVE_DIR_STRUCT
1172 /* Extract piece size from filename */
1174 xpm_getsize (char *name, int len, char *ext)
1182 if ((p=strchr(name, '.')) == NULL ||
1183 StrCaseCmp(p+1, ext) != 0)
1189 while (*p && isdigit(*p))
1196 /* Setup xpm_avail */
1198 xpm_getavail (char *dirname, char *ext)
1204 for (i=0; i<MAXSQSIZE; ++i)
1207 if (appData.debugMode)
1208 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1210 dir = opendir(dirname);
1213 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1214 programName, dirname);
1218 while ((ent=readdir(dir)) != NULL) {
1219 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1220 if (i > 0 && i < MAXSQSIZE)
1230 xpm_print_avail (FILE *fp, char *ext)
1234 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1235 for (i=1; i<MAXSQSIZE; ++i) {
1241 /* Return XPM piecesize closest to size */
1243 xpm_closest_to (char *dirname, int size, char *ext)
1246 int sm_diff = MAXSQSIZE;
1250 xpm_getavail(dirname, ext);
1252 if (appData.debugMode)
1253 xpm_print_avail(stderr, ext);
1255 for (i=1; i<MAXSQSIZE; ++i) {
1258 diff = (diff<0) ? -diff : diff;
1259 if (diff < sm_diff) {
1267 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1273 #else /* !HAVE_DIR_STRUCT */
1274 /* If we are on a system without a DIR struct, we can't
1275 read the directory, so we can't collect a list of
1276 filenames, etc., so we can't do any size-fitting. */
1278 xpm_closest_to (char *dirname, int size, char *ext)
1280 fprintf(stderr, _("\
1281 Warning: No DIR structure found on this system --\n\
1282 Unable to autosize for XPM/XIM pieces.\n\
1283 Please report this error to %s.\n\
1284 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1287 #endif /* HAVE_DIR_STRUCT */
1289 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1290 "magenta", "cyan", "white" };
1294 TextColors textColors[(int)NColorClasses];
1296 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1298 parse_color (char *str, int which)
1300 char *p, buf[100], *d;
1303 if (strlen(str) > 99) /* watch bounds on buf */
1308 for (i=0; i<which; ++i) {
1315 /* Could be looking at something like:
1317 .. in which case we want to stop on a comma also */
1318 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1322 return -1; /* Use default for empty field */
1325 if (which == 2 || isdigit(*p))
1328 while (*p && isalpha(*p))
1333 for (i=0; i<8; ++i) {
1334 if (!StrCaseCmp(buf, cnames[i]))
1335 return which? (i+40) : (i+30);
1337 if (!StrCaseCmp(buf, "default")) return -1;
1339 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1344 parse_cpair (ColorClass cc, char *str)
1346 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1347 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1352 /* bg and attr are optional */
1353 textColors[(int)cc].bg = parse_color(str, 1);
1354 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1355 textColors[(int)cc].attr = 0;
1361 /* Arrange to catch delete-window events */
1362 Atom wm_delete_window;
1364 CatchDeleteWindow (Widget w, String procname)
1367 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1368 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1369 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1376 XtSetArg(args[0], XtNiconic, False);
1377 XtSetValues(shellWidget, args, 1);
1379 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1382 //---------------------------------------------------------------------------------------------------------
1383 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1386 #define CW_USEDEFAULT (1<<31)
1387 #define ICS_TEXT_MENU_SIZE 90
1388 #define DEBUG_FILE "xboard.debug"
1389 #define SetCurrentDirectory chdir
1390 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1394 // these two must some day move to frontend.h, when they are implemented
1395 Boolean GameListIsUp();
1397 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1400 // front-end part of option handling
1402 // [HGM] This platform-dependent table provides the location for storing the color info
1403 extern char *crWhite, * crBlack;
1407 &appData.whitePieceColor,
1408 &appData.blackPieceColor,
1409 &appData.lightSquareColor,
1410 &appData.darkSquareColor,
1411 &appData.highlightSquareColor,
1412 &appData.premoveHighlightColor,
1413 &appData.lowTimeWarningColor,
1424 // [HGM] font: keep a font for each square size, even non-stndard ones
1425 #define NUM_SIZES 18
1426 #define MAX_SIZE 130
1427 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1428 char *fontTable[NUM_FONTS][MAX_SIZE];
1431 ParseFont (char *name, int number)
1432 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1434 if(sscanf(name, "size%d:", &size)) {
1435 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1436 // defer processing it until we know if it matches our board size
1437 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1438 fontTable[number][size] = strdup(strchr(name, ':')+1);
1439 fontValid[number][size] = True;
1444 case 0: // CLOCK_FONT
1445 appData.clockFont = strdup(name);
1447 case 1: // MESSAGE_FONT
1448 appData.font = strdup(name);
1450 case 2: // COORD_FONT
1451 appData.coordFont = strdup(name);
1456 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1461 { // only 2 fonts currently
1462 appData.clockFont = CLOCK_FONT_NAME;
1463 appData.coordFont = COORD_FONT_NAME;
1464 appData.font = DEFAULT_FONT_NAME;
1469 { // no-op, until we identify the code for this already in XBoard and move it here
1473 ParseColor (int n, char *name)
1474 { // in XBoard, just copy the color-name string
1475 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1479 ParseTextAttribs (ColorClass cc, char *s)
1481 (&appData.colorShout)[cc] = strdup(s);
1485 ParseBoardSize (void *addr, char *name)
1487 appData.boardSize = strdup(name);
1492 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1496 SetCommPortDefaults ()
1497 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1500 // [HGM] args: these three cases taken out to stay in front-end
1502 SaveFontArg (FILE *f, ArgDescriptor *ad)
1505 int i, n = (int)(intptr_t)ad->argLoc;
1507 case 0: // CLOCK_FONT
1508 name = appData.clockFont;
1510 case 1: // MESSAGE_FONT
1511 name = appData.font;
1513 case 2: // COORD_FONT
1514 name = appData.coordFont;
1519 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1520 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1521 fontTable[n][squareSize] = strdup(name);
1522 fontValid[n][squareSize] = True;
1525 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1526 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1531 { // nothing to do, as the sounds are at all times represented by their text-string names already
1535 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
1536 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1537 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1541 SaveColor (FILE *f, ArgDescriptor *ad)
1542 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1543 if(colorVariable[(int)(intptr_t)ad->argLoc])
1544 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1548 SaveBoardSize (FILE *f, char *name, void *addr)
1549 { // wrapper to shield back-end from BoardSize & sizeInfo
1550 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1554 ParseCommPortSettings (char *s)
1555 { // no such option in XBoard (yet)
1558 extern Widget engineOutputShell;
1561 GetActualPlacement (Widget wg, WindowPlacement *wp)
1571 XtSetArg(args[i], XtNx, &x); i++;
1572 XtSetArg(args[i], XtNy, &y); i++;
1573 XtSetArg(args[i], XtNwidth, &w); i++;
1574 XtSetArg(args[i], XtNheight, &h); i++;
1575 XtGetValues(wg, args, i);
1584 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1585 // In XBoard this will have to wait until awareness of window parameters is implemented
1586 GetActualPlacement(shellWidget, &wpMain);
1587 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput);
1588 if(MoveHistoryIsUp()) GetActualPlacement(shells[7], &wpMoveHistory);
1589 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1590 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1591 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1592 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1596 PrintCommPortSettings (FILE *f, char *name)
1597 { // This option does not exist in XBoard
1601 MySearchPath (char *installDir, char *name, char *fullname)
1602 { // just append installDir and name. Perhaps ExpandPath should be used here?
1603 name = ExpandPathName(name);
1604 if(name && name[0] == '/')
1605 safeStrCpy(fullname, name, MSG_SIZ );
1607 sprintf(fullname, "%s%c%s", installDir, '/', name);
1613 MyGetFullPathName (char *name, char *fullname)
1614 { // should use ExpandPath?
1615 name = ExpandPathName(name);
1616 safeStrCpy(fullname, name, MSG_SIZ );
1621 EnsureOnScreen (int *x, int *y, int minX, int minY)
1628 { // [HGM] args: allows testing if main window is realized from back-end
1629 return xBoardWindow != 0;
1633 PopUpStartupDialog ()
1634 { // start menu not implemented in XBoard
1638 ConvertToLine (int argc, char **argv)
1640 static char line[128*1024], buf[1024];
1644 for(i=1; i<argc; i++)
1646 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
1647 && argv[i][0] != '{' )
1648 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1650 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1651 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1654 line[strlen(line)-1] = NULLCHAR;
1658 //--------------------------------------------------------------------------------------------
1660 extern Boolean twoBoards, partnerUp;
1663 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1665 #define BoardSize int
1667 InitDrawingSizes (BoardSize boardSize, int flags)
1668 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1669 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1671 XtGeometryResult gres;
1673 static Dimension oldWidth, oldHeight;
1674 static VariantClass oldVariant;
1675 static int oldDual = -1, oldMono = -1;
1677 if(!formWidget) return;
1679 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1680 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1681 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1683 if(boardWidth != oldWidth || boardHeight != oldHeight || oldDual != twoBoards) { // do resizing stuff only if size actually changed
1685 * Enable shell resizing.
1687 shellArgs[0].value = (XtArgVal) &w;
1688 shellArgs[1].value = (XtArgVal) &h;
1689 XtGetValues(shellWidget, shellArgs, 2);
1691 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1692 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1693 XtSetValues(shellWidget, &shellArgs[2], 4);
1695 XtSetArg(args[0], XtNdefaultDistance, &sep);
1696 XtGetValues(formWidget, args, 1);
1698 oldWidth = boardWidth; oldHeight = boardHeight; oldDual = twoBoards;
1700 hOffset = boardWidth + 10;
1701 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1702 secondSegments[i] = gridSegments[i];
1703 secondSegments[i].x1 += hOffset;
1704 secondSegments[i].x2 += hOffset;
1707 XtSetArg(args[0], XtNwidth, boardWidth);
1708 XtSetArg(args[1], XtNheight, boardHeight);
1709 XtSetValues(boardWidget, args, 2);
1711 timerWidth = (boardWidth - sep) / 2;
1712 XtSetArg(args[0], XtNwidth, timerWidth);
1713 XtSetValues(whiteTimerWidget, args, 1);
1714 XtSetValues(blackTimerWidget, args, 1);
1716 XawFormDoLayout(formWidget, False);
1718 if (appData.titleInWindow) {
1720 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1721 XtSetArg(args[i], XtNheight, &h); i++;
1722 XtGetValues(titleWidget, args, i);
1724 w = boardWidth - 2*bor;
1726 XtSetArg(args[0], XtNwidth, &w);
1727 XtGetValues(menuBarWidget, args, 1);
1728 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1731 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1732 if (gres != XtGeometryYes && appData.debugMode) {
1734 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1735 programName, gres, w, h, wr, hr);
1739 XawFormDoLayout(formWidget, True);
1742 * Inhibit shell resizing.
1744 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1745 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1746 shellArgs[4].value = shellArgs[2].value = w;
1747 shellArgs[5].value = shellArgs[3].value = h;
1748 XtSetValues(shellWidget, &shellArgs[0], 6);
1751 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1754 if(gameInfo.variant != oldVariant) { // and only if variant changed
1757 for(i=0; i<4; i++) {
1759 for(p=0; p<=(int)WhiteKing; p++)
1760 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1761 if(gameInfo.variant == VariantShogi) {
1762 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1763 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1764 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1765 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1766 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1769 if(gameInfo.variant == VariantGothic) {
1770 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1773 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1774 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1775 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1778 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1779 for(p=0; p<=(int)WhiteKing; p++)
1780 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1781 if(gameInfo.variant == VariantShogi) {
1782 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1783 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1784 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1785 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1786 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1789 if(gameInfo.variant == VariantGothic) {
1790 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1793 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1794 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1795 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1800 for(i=0; i<2; i++) {
1802 for(p=0; p<=(int)WhiteKing; p++)
1803 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1804 if(gameInfo.variant == VariantShogi) {
1805 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1806 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1807 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1808 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1809 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1812 if(gameInfo.variant == VariantGothic) {
1813 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1816 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1817 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1818 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1824 if(appData.monoMode == oldMono)
1827 oldMono = appData.monoMode;
1832 ParseIcsTextColors ()
1833 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1834 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1835 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1836 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1837 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1838 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1839 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1840 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1841 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1842 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1843 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1845 if (appData.colorize) {
1847 _("%s: can't parse color names; disabling colorization\n"),
1850 appData.colorize = FALSE;
1856 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1857 XrmValue vFrom, vTo;
1858 int forceMono = False;
1860 if (!appData.monoMode) {
1861 vFrom.addr = (caddr_t) appData.lightSquareColor;
1862 vFrom.size = strlen(appData.lightSquareColor);
1863 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1864 if (vTo.addr == NULL) {
1865 appData.monoMode = True;
1868 lightSquareColor = *(Pixel *) vTo.addr;
1871 if (!appData.monoMode) {
1872 vFrom.addr = (caddr_t) appData.darkSquareColor;
1873 vFrom.size = strlen(appData.darkSquareColor);
1874 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1875 if (vTo.addr == NULL) {
1876 appData.monoMode = True;
1879 darkSquareColor = *(Pixel *) vTo.addr;
1882 if (!appData.monoMode) {
1883 vFrom.addr = (caddr_t) appData.whitePieceColor;
1884 vFrom.size = strlen(appData.whitePieceColor);
1885 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1886 if (vTo.addr == NULL) {
1887 appData.monoMode = True;
1890 whitePieceColor = *(Pixel *) vTo.addr;
1893 if (!appData.monoMode) {
1894 vFrom.addr = (caddr_t) appData.blackPieceColor;
1895 vFrom.size = strlen(appData.blackPieceColor);
1896 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1897 if (vTo.addr == NULL) {
1898 appData.monoMode = True;
1901 blackPieceColor = *(Pixel *) vTo.addr;
1905 if (!appData.monoMode) {
1906 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1907 vFrom.size = strlen(appData.highlightSquareColor);
1908 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1909 if (vTo.addr == NULL) {
1910 appData.monoMode = True;
1913 highlightSquareColor = *(Pixel *) vTo.addr;
1917 if (!appData.monoMode) {
1918 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1919 vFrom.size = strlen(appData.premoveHighlightColor);
1920 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1921 if (vTo.addr == NULL) {
1922 appData.monoMode = True;
1925 premoveHighlightColor = *(Pixel *) vTo.addr;
1933 { // [HGM] taken out of main
1935 if (appData.monoMode && // [HGM] no sense to go on to certain doom
1936 (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1937 appData.bitmapDirectory = strdup(DEF_BITMAP_DIR);
1939 if (appData.bitmapDirectory[0] != NULLCHAR) {
1943 CreateXPMBoard(appData.liteBackTextureFile, 1);
1944 CreateXPMBoard(appData.darkBackTextureFile, 0);
1948 /* Create regular pieces */
1949 if (!useImages) CreatePieces();
1954 main (int argc, char **argv)
1956 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1957 XSetWindowAttributes window_attributes;
1959 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1960 XrmValue vFrom, vTo;
1961 XtGeometryResult gres;
1964 int forceMono = False;
1966 srandom(time(0)); // [HGM] book: make random truly random
1968 setbuf(stdout, NULL);
1969 setbuf(stderr, NULL);
1972 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1973 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1977 programName = strrchr(argv[0], '/');
1978 if (programName == NULL)
1979 programName = argv[0];
1984 XtSetLanguageProc(NULL, NULL, NULL);
1985 bindtextdomain(PACKAGE, LOCALEDIR);
1986 textdomain(PACKAGE);
1990 XtAppInitialize(&appContext, "XBoard", shellOptions,
1991 XtNumber(shellOptions),
1992 &argc, argv, xboardResources, NULL, 0);
1993 appData.boardSize = "";
1994 InitAppData(ConvertToLine(argc, argv));
1996 if (p == NULL) p = "/tmp";
1997 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1998 gameCopyFilename = (char*) malloc(i);
1999 gamePasteFilename = (char*) malloc(i);
2000 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
2001 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
2003 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2004 clientResources, XtNumber(clientResources),
2007 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
2008 static char buf[MSG_SIZ];
2009 EscapeExpand(buf, appData.firstInitString);
2010 appData.firstInitString = strdup(buf);
2011 EscapeExpand(buf, appData.secondInitString);
2012 appData.secondInitString = strdup(buf);
2013 EscapeExpand(buf, appData.firstComputerString);
2014 appData.firstComputerString = strdup(buf);
2015 EscapeExpand(buf, appData.secondComputerString);
2016 appData.secondComputerString = strdup(buf);
2019 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2022 if (chdir(chessDir) != 0) {
2023 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2029 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2030 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2031 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
2032 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2035 setbuf(debugFP, NULL);
2039 if (appData.debugMode) {
2040 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2044 /* [HGM,HR] make sure board size is acceptable */
2045 if(appData.NrFiles > BOARD_FILES ||
2046 appData.NrRanks > BOARD_RANKS )
2047 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2050 /* This feature does not work; animation needs a rewrite */
2051 appData.highlightDragging = FALSE;
2055 xDisplay = XtDisplay(shellWidget);
2056 xScreen = DefaultScreen(xDisplay);
2057 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2059 gameInfo.variant = StringToVariant(appData.variant);
2060 InitPosition(FALSE);
2063 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2065 if (isdigit(appData.boardSize[0])) {
2066 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2067 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2068 &fontPxlSize, &smallLayout, &tinyLayout);
2070 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2071 programName, appData.boardSize);
2075 /* Find some defaults; use the nearest known size */
2076 SizeDefaults *szd, *nearest;
2077 int distance = 99999;
2078 nearest = szd = sizeDefaults;
2079 while (szd->name != NULL) {
2080 if (abs(szd->squareSize - squareSize) < distance) {
2082 distance = abs(szd->squareSize - squareSize);
2083 if (distance == 0) break;
2087 if (i < 2) lineGap = nearest->lineGap;
2088 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2089 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2090 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2091 if (i < 6) smallLayout = nearest->smallLayout;
2092 if (i < 7) tinyLayout = nearest->tinyLayout;
2095 SizeDefaults *szd = sizeDefaults;
2096 if (*appData.boardSize == NULLCHAR) {
2097 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2098 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2101 if (szd->name == NULL) szd--;
2102 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2104 while (szd->name != NULL &&
2105 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2106 if (szd->name == NULL) {
2107 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2108 programName, appData.boardSize);
2112 squareSize = szd->squareSize;
2113 lineGap = szd->lineGap;
2114 clockFontPxlSize = szd->clockFontPxlSize;
2115 coordFontPxlSize = szd->coordFontPxlSize;
2116 fontPxlSize = szd->fontPxlSize;
2117 smallLayout = szd->smallLayout;
2118 tinyLayout = szd->tinyLayout;
2119 // [HGM] font: use defaults from settings file if available and not overruled
2121 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2122 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2123 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2124 appData.font = fontTable[MESSAGE_FONT][squareSize];
2125 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2126 appData.coordFont = fontTable[COORD_FONT][squareSize];
2128 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2129 if (strlen(appData.pixmapDirectory) > 0) {
2130 p = ExpandPathName(appData.pixmapDirectory);
2132 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2133 appData.pixmapDirectory);
2136 if (appData.debugMode) {
2137 fprintf(stderr, _("\
2138 XBoard square size (hint): %d\n\
2139 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2141 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2142 if (appData.debugMode) {
2143 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2146 defaultLineGap = lineGap;
2147 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2149 /* [HR] height treated separately (hacked) */
2150 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2151 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2152 if (appData.showJail == 1) {
2153 /* Jail on top and bottom */
2154 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2155 XtSetArg(boardArgs[2], XtNheight,
2156 boardHeight + 2*(lineGap + squareSize));
2157 } else if (appData.showJail == 2) {
2159 XtSetArg(boardArgs[1], XtNwidth,
2160 boardWidth + 2*(lineGap + squareSize));
2161 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2164 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2165 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2169 * Determine what fonts to use.
2172 appData.font = InsertPxlSize(appData.font, fontPxlSize);
2173 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2174 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2175 fontSet = CreateFontSet(appData.font);
2176 clockFontSet = CreateFontSet(appData.clockFont);
2178 /* For the coordFont, use the 0th font of the fontset. */
2179 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2180 XFontStruct **font_struct_list;
2181 char **font_name_list;
2182 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2183 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2184 coordFontStruct = XQueryFont(xDisplay, coordFontID);
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 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2468 XtSetArg(args[1], XtNright, XtChainRight);
2469 XtSetValues(messageWidget, args, 2);
2471 if (appData.titleInWindow) {
2473 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2474 XtSetArg(args[i], XtNheight, &h); i++;
2475 XtGetValues(titleWidget, args, i);
2477 w = boardWidth - 2*bor;
2479 XtSetArg(args[0], XtNwidth, &w);
2480 XtGetValues(menuBarWidget, args, 1);
2481 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2484 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2485 if (gres != XtGeometryYes && appData.debugMode) {
2487 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2488 programName, gres, w, h, wr, hr);
2491 XawFormDoLayout(formWidget, True);
2493 xBoardWindow = XtWindow(boardWidget);
2495 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2496 // not need to go into InitDrawingSizes().
2500 * Create X checkmark bitmap and initialize option menu checks.
2502 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2503 checkmark_bits, checkmark_width, checkmark_height);
2504 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2505 #ifndef OPTIONSDIALOG
2506 if (appData.alwaysPromoteToQueen) {
2507 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2510 if (appData.animateDragging) {
2511 XtSetValues(XtNameToWidget(menuBarWidget,
2512 "menuOptions.Animate Dragging"),
2515 if (appData.animate) {
2516 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2519 if (appData.autoCallFlag) {
2520 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2523 if (appData.autoFlipView) {
2524 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2527 if (appData.blindfold) {
2528 XtSetValues(XtNameToWidget(menuBarWidget,
2529 "menuOptions.Blindfold"), args, 1);
2531 if (appData.flashCount > 0) {
2532 XtSetValues(XtNameToWidget(menuBarWidget,
2533 "menuOptions.Flash Moves"),
2537 if (appData.highlightDragging) {
2538 XtSetValues(XtNameToWidget(menuBarWidget,
2539 "menuOptions.Highlight Dragging"),
2543 if (appData.highlightLastMove) {
2544 XtSetValues(XtNameToWidget(menuBarWidget,
2545 "menuOptions.Highlight Last Move"),
2548 if (appData.highlightMoveWithArrow) {
2549 XtSetValues(XtNameToWidget(menuBarWidget,
2550 "menuOptions.Arrow"),
2553 // if (appData.icsAlarm) {
2554 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2557 if (appData.ringBellAfterMoves) {
2558 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2561 if (appData.oneClick) {
2562 XtSetValues(XtNameToWidget(menuBarWidget,
2563 "menuOptions.OneClick"), args, 1);
2565 if (appData.periodicUpdates) {
2566 XtSetValues(XtNameToWidget(menuBarWidget,
2567 "menuOptions.Periodic Updates"), args, 1);
2569 if (appData.ponderNextMove) {
2570 XtSetValues(XtNameToWidget(menuBarWidget,
2571 "menuOptions.Ponder Next Move"), args, 1);
2573 if (appData.popupExitMessage) {
2574 XtSetValues(XtNameToWidget(menuBarWidget,
2575 "menuOptions.Popup Exit Message"), args, 1);
2577 if (appData.popupMoveErrors) {
2578 XtSetValues(XtNameToWidget(menuBarWidget,
2579 "menuOptions.Popup Move Errors"), args, 1);
2581 // if (appData.premove) {
2582 // XtSetValues(XtNameToWidget(menuBarWidget,
2583 // "menuOptions.Premove"), args, 1);
2585 if (appData.showCoords) {
2586 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2589 if (appData.hideThinkingFromHuman) {
2590 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2593 if (appData.testLegality) {
2594 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2598 if (saveSettingsOnExit) {
2599 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2606 ReadBitmap(&wIconPixmap, "icon_white.bm",
2607 icon_white_bits, icon_white_width, icon_white_height);
2608 ReadBitmap(&bIconPixmap, "icon_black.bm",
2609 icon_black_bits, icon_black_width, icon_black_height);
2610 iconPixmap = wIconPixmap;
2612 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2613 XtSetValues(shellWidget, args, i);
2616 * Create a cursor for the board widget.
2618 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2619 XChangeWindowAttributes(xDisplay, xBoardWindow,
2620 CWCursor, &window_attributes);
2623 * Inhibit shell resizing.
2625 shellArgs[0].value = (XtArgVal) &w;
2626 shellArgs[1].value = (XtArgVal) &h;
2627 XtGetValues(shellWidget, shellArgs, 2);
2628 shellArgs[4].value = shellArgs[2].value = w;
2629 shellArgs[5].value = shellArgs[3].value = h;
2630 XtSetValues(shellWidget, &shellArgs[2], 4);
2631 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2632 marginH = h - boardHeight;
2634 CatchDeleteWindow(shellWidget, "QuitProc");
2642 if (appData.animate || appData.animateDragging)
2645 XtAugmentTranslations(formWidget,
2646 XtParseTranslationTable(globalTranslations));
2647 XtAugmentTranslations(boardWidget,
2648 XtParseTranslationTable(boardTranslations));
2649 XtAugmentTranslations(whiteTimerWidget,
2650 XtParseTranslationTable(whiteTranslations));
2651 XtAugmentTranslations(blackTimerWidget,
2652 XtParseTranslationTable(blackTranslations));
2654 /* Why is the following needed on some versions of X instead
2655 * of a translation? */
2656 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2657 (XtEventHandler) EventProc, NULL);
2659 XtAddEventHandler(formWidget, KeyPressMask, False,
2660 (XtEventHandler) MoveTypeInProc, NULL);
2662 /* [AS] Restore layout */
2663 if( wpMoveHistory.visible ) {
2667 if( wpEvalGraph.visible )
2672 if( wpEngineOutput.visible ) {
2673 EngineOutputPopUp();
2678 if (errorExitStatus == -1) {
2679 if (appData.icsActive) {
2680 /* We now wait until we see "login:" from the ICS before
2681 sending the logon script (problems with timestamp otherwise) */
2682 /*ICSInitScript();*/
2683 if (appData.icsInputBox) ICSInputBoxPopUp();
2687 signal(SIGWINCH, TermSizeSigHandler);
2689 signal(SIGINT, IntSigHandler);
2690 signal(SIGTERM, IntSigHandler);
2691 if (*appData.cmailGameName != NULLCHAR) {
2692 signal(SIGUSR1, CmailSigHandler);
2695 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2697 // XtSetKeyboardFocus(shellWidget, formWidget);
2698 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2700 XtAppMainLoop(appContext);
2701 if (appData.debugMode) fclose(debugFP); // [DM] debug
2705 static Boolean noEcho;
2710 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2711 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2713 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2714 unlink(gameCopyFilename);
2715 unlink(gamePasteFilename);
2716 if(noEcho) EchoOn();
2720 TermSizeSigHandler (int sig)
2726 IntSigHandler (int sig)
2732 CmailSigHandler (int sig)
2737 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2739 /* Activate call-back function CmailSigHandlerCallBack() */
2740 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2742 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2746 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
2749 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2751 /**** end signal code ****/
2757 /* try to open the icsLogon script, either in the location given
2758 * or in the users HOME directory
2765 f = fopen(appData.icsLogon, "r");
2768 homedir = getenv("HOME");
2769 if (homedir != NULL)
2771 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2772 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2773 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2774 f = fopen(buf, "r");
2779 ProcessICSInitScript(f);
2781 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2800 GreyRevert (Boolean grey)
2803 if (!menuBarWidget) return;
2804 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2806 DisplayError("menuEdit.Revert", 0);
2808 XtSetSensitive(w, !grey);
2810 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2812 DisplayError("menuEdit.Annotate", 0);
2814 XtSetSensitive(w, !grey);
2819 SetMenuEnables (Enables *enab)
2822 if (!menuBarWidget) return;
2823 while (enab->name != NULL) {
2824 w = XtNameToWidget(menuBarWidget, enab->name);
2826 DisplayError(enab->name, 0);
2828 XtSetSensitive(w, enab->value);
2834 Enables icsEnables[] = {
2835 { "menuFile.Mail Move", False },
2836 { "menuFile.Reload CMail Message", False },
2837 { "menuMode.Machine Black", False },
2838 { "menuMode.Machine White", False },
2839 { "menuMode.Analysis Mode", False },
2840 { "menuMode.Analyze File", False },
2841 { "menuMode.Two Machines", False },
2842 { "menuMode.Machine Match", False },
2844 { "menuEngine.Hint", False },
2845 { "menuEngine.Book", False },
2846 { "menuEngine.Move Now", False },
2847 #ifndef OPTIONSDIALOG
2848 { "menuOptions.Periodic Updates", False },
2849 { "menuOptions.Hide Thinking", False },
2850 { "menuOptions.Ponder Next Move", False },
2853 { "menuEngine.Engine #1 Settings", False },
2854 { "menuEngine.Engine #2 Settings", False },
2855 { "menuEngine.Load Engine", False },
2856 { "menuEdit.Annotate", False },
2857 { "menuOptions.Match", False },
2861 Enables ncpEnables[] = {
2862 { "menuFile.Mail Move", False },
2863 { "menuFile.Reload CMail Message", False },
2864 { "menuMode.Machine White", False },
2865 { "menuMode.Machine Black", False },
2866 { "menuMode.Analysis Mode", False },
2867 { "menuMode.Analyze File", False },
2868 { "menuMode.Two Machines", False },
2869 { "menuMode.Machine Match", False },
2870 { "menuMode.ICS Client", False },
2871 { "menuView.ICStex", False },
2872 { "menuView.ICS Input Box", False },
2873 { "Action", False },
2874 { "menuEdit.Revert", False },
2875 { "menuEdit.Annotate", False },
2876 { "menuEngine.Engine #1 Settings", False },
2877 { "menuEngine.Engine #2 Settings", False },
2878 { "menuEngine.Move Now", False },
2879 { "menuEngine.Retract Move", False },
2880 { "menuOptions.ICS", False },
2881 #ifndef OPTIONSDIALOG
2882 { "menuOptions.Auto Flag", False },
2883 { "menuOptions.Auto Flip View", False },
2884 // { "menuOptions.ICS Alarm", False },
2885 { "menuOptions.Move Sound", False },
2886 { "menuOptions.Hide Thinking", False },
2887 { "menuOptions.Periodic Updates", False },
2888 { "menuOptions.Ponder Next Move", False },
2890 { "menuEngine.Hint", False },
2891 { "menuEngine.Book", False },
2895 Enables gnuEnables[] = {
2896 { "menuMode.ICS Client", False },
2897 { "menuView.ICStex", False },
2898 { "menuView.ICS Input Box", False },
2899 { "menuAction.Accept", False },
2900 { "menuAction.Decline", False },
2901 { "menuAction.Rematch", False },
2902 { "menuAction.Adjourn", False },
2903 { "menuAction.Stop Examining", False },
2904 { "menuAction.Stop Observing", False },
2905 { "menuAction.Upload to Examine", False },
2906 { "menuEdit.Revert", False },
2907 { "menuEdit.Annotate", False },
2908 { "menuOptions.ICS", False },
2910 /* The next two options rely on SetCmailMode being called *after* */
2911 /* SetGNUMode so that when GNU is being used to give hints these */
2912 /* menu options are still available */
2914 { "menuFile.Mail Move", False },
2915 { "menuFile.Reload CMail Message", False },
2916 // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2917 { "menuMode.Machine White", True },
2918 { "menuMode.Machine Black", True },
2919 { "menuMode.Analysis Mode", True },
2920 { "menuMode.Analyze File", True },
2921 { "menuMode.Two Machines", True },
2922 { "menuMode.Machine Match", True },
2923 { "menuEngine.Engine #1 Settings", True },
2924 { "menuEngine.Engine #2 Settings", True },
2925 { "menuEngine.Hint", True },
2926 { "menuEngine.Book", True },
2927 { "menuEngine.Move Now", True },
2928 { "menuEngine.Retract Move", True },
2933 Enables cmailEnables[] = {
2935 { "menuAction.Call Flag", False },
2936 { "menuAction.Draw", True },
2937 { "menuAction.Adjourn", False },
2938 { "menuAction.Abort", False },
2939 { "menuAction.Stop Observing", False },
2940 { "menuAction.Stop Examining", False },
2941 { "menuFile.Mail Move", True },
2942 { "menuFile.Reload CMail Message", True },
2946 Enables trainingOnEnables[] = {
2947 { "menuMode.Edit Comment", False },
2948 { "menuMode.Pause", False },
2949 { "menuEdit.Forward", False },
2950 { "menuEdit.Backward", False },
2951 { "menuEdit.Forward to End", False },
2952 { "menuEdit.Back to Start", False },
2953 { "menuEngine.Move Now", False },
2954 { "menuEdit.Truncate Game", False },
2958 Enables trainingOffEnables[] = {
2959 { "menuMode.Edit Comment", True },
2960 { "menuMode.Pause", True },
2961 { "menuEdit.Forward", True },
2962 { "menuEdit.Backward", True },
2963 { "menuEdit.Forward to End", True },
2964 { "menuEdit.Back to Start", True },
2965 { "menuEngine.Move Now", True },
2966 { "menuEdit.Truncate Game", True },
2970 Enables machineThinkingEnables[] = {
2971 { "menuFile.Load Game", False },
2972 // { "menuFile.Load Next Game", False },
2973 // { "menuFile.Load Previous Game", False },
2974 // { "menuFile.Reload Same Game", False },
2975 { "menuEdit.Paste Game", False },
2976 { "menuFile.Load Position", False },
2977 // { "menuFile.Load Next Position", False },
2978 // { "menuFile.Load Previous Position", False },
2979 // { "menuFile.Reload Same Position", False },
2980 { "menuEdit.Paste Position", False },
2981 { "menuMode.Machine White", False },
2982 { "menuMode.Machine Black", False },
2983 { "menuMode.Two Machines", False },
2984 // { "menuMode.Machine Match", False },
2985 { "menuEngine.Retract Move", False },
2989 Enables userThinkingEnables[] = {
2990 { "menuFile.Load Game", True },
2991 // { "menuFile.Load Next Game", True },
2992 // { "menuFile.Load Previous Game", True },
2993 // { "menuFile.Reload Same Game", True },
2994 { "menuEdit.Paste Game", True },
2995 { "menuFile.Load Position", True },
2996 // { "menuFile.Load Next Position", True },
2997 // { "menuFile.Load Previous Position", True },
2998 // { "menuFile.Reload Same Position", True },
2999 { "menuEdit.Paste Position", True },
3000 { "menuMode.Machine White", True },
3001 { "menuMode.Machine Black", True },
3002 { "menuMode.Two Machines", True },
3003 // { "menuMode.Machine Match", True },
3004 { "menuEngine.Retract Move", True },
3011 SetMenuEnables(icsEnables);
3014 if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3015 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3016 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3024 SetMenuEnables(ncpEnables);
3030 SetMenuEnables(gnuEnables);
3036 SetMenuEnables(cmailEnables);
3040 SetTrainingModeOn ()
3042 SetMenuEnables(trainingOnEnables);
3043 if (appData.showButtonBar) {
3044 XtSetSensitive(buttonBarWidget, False);
3050 SetTrainingModeOff ()
3052 SetMenuEnables(trainingOffEnables);
3053 if (appData.showButtonBar) {
3054 XtSetSensitive(buttonBarWidget, True);
3059 SetUserThinkingEnables ()
3061 if (appData.noChessProgram) return;
3062 SetMenuEnables(userThinkingEnables);
3066 SetMachineThinkingEnables ()
3068 if (appData.noChessProgram) return;
3069 SetMenuEnables(machineThinkingEnables);
3071 case MachinePlaysBlack:
3072 case MachinePlaysWhite:
3073 case TwoMachinesPlay:
3074 XtSetSensitive(XtNameToWidget(menuBarWidget,
3075 ModeToWidgetName(gameMode)), True);
3082 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3083 #define HISTORY_SIZE 64
3084 static char *history[HISTORY_SIZE];
3085 int histIn = 0, histP = 0;
3088 SaveInHistory (char *cmd)
3090 if (history[histIn] != NULL) {
3091 free(history[histIn]);
3092 history[histIn] = NULL;
3094 if (*cmd == NULLCHAR) return;
3095 history[histIn] = StrSave(cmd);
3096 histIn = (histIn + 1) % HISTORY_SIZE;
3097 if (history[histIn] != NULL) {
3098 free(history[histIn]);
3099 history[histIn] = NULL;
3105 PrevInHistory (char *cmd)
3108 if (histP == histIn) {
3109 if (history[histIn] != NULL) free(history[histIn]);
3110 history[histIn] = StrSave(cmd);
3112 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3113 if (newhp == histIn || history[newhp] == NULL) return NULL;
3115 return history[histP];
3121 if (histP == histIn) return NULL;
3122 histP = (histP + 1) % HISTORY_SIZE;
3123 return history[histP];
3125 // end of borrowed code
3127 #define Abs(n) ((n)<0 ? -(n) : (n))
3131 InsertPxlSize (char *pattern, int targetPxlSize)
3133 char *base_fnt_lst, strInt[12], *p, *q;
3134 int alternatives, i, len, strIntLen;
3137 * Replace the "*" (if present) in the pixel-size slot of each
3138 * alternative with the targetPxlSize.
3142 while ((p = strchr(p, ',')) != NULL) {
3146 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3147 strIntLen = strlen(strInt);
3148 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3152 while (alternatives--) {
3153 char *comma = strchr(p, ',');
3154 for (i=0; i<14; i++) {
3155 char *hyphen = strchr(p, '-');
3157 if (comma && hyphen > comma) break;
3158 len = hyphen + 1 - p;
3159 if (i == 7 && *p == '*' && len == 2) {
3161 memcpy(q, strInt, strIntLen);
3171 len = comma + 1 - p;
3178 return base_fnt_lst;
3182 CreateFontSet (char *base_fnt_lst)
3185 char **missing_list;
3189 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3190 &missing_list, &missing_count, &def_string);
3191 if (appData.debugMode) {
3193 XFontStruct **font_struct_list;
3194 char **font_name_list;
3195 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3197 fprintf(debugFP, " got list %s, locale %s\n",
3198 XBaseFontNameListOfFontSet(fntSet),
3199 XLocaleOfFontSet(fntSet));
3200 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3201 for (i = 0; i < count; i++) {
3202 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3205 for (i = 0; i < missing_count; i++) {
3206 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3209 if (fntSet == NULL) {
3210 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3215 #else // not ENABLE_NLS
3217 * Find a font that matches "pattern" that is as close as
3218 * possible to the targetPxlSize. Prefer fonts that are k
3219 * pixels smaller to fonts that are k pixels larger. The
3220 * pattern must be in the X Consortium standard format,
3221 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3222 * The return value should be freed with XtFree when no
3226 FindFont (char *pattern, int targetPxlSize)
3228 char **fonts, *p, *best, *scalable, *scalableTail;
3229 int i, j, nfonts, minerr, err, pxlSize;
3231 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3233 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3234 programName, pattern);
3241 for (i=0; i<nfonts; i++) {
3244 if (*p != '-') continue;
3246 if (*p == NULLCHAR) break;
3247 if (*p++ == '-') j++;
3249 if (j < 7) continue;
3252 scalable = fonts[i];
3255 err = pxlSize - targetPxlSize;
3256 if (Abs(err) < Abs(minerr) ||
3257 (minerr > 0 && err < 0 && -err == minerr)) {
3263 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3264 /* If the error is too big and there is a scalable font,
3265 use the scalable font. */
3266 int headlen = scalableTail - scalable;
3267 p = (char *) XtMalloc(strlen(scalable) + 10);
3268 while (isdigit(*scalableTail)) scalableTail++;
3269 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3271 p = (char *) XtMalloc(strlen(best) + 2);
3272 safeStrCpy(p, best, strlen(best)+1 );
3274 if (appData.debugMode) {
3275 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3276 pattern, targetPxlSize, p);
3278 XFreeFontNames(fonts);
3285 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3286 // must be called before all non-first callse to CreateGCs()
3287 XtReleaseGC(shellWidget, highlineGC);
3288 XtReleaseGC(shellWidget, lightSquareGC);
3289 XtReleaseGC(shellWidget, darkSquareGC);
3290 XtReleaseGC(shellWidget, lineGC);
3291 if (appData.monoMode) {
3292 if (DefaultDepth(xDisplay, xScreen) == 1) {
3293 XtReleaseGC(shellWidget, wbPieceGC);
3295 XtReleaseGC(shellWidget, bwPieceGC);
3298 XtReleaseGC(shellWidget, prelineGC);
3299 XtReleaseGC(shellWidget, jailSquareGC);
3300 XtReleaseGC(shellWidget, wdPieceGC);
3301 XtReleaseGC(shellWidget, wlPieceGC);
3302 XtReleaseGC(shellWidget, wjPieceGC);
3303 XtReleaseGC(shellWidget, bdPieceGC);
3304 XtReleaseGC(shellWidget, blPieceGC);
3305 XtReleaseGC(shellWidget, bjPieceGC);
3310 CreateGCs (int redo)
3312 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3313 | GCBackground | GCFunction | GCPlaneMask;
3314 XGCValues gc_values;
3317 gc_values.plane_mask = AllPlanes;
3318 gc_values.line_width = lineGap;
3319 gc_values.line_style = LineSolid;
3320 gc_values.function = GXcopy;
3323 DeleteGCs(); // called a second time; clean up old GCs first
3324 } else { // [HGM] grid and font GCs created on first call only
3325 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3326 gc_values.background = XWhitePixel(xDisplay, xScreen);
3327 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3328 XSetFont(xDisplay, coordGC, coordFontID);
3330 // [HGM] make font for holdings counts (white on black)
3331 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3332 gc_values.background = XBlackPixel(xDisplay, xScreen);
3333 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3334 XSetFont(xDisplay, countGC, countFontID);
3336 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3337 gc_values.background = XBlackPixel(xDisplay, xScreen);
3338 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3340 if (appData.monoMode) {
3341 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3342 gc_values.background = XWhitePixel(xDisplay, xScreen);
3343 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3345 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3346 gc_values.background = XBlackPixel(xDisplay, xScreen);
3347 lightSquareGC = wbPieceGC
3348 = XtGetGC(shellWidget, value_mask, &gc_values);
3350 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3351 gc_values.background = XWhitePixel(xDisplay, xScreen);
3352 darkSquareGC = bwPieceGC
3353 = XtGetGC(shellWidget, value_mask, &gc_values);
3355 if (DefaultDepth(xDisplay, xScreen) == 1) {
3356 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3357 gc_values.function = GXcopyInverted;
3358 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3359 gc_values.function = GXcopy;
3360 if (XBlackPixel(xDisplay, xScreen) == 1) {
3361 bwPieceGC = darkSquareGC;
3362 wbPieceGC = copyInvertedGC;
3364 bwPieceGC = copyInvertedGC;
3365 wbPieceGC = lightSquareGC;
3369 gc_values.foreground = highlightSquareColor;
3370 gc_values.background = highlightSquareColor;
3371 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3373 gc_values.foreground = premoveHighlightColor;
3374 gc_values.background = premoveHighlightColor;
3375 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3377 gc_values.foreground = lightSquareColor;
3378 gc_values.background = darkSquareColor;
3379 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3381 gc_values.foreground = darkSquareColor;
3382 gc_values.background = lightSquareColor;
3383 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3385 gc_values.foreground = jailSquareColor;
3386 gc_values.background = jailSquareColor;
3387 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3389 gc_values.foreground = whitePieceColor;
3390 gc_values.background = darkSquareColor;
3391 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3393 gc_values.foreground = whitePieceColor;
3394 gc_values.background = lightSquareColor;
3395 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3397 gc_values.foreground = whitePieceColor;
3398 gc_values.background = jailSquareColor;
3399 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3401 gc_values.foreground = blackPieceColor;
3402 gc_values.background = darkSquareColor;
3403 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3405 gc_values.foreground = blackPieceColor;
3406 gc_values.background = lightSquareColor;
3407 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3409 gc_values.foreground = blackPieceColor;
3410 gc_values.background = jailSquareColor;
3411 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3416 loadXIM (XImage *xim, XImage *xmask, char *filename, Pixmap *dest, Pixmap *mask)
3424 fp = fopen(filename, "rb");
3426 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3433 for (y=0; y<h; ++y) {
3434 for (x=0; x<h; ++x) {
3439 XPutPixel(xim, x, y, blackPieceColor);
3441 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3444 XPutPixel(xim, x, y, darkSquareColor);
3446 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3449 XPutPixel(xim, x, y, whitePieceColor);
3451 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3454 XPutPixel(xim, x, y, lightSquareColor);
3456 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3464 /* create Pixmap of piece */
3465 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3467 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3470 /* create Pixmap of clipmask
3471 Note: We assume the white/black pieces have the same
3472 outline, so we make only 6 masks. This is okay
3473 since the XPM clipmask routines do the same. */
3475 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3477 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3480 /* now create the 1-bit version */
3481 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3484 values.foreground = 1;
3485 values.background = 0;
3487 /* Don't use XtGetGC, not read only */
3488 maskGC = XCreateGC(xDisplay, *mask,
3489 GCForeground | GCBackground, &values);
3490 XCopyPlane(xDisplay, temp, *mask, maskGC,
3491 0, 0, squareSize, squareSize, 0, 0, 1);
3492 XFreePixmap(xDisplay, temp);
3497 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3505 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3510 /* The XSynchronize calls were copied from CreatePieces.
3511 Not sure if needed, but can't hurt */
3512 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3515 /* temp needed by loadXIM() */
3516 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3517 0, 0, ss, ss, AllPlanes, XYPixmap);
3519 if (strlen(appData.pixmapDirectory) == 0) {
3523 if (appData.monoMode) {
3524 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3528 fprintf(stderr, _("\nLoading XIMs...\n"));
3530 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3531 fprintf(stderr, "%d", piece+1);
3532 for (kind=0; kind<4; kind++) {
3533 fprintf(stderr, ".");
3534 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3535 ExpandPathName(appData.pixmapDirectory),
3536 piece <= (int) WhiteKing ? "" : "w",
3537 pieceBitmapNames[piece],
3539 ximPieceBitmap[kind][piece] =
3540 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3541 0, 0, ss, ss, AllPlanes, XYPixmap);
3542 if (appData.debugMode)
3543 fprintf(stderr, _("(File:%s:) "), buf);
3544 loadXIM(ximPieceBitmap[kind][piece],
3546 &(xpmPieceBitmap2[kind][piece]),
3547 &(ximMaskPm2[piece]));
3548 if(piece <= (int)WhiteKing)
3549 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3551 fprintf(stderr," ");
3553 /* Load light and dark squares */
3554 /* If the LSQ and DSQ pieces don't exist, we will
3555 draw them with solid squares. */
3556 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3557 if (access(buf, 0) != 0) {
3561 fprintf(stderr, _("light square "));
3563 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3564 0, 0, ss, ss, AllPlanes, XYPixmap);
3565 if (appData.debugMode)
3566 fprintf(stderr, _("(File:%s:) "), buf);
3568 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3569 fprintf(stderr, _("dark square "));
3570 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3571 ExpandPathName(appData.pixmapDirectory), ss);
3572 if (appData.debugMode)
3573 fprintf(stderr, _("(File:%s:) "), buf);
3575 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3576 0, 0, ss, ss, AllPlanes, XYPixmap);
3577 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3578 xpmJailSquare = xpmLightSquare;
3580 fprintf(stderr, _("Done.\n"));
3582 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3585 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3589 CreateXPMBoard (char *s, int kind)
3593 if(!appData.useBitmaps || s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3594 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3595 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3601 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3602 // thisroutine has to be called t free the old piece pixmaps
3604 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3605 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3607 XFreePixmap(xDisplay, xpmLightSquare);
3608 XFreePixmap(xDisplay, xpmDarkSquare);
3617 u_int ss = squareSize;
3619 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3620 XpmColorSymbol symbols[4];
3621 static int redo = False;
3623 if(redo) FreeXPMPieces(); else redo = 1;
3625 /* The XSynchronize calls were copied from CreatePieces.
3626 Not sure if needed, but can't hurt */
3627 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3629 /* Setup translations so piece colors match square colors */
3630 symbols[0].name = "light_piece";
3631 symbols[0].value = appData.whitePieceColor;
3632 symbols[1].name = "dark_piece";
3633 symbols[1].value = appData.blackPieceColor;
3634 symbols[2].name = "light_square";
3635 symbols[2].value = appData.lightSquareColor;
3636 symbols[3].name = "dark_square";
3637 symbols[3].value = appData.darkSquareColor;
3639 attr.valuemask = XpmColorSymbols;
3640 attr.colorsymbols = symbols;
3641 attr.numsymbols = 4;
3643 if (appData.monoMode) {
3644 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3648 if (strlen(appData.pixmapDirectory) == 0) {
3649 XpmPieces* pieces = builtInXpms;
3652 while (pieces->size != squareSize && pieces->size) pieces++;
3653 if (!pieces->size) {
3654 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3657 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3658 for (kind=0; kind<4; kind++) {
3660 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3661 pieces->xpm[piece][kind],
3662 &(xpmPieceBitmap2[kind][piece]),
3663 NULL, &attr)) != 0) {
3664 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3668 if(piece <= (int) WhiteKing)
3669 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3673 xpmJailSquare = xpmLightSquare;
3677 fprintf(stderr, _("\nLoading XPMs...\n"));
3680 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3681 fprintf(stderr, "%d ", piece+1);
3682 for (kind=0; kind<4; kind++) {
3683 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3684 ExpandPathName(appData.pixmapDirectory),
3685 piece > (int) WhiteKing ? "w" : "",
3686 pieceBitmapNames[piece],
3688 if (appData.debugMode) {
3689 fprintf(stderr, _("(File:%s:) "), buf);
3691 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3692 &(xpmPieceBitmap2[kind][piece]),
3693 NULL, &attr)) != 0) {
3694 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3695 // [HGM] missing: read of unorthodox piece failed; substitute King.
3696 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3697 ExpandPathName(appData.pixmapDirectory),
3699 if (appData.debugMode) {
3700 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3702 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3703 &(xpmPieceBitmap2[kind][piece]),
3707 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3712 if(piece <= (int) WhiteKing)
3713 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3716 /* Load light and dark squares */
3717 /* If the LSQ and DSQ pieces don't exist, we will
3718 draw them with solid squares. */
3719 fprintf(stderr, _("light square "));
3720 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3721 if (access(buf, 0) != 0) {
3725 if (appData.debugMode)
3726 fprintf(stderr, _("(File:%s:) "), buf);
3728 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3729 &xpmLightSquare, NULL, &attr)) != 0) {
3730 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3733 fprintf(stderr, _("dark square "));
3734 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3735 ExpandPathName(appData.pixmapDirectory), ss);
3736 if (appData.debugMode) {
3737 fprintf(stderr, _("(File:%s:) "), buf);
3739 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3740 &xpmDarkSquare, NULL, &attr)) != 0) {
3741 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3745 xpmJailSquare = xpmLightSquare;
3746 fprintf(stderr, _("Done.\n"));
3748 oldVariant = -1; // kludge to force re-makig of animation masks
3749 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3752 #endif /* HAVE_LIBXPM */
3755 /* No built-in bitmaps */
3760 u_int ss = squareSize;
3762 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3765 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3766 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3767 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3768 pieceBitmapNames[piece],
3769 ss, kind == SOLID ? 's' : 'o');
3770 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3771 if(piece <= (int)WhiteKing)
3772 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3776 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3780 /* With built-in bitmaps */
3784 BuiltInBits* bib = builtInBits;
3787 u_int ss = squareSize;
3789 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3792 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3794 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3795 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3796 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3797 pieceBitmapNames[piece],
3798 ss, kind == SOLID ? 's' : 'o');
3799 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3800 bib->bits[kind][piece], ss, ss);
3801 if(piece <= (int)WhiteKing)
3802 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3806 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3812 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
3817 char msg[MSG_SIZ], fullname[MSG_SIZ];
3819 if (*appData.bitmapDirectory != NULLCHAR) {
3820 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3821 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3822 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3823 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3824 &w, &h, pm, &x_hot, &y_hot);
3825 fprintf(stderr, "load %s\n", name);
3826 if (errcode != BitmapSuccess) {
3828 case BitmapOpenFailed:
3829 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3831 case BitmapFileInvalid:
3832 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3834 case BitmapNoMemory:
3835 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3839 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3843 fprintf(stderr, _("%s: %s...using built-in\n"),
3845 } else if (w != wreq || h != hreq) {
3847 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3848 programName, fullname, w, h, wreq, hreq);
3854 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3864 if (lineGap == 0) return;
3866 /* [HR] Split this into 2 loops for non-square boards. */
3868 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3869 gridSegments[i].x1 = 0;
3870 gridSegments[i].x2 =
3871 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3872 gridSegments[i].y1 = gridSegments[i].y2
3873 = lineGap / 2 + (i * (squareSize + lineGap));
3876 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3877 gridSegments[j + i].y1 = 0;
3878 gridSegments[j + i].y2 =
3879 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3880 gridSegments[j + i].x1 = gridSegments[j + i].x2
3881 = lineGap / 2 + (j * (squareSize + lineGap));
3886 MenuBarSelect (Widget w, caddr_t addr, caddr_t index)
3888 XtActionProc proc = (XtActionProc) addr;
3890 (proc)(NULL, NULL, NULL, NULL);
3894 CreateMenuBarPopup (Widget parent, String name, Menu *mb)
3901 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3904 XtSetArg(args[j], XtNleftMargin, 20); j++;
3905 XtSetArg(args[j], XtNrightMargin, 20); j++;
3907 while (mi->string != NULL) {
3908 if (strcmp(mi->string, "----") == 0) {
3909 entry = XtCreateManagedWidget(_(mi->string), smeLineObjectClass,
3912 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3913 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3915 XtAddCallback(entry, XtNcallback,
3916 (XtCallbackProc) MenuBarSelect,
3917 (caddr_t) mi->proc);
3924 CreateMenuBar (Menu *mb, int boardWidth)
3926 int i, j, nr = 0, wtot = 0, widths[10];
3929 char menuName[MSG_SIZ];
3934 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3935 XtSetArg(args[j], XtNvSpace, 0); j++;
3936 XtSetArg(args[j], XtNborderWidth, 0); j++;
3937 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3938 formWidget, args, j);
3940 while (mb->name != NULL) {
3941 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3942 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3944 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3945 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3946 XtSetArg(args[j], XtNborderWidth, 0); j++;
3947 mb->subMenu = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3949 CreateMenuBarPopup(menuBar, menuName, mb);
3951 XtSetArg(args[j], XtNwidth, &w); j++;
3952 XtGetValues(mb->subMenu, args, j);
3953 wtot += mb->textWidth = widths[nr++] = w;
3956 while(wtot > boardWidth - 40) {
3958 for(i=0; i<nr; i++) if(widths[i] > wmax) wmax = widths[imax=i];
3962 for(i=0; i<nr; i++) if(widths[i] != ma[i].textWidth) {
3964 XtSetArg(args[j], XtNwidth, widths[i]); j++;
3965 XtSetValues(ma[i].subMenu, args, j);
3971 CreateButtonBar (MenuItem *mi)
3974 Widget button, buttonBar;
3978 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3980 XtSetArg(args[j], XtNhSpace, 0); j++;
3982 XtSetArg(args[j], XtNborderWidth, 0); j++;
3983 XtSetArg(args[j], XtNvSpace, 0); j++;
3984 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3985 formWidget, args, j);
3987 while (mi->string != NULL) {
3990 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3991 XtSetArg(args[j], XtNborderWidth, 0); j++;
3993 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3994 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3995 buttonBar, args, j);
3996 XtAddCallback(button, XtNcallback,
3997 (XtCallbackProc) MenuBarSelect,
3998 (caddr_t) mi->proc);
4005 CreatePieceMenu (char *name, int color)
4010 ChessSquare selection;
4012 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
4013 boardWidget, args, 0);
4015 for (i = 0; i < PIECE_MENU_SIZE; i++) {
4016 String item = pieceMenuStrings[color][i];
4018 if (strcmp(item, "----") == 0) {
4019 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4022 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4023 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4025 selection = pieceMenuTranslation[color][i];
4026 XtAddCallback(entry, XtNcallback,
4027 (XtCallbackProc) PieceMenuSelect,
4028 (caddr_t) selection);
4029 if (selection == WhitePawn || selection == BlackPawn) {
4030 XtSetArg(args[0], XtNpopupOnEntry, entry);
4031 XtSetValues(menu, args, 1);
4044 ChessSquare selection;
4046 whitePieceMenu = CreatePieceMenu("menuW", 0);
4047 blackPieceMenu = CreatePieceMenu("menuB", 1);
4049 XtRegisterGrabAction(PieceMenuPopup, True,
4050 (unsigned)(ButtonPressMask|ButtonReleaseMask),
4051 GrabModeAsync, GrabModeAsync);
4053 XtSetArg(args[0], XtNlabel, _("Drop"));
4054 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
4055 boardWidget, args, 1);
4056 for (i = 0; i < DROP_MENU_SIZE; i++) {
4057 String item = dropMenuStrings[i];
4059 if (strcmp(item, "----") == 0) {
4060 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4063 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4064 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4066 selection = dropMenuTranslation[i];
4067 XtAddCallback(entry, XtNcallback,
4068 (XtCallbackProc) DropMenuSelect,
4069 (caddr_t) selection);
4083 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
4084 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
4085 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
4086 dmEnables[i].piece);
4087 XtSetSensitive(entry, p != NULL || !appData.testLegality
4088 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
4089 && !appData.icsActive));
4091 while (p && *p++ == dmEnables[i].piece) count++;
4092 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
4094 XtSetArg(args[j], XtNlabel, label); j++;
4095 XtSetValues(entry, args, j);
4100 PieceMenuPopup (Widget w, XEvent *event, String *params, Cardinal *num_params)
4102 String whichMenu; int menuNr = -2;
4103 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
4104 if (event->type == ButtonRelease)
4105 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4106 else if (event->type == ButtonPress)
4107 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4109 case 0: whichMenu = params[0]; break;
4110 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
4112 case -1: if (errorUp) ErrorPopDown();
4115 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
4119 PieceMenuSelect (Widget w, ChessSquare piece, caddr_t junk)
4121 if (pmFromX < 0 || pmFromY < 0) return;
4122 EditPositionMenuEvent(piece, pmFromX, pmFromY);
4126 DropMenuSelect (Widget w, ChessSquare piece, caddr_t junk)
4128 if (pmFromX < 0 || pmFromY < 0) return;
4129 DropMenuEvent(piece, pmFromX, pmFromY);
4133 WhiteClock (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4135 shiftKey = prms[0][0] & 1;
4140 BlackClock (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4142 shiftKey = prms[0][0] & 1;
4148 * If the user selects on a border boundary, return -1; if off the board,
4149 * return -2. Otherwise map the event coordinate to the square.
4152 EventToSquare (int x, int limit)
4159 if ((x % (squareSize + lineGap)) >= squareSize)
4161 x /= (squareSize + lineGap);
4168 do_flash_delay (unsigned long msec)
4174 drawHighlight (int file, int rank, GC gc)
4178 if (lineGap == 0) return;
4181 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4182 (squareSize + lineGap);
4183 y = lineGap/2 + rank * (squareSize + lineGap);
4185 x = lineGap/2 + file * (squareSize + lineGap);
4186 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4187 (squareSize + lineGap);
4190 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4191 squareSize+lineGap, squareSize+lineGap);
4194 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4195 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4198 SetHighlights (int fromX, int fromY, int toX, int toY)
4200 if (hi1X != fromX || hi1Y != fromY) {
4201 if (hi1X >= 0 && hi1Y >= 0) {
4202 drawHighlight(hi1X, hi1Y, lineGC);
4204 } // [HGM] first erase both, then draw new!
4205 if (hi2X != toX || hi2Y != toY) {
4206 if (hi2X >= 0 && hi2Y >= 0) {
4207 drawHighlight(hi2X, hi2Y, lineGC);
4210 if (hi1X != fromX || hi1Y != fromY) {
4211 if (fromX >= 0 && fromY >= 0) {
4212 drawHighlight(fromX, fromY, highlineGC);
4215 if (hi2X != toX || hi2Y != toY) {
4216 if (toX >= 0 && toY >= 0) {
4217 drawHighlight(toX, toY, highlineGC);
4229 SetHighlights(-1, -1, -1, -1);
4234 SetPremoveHighlights (int fromX, int fromY, int toX, int toY)
4236 if (pm1X != fromX || pm1Y != fromY) {
4237 if (pm1X >= 0 && pm1Y >= 0) {
4238 drawHighlight(pm1X, pm1Y, lineGC);
4240 if (fromX >= 0 && fromY >= 0) {
4241 drawHighlight(fromX, fromY, prelineGC);
4244 if (pm2X != toX || pm2Y != toY) {
4245 if (pm2X >= 0 && pm2Y >= 0) {
4246 drawHighlight(pm2X, pm2Y, lineGC);
4248 if (toX >= 0 && toY >= 0) {
4249 drawHighlight(toX, toY, prelineGC);
4259 ClearPremoveHighlights ()
4261 SetPremoveHighlights(-1, -1, -1, -1);
4265 CutOutSquare (int x, int y, int *x0, int *y0, int kind)
4267 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4268 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4270 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4271 if(textureW[kind] < W*squareSize)
4272 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4274 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4275 if(textureH[kind] < H*squareSize)
4276 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4278 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4283 BlankSquare (int x, int y, int color, ChessSquare piece, Drawable dest, int fac)
4284 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4286 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4287 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4288 squareSize, squareSize, x*fac, y*fac);
4290 if (useImages && useImageSqs) {
4294 pm = xpmLightSquare;
4299 case 2: /* neutral */
4304 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4305 squareSize, squareSize, x*fac, y*fac);
4315 case 2: /* neutral */
4320 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4325 I split out the routines to draw a piece so that I could
4326 make a generic flash routine.
4329 monoDrawPiece_1bit (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4331 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4332 switch (square_color) {
4334 case 2: /* neutral */
4336 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4337 ? *pieceToOutline(piece)
4338 : *pieceToSolid(piece),
4339 dest, bwPieceGC, 0, 0,
4340 squareSize, squareSize, x, y);
4343 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4344 ? *pieceToSolid(piece)
4345 : *pieceToOutline(piece),
4346 dest, wbPieceGC, 0, 0,
4347 squareSize, squareSize, x, y);
4353 monoDrawPiece (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4355 switch (square_color) {
4357 case 2: /* neutral */
4359 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4360 ? *pieceToOutline(piece)
4361 : *pieceToSolid(piece),
4362 dest, bwPieceGC, 0, 0,
4363 squareSize, squareSize, x, y, 1);
4366 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4367 ? *pieceToSolid(piece)
4368 : *pieceToOutline(piece),
4369 dest, wbPieceGC, 0, 0,
4370 squareSize, squareSize, x, y, 1);
4376 colorDrawPiece (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4378 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4379 switch (square_color) {
4381 XCopyPlane(xDisplay, *pieceToSolid(piece),
4382 dest, (int) piece < (int) BlackPawn
4383 ? wlPieceGC : blPieceGC, 0, 0,
4384 squareSize, squareSize, x, y, 1);
4387 XCopyPlane(xDisplay, *pieceToSolid(piece),
4388 dest, (int) piece < (int) BlackPawn
4389 ? wdPieceGC : bdPieceGC, 0, 0,
4390 squareSize, squareSize, x, y, 1);
4392 case 2: /* neutral */
4394 XCopyPlane(xDisplay, *pieceToSolid(piece),
4395 dest, (int) piece < (int) BlackPawn
4396 ? wjPieceGC : bjPieceGC, 0, 0,
4397 squareSize, squareSize, x, y, 1);
4403 colorDrawPieceImage (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4405 int kind, p = piece;
4407 switch (square_color) {
4409 case 2: /* neutral */
4411 if ((int)piece < (int) BlackPawn) {
4419 if ((int)piece < (int) BlackPawn) {
4427 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4428 if(useTexture & square_color+1) {
4429 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4430 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4431 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4432 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4433 XSetClipMask(xDisplay, wlPieceGC, None);
4434 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4436 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4437 dest, wlPieceGC, 0, 0,
4438 squareSize, squareSize, x, y);
4441 typedef void (*DrawFunc)();
4446 if (appData.monoMode) {
4447 if (DefaultDepth(xDisplay, xScreen) == 1) {
4448 return monoDrawPiece_1bit;
4450 return monoDrawPiece;
4454 return colorDrawPieceImage;
4456 return colorDrawPiece;
4460 /* [HR] determine square color depending on chess variant. */
4462 SquareColor (int row, int column)
4466 if (gameInfo.variant == VariantXiangqi) {
4467 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4469 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4471 } else if (row <= 4) {
4477 square_color = ((column + row) % 2) == 1;
4480 /* [hgm] holdings: next line makes all holdings squares light */
4481 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4483 return square_color;
4487 DrawSquare (int row, int column, ChessSquare piece, int do_flash)
4489 int square_color, x, y, direction, font_ascent, font_descent;
4492 XCharStruct overall;
4496 /* Calculate delay in milliseconds (2-delays per complete flash) */
4497 flash_delay = 500 / appData.flashRate;
4500 x = lineGap + ((BOARD_WIDTH-1)-column) *
4501 (squareSize + lineGap);
4502 y = lineGap + row * (squareSize + lineGap);
4504 x = lineGap + column * (squareSize + lineGap);
4505 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4506 (squareSize + lineGap);
4509 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4511 square_color = SquareColor(row, column);
4513 if ( // [HGM] holdings: blank out area between board and holdings
4514 column == BOARD_LEFT-1 || column == BOARD_RGHT
4515 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4516 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4517 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4519 // [HGM] print piece counts next to holdings
4520 string[1] = NULLCHAR;
4521 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4522 string[0] = '0' + piece;
4523 XTextExtents(countFontStruct, string, 1, &direction,
4524 &font_ascent, &font_descent, &overall);
4525 if (appData.monoMode) {
4526 XDrawImageString(xDisplay, xBoardWindow, countGC,
4527 x + squareSize - overall.width - 2,
4528 y + font_ascent + 1, string, 1);
4530 XDrawString(xDisplay, xBoardWindow, countGC,
4531 x + squareSize - overall.width - 2,
4532 y + font_ascent + 1, string, 1);
4535 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4536 string[0] = '0' + piece;
4537 XTextExtents(countFontStruct, string, 1, &direction,
4538 &font_ascent, &font_descent, &overall);
4539 if (appData.monoMode) {
4540 XDrawImageString(xDisplay, xBoardWindow, countGC,
4541 x + 2, y + font_ascent + 1, string, 1);
4543 XDrawString(xDisplay, xBoardWindow, countGC,
4544 x + 2, y + font_ascent + 1, string, 1);
4548 if (piece == EmptySquare || appData.blindfold) {
4549 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4551 drawfunc = ChooseDrawFunc();
4553 if (do_flash && appData.flashCount > 0) {
4554 for (i=0; i<appData.flashCount; ++i) {
4555 drawfunc(piece, square_color, x, y, xBoardWindow);
4556 XSync(xDisplay, False);
4557 do_flash_delay(flash_delay);
4559 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4560 XSync(xDisplay, False);
4561 do_flash_delay(flash_delay);
4564 drawfunc(piece, square_color, x, y, xBoardWindow);
4568 string[1] = NULLCHAR;
4569 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4570 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4571 string[0] = 'a' + column - BOARD_LEFT;
4572 XTextExtents(coordFontStruct, string, 1, &direction,
4573 &font_ascent, &font_descent, &overall);
4574 if (appData.monoMode) {
4575 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4576 x + squareSize - overall.width - 2,
4577 y + squareSize - font_descent - 1, string, 1);
4579 XDrawString(xDisplay, xBoardWindow, coordGC,
4580 x + squareSize - overall.width - 2,
4581 y + squareSize - font_descent - 1, string, 1);
4584 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4585 string[0] = ONE + row;
4586 XTextExtents(coordFontStruct, string, 1, &direction,
4587 &font_ascent, &font_descent, &overall);
4588 if (appData.monoMode) {
4589 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4590 x + 2, y + font_ascent + 1, string, 1);
4592 XDrawString(xDisplay, xBoardWindow, coordGC,
4593 x + 2, y + font_ascent + 1, string, 1);
4596 if(!partnerUp && marker[row][column]) {
4597 if(appData.monoMode) {
4598 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? darkSquareGC : lightSquareGC,
4599 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4600 XDrawArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? lightSquareGC : darkSquareGC,
4601 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4603 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4604 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4609 /* Why is this needed on some versions of X? */
4611 EventProc (Widget widget, caddr_t unused, XEvent *event)
4613 if (!XtIsRealized(widget))
4616 switch (event->type) {
4618 if (event->xexpose.count > 0) return; /* no clipping is done */
4619 XDrawPosition(widget, True, NULL);
4620 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4621 flipView = !flipView; partnerUp = !partnerUp;
4622 XDrawPosition(widget, True, NULL);
4623 flipView = !flipView; partnerUp = !partnerUp;
4627 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4635 DrawPosition (int fullRedraw, Board board)
4637 XDrawPosition(boardWidget, fullRedraw, board);
4640 /* Returns 1 if there are "too many" differences between b1 and b2
4641 (i.e. more than 1 move was made) */
4643 too_many_diffs (Board b1, Board b2)
4648 for (i=0; i<BOARD_HEIGHT; ++i) {
4649 for (j=0; j<BOARD_WIDTH; ++j) {
4650 if (b1[i][j] != b2[i][j]) {
4651 if (++c > 4) /* Castling causes 4 diffs */
4659 /* Matrix describing castling maneuvers */
4660 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4661 static int castling_matrix[4][5] = {
4662 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4663 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4664 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4665 { 7, 7, 4, 5, 6 } /* 0-0, black */
4668 /* Checks whether castling occurred. If it did, *rrow and *rcol
4669 are set to the destination (row,col) of the rook that moved.
4671 Returns 1 if castling occurred, 0 if not.
4673 Note: Only handles a max of 1 castling move, so be sure
4674 to call too_many_diffs() first.
4677 check_castle_draw (Board newb, Board oldb, int *rrow, int *rcol)
4682 /* For each type of castling... */
4683 for (i=0; i<4; ++i) {
4684 r = castling_matrix[i];
4686 /* Check the 4 squares involved in the castling move */
4688 for (j=1; j<=4; ++j) {
4689 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4696 /* All 4 changed, so it must be a castling move */
4705 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4707 DrawSeekAxis (int x, int y, int xTo, int yTo)
4709 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4713 DrawSeekBackground (int left, int top, int right, int bottom)
4715 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4719 DrawSeekText (char *buf, int x, int y)
4721 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4725 DrawSeekDot (int x, int y, int colorNr)
4727 int square = colorNr & 0x80;
4730 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4732 XFillRectangle(xDisplay, xBoardWindow, color,
4733 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4735 XFillArc(xDisplay, xBoardWindow, color,
4736 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4739 static int damage[2][BOARD_RANKS][BOARD_FILES];
4742 * event handler for redrawing the board
4745 XDrawPosition (Widget w, int repaint, Board board)
4748 static int lastFlipView = 0;
4749 static int lastBoardValid[2] = {0, 0};
4750 static Board lastBoard[2];
4753 int nr = twoBoards*partnerUp;
4755 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4757 if (board == NULL) {
4758 if (!lastBoardValid[nr]) return;
4759 board = lastBoard[nr];
4761 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4762 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4763 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4768 * It would be simpler to clear the window with XClearWindow()
4769 * but this causes a very distracting flicker.
4772 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4774 if ( lineGap && IsDrawArrowEnabled())
4775 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4776 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4778 /* If too much changes (begin observing new game, etc.), don't
4780 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4782 /* Special check for castling so we don't flash both the king
4783 and the rook (just flash the king). */
4785 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4786 /* Draw rook with NO flashing. King will be drawn flashing later */
4787 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4788 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4792 /* First pass -- Draw (newly) empty squares and repair damage.
4793 This prevents you from having a piece show up twice while it
4794 is flashing on its new square */
4795 for (i = 0; i < BOARD_HEIGHT; i++)
4796 for (j = 0; j < BOARD_WIDTH; j++)
4797 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4798 || damage[nr][i][j]) {
4799 DrawSquare(i, j, board[i][j], 0);
4800 damage[nr][i][j] = False;
4803 /* Second pass -- Draw piece(s) in new position and flash them */
4804 for (i = 0; i < BOARD_HEIGHT; i++)
4805 for (j = 0; j < BOARD_WIDTH; j++)
4806 if (board[i][j] != lastBoard[nr][i][j]) {
4807 DrawSquare(i, j, board[i][j], do_flash);
4811 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4812 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4813 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4815 for (i = 0; i < BOARD_HEIGHT; i++)
4816 for (j = 0; j < BOARD_WIDTH; j++) {
4817 DrawSquare(i, j, board[i][j], 0);
4818 damage[nr][i][j] = False;
4822 CopyBoard(lastBoard[nr], board);
4823 lastBoardValid[nr] = 1;
4824 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4825 lastFlipView = flipView;
4827 /* Draw highlights */
4828 if (pm1X >= 0 && pm1Y >= 0) {
4829 drawHighlight(pm1X, pm1Y, prelineGC);
4831 if (pm2X >= 0 && pm2Y >= 0) {
4832 drawHighlight(pm2X, pm2Y, prelineGC);
4834 if (hi1X >= 0 && hi1Y >= 0) {
4835 drawHighlight(hi1X, hi1Y, highlineGC);
4837 if (hi2X >= 0 && hi2Y >= 0) {
4838 drawHighlight(hi2X, hi2Y, highlineGC);
4840 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4842 /* If piece being dragged around board, must redraw that too */
4845 XSync(xDisplay, False);
4850 * event handler for redrawing the board
4853 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4855 XDrawPosition(w, True, NULL);
4860 * event handler for parsing user moves
4862 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4863 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4864 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4865 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4866 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4867 // and at the end FinishMove() to perform the move after optional promotion popups.
4868 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4870 HandleUserMove (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4872 if (w != boardWidget || errorExitStatus != -1) return;
4873 if(nprms) shiftKey = !strcmp(prms[0], "1");
4876 if (event->type == ButtonPress) {
4877 XtPopdown(promotionShell);
4878 XtDestroyWidget(promotionShell);
4879 promotionUp = False;
4887 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4888 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4889 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4893 AnimateUserMove (Widget w, XEvent *event, String *params, Cardinal *nParams)
4895 if(!PromoScroll(event->xmotion.x, event->xmotion.y))
4896 DragPieceMove(event->xmotion.x, event->xmotion.y);
4900 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
4901 { // [HGM] pv: walk PV
4902 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4905 static int savedIndex; /* gross that this is global */
4908 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4911 XawTextPosition index, dummy;
4914 XawTextGetSelectionPos(w, &index, &dummy);
4915 XtSetArg(arg, XtNstring, &val);
4916 XtGetValues(w, &arg, 1);
4917 ReplaceComment(savedIndex, val);
4918 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4919 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4923 EditCommentPopUp (int index, char *title, char *text)
4926 if (text == NULL) text = "";
4927 NewCommentPopup(title, text, index);
4936 extern Option boxOptions[];
4946 edit = boxOptions[0].handle;
4948 XtSetArg(args[j], XtNstring, &val); j++;
4949 XtGetValues(edit, args, j);
4951 SendMultiLineToICS(val);
4952 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4953 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4957 ICSInputBoxPopDown ()
4963 CommentPopUp (char *title, char *text)
4965 savedIndex = currentMove; // [HGM] vari
4966 NewCommentPopup(title, text, currentMove);
4975 static char *openName;
4981 (void) (*fileProc)(openFP, 0, openName);
4985 FileNamePopUp (char *label, char *def, char *filter, FileProc proc, char *openMode)
4987 fileProc = proc; /* I can't see a way not */
4988 fileOpenMode = openMode; /* to use globals here */
4989 { // [HGM] use file-selector dialog stolen from Ghostview
4990 int index; // this is not supported yet
4991 if(openFP = XsraSelFile(shellWidget, label, NULL, NULL, _("could not open: "),
4992 (def[0] ? def : NULL), filter, openMode, NULL, &openName))
4993 // [HGM] delay to give expose event opportunity to redraw board after browser-dialog popdown before lengthy load starts
4994 ScheduleDelayedEvent(&DelayedLoad, 50);
5001 if (!filenameUp) return;
5002 XtPopdown(fileNameShell);
5003 XtDestroyWidget(fileNameShell);
5009 FileNameCallback (Widget w, XtPointer client_data, XtPointer call_data)
5014 XtSetArg(args[0], XtNlabel, &name);
5015 XtGetValues(w, args, 1);
5017 if (strcmp(name, _("cancel")) == 0) {
5022 FileNameAction(w, NULL, NULL, NULL);
5026 FileNameAction (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5034 name = XawDialogGetValueString(w = XtParent(w));
5036 if ((name != NULL) && (*name != NULLCHAR)) {
5037 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5038 XtPopdown(w = XtParent(XtParent(w)));
5042 p = strrchr(buf, ' ');
5049 fullname = ExpandPathName(buf);
5051 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5054 f = fopen(fullname, fileOpenMode);
5056 DisplayError(_("Failed to open file"), errno);
5058 (void) (*fileProc)(f, index, buf);
5065 XtPopdown(w = XtParent(XtParent(w)));
5075 Widget dialog, layout;
5077 Dimension bw_width, pw_width;
5079 char *PromoChars = "wglcqrbnkac+=\0";
5082 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5083 XtGetValues(boardWidget, args, j);
5086 XtSetArg(args[j], XtNresizable, True); j++;
5087 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5089 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5090 shellWidget, args, j);
5092 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5093 layoutArgs, XtNumber(layoutArgs));
5096 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5097 XtSetArg(args[j], XtNborderWidth, 0); j++;
5098 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5101 if(gameInfo.variant != VariantShogi) {
5102 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5103 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback, PromoChars + 0);
5104 XawDialogAddButton(dialog, _("General"), PromotionCallback, PromoChars + 1);
5105 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback, PromoChars + 2);
5106 XawDialogAddButton(dialog, _("Captain"), PromotionCallback, PromoChars + 3);
5108 XawDialogAddButton(dialog, _("Queen"), PromotionCallback, PromoChars + 4);
5109 XawDialogAddButton(dialog, _("Rook"), PromotionCallback, PromoChars + 5);
5110 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback, PromoChars + 6);
5111 XawDialogAddButton(dialog, _("Knight"), PromotionCallback, PromoChars + 7);
5113 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5114 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
5115 gameInfo.variant == VariantGiveaway) {
5116 XawDialogAddButton(dialog, _("King"), PromotionCallback, PromoChars + 8);
5118 if(gameInfo.variant == VariantCapablanca ||
5119 gameInfo.variant == VariantGothic ||
5120 gameInfo.variant == VariantCapaRandom) {
5121 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback, PromoChars + 9);
5122 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback, PromoChars + 10);
5124 } else // [HGM] shogi
5126 XawDialogAddButton(dialog, _("Promote"), PromotionCallback, PromoChars + 11);
5127 XawDialogAddButton(dialog, _("Defer"), PromotionCallback, PromoChars + 12);
5129 XawDialogAddButton(dialog, _("cancel"), PromotionCallback, PromoChars + 13);
5131 XtRealizeWidget(promotionShell);
5132 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5135 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5136 XtGetValues(promotionShell, args, j);
5138 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5139 lineGap + squareSize/3 +
5140 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5141 0 : 6*(squareSize + lineGap)), &x, &y);
5144 XtSetArg(args[j], XtNx, x); j++;
5145 XtSetArg(args[j], XtNy, y); j++;
5146 XtSetValues(promotionShell, args, j);
5148 XtPopup(promotionShell, XtGrabNone);
5156 if (!promotionUp) return;
5157 XtPopdown(promotionShell);
5158 XtDestroyWidget(promotionShell);
5159 promotionUp = False;
5163 PromotionCallback (Widget w, XtPointer client_data, XtPointer call_data)
5165 int promoChar = * (const char *) client_data;
5169 if (fromX == -1) return;
5176 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5178 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5179 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5185 ErrorCallback (Widget w, XtPointer client_data, XtPointer call_data)
5188 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5190 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5197 if (!errorUp) return;
5199 XtPopdown(errorShell);
5200 XtDestroyWidget(errorShell);
5201 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5205 ErrorPopUp (char *title, char *label, int modal)
5208 Widget dialog, layout;
5212 Dimension bw_width, pw_width;
5213 Dimension pw_height;
5217 XtSetArg(args[i], XtNresizable, True); i++;
5218 XtSetArg(args[i], XtNtitle, title); i++;
5220 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5221 shellWidget, args, i);
5223 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5224 layoutArgs, XtNumber(layoutArgs));
5227 XtSetArg(args[i], XtNlabel, label); i++;
5228 XtSetArg(args[i], XtNborderWidth, 0); i++;
5229 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5232 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5234 XtRealizeWidget(errorShell);
5235 CatchDeleteWindow(errorShell, "ErrorPopDown");
5238 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5239 XtGetValues(boardWidget, args, i);
5241 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5242 XtSetArg(args[i], XtNheight, &pw_height); i++;
5243 XtGetValues(errorShell, args, i);
5246 /* This code seems to tickle an X bug if it is executed too soon
5247 after xboard starts up. The coordinates get transformed as if
5248 the main window was positioned at (0, 0).
5250 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5251 0 - pw_height + squareSize / 3, &x, &y);
5253 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5254 RootWindowOfScreen(XtScreen(boardWidget)),
5255 (bw_width - pw_width) / 2,
5256 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5260 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5263 XtSetArg(args[i], XtNx, x); i++;
5264 XtSetArg(args[i], XtNy, y); i++;
5265 XtSetValues(errorShell, args, i);
5268 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5271 /* Disable all user input other than deleting the window */
5272 static int frozen = 0;
5278 /* Grab by a widget that doesn't accept input */
5279 XtAddGrab(messageWidget, TRUE, FALSE);
5283 /* Undo a FreezeUI */
5287 if (!frozen) return;
5288 XtRemoveGrab(messageWidget);
5293 ModeToWidgetName (GameMode mode)
5296 case BeginningOfGame:
5297 if (appData.icsActive)
5298 return "menuMode.ICS Client";
5299 else if (appData.noChessProgram ||
5300 *appData.cmailGameName != NULLCHAR)
5301 return "menuMode.Edit Game";
5303 return "menuMode.Machine Black";
5304 case MachinePlaysBlack:
5305 return "menuMode.Machine Black";
5306 case MachinePlaysWhite:
5307 return "menuMode.Machine White";
5309 return "menuMode.Analysis Mode";
5311 return "menuMode.Analyze File";
5312 case TwoMachinesPlay:
5313 return "menuMode.Two Machines";
5315 return "menuMode.Edit Game";
5316 case PlayFromGameFile:
5317 return "menuFile.Load Game";
5319 return "menuMode.Edit Position";
5321 return "menuMode.Training";
5322 case IcsPlayingWhite:
5323 case IcsPlayingBlack:
5327 return "menuMode.ICS Client";
5338 static int oldPausing = FALSE;
5339 static GameMode oldmode = (GameMode) -1;
5342 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5344 if (pausing != oldPausing) {
5345 oldPausing = pausing;
5347 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5349 XtSetArg(args[0], XtNleftBitmap, None);
5351 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5354 if (appData.showButtonBar) {
5355 /* Always toggle, don't set. Previous code messes up when
5356 invoked while the button is pressed, as releasing it
5357 toggles the state again. */
5360 XtSetArg(args[0], XtNbackground, &oldbg);
5361 XtSetArg(args[1], XtNforeground, &oldfg);
5362 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5364 XtSetArg(args[0], XtNbackground, oldfg);
5365 XtSetArg(args[1], XtNforeground, oldbg);
5367 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5371 wname = ModeToWidgetName(oldmode);
5372 if (wname != NULL) {
5373 XtSetArg(args[0], XtNleftBitmap, None);
5374 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5376 wname = ModeToWidgetName(gameMode);
5377 if (wname != NULL) {
5378 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5379 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5382 XtSetArg(args[0], XtNleftBitmap, matchMode && matchGame < appData.matchGames ? xMarkPixmap : None);
5383 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Machine Match"), args, 1);
5385 /* Maybe all the enables should be handled here, not just this one */
5386 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5387 gameMode == Training || gameMode == PlayFromGameFile);
5392 * Button/menu procedures
5395 ResetProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5401 LoadGamePopUp (FILE *f, int gameNumber, char *title)
5403 cmailMsgLoaded = FALSE;
5404 if (gameNumber == 0) {
5405 int error = GameListBuild(f);
5407 DisplayError(_("Cannot build game list"), error);
5408 } else if (!ListEmpty(&gameList) &&
5409 ((ListGame *) gameList.tailPred)->number > 1) {
5410 GameListPopUp(f, title);
5416 return LoadGame(f, gameNumber, title, FALSE);
5420 LoadGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5422 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5425 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5429 LoadNextGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5435 LoadPrevGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5441 ReloadGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5447 LoadNextPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5453 LoadPrevPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5459 ReloadPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5465 LoadPositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5467 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5470 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5474 SaveGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5476 FileNamePopUp(_("Save game file name?"),
5477 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5478 appData.oldSaveStyle ? ".game" : ".pgn",
5483 SavePositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5485 FileNamePopUp(_("Save position file name?"),
5486 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5487 appData.oldSaveStyle ? ".pos" : ".fen",
5492 ReloadCmailMsgProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5494 ReloadCmailMsgEvent(FALSE);
5498 MailMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5503 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5504 char *selected_fen_position=NULL;
5507 SendPositionSelection (Widget w, Atom *selection, Atom *target,
5508 Atom *type_return, XtPointer *value_return,
5509 unsigned long *length_return, int *format_return)
5511 char *selection_tmp;
5513 if (!selected_fen_position) return False; /* should never happen */
5514 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5515 /* note: since no XtSelectionDoneProc was registered, Xt will
5516 * automatically call XtFree on the value returned. So have to
5517 * make a copy of it allocated with XtMalloc */
5518 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5519 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5521 *value_return=selection_tmp;
5522 *length_return=strlen(selection_tmp);
5523 *type_return=*target;
5524 *format_return = 8; /* bits per byte */
5526 } else if (*target == XA_TARGETS(xDisplay)) {
5527 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5528 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5529 targets_tmp[1] = XA_STRING;
5530 *value_return = targets_tmp;
5531 *type_return = XA_ATOM;
5534 // This code leads to a read of value_return out of bounds on 64-bit systems.
5535 // Other code which I have seen always sets *format_return to 32 independent of
5536 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
5537 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
5538 *format_return = 8 * sizeof(Atom);
5539 if (*format_return > 32) {
5540 *length_return *= *format_return / 32;
5541 *format_return = 32;
5544 *format_return = 32;
5552 /* note: when called from menu all parameters are NULL, so no clue what the
5553 * Widget which was clicked on was, or what the click event was
5556 CopyPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5559 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5560 * have a notion of a position that is selected but not copied.
5561 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5563 if(gameMode == EditPosition) EditPositionDone(TRUE);
5564 if (selected_fen_position) free(selected_fen_position);
5565 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5566 if (!selected_fen_position) return;
5567 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5569 SendPositionSelection,
5570 NULL/* lose_ownership_proc */ ,
5571 NULL/* transfer_done_proc */);
5572 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5574 SendPositionSelection,
5575 NULL/* lose_ownership_proc */ ,
5576 NULL/* transfer_done_proc */);
5579 /* function called when the data to Paste is ready */
5581 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
5582 Atom *type, XtPointer value, unsigned long *len, int *format)
5585 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5586 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5587 EditPositionPasteFEN(fenstr);
5591 /* called when Paste Position button is pressed,
5592 * all parameters will be NULL */
5593 void PastePositionProc(w, event, prms, nprms)
5599 XtGetSelectionValue(menuBarWidget,
5600 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5601 /* (XtSelectionCallbackProc) */ PastePositionCB,
5602 NULL, /* client_data passed to PastePositionCB */
5604 /* better to use the time field from the event that triggered the
5605 * call to this function, but that isn't trivial to get
5613 SendGameSelection (Widget w, Atom *selection, Atom *target,
5614 Atom *type_return, XtPointer *value_return,
5615 unsigned long *length_return, int *format_return)
5617 char *selection_tmp;
5619 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5620 FILE* f = fopen(gameCopyFilename, "r");
5623 if (f == NULL) return False;
5627 selection_tmp = XtMalloc(len + 1);
5628 count = fread(selection_tmp, 1, len, f);
5631 XtFree(selection_tmp);
5634 selection_tmp[len] = NULLCHAR;
5635 *value_return = selection_tmp;
5636 *length_return = len;
5637 *type_return = *target;
5638 *format_return = 8; /* bits per byte */
5640 } else if (*target == XA_TARGETS(xDisplay)) {
5641 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5642 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5643 targets_tmp[1] = XA_STRING;
5644 *value_return = targets_tmp;
5645 *type_return = XA_ATOM;
5648 // This code leads to a read of value_return out of bounds on 64-bit systems.
5649 // Other code which I have seen always sets *format_return to 32 independent of
5650 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
5651 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
5652 *format_return = 8 * sizeof(Atom);
5653 if (*format_return > 32) {
5654 *length_return *= *format_return / 32;
5655 *format_return = 32;
5658 *format_return = 32;
5670 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5671 * have a notion of a game that is selected but not copied.
5672 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5674 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5677 NULL/* lose_ownership_proc */ ,
5678 NULL/* transfer_done_proc */);
5679 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5682 NULL/* lose_ownership_proc */ ,
5683 NULL/* transfer_done_proc */);
5686 /* note: when called from menu all parameters are NULL, so no clue what the
5687 * Widget which was clicked on was, or what the click event was
5690 CopyGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5694 ret = SaveGameToFile(gameCopyFilename, FALSE);
5701 CopyGameListProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5703 if(!SaveGameListAsText(fopen(gameCopyFilename, "w"))) return;
5707 /* function called when the data to Paste is ready */
5709 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
5710 Atom *type, XtPointer value, unsigned long *len, int *format)
5713 if (value == NULL || *len == 0) {
5714 return; /* nothing had been selected to copy */
5716 f = fopen(gamePasteFilename, "w");
5718 DisplayError(_("Can't open temp file"), errno);
5721 fwrite(value, 1, *len, f);
5724 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5727 /* called when Paste Game button is pressed,
5728 * all parameters will be NULL */
5730 PasteGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5732 XtGetSelectionValue(menuBarWidget,
5733 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5734 /* (XtSelectionCallbackProc) */ PasteGameCB,
5735 NULL, /* client_data passed to PasteGameCB */
5737 /* better to use the time field from the event that triggered the
5738 * call to this function, but that isn't trivial to get
5749 SaveGameProc(NULL, NULL, NULL, NULL);
5754 QuitProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5760 PauseProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5766 MachineBlackProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5768 MachineBlackEvent();
5772 MachineWhiteProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5774 MachineWhiteEvent();
5778 AnalyzeModeProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5782 if (!first.analysisSupport) {
5783 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5784 DisplayError(buf, 0);
5787 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5788 if (appData.icsActive) {
5789 if (gameMode != IcsObserving) {
5790 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5791 DisplayError(buf, 0);
5793 if (appData.icsEngineAnalyze) {
5794 if (appData.debugMode)
5795 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5801 /* if enable, use want disable icsEngineAnalyze */
5802 if (appData.icsEngineAnalyze) {
5807 appData.icsEngineAnalyze = TRUE;
5808 if (appData.debugMode)
5809 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5811 #ifndef OPTIONSDIALOG
5812 if (!appData.showThinking)
5813 ShowThinkingProc(w,event,prms,nprms);
5820 AnalyzeFileProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5822 if (!first.analysisSupport) {
5824 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5825 DisplayError(buf, 0);
5828 // Reset(FALSE, TRUE);
5829 #ifndef OPTIONSDIALOG
5830 if (!appData.showThinking)
5831 ShowThinkingProc(w,event,prms,nprms);
5834 // FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5835 AnalysisPeriodicEvent(1);
5839 TwoMachinesProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5845 MatchProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5851 IcsClientProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5857 EditGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5863 EditPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5865 EditPositionEvent();
5869 TrainingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5875 EditCommentProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5879 if (PopDown(1)) { // popdown succesful
5881 XtSetArg(args[j], XtNleftBitmap, None); j++;
5882 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
5883 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
5884 } else // was not up
5889 IcsInputBoxProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5891 if (!PopDown(4)) ICSInputBoxPopUp();
5895 AcceptProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5901 DeclineProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5907 RematchProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5913 CallFlagProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5919 DrawProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5925 AbortProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5931 AdjournProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5937 ResignProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5943 AdjuWhiteProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5945 UserAdjudicationEvent(+1);
5949 AdjuBlackProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5951 UserAdjudicationEvent(-1);
5955 AdjuDrawProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5957 UserAdjudicationEvent(0);
5961 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5963 if (shellUp[4] == True)
5968 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5969 { // [HGM] input: let up-arrow recall previous line from history
5976 if (!shellUp[4]) return;
5977 edit = boxOptions[0].handle;
5979 XtSetArg(args[j], XtNstring, &val); j++;
5980 XtGetValues(edit, args, j);
5981 val = PrevInHistory(val);
5982 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5983 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5985 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
5986 XawTextReplace(edit, 0, 0, &t);
5987 XawTextSetInsertionPoint(edit, 9999);
5992 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5993 { // [HGM] input: let down-arrow recall next line from history
5998 if (!shellUp[4]) return;
5999 edit = boxOptions[0].handle;
6000 val = NextInHistory();
6001 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6002 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6004 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6005 XawTextReplace(edit, 0, 0, &t);
6006 XawTextSetInsertionPoint(edit, 9999);
6011 StopObservingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6013 StopObservingEvent();
6017 StopExaminingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6019 StopExaminingEvent();
6023 UploadProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6030 ForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6037 BackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6043 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6045 if (!TempBackwardActive) {
6046 TempBackwardActive = True;
6052 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6054 /* Check to see if triggered by a key release event for a repeating key.
6055 * If so the next queued event will be a key press of the same key at the same time */
6056 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
6058 XPeekEvent(xDisplay, &next);
6059 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
6060 next.xkey.keycode == event->xkey.keycode)
6064 TempBackwardActive = False;
6068 ToStartProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6074 ToEndProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6080 RevertProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6086 AnnotateProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6092 TruncateGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6094 TruncateGameEvent();
6098 RetractMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6104 MoveNowProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6110 FlipViewProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6112 flipView = !flipView;
6113 DrawPosition(True, NULL);
6117 PonderNextMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6121 PonderNextMoveEvent(!appData.ponderNextMove);
6122 #ifndef OPTIONSDIALOG
6123 if (appData.ponderNextMove) {
6124 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6126 XtSetArg(args[0], XtNleftBitmap, None);
6128 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6133 #ifndef OPTIONSDIALOG
6135 AlwaysQueenProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6139 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6141 if (appData.alwaysPromoteToQueen) {
6142 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6144 XtSetArg(args[0], XtNleftBitmap, None);
6146 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6151 AnimateDraggingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6155 appData.animateDragging = !appData.animateDragging;
6157 if (appData.animateDragging) {
6158 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6161 XtSetArg(args[0], XtNleftBitmap, None);
6163 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6168 AnimateMovingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6172 appData.animate = !appData.animate;
6174 if (appData.animate) {
6175 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6178 XtSetArg(args[0], XtNleftBitmap, None);
6180 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6185 AutoflagProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6189 appData.autoCallFlag = !appData.autoCallFlag;
6191 if (appData.autoCallFlag) {
6192 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6194 XtSetArg(args[0], XtNleftBitmap, None);
6196 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6201 AutoflipProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6205 appData.autoFlipView = !appData.autoFlipView;
6207 if (appData.autoFlipView) {
6208 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6210 XtSetArg(args[0], XtNleftBitmap, None);
6212 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6217 BlindfoldProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6221 appData.blindfold = !appData.blindfold;
6223 if (appData.blindfold) {
6224 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6226 XtSetArg(args[0], XtNleftBitmap, None);
6228 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6231 DrawPosition(True, NULL);
6235 TestLegalityProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6239 appData.testLegality = !appData.testLegality;
6241 if (appData.testLegality) {
6242 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6244 XtSetArg(args[0], XtNleftBitmap, None);
6246 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6252 FlashMovesProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6256 if (appData.flashCount == 0) {
6257 appData.flashCount = 3;
6259 appData.flashCount = -appData.flashCount;
6262 if (appData.flashCount > 0) {
6263 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6265 XtSetArg(args[0], XtNleftBitmap, None);
6267 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6273 HighlightDraggingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6277 appData.highlightDragging = !appData.highlightDragging;
6279 if (appData.highlightDragging) {
6280 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6282 XtSetArg(args[0], XtNleftBitmap, None);
6284 XtSetValues(XtNameToWidget(menuBarWidget,
6285 "menuOptions.Highlight Dragging"), args, 1);
6290 HighlightLastMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6294 appData.highlightLastMove = !appData.highlightLastMove;
6296 if (appData.highlightLastMove) {
6297 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6299 XtSetArg(args[0], XtNleftBitmap, None);
6301 XtSetValues(XtNameToWidget(menuBarWidget,
6302 "menuOptions.Highlight Last Move"), args, 1);
6306 HighlightArrowProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6310 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6312 if (appData.highlightMoveWithArrow) {
6313 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6315 XtSetArg(args[0], XtNleftBitmap, None);
6317 XtSetValues(XtNameToWidget(menuBarWidget,
6318 "menuOptions.Arrow"), args, 1);
6323 IcsAlarmProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6327 appData.icsAlarm = !appData.icsAlarm;
6329 if (appData.icsAlarm) {
6330 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6332 XtSetArg(args[0], XtNleftBitmap, None);
6334 XtSetValues(XtNameToWidget(menuBarWidget,
6335 "menuOptions.ICS Alarm"), args, 1);
6340 MoveSoundProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6344 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6346 if (appData.ringBellAfterMoves) {
6347 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6349 XtSetArg(args[0], XtNleftBitmap, None);
6351 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6356 OneClickProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6360 appData.oneClick = !appData.oneClick;
6362 if (appData.oneClick) {
6363 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6365 XtSetArg(args[0], XtNleftBitmap, None);
6367 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6372 PeriodicUpdatesProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6376 PeriodicUpdatesEvent(!appData.periodicUpdates);
6378 if (appData.periodicUpdates) {
6379 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6381 XtSetArg(args[0], XtNleftBitmap, None);
6383 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6388 PopupExitMessageProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6392 appData.popupExitMessage = !appData.popupExitMessage;
6394 if (appData.popupExitMessage) {
6395 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6397 XtSetArg(args[0], XtNleftBitmap, None);
6399 XtSetValues(XtNameToWidget(menuBarWidget,
6400 "menuOptions.Popup Exit Message"), args, 1);
6404 PopupMoveErrorsProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6408 appData.popupMoveErrors = !appData.popupMoveErrors;
6410 if (appData.popupMoveErrors) {
6411 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6413 XtSetArg(args[0], XtNleftBitmap, None);
6415 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6421 PremoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6425 appData.premove = !appData.premove;
6427 if (appData.premove) {
6428 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6430 XtSetArg(args[0], XtNleftBitmap, None);
6432 XtSetValues(XtNameToWidget(menuBarWidget,
6433 "menuOptions.Premove"), args, 1);
6438 ShowCoordsProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6442 appData.showCoords = !appData.showCoords;
6444 if (appData.showCoords) {
6445 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6447 XtSetArg(args[0], XtNleftBitmap, None);
6449 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6452 DrawPosition(True, NULL);
6456 ShowThinkingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6458 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6459 ShowThinkingEvent();
6463 HideThinkingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6467 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6468 ShowThinkingEvent();
6470 if (appData.hideThinkingFromHuman) {
6471 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6473 XtSetArg(args[0], XtNleftBitmap, None);
6475 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6481 SaveOnExitProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6485 saveSettingsOnExit = !saveSettingsOnExit;
6487 if (saveSettingsOnExit) {
6488 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6490 XtSetArg(args[0], XtNleftBitmap, None);
6492 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6497 SaveSettingsProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6499 SaveSettings(settingsFileName);
6503 InfoProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6506 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6512 ManProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6516 if (nprms && *nprms > 0)
6520 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6525 HintProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6531 BookProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6537 AboutProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6541 char *zippy = _(" (with Zippy code)");
6545 snprintf(buf, sizeof(buf),
6547 "Copyright 1991 Digital Equipment Corporation\n"
6548 "Enhancements Copyright 1992-2009 Free Software Foundation\n"
6549 "Enhancements Copyright 2005 Alessandro Scotti\n\n"
6550 "%s is free software and carries NO WARRANTY;"
6551 "see the file COPYING for more information."),
6552 programVersion, zippy, PACKAGE);
6553 ErrorPopUp(_("About XBoard"), buf, FALSE);
6557 DebugProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6559 appData.debugMode = !appData.debugMode;
6563 AboutGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6569 NothingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6575 DisplayMessage (char *message, char *extMessage)
6577 /* display a message in the message widget */
6586 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6591 message = extMessage;
6595 safeStrCpy(lastMsg, message, MSG_SIZ); // [HGM] make available
6597 /* need to test if messageWidget already exists, since this function
6598 can also be called during the startup, if for example a Xresource
6599 is not set up correctly */
6602 XtSetArg(arg, XtNlabel, message);
6603 XtSetValues(messageWidget, &arg, 1);
6610 DisplayTitle (char *text)
6614 char title[MSG_SIZ];
6617 if (text == NULL) text = "";
6619 if (appData.titleInWindow) {
6621 XtSetArg(args[i], XtNlabel, text); i++;
6622 XtSetValues(titleWidget, args, i);
6625 if (*text != NULLCHAR) {
6626 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6627 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6628 } else if (appData.icsActive) {
6629 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6630 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6631 } else if (appData.cmailGameName[0] != NULLCHAR) {
6632 snprintf(icon, sizeof(icon), "%s", "CMail");
6633 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6635 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6636 } else if (gameInfo.variant == VariantGothic) {
6637 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6638 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6641 } else if (gameInfo.variant == VariantFalcon) {
6642 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6643 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6645 } else if (appData.noChessProgram) {
6646 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6647 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6649 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6650 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6653 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6654 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6655 XtSetValues(shellWidget, args, i);
6656 XSync(xDisplay, False);
6661 DisplayError (String message, int error)
6666 if (appData.debugMode || appData.matchMode) {
6667 fprintf(stderr, "%s: %s\n", programName, message);
6670 if (appData.debugMode || appData.matchMode) {
6671 fprintf(stderr, "%s: %s: %s\n",
6672 programName, message, strerror(error));
6674 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6677 ErrorPopUp(_("Error"), message, FALSE);
6682 DisplayMoveError (String message)
6686 DrawPosition(FALSE, NULL);
6687 if (appData.debugMode || appData.matchMode) {
6688 fprintf(stderr, "%s: %s\n", programName, message);
6690 if (appData.popupMoveErrors) {
6691 ErrorPopUp(_("Error"), message, FALSE);
6693 DisplayMessage(message, "");
6699 DisplayFatalError (String message, int error, int status)
6703 errorExitStatus = status;
6705 fprintf(stderr, "%s: %s\n", programName, message);
6707 fprintf(stderr, "%s: %s: %s\n",
6708 programName, message, strerror(error));
6709 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6712 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6713 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6720 DisplayInformation (String message)
6723 ErrorPopUp(_("Information"), message, TRUE);
6727 DisplayNote (String message)
6730 ErrorPopUp(_("Note"), message, FALSE);
6734 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
6740 DisplayIcsInteractionTitle (String message)
6742 if (oldICSInteractionTitle == NULL) {
6743 /* Magic to find the old window title, adapted from vim */
6744 char *wina = getenv("WINDOWID");
6746 Window win = (Window) atoi(wina);
6747 Window root, parent, *children;
6748 unsigned int nchildren;
6749 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6751 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6752 if (!XQueryTree(xDisplay, win, &root, &parent,
6753 &children, &nchildren)) break;
6754 if (children) XFree((void *)children);
6755 if (parent == root || parent == 0) break;
6758 XSetErrorHandler(oldHandler);
6760 if (oldICSInteractionTitle == NULL) {
6761 oldICSInteractionTitle = "xterm";
6764 printf("\033]0;%s\007", message);
6768 char pendingReplyPrefix[MSG_SIZ];
6769 ProcRef pendingReplyPR;
6772 AskQuestionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6775 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6779 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6783 AskQuestionPopDown ()
6785 if (!askQuestionUp) return;
6786 XtPopdown(askQuestionShell);
6787 XtDestroyWidget(askQuestionShell);
6788 askQuestionUp = False;
6792 AskQuestionReplyAction (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6798 reply = XawDialogGetValueString(w = XtParent(w));
6799 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
6800 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
6801 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
6802 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
6803 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
6804 AskQuestionPopDown();
6806 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
6810 AskQuestionCallback (Widget w, XtPointer client_data, XtPointer call_data)
6815 XtSetArg(args[0], XtNlabel, &name);
6816 XtGetValues(w, args, 1);
6818 if (strcmp(name, _("cancel")) == 0) {
6819 AskQuestionPopDown();
6821 AskQuestionReplyAction(w, NULL, NULL, NULL);
6826 AskQuestion (char *title, char *question, char *replyPrefix, ProcRef pr)
6829 Widget popup, layout, dialog, edit;
6835 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
6836 pendingReplyPR = pr;
6839 XtSetArg(args[i], XtNresizable, True); i++;
6840 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
6841 askQuestionShell = popup =
6842 XtCreatePopupShell(title, transientShellWidgetClass,
6843 shellWidget, args, i);
6846 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
6847 layoutArgs, XtNumber(layoutArgs));
6850 XtSetArg(args[i], XtNlabel, question); i++;
6851 XtSetArg(args[i], XtNvalue, ""); i++;
6852 XtSetArg(args[i], XtNborderWidth, 0); i++;
6853 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
6856 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
6857 (XtPointer) dialog);
6858 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
6859 (XtPointer) dialog);
6861 XtRealizeWidget(popup);
6862 CatchDeleteWindow(popup, "AskQuestionPopDown");
6864 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
6865 &x, &y, &win_x, &win_y, &mask);
6867 XtSetArg(args[0], XtNx, x - 10);
6868 XtSetArg(args[1], XtNy, y - 30);
6869 XtSetValues(popup, args, 2);
6871 XtPopup(popup, XtGrabExclusive);
6872 askQuestionUp = True;
6874 edit = XtNameToWidget(dialog, "*value");
6875 XtSetKeyboardFocus(popup, edit);
6880 PlaySound (char *name)
6882 if (*name == NULLCHAR) {
6884 } else if (strcmp(name, "$") == 0) {
6885 putc(BELLCHAR, stderr);
6888 char *prefix = "", *sep = "";
6889 if(appData.soundProgram[0] == NULLCHAR) return;
6890 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
6891 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
6899 PlaySound(appData.soundMove);
6905 PlaySound(appData.soundIcsWin);
6911 PlaySound(appData.soundIcsLoss);
6917 PlaySound(appData.soundIcsDraw);
6921 PlayIcsUnfinishedSound ()
6923 PlaySound(appData.soundIcsUnfinished);
6929 PlaySound(appData.soundIcsAlarm);
6935 PlaySound(appData.soundTell);
6941 system("stty echo");
6948 system("stty -echo");
6953 RunCommand (char *buf)
6959 Colorize (ColorClass cc, int continuation)
6962 int count, outCount, error;
6964 if (textColors[(int)cc].bg > 0) {
6965 if (textColors[(int)cc].fg > 0) {
6966 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
6967 textColors[(int)cc].fg, textColors[(int)cc].bg);
6969 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
6970 textColors[(int)cc].bg);
6973 if (textColors[(int)cc].fg > 0) {
6974 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
6975 textColors[(int)cc].fg);
6977 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
6980 count = strlen(buf);
6981 outCount = OutputToProcess(NoProc, buf, count, &error);
6982 if (outCount < count) {
6983 DisplayFatalError(_("Error writing to display"), error, 1);
6986 if (continuation) return;
6989 PlaySound(appData.soundShout);
6992 PlaySound(appData.soundSShout);
6995 PlaySound(appData.soundChannel1);
6998 PlaySound(appData.soundChannel);
7001 PlaySound(appData.soundKibitz);
7004 PlaySound(appData.soundTell);
7006 case ColorChallenge:
7007 PlaySound(appData.soundChallenge);
7010 PlaySound(appData.soundRequest);
7013 PlaySound(appData.soundSeek);
7025 return getpwuid(getuid())->pw_name;
7029 ExpandPathName (char *path)
7031 static char static_buf[4*MSG_SIZ];
7032 char *d, *s, buf[4*MSG_SIZ];
7038 while (*s && isspace(*s))
7047 if (*(s+1) == '/') {
7048 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7052 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7053 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7054 pwd = getpwnam(buf);
7057 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7061 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7062 strcat(d, strchr(s+1, '/'));
7066 safeStrCpy(d, s, 4*MSG_SIZ );
7074 static char host_name[MSG_SIZ];
7076 #if HAVE_GETHOSTNAME
7077 gethostname(host_name, MSG_SIZ);
7079 #else /* not HAVE_GETHOSTNAME */
7080 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7081 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7083 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7085 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7086 #endif /* not HAVE_GETHOSTNAME */
7089 XtIntervalId delayedEventTimerXID = 0;
7090 DelayedEventCallback delayedEventCallback = 0;
7095 delayedEventTimerXID = 0;
7096 delayedEventCallback();
7100 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
7102 if(delayedEventTimerXID && delayedEventCallback == cb)
7103 // [HGM] alive: replace, rather than add or flush identical event
7104 XtRemoveTimeOut(delayedEventTimerXID);
7105 delayedEventCallback = cb;
7106 delayedEventTimerXID =
7107 XtAppAddTimeOut(appContext, millisec,
7108 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7111 DelayedEventCallback
7114 if (delayedEventTimerXID) {
7115 return delayedEventCallback;
7122 CancelDelayedEvent ()
7124 if (delayedEventTimerXID) {
7125 XtRemoveTimeOut(delayedEventTimerXID);
7126 delayedEventTimerXID = 0;
7130 XtIntervalId loadGameTimerXID = 0;
7133 LoadGameTimerRunning ()
7135 return loadGameTimerXID != 0;
7139 StopLoadGameTimer ()
7141 if (loadGameTimerXID != 0) {
7142 XtRemoveTimeOut(loadGameTimerXID);
7143 loadGameTimerXID = 0;
7151 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
7153 loadGameTimerXID = 0;
7158 StartLoadGameTimer (long millisec)
7161 XtAppAddTimeOut(appContext, millisec,
7162 (XtTimerCallbackProc) LoadGameTimerCallback,
7166 XtIntervalId analysisClockXID = 0;
7169 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
7171 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7172 || appData.icsEngineAnalyze) { // [DM]
7173 AnalysisPeriodicEvent(0);
7174 StartAnalysisClock();
7179 StartAnalysisClock ()
7182 XtAppAddTimeOut(appContext, 2000,
7183 (XtTimerCallbackProc) AnalysisClockCallback,
7187 XtIntervalId clockTimerXID = 0;
7190 ClockTimerRunning ()
7192 return clockTimerXID != 0;
7198 if (clockTimerXID != 0) {
7199 XtRemoveTimeOut(clockTimerXID);
7208 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
7215 StartClockTimer (long millisec)
7218 XtAppAddTimeOut(appContext, millisec,
7219 (XtTimerCallbackProc) ClockTimerCallback,
7224 DisplayTimerLabel (Widget w, char *color, long timer, int highlight)
7229 /* check for low time warning */
7230 Pixel foregroundOrWarningColor = timerForegroundPixel;
7233 appData.lowTimeWarning &&
7234 (timer / 1000) < appData.icsAlarmTime)
7235 foregroundOrWarningColor = lowTimeWarningColor;
7237 if (appData.clockMode) {
7238 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7239 XtSetArg(args[0], XtNlabel, buf);
7241 snprintf(buf, MSG_SIZ, "%s ", color);
7242 XtSetArg(args[0], XtNlabel, buf);
7247 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7248 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7250 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7251 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7254 XtSetValues(w, args, 3);
7258 DisplayWhiteClock (long timeRemaining, int highlight)
7262 if(appData.noGUI) return;
7263 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7264 if (highlight && iconPixmap == bIconPixmap) {
7265 iconPixmap = wIconPixmap;
7266 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7267 XtSetValues(shellWidget, args, 1);
7272 DisplayBlackClock (long timeRemaining, int highlight)
7276 if(appData.noGUI) return;
7277 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7278 if (highlight && iconPixmap == wIconPixmap) {
7279 iconPixmap = bIconPixmap;
7280 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7281 XtSetValues(shellWidget, args, 1);
7300 StartChildProcess (char *cmdLine, char *dir, ProcRef *pr)
7304 int to_prog[2], from_prog[2];
7308 if (appData.debugMode) {
7309 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7312 /* We do NOT feed the cmdLine to the shell; we just
7313 parse it into blank-separated arguments in the
7314 most simple-minded way possible.
7317 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7320 while(*p == ' ') p++;
7322 if(*p == '"' || *p == '\'')
7323 p = strchr(++argv[i-1], *p);
7324 else p = strchr(p, ' ');
7325 if (p == NULL) break;
7330 SetUpChildIO(to_prog, from_prog);
7332 if ((pid = fork()) == 0) {
7334 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7335 close(to_prog[1]); // first close the unused pipe ends
7336 close(from_prog[0]);
7337 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7338 dup2(from_prog[1], 1);
7339 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7340 close(from_prog[1]); // and closing again loses one of the pipes!
7341 if(fileno(stderr) >= 2) // better safe than sorry...
7342 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7344 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7349 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7351 execvp(argv[0], argv);
7353 /* If we get here, exec failed */
7358 /* Parent process */
7360 close(from_prog[1]);
7362 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7365 cp->fdFrom = from_prog[0];
7366 cp->fdTo = to_prog[1];
7371 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7373 AlarmCallBack (int n)
7379 DestroyChildProcess (ProcRef pr, int signalType)
7381 ChildProc *cp = (ChildProc *) pr;
7383 if (cp->kind != CPReal) return;
7385 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7386 signal(SIGALRM, AlarmCallBack);
7388 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7389 kill(cp->pid, SIGKILL); // kill it forcefully
7390 wait((int *) 0); // and wait again
7394 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7396 /* Process is exiting either because of the kill or because of
7397 a quit command sent by the backend; either way, wait for it to die.
7406 InterruptChildProcess (ProcRef pr)
7408 ChildProc *cp = (ChildProc *) pr;
7410 if (cp->kind != CPReal) return;
7411 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7415 OpenTelnet (char *host, char *port, ProcRef *pr)
7417 char cmdLine[MSG_SIZ];
7419 if (port[0] == NULLCHAR) {
7420 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7422 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7424 return StartChildProcess(cmdLine, "", pr);
7428 OpenTCP (char *host, char *port, ProcRef *pr)
7431 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7432 #else /* !OMIT_SOCKETS */
7433 struct addrinfo hints;
7434 struct addrinfo *ais, *ai;
7439 memset(&hints, 0, sizeof(hints));
7440 hints.ai_family = AF_UNSPEC;
7441 hints.ai_socktype = SOCK_STREAM;
7443 error = getaddrinfo(host, port, &hints, &ais);
7445 /* a getaddrinfo error is not an errno, so can't return it */
7446 fprintf(debugFP, "getaddrinfo(%s, %s): %s\n",
7447 host, port, gai_strerror(error));
7451 for (ai = ais; ai != NULL; ai = ai->ai_next) {
7452 if ((s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
7456 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
7469 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7475 #endif /* !OMIT_SOCKETS */
7481 OpenCommPort (char *name, ProcRef *pr)
7486 fd = open(name, 2, 0);
7487 if (fd < 0) return errno;
7489 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7500 OpenLoopback (ProcRef *pr)
7505 SetUpChildIO(to, from);
7507 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7510 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7518 OpenRcmd (char *host, char *user, char *cmd, ProcRef *pr)
7520 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7524 #define INPUT_SOURCE_BUF_SIZE 8192
7533 char buf[INPUT_SOURCE_BUF_SIZE];
7538 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
7540 InputSource *is = (InputSource *) closure;
7545 if (is->lineByLine) {
7546 count = read(is->fd, is->unused,
7547 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7549 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7552 is->unused += count;
7554 while (p < is->unused) {
7555 q = memchr(p, '\n', is->unused - p);
7556 if (q == NULL) break;
7558 (is->func)(is, is->closure, p, q - p, 0);
7562 while (p < is->unused) {
7567 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7572 (is->func)(is, is->closure, is->buf, count, error);
7577 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
7580 ChildProc *cp = (ChildProc *) pr;
7582 is = (InputSource *) calloc(1, sizeof(InputSource));
7583 is->lineByLine = lineByLine;
7587 is->fd = fileno(stdin);
7589 is->kind = cp->kind;
7590 is->fd = cp->fdFrom;
7593 is->unused = is->buf;
7596 is->xid = XtAppAddInput(appContext, is->fd,
7597 (XtPointer) (XtInputReadMask),
7598 (XtInputCallbackProc) DoInputCallback,
7600 is->closure = closure;
7601 return (InputSourceRef) is;
7605 RemoveInputSource (InputSourceRef isr)
7607 InputSource *is = (InputSource *) isr;
7609 if (is->xid == 0) return;
7610 XtRemoveInput(is->xid);
7615 OutputToProcess (ProcRef pr, char *message, int count, int *outError)
7617 static int line = 0;
7618 ChildProc *cp = (ChildProc *) pr;
7623 if (appData.noJoin || !appData.useInternalWrap)
7624 outCount = fwrite(message, 1, count, stdout);
7627 int width = get_term_width();
7628 int len = wrap(NULL, message, count, width, &line);
7629 char *msg = malloc(len);
7633 outCount = fwrite(message, 1, count, stdout);
7636 dbgchk = wrap(msg, message, count, width, &line);
7637 if (dbgchk != len && appData.debugMode)
7638 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7639 outCount = fwrite(msg, 1, dbgchk, stdout);
7645 outCount = write(cp->fdTo, message, count);
7655 /* Output message to process, with "ms" milliseconds of delay
7656 between each character. This is needed when sending the logon
7657 script to ICC, which for some reason doesn't like the
7658 instantaneous send. */
7660 OutputToProcessDelayed (ProcRef pr, char *message, int count, int *outError, long msdelay)
7662 ChildProc *cp = (ChildProc *) pr;
7667 r = write(cp->fdTo, message++, 1);
7680 /**** Animation code by Hugh Fisher, DCS, ANU.
7682 Known problem: if a window overlapping the board is
7683 moved away while a piece is being animated underneath,
7684 the newly exposed area won't be updated properly.
7685 I can live with this.
7687 Known problem: if you look carefully at the animation
7688 of pieces in mono mode, they are being drawn as solid
7689 shapes without interior detail while moving. Fixing
7690 this would be a major complication for minimal return.
7693 /* Masks for XPM pieces. Black and white pieces can have
7694 different shapes, but in the interest of retaining my
7695 sanity pieces must have the same outline on both light
7696 and dark squares, and all pieces must use the same
7697 background square colors/images. */
7699 static int xpmDone = 0;
7702 CreateAnimMasks (int pieceDepth)
7708 unsigned long plane;
7711 /* Need a bitmap just to get a GC with right depth */
7712 buf = XCreatePixmap(xDisplay, xBoardWindow,
7714 values.foreground = 1;
7715 values.background = 0;
7716 /* Don't use XtGetGC, not read only */
7717 maskGC = XCreateGC(xDisplay, buf,
7718 GCForeground | GCBackground, &values);
7719 XFreePixmap(xDisplay, buf);
7721 buf = XCreatePixmap(xDisplay, xBoardWindow,
7722 squareSize, squareSize, pieceDepth);
7723 values.foreground = XBlackPixel(xDisplay, xScreen);
7724 values.background = XWhitePixel(xDisplay, xScreen);
7725 bufGC = XCreateGC(xDisplay, buf,
7726 GCForeground | GCBackground, &values);
7728 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7729 /* Begin with empty mask */
7730 if(!xpmDone) // [HGM] pieces: keep using existing
7731 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7732 squareSize, squareSize, 1);
7733 XSetFunction(xDisplay, maskGC, GXclear);
7734 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7735 0, 0, squareSize, squareSize);
7737 /* Take a copy of the piece */
7742 XSetFunction(xDisplay, bufGC, GXcopy);
7743 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7745 0, 0, squareSize, squareSize, 0, 0);
7747 /* XOR the background (light) over the piece */
7748 XSetFunction(xDisplay, bufGC, GXxor);
7750 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7751 0, 0, squareSize, squareSize, 0, 0);
7753 XSetForeground(xDisplay, bufGC, lightSquareColor);
7754 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7757 /* We now have an inverted piece image with the background
7758 erased. Construct mask by just selecting all the non-zero
7759 pixels - no need to reconstruct the original image. */
7760 XSetFunction(xDisplay, maskGC, GXor);
7762 /* Might be quicker to download an XImage and create bitmap
7763 data from it rather than this N copies per piece, but it
7764 only takes a fraction of a second and there is a much
7765 longer delay for loading the pieces. */
7766 for (n = 0; n < pieceDepth; n ++) {
7767 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7768 0, 0, squareSize, squareSize,
7774 XFreePixmap(xDisplay, buf);
7775 XFreeGC(xDisplay, bufGC);
7776 XFreeGC(xDisplay, maskGC);
7780 InitAnimState (AnimState *anim, XWindowAttributes *info)
7785 /* Each buffer is square size, same depth as window */
7786 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
7787 squareSize, squareSize, info->depth);
7788 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
7789 squareSize, squareSize, info->depth);
7791 /* Create a plain GC for blitting */
7792 mask = GCForeground | GCBackground | GCFunction |
7793 GCPlaneMask | GCGraphicsExposures;
7794 values.foreground = XBlackPixel(xDisplay, xScreen);
7795 values.background = XWhitePixel(xDisplay, xScreen);
7796 values.function = GXcopy;
7797 values.plane_mask = AllPlanes;
7798 values.graphics_exposures = False;
7799 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
7801 /* Piece will be copied from an existing context at
7802 the start of each new animation/drag. */
7803 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
7805 /* Outline will be a read-only copy of an existing */
7806 anim->outlineGC = None;
7812 XWindowAttributes info;
7814 if (xpmDone && gameInfo.variant == oldVariant) return;
7815 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
7816 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
7818 InitAnimState(&game, &info);
7819 InitAnimState(&player, &info);
7821 /* For XPM pieces, we need bitmaps to use as masks. */
7823 CreateAnimMasks(info.depth), xpmDone = 1;
7828 static Boolean frameWaiting;
7831 FrameAlarm (int sig)
7833 frameWaiting = False;
7834 /* In case System-V style signals. Needed?? */
7835 signal(SIGALRM, FrameAlarm);
7839 FrameDelay (int time)
7841 struct itimerval delay;
7843 XSync(xDisplay, False);
7846 frameWaiting = True;
7847 signal(SIGALRM, FrameAlarm);
7848 delay.it_interval.tv_sec =
7849 delay.it_value.tv_sec = time / 1000;
7850 delay.it_interval.tv_usec =
7851 delay.it_value.tv_usec = (time % 1000) * 1000;
7852 setitimer(ITIMER_REAL, &delay, NULL);
7853 while (frameWaiting) pause();
7854 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
7855 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
7856 setitimer(ITIMER_REAL, &delay, NULL);
7863 FrameDelay (int time)
7865 XSync(xDisplay, False);
7867 usleep(time * 1000);
7878 /* Convert board position to corner of screen rect and color */
7881 ScreenSquare (int column, int row, XPoint *pt, int *color)
7884 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
7885 pt->y = lineGap + row * (squareSize + lineGap);
7887 pt->x = lineGap + column * (squareSize + lineGap);
7888 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
7890 *color = SquareColor(row, column);
7893 /* Convert window coords to square */
7896 BoardSquare (int x, int y, int *column, int *row)
7898 *column = EventToSquare(x, BOARD_WIDTH);
7899 if (flipView && *column >= 0)
7900 *column = BOARD_WIDTH - 1 - *column;
7901 *row = EventToSquare(y, BOARD_HEIGHT);
7902 if (!flipView && *row >= 0)
7903 *row = BOARD_HEIGHT - 1 - *row;
7908 #undef Max /* just in case */
7910 #define Max(a, b) ((a) > (b) ? (a) : (b))
7911 #define Min(a, b) ((a) < (b) ? (a) : (b))
7914 SetRect (XRectangle *rect, int x, int y, int width, int height)
7918 rect->width = width;
7919 rect->height = height;
7922 /* Test if two frames overlap. If they do, return
7923 intersection rect within old and location of
7924 that rect within new. */
7927 Intersect ( XPoint *old, XPoint *new, int size, XRectangle *area, XPoint *pt)
7929 if (old->x > new->x + size || new->x > old->x + size ||
7930 old->y > new->y + size || new->y > old->y + size) {
7933 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
7934 size - abs(old->x - new->x), size - abs(old->y - new->y));
7935 pt->x = Max(old->x - new->x, 0);
7936 pt->y = Max(old->y - new->y, 0);
7941 /* For two overlapping frames, return the rect(s)
7942 in the old that do not intersect with the new. */
7945 CalcUpdateRects (XPoint *old, XPoint *new, int size, XRectangle update[], int *nUpdates)
7949 /* If old = new (shouldn't happen) then nothing to draw */
7950 if (old->x == new->x && old->y == new->y) {
7954 /* Work out what bits overlap. Since we know the rects
7955 are the same size we don't need a full intersect calc. */
7957 /* Top or bottom edge? */
7958 if (new->y > old->y) {
7959 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
7961 } else if (old->y > new->y) {
7962 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
7963 size, old->y - new->y);
7966 /* Left or right edge - don't overlap any update calculated above. */
7967 if (new->x > old->x) {
7968 SetRect(&(update[count]), old->x, Max(new->y, old->y),
7969 new->x - old->x, size - abs(new->y - old->y));
7971 } else if (old->x > new->x) {
7972 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
7973 old->x - new->x, size - abs(new->y - old->y));
7980 /* Generate a series of frame coords from start->mid->finish.
7981 The movement rate doubles until the half way point is
7982 reached, then halves back down to the final destination,
7983 which gives a nice slow in/out effect. The algorithmn
7984 may seem to generate too many intermediates for short
7985 moves, but remember that the purpose is to attract the
7986 viewers attention to the piece about to be moved and
7987 then to where it ends up. Too few frames would be less
7991 Tween (XPoint *start, XPoint *mid, XPoint *finish, int factor, XPoint frames[], int *nFrames)
7993 int fraction, n, count;
7997 /* Slow in, stepping 1/16th, then 1/8th, ... */
7999 for (n = 0; n < factor; n++)
8001 for (n = 0; n < factor; n++) {
8002 frames[count].x = start->x + (mid->x - start->x) / fraction;
8003 frames[count].y = start->y + (mid->y - start->y) / fraction;
8005 fraction = fraction / 2;
8009 frames[count] = *mid;
8012 /* Slow out, stepping 1/2, then 1/4, ... */
8014 for (n = 0; n < factor; n++) {
8015 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8016 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8018 fraction = fraction * 2;
8023 /* Draw a piece on the screen without disturbing what's there */
8026 SelectGCMask (ChessSquare piece, GC *clip, GC *outline, Pixmap *mask)
8030 /* Bitmap for piece being moved. */
8031 if (appData.monoMode) {
8032 *mask = *pieceToSolid(piece);
8033 } else if (useImages) {
8035 *mask = xpmMask[piece];
8037 *mask = ximMaskPm[piece];
8040 *mask = *pieceToSolid(piece);
8043 /* GC for piece being moved. Square color doesn't matter, but
8044 since it gets modified we make a copy of the original. */
8046 if (appData.monoMode)
8051 if (appData.monoMode)
8056 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8058 /* Outline only used in mono mode and is not modified */
8060 *outline = bwPieceGC;
8062 *outline = wbPieceGC;
8066 OverlayPiece (ChessSquare piece, GC clip, GC outline, Drawable dest)
8071 /* Draw solid rectangle which will be clipped to shape of piece */
8072 XFillRectangle(xDisplay, dest, clip,
8073 0, 0, squareSize, squareSize);
8074 if (appData.monoMode)
8075 /* Also draw outline in contrasting color for black
8076 on black / white on white cases */
8077 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8078 0, 0, squareSize, squareSize, 0, 0, 1);
8080 /* Copy the piece */
8085 if(appData.upsideDown && flipView) kind ^= 2;
8086 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8088 0, 0, squareSize, squareSize,
8093 /* Animate the movement of a single piece */
8096 BeginAnimation (AnimState *anim, ChessSquare piece, int startColor, XPoint *start)
8100 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8101 /* The old buffer is initialised with the start square (empty) */
8102 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8103 anim->prevFrame = *start;
8105 /* The piece will be drawn using its own bitmap as a matte */
8106 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8107 XSetClipMask(xDisplay, anim->pieceGC, mask);
8111 AnimationFrame (AnimState *anim, XPoint *frame, ChessSquare piece)
8113 XRectangle updates[4];
8118 /* Save what we are about to draw into the new buffer */
8119 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8120 frame->x, frame->y, squareSize, squareSize,
8123 /* Erase bits of the previous frame */
8124 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8125 /* Where the new frame overlapped the previous,
8126 the contents in newBuf are wrong. */
8127 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8128 overlap.x, overlap.y,
8129 overlap.width, overlap.height,
8131 /* Repaint the areas in the old that don't overlap new */
8132 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8133 for (i = 0; i < count; i++)
8134 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8135 updates[i].x - anim->prevFrame.x,
8136 updates[i].y - anim->prevFrame.y,
8137 updates[i].width, updates[i].height,
8138 updates[i].x, updates[i].y);
8140 /* Easy when no overlap */
8141 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8142 0, 0, squareSize, squareSize,
8143 anim->prevFrame.x, anim->prevFrame.y);
8146 /* Save this frame for next time round */
8147 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8148 0, 0, squareSize, squareSize,
8150 anim->prevFrame = *frame;
8152 /* Draw piece over original screen contents, not current,
8153 and copy entire rect. Wipes out overlapping piece images. */
8154 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8155 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8156 0, 0, squareSize, squareSize,
8157 frame->x, frame->y);
8161 EndAnimation (AnimState *anim, XPoint *finish)
8163 XRectangle updates[4];
8168 /* The main code will redraw the final square, so we
8169 only need to erase the bits that don't overlap. */
8170 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8171 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8172 for (i = 0; i < count; i++)
8173 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8174 updates[i].x - anim->prevFrame.x,
8175 updates[i].y - anim->prevFrame.y,
8176 updates[i].width, updates[i].height,
8177 updates[i].x, updates[i].y);
8179 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8180 0, 0, squareSize, squareSize,
8181 anim->prevFrame.x, anim->prevFrame.y);
8186 FrameSequence (AnimState *anim, ChessSquare piece, int startColor, XPoint *start, XPoint *finish, XPoint frames[], int nFrames)
8190 BeginAnimation(anim, piece, startColor, start);
8191 for (n = 0; n < nFrames; n++) {
8192 AnimationFrame(anim, &(frames[n]), piece);
8193 FrameDelay(appData.animSpeed);
8195 EndAnimation(anim, finish);
8199 AnimateAtomicCapture (Board board, int fromX, int fromY, int toX, int toY)
8202 ChessSquare piece = board[fromY][toY];
8203 board[fromY][toY] = EmptySquare;
8204 DrawPosition(FALSE, board);
8206 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8207 y = lineGap + toY * (squareSize + lineGap);
8209 x = lineGap + toX * (squareSize + lineGap);
8210 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8212 for(i=1; i<4*kFactor; i++) {
8213 int r = squareSize * 9 * i/(20*kFactor - 5);
8214 XFillArc(xDisplay, xBoardWindow, highlineGC,
8215 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8216 FrameDelay(appData.animSpeed);
8218 board[fromY][toY] = piece;
8221 /* Main control logic for deciding what to animate and how */
8224 AnimateMove (Board board, int fromX, int fromY, int toX, int toY)
8228 XPoint start, finish, mid;
8229 XPoint frames[kFactor * 2 + 1];
8230 int nFrames, startColor, endColor;
8232 /* Are we animating? */
8233 if (!appData.animate || appData.blindfold)
8236 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8237 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8238 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8240 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8241 piece = board[fromY][fromX];
8242 if (piece >= EmptySquare) return;
8247 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8250 if (appData.debugMode) {
8251 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8252 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8253 piece, fromX, fromY, toX, toY); }
8255 ScreenSquare(fromX, fromY, &start, &startColor);
8256 ScreenSquare(toX, toY, &finish, &endColor);
8259 /* Knight: make straight movement then diagonal */
8260 if (abs(toY - fromY) < abs(toX - fromX)) {
8261 mid.x = start.x + (finish.x - start.x) / 2;
8265 mid.y = start.y + (finish.y - start.y) / 2;
8268 mid.x = start.x + (finish.x - start.x) / 2;
8269 mid.y = start.y + (finish.y - start.y) / 2;
8272 /* Don't use as many frames for very short moves */
8273 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8274 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8276 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8277 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8278 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8280 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8281 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8284 /* Be sure end square is redrawn */
8285 damage[0][toY][toX] = True;
8289 DragPieceBegin (int x, int y, Boolean instantly)
8291 int boardX, boardY, color;
8294 /* Are we animating? */
8295 if (!appData.animateDragging || appData.blindfold)
8298 /* Figure out which square we start in and the
8299 mouse position relative to top left corner. */
8300 BoardSquare(x, y, &boardX, &boardY);
8301 player.startBoardX = boardX;
8302 player.startBoardY = boardY;
8303 ScreenSquare(boardX, boardY, &corner, &color);
8304 player.startSquare = corner;
8305 player.startColor = color;
8306 /* As soon as we start dragging, the piece will jump slightly to
8307 be centered over the mouse pointer. */
8308 player.mouseDelta.x = squareSize/2;
8309 player.mouseDelta.y = squareSize/2;
8310 /* Initialise animation */
8311 player.dragPiece = PieceForSquare(boardX, boardY);
8313 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8314 player.dragActive = True;
8315 BeginAnimation(&player, player.dragPiece, color, &corner);
8316 /* Mark this square as needing to be redrawn. Note that
8317 we don't remove the piece though, since logically (ie
8318 as seen by opponent) the move hasn't been made yet. */
8319 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8320 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8321 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8322 corner.x, corner.y, squareSize, squareSize,
8323 0, 0); // [HGM] zh: unstack in stead of grab
8324 if(gatingPiece != EmptySquare) {
8325 /* Kludge alert: When gating we want the introduced
8326 piece to appear on the from square. To generate an
8327 image of it, we draw it on the board, copy the image,
8328 and draw the original piece again. */
8329 ChessSquare piece = boards[currentMove][boardY][boardX];
8330 DrawSquare(boardY, boardX, gatingPiece, 0);
8331 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8332 corner.x, corner.y, squareSize, squareSize, 0, 0);
8333 DrawSquare(boardY, boardX, piece, 0);
8335 damage[0][boardY][boardX] = True;
8337 player.dragActive = False;
8342 ChangeDragPiece (ChessSquare piece)
8345 player.dragPiece = piece;
8346 /* The piece will be drawn using its own bitmap as a matte */
8347 SelectGCMask(piece, &player.pieceGC, &player.outlineGC, &mask);
8348 XSetClipMask(xDisplay, player.pieceGC, mask);
8352 DragPieceMove (int x, int y)
8356 /* Are we animating? */
8357 if (!appData.animateDragging || appData.blindfold)
8361 if (! player.dragActive)
8363 /* Move piece, maintaining same relative position
8364 of mouse within square */
8365 corner.x = x - player.mouseDelta.x;
8366 corner.y = y - player.mouseDelta.y;
8367 AnimationFrame(&player, &corner, player.dragPiece);
8369 if (appData.highlightDragging) {
8371 BoardSquare(x, y, &boardX, &boardY);
8372 SetHighlights(fromX, fromY, boardX, boardY);
8378 DragPieceEnd (int x, int y)
8380 int boardX, boardY, color;
8383 /* Are we animating? */
8384 if (!appData.animateDragging || appData.blindfold)
8388 if (! player.dragActive)
8390 /* Last frame in sequence is square piece is
8391 placed on, which may not match mouse exactly. */
8392 BoardSquare(x, y, &boardX, &boardY);
8393 ScreenSquare(boardX, boardY, &corner, &color);
8394 EndAnimation(&player, &corner);
8396 /* Be sure end square is redrawn */
8397 damage[0][boardY][boardX] = True;
8399 /* This prevents weird things happening with fast successive
8400 clicks which on my Sun at least can cause motion events
8401 without corresponding press/release. */
8402 player.dragActive = False;
8405 /* Handle expose event while piece being dragged */
8410 if (!player.dragActive || appData.blindfold)
8413 /* What we're doing: logically, the move hasn't been made yet,
8414 so the piece is still in it's original square. But visually
8415 it's being dragged around the board. So we erase the square
8416 that the piece is on and draw it at the last known drag point. */
8417 BlankSquare(player.startSquare.x, player.startSquare.y,
8418 player.startColor, EmptySquare, xBoardWindow, 1);
8419 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8420 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8423 #include <sys/ioctl.h>
8427 int fd, default_width;
8430 default_width = 79; // this is FICS default anyway...
8432 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8434 if (!ioctl(fd, TIOCGSIZE, &win))
8435 default_width = win.ts_cols;
8436 #elif defined(TIOCGWINSZ)
8438 if (!ioctl(fd, TIOCGWINSZ, &win))
8439 default_width = win.ws_col;
8441 return default_width;
8447 static int old_width = 0;
8448 int new_width = get_term_width();
8450 if (old_width != new_width)
8451 ics_printf("set width %d\n", new_width);
8452 old_width = new_width;
8456 NotifyFrontendLogin ()
8461 /* [AS] Arrow highlighting support */
8463 static double A_WIDTH = 5; /* Width of arrow body */
8465 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8466 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8477 return (int) (x + 0.5);
8481 SquareToPos (int rank, int file, int *x, int *y)
8484 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8485 *y = lineGap + rank * (squareSize + lineGap);
8487 *x = lineGap + file * (squareSize + lineGap);
8488 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8492 /* Draw an arrow between two points using current settings */
8494 DrawArrowBetweenPoints (int s_x, int s_y, int d_x, int d_y)
8497 double dx, dy, j, k, x, y;
8500 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8502 arrow[0].x = s_x + A_WIDTH + 0.5;
8505 arrow[1].x = s_x + A_WIDTH + 0.5;
8506 arrow[1].y = d_y - h;
8508 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8509 arrow[2].y = d_y - h;
8514 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8515 arrow[5].y = d_y - h;
8517 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8518 arrow[4].y = d_y - h;
8520 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8523 else if( d_y == s_y ) {
8524 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8527 arrow[0].y = s_y + A_WIDTH + 0.5;
8529 arrow[1].x = d_x - w;
8530 arrow[1].y = s_y + A_WIDTH + 0.5;
8532 arrow[2].x = d_x - w;
8533 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8538 arrow[5].x = d_x - w;
8539 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8541 arrow[4].x = d_x - w;
8542 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8545 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8548 /* [AS] Needed a lot of paper for this! :-) */
8549 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8550 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8552 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8554 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8559 arrow[0].x = Round(x - j);
8560 arrow[0].y = Round(y + j*dx);
8562 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8563 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8566 x = (double) d_x - k;
8567 y = (double) d_y - k*dy;
8570 x = (double) d_x + k;
8571 y = (double) d_y + k*dy;
8574 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8576 arrow[6].x = Round(x - j);
8577 arrow[6].y = Round(y + j*dx);
8579 arrow[2].x = Round(arrow[6].x + 2*j);
8580 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8582 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8583 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8588 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8589 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8592 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8593 if(appData.monoMode) arrow[7] = arrow[0], XDrawLines(xDisplay, xBoardWindow, darkSquareGC, arrow, 8, CoordModeOrigin);
8594 // Polygon( hdc, arrow, 7 );
8597 /* [AS] Draw an arrow between two squares */
8599 DrawArrowBetweenSquares (int s_col, int s_row, int d_col, int d_row)
8601 int s_x, s_y, d_x, d_y, hor, vert, i;
8603 if( s_col == d_col && s_row == d_row ) {
8607 /* Get source and destination points */
8608 SquareToPos( s_row, s_col, &s_x, &s_y);
8609 SquareToPos( d_row, d_col, &d_x, &d_y);
8612 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8614 else if( d_y < s_y ) {
8615 d_y += squareSize / 2 + squareSize / 4;
8618 d_y += squareSize / 2;
8622 d_x += squareSize / 2 - squareSize / 4;
8624 else if( d_x < s_x ) {
8625 d_x += squareSize / 2 + squareSize / 4;
8628 d_x += squareSize / 2;
8631 s_x += squareSize / 2;
8632 s_y += squareSize / 2;
8635 A_WIDTH = squareSize / 14.; //[HGM] make float
8637 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
8639 hor = 64*s_col + 32; vert = 64*s_row + 32;
8640 for(i=0; i<= 64; i++) {
8641 damage[0][vert+6>>6][hor+6>>6] = True;
8642 damage[0][vert-6>>6][hor+6>>6] = True;
8643 damage[0][vert+6>>6][hor-6>>6] = True;
8644 damage[0][vert-6>>6][hor-6>>6] = True;
8645 hor += d_col - s_col; vert += d_row - s_row;
8650 IsDrawArrowEnabled ()
8652 return appData.highlightMoveWithArrow && squareSize >= 32;
8656 DrawArrowHighlight (int fromX, int fromY, int toX,int toY)
8658 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
8659 DrawArrowBetweenSquares(fromX, fromY, toX, toY);
8663 UpdateLogos (int displ)
8665 return; // no logos in XBoard yet