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 DelayedDrag P((void));
277 void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
278 void HandleUserMove P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AnimateUserMove P((Widget w, XEvent * event,
281 String * params, Cardinal * nParams));
282 void HandlePV P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void SelectPV P((Widget w, XEvent * event,
285 String * params, Cardinal * nParams));
286 void StopPV P((Widget w, XEvent * event,
287 String * params, Cardinal * nParams));
288 void WhiteClock P((Widget w, XEvent *event,
289 String *prms, Cardinal *nprms));
290 void BlackClock P((Widget w, XEvent *event,
291 String *prms, Cardinal *nprms));
292 void DrawPositionProc P((Widget w, XEvent *event,
293 String *prms, Cardinal *nprms));
294 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
296 void CommentClick P((Widget w, XEvent * event,
297 String * params, Cardinal * nParams));
298 void CommentPopUp P((char *title, char *label));
299 void CommentPopDown P((void));
300 void ICSInputBoxPopUp P((void));
301 void ICSInputBoxPopDown P((void));
302 void FileNamePopUp P((char *label, char *def, char *filter,
303 FileProc proc, char *openMode));
304 void FileNamePopDown P((void));
305 void FileNameCallback P((Widget w, XtPointer client_data,
306 XtPointer call_data));
307 void FileNameAction P((Widget w, XEvent *event,
308 String *prms, Cardinal *nprms));
309 void AskQuestionReplyAction P((Widget w, XEvent *event,
310 String *prms, Cardinal *nprms));
311 void AskQuestionProc P((Widget w, XEvent *event,
312 String *prms, Cardinal *nprms));
313 void AskQuestionPopDown P((void));
314 void PromotionPopDown P((void));
315 void PromotionCallback P((Widget w, XtPointer client_data,
316 XtPointer call_data));
317 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
318 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
322 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
324 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
326 void LoadPositionProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
330 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
332 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
334 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
336 void PastePositionProc P((Widget w, XEvent *event, String *prms,
338 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void CopyGameListProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
340 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void SavePositionProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
347 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
351 void MachineWhiteProc P((Widget w, XEvent *event,
352 String *prms, Cardinal *nprms));
353 void AnalyzeModeProc P((Widget w, XEvent *event,
354 String *prms, Cardinal *nprms));
355 void AnalyzeFileProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
359 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void IcsClientProc P((Widget w, XEvent *event, String *prms,
363 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void EditPositionProc P((Widget w, XEvent *event,
365 String *prms, Cardinal *nprms));
366 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void EditCommentProc P((Widget w, XEvent *event,
368 String *prms, Cardinal *nprms));
369 void IcsInputBoxProc P((Widget w, XEvent *event,
370 String *prms, Cardinal *nprms));
371 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void TypeInProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void StopObservingProc P((Widget w, XEvent *event, String *prms,
388 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
390 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 Boolean TempBackwardActive = False;
396 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
402 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
404 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
407 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
409 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
411 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
412 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
416 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
419 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
421 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
423 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
428 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
430 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
432 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
434 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
437 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
439 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
441 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
443 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void GuideProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void HomePageProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void NewsPageProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void BugReportProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void DisplayMove P((int moveNumber));
458 void DisplayTitle P((char *title));
459 void ICSInitScript P((void));
460 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
461 void ErrorPopUp P((char *title, char *text, int modal));
462 void ErrorPopDown P((void));
463 static char *ExpandPathName P((char *path));
464 static void CreateAnimVars P((void));
465 static void DragPieceMove P((int x, int y));
466 static void DrawDragPiece P((void));
467 char *ModeToWidgetName P((GameMode mode));
468 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
469 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
470 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
471 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
472 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
473 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
474 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
475 void LoadEngineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
476 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
477 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
478 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
479 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
480 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
481 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
482 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
483 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
484 void EditBookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
485 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
486 void GameListOptionsPopDown P(());
487 void GenericPopDown P(());
488 void update_ics_width P(());
489 int get_term_width P(());
490 int CopyMemoProc P(());
491 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
492 Boolean IsDrawArrowEnabled P(());
495 * XBoard depends on Xt R4 or higher
497 int xtVersion = XtSpecificationRelease;
502 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
503 jailSquareColor, highlightSquareColor, premoveHighlightColor;
504 Pixel lowTimeWarningColor;
505 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
506 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
507 wjPieceGC, bjPieceGC, prelineGC, countGC;
508 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
509 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
510 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
511 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
512 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
513 ICSInputShell, fileNameShell, askQuestionShell;
514 Widget historyShell, evalGraphShell, gameListShell;
515 int hOffset; // [HGM] dual
516 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
517 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
518 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
520 XFontSet fontSet, clockFontSet;
523 XFontStruct *clockFontStruct;
525 Font coordFontID, countFontID;
526 XFontStruct *coordFontStruct, *countFontStruct;
527 XtAppContext appContext;
529 char *oldICSInteractionTitle;
533 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
535 Position commentX = -1, commentY = -1;
536 Dimension commentW, commentH;
537 typedef unsigned int BoardSize;
539 Boolean chessProgram;
541 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
542 int squareSize, smallLayout = 0, tinyLayout = 0,
543 marginW, marginH, // [HGM] for run-time resizing
544 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
545 ICSInputBoxUp = False, askQuestionUp = False,
546 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
547 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
548 Dimension textHeight;
549 Pixel timerForegroundPixel, timerBackgroundPixel;
550 Pixel buttonForegroundPixel, buttonBackgroundPixel;
551 char *chessDir, *programName, *programVersion,
552 *gameCopyFilename, *gamePasteFilename;
553 Boolean alwaysOnTop = False;
554 Boolean saveSettingsOnExit;
555 char *settingsFileName;
556 char *icsTextMenuString;
558 char *firstChessProgramNames;
559 char *secondChessProgramNames;
561 WindowPlacement wpMain;
562 WindowPlacement wpConsole;
563 WindowPlacement wpComment;
564 WindowPlacement wpMoveHistory;
565 WindowPlacement wpEvalGraph;
566 WindowPlacement wpEngineOutput;
567 WindowPlacement wpGameList;
568 WindowPlacement wpTags;
570 extern Widget shells[];
571 extern Boolean shellUp[];
575 Pixmap pieceBitmap[2][(int)BlackPawn];
576 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
577 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
578 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
579 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
580 Pixmap xpmBoardBitmap[2];
581 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
582 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
583 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
584 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
585 XImage *ximLightSquare, *ximDarkSquare;
588 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
589 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
591 #define White(piece) ((int)(piece) < (int)BlackPawn)
593 /* Variables for doing smooth animation. This whole thing
594 would be much easier if the board was double-buffered,
595 but that would require a fairly major rewrite. */
600 GC blitGC, pieceGC, outlineGC;
601 XPoint startSquare, prevFrame, mouseDelta;
605 int startBoardX, startBoardY;
608 /* There can be two pieces being animated at once: a player
609 can begin dragging a piece before the remote opponent has moved. */
611 static AnimState game, player;
613 /* Bitmaps for use as masks when drawing XPM pieces.
614 Need one for each black and white piece. */
615 static Pixmap xpmMask[BlackKing + 1];
617 /* This magic number is the number of intermediate frames used
618 in each half of the animation. For short moves it's reduced
619 by 1. The total number of frames will be factor * 2 + 1. */
622 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
624 MenuItem fileMenu[] = {
625 {N_("New Game Ctrl+N"), "New Game", ResetProc},
626 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
627 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
628 {"----", NULL, NothingProc},
629 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
630 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
631 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
632 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
633 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
634 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
635 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
636 {"----", NULL, NothingProc},
637 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
638 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
639 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
640 {"----", NULL, NothingProc},
641 {N_("Mail Move"), "Mail Move", MailMoveProc},
642 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
643 {"----", NULL, NothingProc},
644 {N_("Quit Ctr+Q"), "Exit", QuitProc},
648 MenuItem editMenu[] = {
649 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
650 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
651 {N_("Copy Game List"), "Copy Game List", CopyGameListProc},
652 {"----", NULL, NothingProc},
653 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
654 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
655 {"----", NULL, NothingProc},
656 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
657 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
658 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
659 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
660 {N_("Edit Book"), "Edit Book", EditBookProc},
661 {"----", NULL, NothingProc},
662 {N_("Revert Home"), "Revert", RevertProc},
663 {N_("Annotate"), "Annotate", AnnotateProc},
664 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
665 {"----", NULL, NothingProc},
666 {N_("Backward Alt+Left"), "Backward", BackwardProc},
667 {N_("Forward Alt+Right"), "Forward", ForwardProc},
668 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
669 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
673 MenuItem viewMenu[] = {
674 {N_("Flip View F2"), "Flip View", FlipViewProc},
675 {"----", NULL, NothingProc},
676 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
677 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
678 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
679 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
680 {N_("ICS text menu"), "ICStex", IcsTextProc},
681 {"----", NULL, NothingProc},
682 {N_("Tags"), "Show Tags", EditTagsProc},
683 {N_("Comments"), "Show Comments", EditCommentProc},
684 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
685 {"----", NULL, NothingProc},
686 {N_("Board..."), "Board Options", BoardOptionsProc},
687 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
691 MenuItem modeMenu[] = {
692 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
693 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
694 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
695 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
696 {N_("Analyze Game Ctrl+G"), "Analyze File", AnalyzeFileProc },
697 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
698 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
699 {N_("Training"), "Training", TrainingProc},
700 {N_("ICS Client"), "ICS Client", IcsClientProc},
701 {"----", NULL, NothingProc},
702 {N_("Machine Match"), "Machine Match", MatchProc},
703 {N_("Pause Pause"), "Pause", PauseProc},
707 MenuItem actionMenu[] = {
708 {N_("Accept F3"), "Accept", AcceptProc},
709 {N_("Decline F4"), "Decline", DeclineProc},
710 {N_("Rematch F12"), "Rematch", RematchProc},
711 {"----", NULL, NothingProc},
712 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
713 {N_("Draw F6"), "Draw", DrawProc},
714 {N_("Adjourn F7"), "Adjourn", AdjournProc},
715 {N_("Abort F8"),"Abort", AbortProc},
716 {N_("Resign F9"), "Resign", ResignProc},
717 {"----", NULL, NothingProc},
718 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
719 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
720 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
721 {"----", NULL, NothingProc},
722 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
723 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
724 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
728 MenuItem engineMenu[] = {
729 {N_("Load New Engine ..."), "Load Engine", LoadEngineProc},
730 {"----", NULL, NothingProc},
731 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
732 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
733 {"----", NULL, NothingProc},
734 {N_("Hint"), "Hint", HintProc},
735 {N_("Book"), "Book", BookProc},
736 {"----", NULL, NothingProc},
737 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
738 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
742 MenuItem optionsMenu[] = {
743 #define OPTIONSDIALOG
745 {N_("General ..."), "General", OptionsProc},
747 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
748 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
749 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
750 {N_("ICS ..."), "ICS", IcsOptionsProc},
751 {N_("Match ..."), "Match", MatchOptionsProc},
752 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
753 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
754 // {N_(" ..."), "", OptionsProc},
755 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
756 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
757 {"----", NULL, NothingProc},
758 #ifndef OPTIONSDIALOG
759 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
760 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
761 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
762 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
763 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
764 {N_("Blindfold"), "Blindfold", BlindfoldProc},
765 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
767 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
769 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
770 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
771 {N_("Move Sound"), "Move Sound", MoveSoundProc},
772 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
773 {N_("One-Click Moving"), "OneClick", OneClickProc},
774 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
775 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
776 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
777 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
778 // {N_("Premove"), "Premove", PremoveProc},
779 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
780 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
781 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
782 {"----", NULL, NothingProc},
784 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
785 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
789 MenuItem helpMenu[] = {
790 {N_("Info XBoard"), "Info XBoard", InfoProc},
791 {N_("Man XBoard F1"), "Man XBoard", ManProc},
792 {"----", NULL, NothingProc},
793 {N_("XBoard Home Page"), "Home Page", HomePageProc},
794 {N_("On-line User Guide"), "User Guide", GuideProc},
795 {N_("Development News"), "News Page", NewsPageProc},
796 {N_("e-Mail Bug Report"), "Bug Report", BugReportProc},
797 {"----", NULL, NothingProc},
798 {N_("About XBoard"), "About XBoard", AboutProc},
803 {N_("File"), "File", fileMenu},
804 {N_("Edit"), "Edit", editMenu},
805 {N_("View"), "View", viewMenu},
806 {N_("Mode"), "Mode", modeMenu},
807 {N_("Action"), "Action", actionMenu},
808 {N_("Engine"), "Engine", engineMenu},
809 {N_("Options"), "Options", optionsMenu},
810 {N_("Help"), "Help", helpMenu},
814 #define PAUSE_BUTTON "P"
815 MenuItem buttonBar[] = {
816 {"<<", "<<", ToStartProc},
817 {"<", "<", BackwardProc},
818 {N_(PAUSE_BUTTON), PAUSE_BUTTON, PauseProc},
819 {">", ">", ForwardProc},
820 {">>", ">>", ToEndProc},
824 #define PIECE_MENU_SIZE 18
825 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
826 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
827 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
828 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
829 N_("Empty square"), N_("Clear board") },
830 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
831 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
832 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
833 N_("Empty square"), N_("Clear board") }
835 /* must be in same order as pieceMenuStrings! */
836 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
837 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
838 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
839 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
840 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
841 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
842 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
843 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
844 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
847 #define DROP_MENU_SIZE 6
848 String dropMenuStrings[DROP_MENU_SIZE] = {
849 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
851 /* must be in same order as dropMenuStrings! */
852 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
853 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
854 WhiteRook, WhiteQueen
862 DropMenuEnables dmEnables[] = {
880 { XtNborderWidth, 0 },
881 { XtNdefaultDistance, 0 },
885 { XtNborderWidth, 0 },
886 { XtNresizable, (XtArgVal) True },
890 { XtNborderWidth, 0 },
896 { XtNjustify, (XtArgVal) XtJustifyRight },
897 { XtNlabel, (XtArgVal) "..." },
898 { XtNresizable, (XtArgVal) True },
899 { XtNresize, (XtArgVal) False }
902 Arg messageArgs[] = {
903 { XtNjustify, (XtArgVal) XtJustifyLeft },
904 { XtNlabel, (XtArgVal) "..." },
905 { XtNresizable, (XtArgVal) True },
906 { XtNresize, (XtArgVal) False }
910 { XtNborderWidth, 0 },
911 { XtNjustify, (XtArgVal) XtJustifyLeft }
914 XtResource clientResources[] = {
915 { "flashCount", "flashCount", XtRInt, sizeof(int),
916 XtOffset(AppDataPtr, flashCount), XtRImmediate,
917 (XtPointer) FLASH_COUNT },
920 XrmOptionDescRec shellOptions[] = {
921 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
922 { "-flash", "flashCount", XrmoptionNoArg, "3" },
923 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
926 XtActionsRec boardActions[] = {
927 { "DrawPosition", DrawPositionProc },
928 { "HandleUserMove", HandleUserMove },
929 { "AnimateUserMove", AnimateUserMove },
930 { "HandlePV", HandlePV },
931 { "SelectPV", SelectPV },
932 { "StopPV", StopPV },
933 { "FileNameAction", FileNameAction },
934 { "AskQuestionProc", AskQuestionProc },
935 { "AskQuestionReplyAction", AskQuestionReplyAction },
936 { "PieceMenuPopup", PieceMenuPopup },
937 { "WhiteClock", WhiteClock },
938 { "BlackClock", BlackClock },
939 { "ResetProc", ResetProc },
940 { "NewVariantProc", NewVariantProc },
941 { "LoadGameProc", LoadGameProc },
942 { "LoadNextGameProc", LoadNextGameProc },
943 { "LoadPrevGameProc", LoadPrevGameProc },
944 { "LoadSelectedProc", LoadSelectedProc },
945 { "SetFilterProc", SetFilterProc },
946 { "ReloadGameProc", ReloadGameProc },
947 { "LoadPositionProc", LoadPositionProc },
948 { "LoadNextPositionProc", LoadNextPositionProc },
949 { "LoadPrevPositionProc", LoadPrevPositionProc },
950 { "ReloadPositionProc", ReloadPositionProc },
951 { "CopyPositionProc", CopyPositionProc },
952 { "PastePositionProc", PastePositionProc },
953 { "CopyGameProc", CopyGameProc },
954 { "CopyGameListProc", CopyGameListProc },
955 { "PasteGameProc", PasteGameProc },
956 { "SaveGameProc", SaveGameProc },
957 { "SavePositionProc", SavePositionProc },
958 { "MailMoveProc", MailMoveProc },
959 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
960 { "QuitProc", QuitProc },
961 { "MachineWhiteProc", MachineWhiteProc },
962 { "MachineBlackProc", MachineBlackProc },
963 { "AnalysisModeProc", AnalyzeModeProc },
964 { "AnalyzeFileProc", AnalyzeFileProc },
965 { "TwoMachinesProc", TwoMachinesProc },
966 { "IcsClientProc", IcsClientProc },
967 { "EditGameProc", EditGameProc },
968 { "EditPositionProc", EditPositionProc },
969 { "TrainingProc", EditPositionProc },
970 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
971 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
972 { "ShowGameListProc", ShowGameListProc },
973 { "ShowMoveListProc", HistoryShowProc},
974 { "EditTagsProc", EditTagsProc },
975 { "EditBookProc", EditBookProc },
976 { "EditCommentProc", EditCommentProc },
977 { "IcsInputBoxProc", IcsInputBoxProc },
978 { "PauseProc", PauseProc },
979 { "AcceptProc", AcceptProc },
980 { "DeclineProc", DeclineProc },
981 { "RematchProc", RematchProc },
982 { "CallFlagProc", CallFlagProc },
983 { "DrawProc", DrawProc },
984 { "AdjournProc", AdjournProc },
985 { "AbortProc", AbortProc },
986 { "ResignProc", ResignProc },
987 { "AdjuWhiteProc", AdjuWhiteProc },
988 { "AdjuBlackProc", AdjuBlackProc },
989 { "AdjuDrawProc", AdjuDrawProc },
990 { "TypeInProc", TypeInProc },
991 { "EnterKeyProc", EnterKeyProc },
992 { "UpKeyProc", UpKeyProc },
993 { "DownKeyProc", DownKeyProc },
994 { "StopObservingProc", StopObservingProc },
995 { "StopExaminingProc", StopExaminingProc },
996 { "UploadProc", UploadProc },
997 { "BackwardProc", BackwardProc },
998 { "ForwardProc", ForwardProc },
999 { "TempBackwardProc", TempBackwardProc },
1000 { "TempForwardProc", TempForwardProc },
1001 { "ToStartProc", ToStartProc },
1002 { "ToEndProc", ToEndProc },
1003 { "RevertProc", RevertProc },
1004 { "AnnotateProc", AnnotateProc },
1005 { "TruncateGameProc", TruncateGameProc },
1006 { "MoveNowProc", MoveNowProc },
1007 { "RetractMoveProc", RetractMoveProc },
1008 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
1009 { "UciMenuProc", (XtActionProc) UciMenuProc },
1010 { "TimeControlProc", (XtActionProc) TimeControlProc },
1011 { "FlipViewProc", FlipViewProc },
1012 { "PonderNextMoveProc", PonderNextMoveProc },
1013 #ifndef OPTIONSDIALOG
1014 { "AlwaysQueenProc", AlwaysQueenProc },
1015 { "AnimateDraggingProc", AnimateDraggingProc },
1016 { "AnimateMovingProc", AnimateMovingProc },
1017 { "AutoflagProc", AutoflagProc },
1018 { "AutoflipProc", AutoflipProc },
1019 { "BlindfoldProc", BlindfoldProc },
1020 { "FlashMovesProc", FlashMovesProc },
1022 { "HighlightDraggingProc", HighlightDraggingProc },
1024 { "HighlightLastMoveProc", HighlightLastMoveProc },
1025 // { "IcsAlarmProc", IcsAlarmProc },
1026 { "MoveSoundProc", MoveSoundProc },
1027 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1028 { "PopupExitMessageProc", PopupExitMessageProc },
1029 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1030 // { "PremoveProc", PremoveProc },
1031 { "ShowCoordsProc", ShowCoordsProc },
1032 { "ShowThinkingProc", ShowThinkingProc },
1033 { "HideThinkingProc", HideThinkingProc },
1034 { "TestLegalityProc", TestLegalityProc },
1036 { "SaveSettingsProc", SaveSettingsProc },
1037 { "SaveOnExitProc", SaveOnExitProc },
1038 { "InfoProc", InfoProc },
1039 { "ManProc", ManProc },
1040 { "HintProc", HintProc },
1041 { "BookProc", BookProc },
1042 { "AboutGameProc", AboutGameProc },
1043 { "AboutProc", AboutProc },
1044 { "DebugProc", DebugProc },
1045 { "NothingProc", NothingProc },
1046 { "CommentClick", (XtActionProc) CommentClick },
1047 { "CommentPopDown", (XtActionProc) CommentPopDown },
1048 { "TagsPopDown", (XtActionProc) TagsPopDown },
1049 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1050 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1051 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1052 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1053 { "GameListPopDown", (XtActionProc) GameListPopDown },
1054 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1055 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1056 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1057 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1058 { "GenericPopDown", (XtActionProc) GenericPopDown },
1059 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1060 { "SelectMove", (XtActionProc) SelectMove },
1063 char globalTranslations[] =
1064 ":<Key>F9: ResignProc() \n \
1065 :Ctrl<Key>n: ResetProc() \n \
1066 :Meta<Key>V: NewVariantProc() \n \
1067 :Ctrl<Key>o: LoadGameProc() \n \
1068 :Meta<Key>Next: LoadNextGameProc() \n \
1069 :Meta<Key>Prior: LoadPrevGameProc() \n \
1070 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
1071 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
1072 :Ctrl<Key>s: SaveGameProc() \n \
1073 :Ctrl<Key>c: CopyGameProc() \n \
1074 :Ctrl<Key>v: PasteGameProc() \n \
1075 :Ctrl<Key>O: LoadPositionProc() \n \
1076 :Shift<Key>Next: LoadNextPositionProc() \n \
1077 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1078 :Ctrl<Key>S: SavePositionProc() \n \
1079 :Ctrl<Key>C: CopyPositionProc() \n \
1080 :Ctrl<Key>V: PastePositionProc() \n \
1081 :Ctrl<Key>q: QuitProc() \n \
1082 :Ctrl<Key>w: MachineWhiteProc() \n \
1083 :Ctrl<Key>b: MachineBlackProc() \n \
1084 :Ctrl<Key>t: TwoMachinesProc() \n \
1085 :Ctrl<Key>a: AnalysisModeProc() \n \
1086 :Ctrl<Key>g: AnalyzeFileProc() \n \
1087 :Ctrl<Key>e: EditGameProc() \n \
1088 :Ctrl<Key>E: EditPositionProc() \n \
1089 :Meta<Key>O: EngineOutputProc() \n \
1090 :Meta<Key>E: EvalGraphProc() \n \
1091 :Meta<Key>G: ShowGameListProc() \n \
1092 :Meta<Key>H: ShowMoveListProc() \n \
1093 :<Key>Pause: PauseProc() \n \
1094 :<Key>F3: AcceptProc() \n \
1095 :<Key>F4: DeclineProc() \n \
1096 :<Key>F12: RematchProc() \n \
1097 :<Key>F5: CallFlagProc() \n \
1098 :<Key>F6: DrawProc() \n \
1099 :<Key>F7: AdjournProc() \n \
1100 :<Key>F8: AbortProc() \n \
1101 :<Key>F10: StopObservingProc() \n \
1102 :<Key>F11: StopExaminingProc() \n \
1103 :Meta Ctrl<Key>F12: DebugProc() \n \
1104 :Meta<Key>End: ToEndProc() \n \
1105 :Meta<Key>Right: ForwardProc() \n \
1106 :Meta<Key>Home: ToStartProc() \n \
1107 :Meta<Key>Left: BackwardProc() \n \
1108 :<Key>Left: BackwardProc() \n \
1109 :<Key>Right: ForwardProc() \n \
1110 :<Key>Home: RevertProc() \n \
1111 :<Key>End: TruncateGameProc() \n \
1112 :Ctrl<Key>m: MoveNowProc() \n \
1113 :Ctrl<Key>x: RetractMoveProc() \n \
1114 :Meta<Key>J: EngineMenuProc() \n \
1115 :Meta<Key>U: UciMenuProc() \n \
1116 :Meta<Key>T: TimeControlProc() \n \
1117 :Ctrl<Key>P: PonderNextMoveProc() \n "
1118 #ifndef OPTIONSDIALOG
1120 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1121 :Ctrl<Key>F: AutoflagProc() \n \
1122 :Ctrl<Key>A: AnimateMovingProc() \n \
1123 :Ctrl<Key>L: TestLegalityProc() \n \
1124 :Ctrl<Key>H: HideThinkingProc() \n "
1127 :<Key>F1: ManProc() \n \
1128 :<Key>F2: FlipViewProc() \n \
1129 :<KeyDown>Return: TempBackwardProc() \n \
1130 :<KeyUp>Return: TempForwardProc() \n";
1132 char boardTranslations[] =
1133 "<Btn1Down>: HandleUserMove(0) \n \
1134 Shift<Btn1Up>: HandleUserMove(1) \n \
1135 <Btn1Up>: HandleUserMove(0) \n \
1136 <Btn1Motion>: AnimateUserMove() \n \
1137 <Btn3Motion>: HandlePV() \n \
1138 <Btn2Motion>: HandlePV() \n \
1139 <Btn3Up>: PieceMenuPopup(menuB) \n \
1140 <Btn2Up>: PieceMenuPopup(menuB) \n \
1141 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1142 PieceMenuPopup(menuB) \n \
1143 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1144 PieceMenuPopup(menuW) \n \
1145 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1146 PieceMenuPopup(menuW) \n \
1147 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1148 PieceMenuPopup(menuB) \n";
1150 char whiteTranslations[] =
1151 "Shift<BtnDown>: WhiteClock(1)\n \
1152 <BtnDown>: WhiteClock(0)\n";
1153 char blackTranslations[] =
1154 "Shift<BtnDown>: BlackClock(1)\n \
1155 <BtnDown>: BlackClock(0)\n";
1157 char ICSInputTranslations[] =
1158 "<Key>Up: UpKeyProc() \n "
1159 "<Key>Down: DownKeyProc() \n "
1160 "<Key>Return: EnterKeyProc() \n";
1162 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1163 // as the widget is destroyed before the up-click can call extend-end
1164 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1166 String xboardResources[] = {
1167 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1168 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1169 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1174 /* Max possible square size */
1175 #define MAXSQSIZE 256
1177 static int xpm_avail[MAXSQSIZE];
1179 #ifdef HAVE_DIR_STRUCT
1181 /* Extract piece size from filename */
1183 xpm_getsize (char *name, int len, char *ext)
1191 if ((p=strchr(name, '.')) == NULL ||
1192 StrCaseCmp(p+1, ext) != 0)
1198 while (*p && isdigit(*p))
1205 /* Setup xpm_avail */
1207 xpm_getavail (char *dirname, char *ext)
1213 for (i=0; i<MAXSQSIZE; ++i)
1216 if (appData.debugMode)
1217 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1219 dir = opendir(dirname);
1222 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1223 programName, dirname);
1227 while ((ent=readdir(dir)) != NULL) {
1228 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1229 if (i > 0 && i < MAXSQSIZE)
1239 xpm_print_avail (FILE *fp, char *ext)
1243 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1244 for (i=1; i<MAXSQSIZE; ++i) {
1250 /* Return XPM piecesize closest to size */
1252 xpm_closest_to (char *dirname, int size, char *ext)
1255 int sm_diff = MAXSQSIZE;
1259 xpm_getavail(dirname, ext);
1261 if (appData.debugMode)
1262 xpm_print_avail(stderr, ext);
1264 for (i=1; i<MAXSQSIZE; ++i) {
1267 diff = (diff<0) ? -diff : diff;
1268 if (diff < sm_diff) {
1276 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1282 #else /* !HAVE_DIR_STRUCT */
1283 /* If we are on a system without a DIR struct, we can't
1284 read the directory, so we can't collect a list of
1285 filenames, etc., so we can't do any size-fitting. */
1287 xpm_closest_to (char *dirname, int size, char *ext)
1289 fprintf(stderr, _("\
1290 Warning: No DIR structure found on this system --\n\
1291 Unable to autosize for XPM/XIM pieces.\n\
1292 Please report this error to %s.\n\
1293 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1296 #endif /* HAVE_DIR_STRUCT */
1298 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1299 "magenta", "cyan", "white" };
1303 TextColors textColors[(int)NColorClasses];
1305 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1307 parse_color (char *str, int which)
1309 char *p, buf[100], *d;
1312 if (strlen(str) > 99) /* watch bounds on buf */
1317 for (i=0; i<which; ++i) {
1324 /* Could be looking at something like:
1326 .. in which case we want to stop on a comma also */
1327 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1331 return -1; /* Use default for empty field */
1334 if (which == 2 || isdigit(*p))
1337 while (*p && isalpha(*p))
1342 for (i=0; i<8; ++i) {
1343 if (!StrCaseCmp(buf, cnames[i]))
1344 return which? (i+40) : (i+30);
1346 if (!StrCaseCmp(buf, "default")) return -1;
1348 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1353 parse_cpair (ColorClass cc, char *str)
1355 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1356 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1361 /* bg and attr are optional */
1362 textColors[(int)cc].bg = parse_color(str, 1);
1363 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1364 textColors[(int)cc].attr = 0;
1370 /* Arrange to catch delete-window events */
1371 Atom wm_delete_window;
1373 CatchDeleteWindow (Widget w, String procname)
1376 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1377 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1378 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1385 XtSetArg(args[0], XtNiconic, False);
1386 XtSetValues(shellWidget, args, 1);
1388 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1391 //---------------------------------------------------------------------------------------------------------
1392 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1395 #define CW_USEDEFAULT (1<<31)
1396 #define ICS_TEXT_MENU_SIZE 90
1397 #define DEBUG_FILE "xboard.debug"
1398 #define SetCurrentDirectory chdir
1399 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1403 // these two must some day move to frontend.h, when they are implemented
1404 Boolean GameListIsUp();
1406 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1409 // front-end part of option handling
1411 // [HGM] This platform-dependent table provides the location for storing the color info
1412 extern char *crWhite, * crBlack;
1416 &appData.whitePieceColor,
1417 &appData.blackPieceColor,
1418 &appData.lightSquareColor,
1419 &appData.darkSquareColor,
1420 &appData.highlightSquareColor,
1421 &appData.premoveHighlightColor,
1422 &appData.lowTimeWarningColor,
1433 // [HGM] font: keep a font for each square size, even non-stndard ones
1434 #define NUM_SIZES 18
1435 #define MAX_SIZE 130
1436 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1437 char *fontTable[NUM_FONTS][MAX_SIZE];
1440 ParseFont (char *name, int number)
1441 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1443 if(sscanf(name, "size%d:", &size)) {
1444 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1445 // defer processing it until we know if it matches our board size
1446 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1447 fontTable[number][size] = strdup(strchr(name, ':')+1);
1448 fontValid[number][size] = True;
1453 case 0: // CLOCK_FONT
1454 appData.clockFont = strdup(name);
1456 case 1: // MESSAGE_FONT
1457 appData.font = strdup(name);
1459 case 2: // COORD_FONT
1460 appData.coordFont = strdup(name);
1465 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1470 { // only 2 fonts currently
1471 appData.clockFont = CLOCK_FONT_NAME;
1472 appData.coordFont = COORD_FONT_NAME;
1473 appData.font = DEFAULT_FONT_NAME;
1478 { // no-op, until we identify the code for this already in XBoard and move it here
1482 ParseColor (int n, char *name)
1483 { // in XBoard, just copy the color-name string
1484 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1488 ParseTextAttribs (ColorClass cc, char *s)
1490 (&appData.colorShout)[cc] = strdup(s);
1494 ParseBoardSize (void *addr, char *name)
1496 appData.boardSize = strdup(name);
1501 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1505 SetCommPortDefaults ()
1506 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1509 // [HGM] args: these three cases taken out to stay in front-end
1511 SaveFontArg (FILE *f, ArgDescriptor *ad)
1514 int i, n = (int)(intptr_t)ad->argLoc;
1516 case 0: // CLOCK_FONT
1517 name = appData.clockFont;
1519 case 1: // MESSAGE_FONT
1520 name = appData.font;
1522 case 2: // COORD_FONT
1523 name = appData.coordFont;
1528 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1529 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1530 fontTable[n][squareSize] = strdup(name);
1531 fontValid[n][squareSize] = True;
1534 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1535 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1540 { // nothing to do, as the sounds are at all times represented by their text-string names already
1544 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
1545 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1546 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1550 SaveColor (FILE *f, ArgDescriptor *ad)
1551 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1552 if(colorVariable[(int)(intptr_t)ad->argLoc])
1553 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1557 SaveBoardSize (FILE *f, char *name, void *addr)
1558 { // wrapper to shield back-end from BoardSize & sizeInfo
1559 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1563 ParseCommPortSettings (char *s)
1564 { // no such option in XBoard (yet)
1567 extern Widget engineOutputShell;
1571 GetActualPlacement (Widget wg, WindowPlacement *wp)
1576 XWindowAttributes winAt;
1583 XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
1584 XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
1585 wp->x = rx - winAt.x;
1586 wp->y = ry - winAt.y;
1587 wp->height = winAt.height;
1588 wp->width = winAt.width;
1589 frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
1594 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1595 // In XBoard this will have to wait until awareness of window parameters is implemented
1596 GetActualPlacement(shellWidget, &wpMain);
1597 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput);
1598 if(MoveHistoryIsUp()) GetActualPlacement(shells[7], &wpMoveHistory);
1599 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1600 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1601 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1602 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1606 PrintCommPortSettings (FILE *f, char *name)
1607 { // This option does not exist in XBoard
1611 MySearchPath (char *installDir, char *name, char *fullname)
1612 { // just append installDir and name. Perhaps ExpandPath should be used here?
1613 name = ExpandPathName(name);
1614 if(name && name[0] == '/')
1615 safeStrCpy(fullname, name, MSG_SIZ );
1617 sprintf(fullname, "%s%c%s", installDir, '/', name);
1623 MyGetFullPathName (char *name, char *fullname)
1624 { // should use ExpandPath?
1625 name = ExpandPathName(name);
1626 safeStrCpy(fullname, name, MSG_SIZ );
1631 EnsureOnScreen (int *x, int *y, int minX, int minY)
1638 { // [HGM] args: allows testing if main window is realized from back-end
1639 return xBoardWindow != 0;
1643 PopUpStartupDialog ()
1644 { // start menu not implemented in XBoard
1648 ConvertToLine (int argc, char **argv)
1650 static char line[128*1024], buf[1024];
1654 for(i=1; i<argc; i++)
1656 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
1657 && argv[i][0] != '{' )
1658 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1660 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1661 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1664 line[strlen(line)-1] = NULLCHAR;
1668 //--------------------------------------------------------------------------------------------
1670 extern Boolean twoBoards, partnerUp;
1673 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1675 #define BoardSize int
1677 InitDrawingSizes (BoardSize boardSize, int flags)
1678 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1679 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1681 XtGeometryResult gres;
1683 static Dimension oldWidth, oldHeight;
1684 static VariantClass oldVariant;
1685 static int oldDual = -1, oldMono = -1;
1687 if(!formWidget) return;
1689 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1690 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1691 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1693 if(boardWidth != oldWidth || boardHeight != oldHeight || oldDual != twoBoards) { // do resizing stuff only if size actually changed
1695 * Enable shell resizing.
1697 shellArgs[0].value = (XtArgVal) &w;
1698 shellArgs[1].value = (XtArgVal) &h;
1699 XtGetValues(shellWidget, shellArgs, 2);
1701 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1702 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1703 XtSetValues(shellWidget, &shellArgs[2], 4);
1705 XtSetArg(args[0], XtNdefaultDistance, &sep);
1706 XtGetValues(formWidget, args, 1);
1708 oldWidth = boardWidth; oldHeight = boardHeight; oldDual = twoBoards;
1710 hOffset = boardWidth + 10;
1711 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1712 secondSegments[i] = gridSegments[i];
1713 secondSegments[i].x1 += hOffset;
1714 secondSegments[i].x2 += hOffset;
1717 XtSetArg(args[0], XtNwidth, boardWidth);
1718 XtSetArg(args[1], XtNheight, boardHeight);
1719 XtSetValues(boardWidget, args, 2);
1721 timerWidth = (boardWidth - sep) / 2;
1722 XtSetArg(args[0], XtNwidth, timerWidth);
1723 XtSetValues(whiteTimerWidget, args, 1);
1724 XtSetValues(blackTimerWidget, args, 1);
1726 XawFormDoLayout(formWidget, False);
1728 if (appData.titleInWindow) {
1730 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1731 XtSetArg(args[i], XtNheight, &h); i++;
1732 XtGetValues(titleWidget, args, i);
1734 w = boardWidth - 2*bor;
1736 XtSetArg(args[0], XtNwidth, &w);
1737 XtGetValues(menuBarWidget, args, 1);
1738 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1741 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1742 if (gres != XtGeometryYes && appData.debugMode) {
1744 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1745 programName, gres, w, h, wr, hr);
1749 XawFormDoLayout(formWidget, True);
1752 * Inhibit shell resizing.
1754 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1755 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1756 shellArgs[4].value = shellArgs[2].value = w;
1757 shellArgs[5].value = shellArgs[3].value = h;
1758 XtSetValues(shellWidget, &shellArgs[0], 6);
1760 XSync(xDisplay, False);
1764 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1767 if(gameInfo.variant != oldVariant) { // and only if variant changed
1770 for(i=0; i<4; i++) {
1772 for(p=0; p<=(int)WhiteKing; p++)
1773 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1774 if(gameInfo.variant == VariantShogi) {
1775 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1776 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1777 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1778 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1779 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1782 if(gameInfo.variant == VariantGothic) {
1783 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1786 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1787 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1788 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1791 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1792 for(p=0; p<=(int)WhiteKing; p++)
1793 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1794 if(gameInfo.variant == VariantShogi) {
1795 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1796 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1797 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1798 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1799 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1802 if(gameInfo.variant == VariantGothic) {
1803 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1806 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1807 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1808 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1813 for(i=0; i<2; i++) {
1815 for(p=0; p<=(int)WhiteKing; p++)
1816 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1817 if(gameInfo.variant == VariantShogi) {
1818 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1819 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1820 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1821 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1822 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1825 if(gameInfo.variant == VariantGothic) {
1826 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1829 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1830 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1831 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1835 oldMono = -10; // kludge to force recreation of animation masks
1836 oldVariant = gameInfo.variant;
1839 if(appData.monoMode != oldMono)
1842 oldMono = appData.monoMode;
1847 ParseIcsTextColors ()
1848 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1849 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1850 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1851 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1852 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1853 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1854 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1855 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1856 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1857 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1858 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1860 if (appData.colorize) {
1862 _("%s: can't parse color names; disabling colorization\n"),
1865 appData.colorize = FALSE;
1871 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1872 XrmValue vFrom, vTo;
1873 int forceMono = False;
1875 if (!appData.monoMode) {
1876 vFrom.addr = (caddr_t) appData.lightSquareColor;
1877 vFrom.size = strlen(appData.lightSquareColor);
1878 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1879 if (vTo.addr == NULL) {
1880 appData.monoMode = True;
1883 lightSquareColor = *(Pixel *) vTo.addr;
1886 if (!appData.monoMode) {
1887 vFrom.addr = (caddr_t) appData.darkSquareColor;
1888 vFrom.size = strlen(appData.darkSquareColor);
1889 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1890 if (vTo.addr == NULL) {
1891 appData.monoMode = True;
1894 darkSquareColor = *(Pixel *) vTo.addr;
1897 if (!appData.monoMode) {
1898 vFrom.addr = (caddr_t) appData.whitePieceColor;
1899 vFrom.size = strlen(appData.whitePieceColor);
1900 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1901 if (vTo.addr == NULL) {
1902 appData.monoMode = True;
1905 whitePieceColor = *(Pixel *) vTo.addr;
1908 if (!appData.monoMode) {
1909 vFrom.addr = (caddr_t) appData.blackPieceColor;
1910 vFrom.size = strlen(appData.blackPieceColor);
1911 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1912 if (vTo.addr == NULL) {
1913 appData.monoMode = True;
1916 blackPieceColor = *(Pixel *) vTo.addr;
1920 if (!appData.monoMode) {
1921 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1922 vFrom.size = strlen(appData.highlightSquareColor);
1923 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1924 if (vTo.addr == NULL) {
1925 appData.monoMode = True;
1928 highlightSquareColor = *(Pixel *) vTo.addr;
1932 if (!appData.monoMode) {
1933 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1934 vFrom.size = strlen(appData.premoveHighlightColor);
1935 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1936 if (vTo.addr == NULL) {
1937 appData.monoMode = True;
1940 premoveHighlightColor = *(Pixel *) vTo.addr;
1948 { // [HGM] taken out of main
1950 if (appData.monoMode && // [HGM] no sense to go on to certain doom
1951 (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1952 appData.bitmapDirectory = strdup(DEF_BITMAP_DIR);
1954 if (appData.bitmapDirectory[0] != NULLCHAR) {
1958 CreateXPMBoard(appData.liteBackTextureFile, 1);
1959 CreateXPMBoard(appData.darkBackTextureFile, 0);
1963 /* Create regular pieces */
1964 if (!useImages) CreatePieces();
1969 main (int argc, char **argv)
1971 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1972 XSetWindowAttributes window_attributes;
1974 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1975 XrmValue vFrom, vTo;
1976 XtGeometryResult gres;
1979 int forceMono = False;
1981 srandom(time(0)); // [HGM] book: make random truly random
1983 setbuf(stdout, NULL);
1984 setbuf(stderr, NULL);
1987 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1988 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1992 programName = strrchr(argv[0], '/');
1993 if (programName == NULL)
1994 programName = argv[0];
1999 XtSetLanguageProc(NULL, NULL, NULL);
2000 bindtextdomain(PACKAGE, LOCALEDIR);
2001 textdomain(PACKAGE);
2005 XtAppInitialize(&appContext, "XBoard", shellOptions,
2006 XtNumber(shellOptions),
2007 &argc, argv, xboardResources, NULL, 0);
2008 appData.boardSize = "";
2009 InitAppData(ConvertToLine(argc, argv));
2011 if (p == NULL) p = "/tmp";
2012 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
2013 gameCopyFilename = (char*) malloc(i);
2014 gamePasteFilename = (char*) malloc(i);
2015 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
2016 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
2018 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2019 clientResources, XtNumber(clientResources),
2022 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
2023 static char buf[MSG_SIZ];
2024 EscapeExpand(buf, appData.firstInitString);
2025 appData.firstInitString = strdup(buf);
2026 EscapeExpand(buf, appData.secondInitString);
2027 appData.secondInitString = strdup(buf);
2028 EscapeExpand(buf, appData.firstComputerString);
2029 appData.firstComputerString = strdup(buf);
2030 EscapeExpand(buf, appData.secondComputerString);
2031 appData.secondComputerString = strdup(buf);
2034 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2037 if (chdir(chessDir) != 0) {
2038 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2044 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2045 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2046 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
2047 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2050 setbuf(debugFP, NULL);
2054 if (appData.debugMode) {
2055 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2059 /* [HGM,HR] make sure board size is acceptable */
2060 if(appData.NrFiles > BOARD_FILES ||
2061 appData.NrRanks > BOARD_RANKS )
2062 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2065 /* This feature does not work; animation needs a rewrite */
2066 appData.highlightDragging = FALSE;
2070 xDisplay = XtDisplay(shellWidget);
2071 xScreen = DefaultScreen(xDisplay);
2072 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2074 gameInfo.variant = StringToVariant(appData.variant);
2075 InitPosition(FALSE);
2078 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2080 if (isdigit(appData.boardSize[0])) {
2081 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2082 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2083 &fontPxlSize, &smallLayout, &tinyLayout);
2085 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2086 programName, appData.boardSize);
2090 /* Find some defaults; use the nearest known size */
2091 SizeDefaults *szd, *nearest;
2092 int distance = 99999;
2093 nearest = szd = sizeDefaults;
2094 while (szd->name != NULL) {
2095 if (abs(szd->squareSize - squareSize) < distance) {
2097 distance = abs(szd->squareSize - squareSize);
2098 if (distance == 0) break;
2102 if (i < 2) lineGap = nearest->lineGap;
2103 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2104 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2105 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2106 if (i < 6) smallLayout = nearest->smallLayout;
2107 if (i < 7) tinyLayout = nearest->tinyLayout;
2110 SizeDefaults *szd = sizeDefaults;
2111 if (*appData.boardSize == NULLCHAR) {
2112 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2113 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2116 if (szd->name == NULL) szd--;
2117 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2119 while (szd->name != NULL &&
2120 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2121 if (szd->name == NULL) {
2122 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2123 programName, appData.boardSize);
2127 squareSize = szd->squareSize;
2128 lineGap = szd->lineGap;
2129 clockFontPxlSize = szd->clockFontPxlSize;
2130 coordFontPxlSize = szd->coordFontPxlSize;
2131 fontPxlSize = szd->fontPxlSize;
2132 smallLayout = szd->smallLayout;
2133 tinyLayout = szd->tinyLayout;
2134 // [HGM] font: use defaults from settings file if available and not overruled
2136 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2137 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2138 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2139 appData.font = fontTable[MESSAGE_FONT][squareSize];
2140 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2141 appData.coordFont = fontTable[COORD_FONT][squareSize];
2143 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2144 if (strlen(appData.pixmapDirectory) > 0) {
2145 p = ExpandPathName(appData.pixmapDirectory);
2147 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2148 appData.pixmapDirectory);
2151 if (appData.debugMode) {
2152 fprintf(stderr, _("\
2153 XBoard square size (hint): %d\n\
2154 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2156 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2157 if (appData.debugMode) {
2158 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2161 defaultLineGap = lineGap;
2162 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2164 /* [HR] height treated separately (hacked) */
2165 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2166 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2167 if (appData.showJail == 1) {
2168 /* Jail on top and bottom */
2169 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2170 XtSetArg(boardArgs[2], XtNheight,
2171 boardHeight + 2*(lineGap + squareSize));
2172 } else if (appData.showJail == 2) {
2174 XtSetArg(boardArgs[1], XtNwidth,
2175 boardWidth + 2*(lineGap + squareSize));
2176 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2179 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2180 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2184 * Determine what fonts to use.
2187 appData.font = InsertPxlSize(appData.font, fontPxlSize);
2188 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2189 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2190 fontSet = CreateFontSet(appData.font);
2191 clockFontSet = CreateFontSet(appData.clockFont);
2193 /* For the coordFont, use the 0th font of the fontset. */
2194 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2195 XFontStruct **font_struct_list;
2196 XFontSetExtents *fontSize;
2197 char **font_name_list;
2198 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2199 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2200 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2201 fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
2202 textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
2205 appData.font = FindFont(appData.font, fontPxlSize);
2206 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2207 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2208 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2209 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2210 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2211 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2213 countFontID = coordFontID; // [HGM] holdings
2214 countFontStruct = coordFontStruct;
2216 xdb = XtDatabase(xDisplay);
2218 XrmPutLineResource(&xdb, "*international: True");
2219 vTo.size = sizeof(XFontSet);
2220 vTo.addr = (XtPointer) &fontSet;
2221 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2223 XrmPutStringResource(&xdb, "*font", appData.font);
2227 * Detect if there are not enough colors available and adapt.
2229 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2230 appData.monoMode = True;
2233 forceMono = MakeColors();
2236 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2238 appData.monoMode = True;
2241 if (appData.lowTimeWarning && !appData.monoMode) {
2242 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2243 vFrom.size = strlen(appData.lowTimeWarningColor);
2244 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2245 if (vTo.addr == NULL)
2246 appData.monoMode = True;
2248 lowTimeWarningColor = *(Pixel *) vTo.addr;
2251 if (appData.monoMode && appData.debugMode) {
2252 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2253 (unsigned long) XWhitePixel(xDisplay, xScreen),
2254 (unsigned long) XBlackPixel(xDisplay, xScreen));
2257 ParseIcsTextColors();
2258 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2259 textColors[ColorNone].attr = 0;
2261 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2267 layoutName = "tinyLayout";
2268 } else if (smallLayout) {
2269 layoutName = "smallLayout";
2271 layoutName = "normalLayout";
2273 /* Outer layoutWidget is there only to provide a name for use in
2274 resources that depend on the layout style */
2276 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2277 layoutArgs, XtNumber(layoutArgs));
2279 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2280 formArgs, XtNumber(formArgs));
2281 XtSetArg(args[0], XtNdefaultDistance, &sep);
2282 XtGetValues(formWidget, args, 1);
2285 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar, boardWidth);
2286 XtSetArg(args[0], XtNtop, XtChainTop);
2287 XtSetArg(args[1], XtNbottom, XtChainTop);
2288 XtSetArg(args[2], XtNright, XtChainLeft);
2289 XtSetValues(menuBarWidget, args, 3);
2291 widgetList[j++] = whiteTimerWidget =
2292 XtCreateWidget("whiteTime", labelWidgetClass,
2293 formWidget, timerArgs, XtNumber(timerArgs));
2295 XtSetArg(args[0], XtNfontSet, clockFontSet);
2297 XtSetArg(args[0], XtNfont, clockFontStruct);
2299 XtSetArg(args[1], XtNtop, XtChainTop);
2300 XtSetArg(args[2], XtNbottom, XtChainTop);
2301 XtSetValues(whiteTimerWidget, args, 3);
2303 widgetList[j++] = blackTimerWidget =
2304 XtCreateWidget("blackTime", labelWidgetClass,
2305 formWidget, timerArgs, XtNumber(timerArgs));
2307 XtSetArg(args[0], XtNfontSet, clockFontSet);
2309 XtSetArg(args[0], XtNfont, clockFontStruct);
2311 XtSetArg(args[1], XtNtop, XtChainTop);
2312 XtSetArg(args[2], XtNbottom, XtChainTop);
2313 XtSetValues(blackTimerWidget, args, 3);
2315 if (appData.titleInWindow) {
2316 widgetList[j++] = titleWidget =
2317 XtCreateWidget("title", labelWidgetClass, formWidget,
2318 titleArgs, XtNumber(titleArgs));
2319 XtSetArg(args[0], XtNtop, XtChainTop);
2320 XtSetArg(args[1], XtNbottom, XtChainTop);
2321 XtSetValues(titleWidget, args, 2);
2324 if (appData.showButtonBar) {
2325 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2326 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2327 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2328 XtSetArg(args[2], XtNtop, XtChainTop);
2329 XtSetArg(args[3], XtNbottom, XtChainTop);
2330 XtSetValues(buttonBarWidget, args, 4);
2333 widgetList[j++] = messageWidget =
2334 XtCreateWidget("message", labelWidgetClass, formWidget,
2335 messageArgs, XtNumber(messageArgs));
2336 XtSetArg(args[0], XtNtop, XtChainTop);
2337 XtSetArg(args[1], XtNbottom, XtChainTop);
2338 XtSetValues(messageWidget, args, 2);
2340 widgetList[j++] = boardWidget =
2341 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2342 XtNumber(boardArgs));
2344 XtManageChildren(widgetList, j);
2346 timerWidth = (boardWidth - sep) / 2;
2347 XtSetArg(args[0], XtNwidth, timerWidth);
2348 XtSetValues(whiteTimerWidget, args, 1);
2349 XtSetValues(blackTimerWidget, args, 1);
2351 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2352 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2353 XtGetValues(whiteTimerWidget, args, 2);
2355 if (appData.showButtonBar) {
2356 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2357 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2358 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2362 * formWidget uses these constraints but they are stored
2366 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2367 XtSetValues(menuBarWidget, args, i);
2368 if (appData.titleInWindow) {
2371 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2372 XtSetValues(whiteTimerWidget, args, i);
2374 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2375 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2376 XtSetValues(blackTimerWidget, args, i);
2378 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2379 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2380 XtSetValues(titleWidget, args, i);
2382 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2383 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2384 XtSetValues(messageWidget, args, i);
2385 if (appData.showButtonBar) {
2387 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2388 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2389 XtSetValues(buttonBarWidget, args, i);
2393 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2394 XtSetValues(whiteTimerWidget, args, i);
2396 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2397 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2398 XtSetValues(blackTimerWidget, args, i);
2400 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2401 XtSetValues(titleWidget, args, i);
2403 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2404 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2405 XtSetValues(messageWidget, args, i);
2406 if (appData.showButtonBar) {
2408 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2409 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2410 XtSetValues(buttonBarWidget, args, i);
2415 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2416 XtSetValues(whiteTimerWidget, args, i);
2418 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2419 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2420 XtSetValues(blackTimerWidget, args, i);
2422 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2423 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2424 XtSetValues(messageWidget, args, i);
2425 if (appData.showButtonBar) {
2427 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2428 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2429 XtSetValues(buttonBarWidget, args, i);
2433 XtSetArg(args[0], XtNfromVert, messageWidget);
2434 XtSetArg(args[1], XtNtop, XtChainTop);
2435 XtSetArg(args[2], XtNbottom, XtChainBottom);
2436 XtSetArg(args[3], XtNleft, XtChainLeft);
2437 XtSetArg(args[4], XtNright, XtChainRight);
2438 XtSetValues(boardWidget, args, 5);
2440 XtRealizeWidget(shellWidget);
2443 XtSetArg(args[0], XtNx, wpMain.x);
2444 XtSetArg(args[1], XtNy, wpMain.y);
2445 XtSetValues(shellWidget, args, 2);
2449 * Correct the width of the message and title widgets.
2450 * It is not known why some systems need the extra fudge term.
2451 * The value "2" is probably larger than needed.
2453 XawFormDoLayout(formWidget, False);
2455 #define WIDTH_FUDGE 2
2457 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2458 XtSetArg(args[i], XtNheight, &h); i++;
2459 XtGetValues(messageWidget, args, i);
2460 if (appData.showButtonBar) {
2462 XtSetArg(args[i], XtNwidth, &w); i++;
2463 XtGetValues(buttonBarWidget, args, i);
2464 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2466 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2469 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2470 if (gres != XtGeometryYes && appData.debugMode) {
2471 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2472 programName, gres, w, h, wr, hr);
2475 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2476 /* The size used for the child widget in layout lags one resize behind
2477 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2479 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2480 if (gres != XtGeometryYes && appData.debugMode) {
2481 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2482 programName, gres, w, h, wr, hr);
2485 if(!textHeight) textHeight = hr; // [HGM] if !NLS textHeight is still undefined, and we grab it from here
2486 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2487 XtSetArg(args[1], XtNright, XtChainRight);
2488 XtSetValues(messageWidget, args, 2);
2490 if (appData.titleInWindow) {
2492 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2493 XtSetArg(args[i], XtNheight, &h); i++;
2494 XtGetValues(titleWidget, args, i);
2496 w = boardWidth - 2*bor;
2498 XtSetArg(args[0], XtNwidth, &w);
2499 XtGetValues(menuBarWidget, args, 1);
2500 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2503 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2504 if (gres != XtGeometryYes && appData.debugMode) {
2506 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2507 programName, gres, w, h, wr, hr);
2510 XawFormDoLayout(formWidget, True);
2512 xBoardWindow = XtWindow(boardWidget);
2514 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2515 // not need to go into InitDrawingSizes().
2519 * Create X checkmark bitmap and initialize option menu checks.
2521 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2522 checkmark_bits, checkmark_width, checkmark_height);
2523 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2524 #ifndef OPTIONSDIALOG
2525 if (appData.alwaysPromoteToQueen) {
2526 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2529 if (appData.animateDragging) {
2530 XtSetValues(XtNameToWidget(menuBarWidget,
2531 "menuOptions.Animate Dragging"),
2534 if (appData.animate) {
2535 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2538 if (appData.autoCallFlag) {
2539 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2542 if (appData.autoFlipView) {
2543 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2546 if (appData.blindfold) {
2547 XtSetValues(XtNameToWidget(menuBarWidget,
2548 "menuOptions.Blindfold"), args, 1);
2550 if (appData.flashCount > 0) {
2551 XtSetValues(XtNameToWidget(menuBarWidget,
2552 "menuOptions.Flash Moves"),
2556 if (appData.highlightDragging) {
2557 XtSetValues(XtNameToWidget(menuBarWidget,
2558 "menuOptions.Highlight Dragging"),
2562 if (appData.highlightLastMove) {
2563 XtSetValues(XtNameToWidget(menuBarWidget,
2564 "menuOptions.Highlight Last Move"),
2567 if (appData.highlightMoveWithArrow) {
2568 XtSetValues(XtNameToWidget(menuBarWidget,
2569 "menuOptions.Arrow"),
2572 // if (appData.icsAlarm) {
2573 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2576 if (appData.ringBellAfterMoves) {
2577 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2580 if (appData.oneClick) {
2581 XtSetValues(XtNameToWidget(menuBarWidget,
2582 "menuOptions.OneClick"), args, 1);
2584 if (appData.periodicUpdates) {
2585 XtSetValues(XtNameToWidget(menuBarWidget,
2586 "menuOptions.Periodic Updates"), args, 1);
2588 if (appData.ponderNextMove) {
2589 XtSetValues(XtNameToWidget(menuBarWidget,
2590 "menuOptions.Ponder Next Move"), args, 1);
2592 if (appData.popupExitMessage) {
2593 XtSetValues(XtNameToWidget(menuBarWidget,
2594 "menuOptions.Popup Exit Message"), args, 1);
2596 if (appData.popupMoveErrors) {
2597 XtSetValues(XtNameToWidget(menuBarWidget,
2598 "menuOptions.Popup Move Errors"), args, 1);
2600 // if (appData.premove) {
2601 // XtSetValues(XtNameToWidget(menuBarWidget,
2602 // "menuOptions.Premove"), args, 1);
2604 if (appData.showCoords) {
2605 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2608 if (appData.hideThinkingFromHuman) {
2609 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2612 if (appData.testLegality) {
2613 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2617 if (saveSettingsOnExit) {
2618 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2625 ReadBitmap(&wIconPixmap, "icon_white.bm",
2626 icon_white_bits, icon_white_width, icon_white_height);
2627 ReadBitmap(&bIconPixmap, "icon_black.bm",
2628 icon_black_bits, icon_black_width, icon_black_height);
2629 iconPixmap = wIconPixmap;
2631 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2632 XtSetValues(shellWidget, args, i);
2635 * Create a cursor for the board widget.
2637 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2638 XChangeWindowAttributes(xDisplay, xBoardWindow,
2639 CWCursor, &window_attributes);
2642 * Inhibit shell resizing.
2644 shellArgs[0].value = (XtArgVal) &w;
2645 shellArgs[1].value = (XtArgVal) &h;
2646 XtGetValues(shellWidget, shellArgs, 2);
2647 shellArgs[4].value = shellArgs[2].value = w;
2648 shellArgs[5].value = shellArgs[3].value = h;
2649 XtSetValues(shellWidget, &shellArgs[2], 4);
2650 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2651 marginH = h - boardHeight;
2653 CatchDeleteWindow(shellWidget, "QuitProc");
2661 if (appData.animate || appData.animateDragging)
2664 XtAugmentTranslations(formWidget,
2665 XtParseTranslationTable(globalTranslations));
2666 XtAugmentTranslations(boardWidget,
2667 XtParseTranslationTable(boardTranslations));
2668 XtAugmentTranslations(whiteTimerWidget,
2669 XtParseTranslationTable(whiteTranslations));
2670 XtAugmentTranslations(blackTimerWidget,
2671 XtParseTranslationTable(blackTranslations));
2673 /* Why is the following needed on some versions of X instead
2674 * of a translation? */
2675 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2676 (XtEventHandler) EventProc, NULL);
2678 XtAddEventHandler(formWidget, KeyPressMask, False,
2679 (XtEventHandler) MoveTypeInProc, NULL);
2680 XtAddEventHandler(shellWidget, StructureNotifyMask, False,
2681 (XtEventHandler) EventProc, NULL);
2683 /* [AS] Restore layout */
2684 if( wpMoveHistory.visible ) {
2688 if( wpEvalGraph.visible )
2693 if( wpEngineOutput.visible ) {
2694 EngineOutputPopUp();
2699 if (errorExitStatus == -1) {
2700 if (appData.icsActive) {
2701 /* We now wait until we see "login:" from the ICS before
2702 sending the logon script (problems with timestamp otherwise) */
2703 /*ICSInitScript();*/
2704 if (appData.icsInputBox) ICSInputBoxPopUp();
2708 signal(SIGWINCH, TermSizeSigHandler);
2710 signal(SIGINT, IntSigHandler);
2711 signal(SIGTERM, IntSigHandler);
2712 if (*appData.cmailGameName != NULLCHAR) {
2713 signal(SIGUSR1, CmailSigHandler);
2716 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2718 // XtSetKeyboardFocus(shellWidget, formWidget);
2719 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2721 XtAppMainLoop(appContext);
2722 if (appData.debugMode) fclose(debugFP); // [DM] debug
2726 static Boolean noEcho;
2731 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2732 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2734 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2735 unlink(gameCopyFilename);
2736 unlink(gamePasteFilename);
2737 if(noEcho) EchoOn();
2741 TermSizeSigHandler (int sig)
2747 IntSigHandler (int sig)
2753 CmailSigHandler (int sig)
2758 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2760 /* Activate call-back function CmailSigHandlerCallBack() */
2761 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2763 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2767 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
2770 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2772 /**** end signal code ****/
2778 /* try to open the icsLogon script, either in the location given
2779 * or in the users HOME directory
2786 f = fopen(appData.icsLogon, "r");
2789 homedir = getenv("HOME");
2790 if (homedir != NULL)
2792 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2793 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2794 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2795 f = fopen(buf, "r");
2800 ProcessICSInitScript(f);
2802 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2821 GreyRevert (Boolean grey)
2824 if (!menuBarWidget) return;
2825 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2827 DisplayError("menuEdit.Revert", 0);
2829 XtSetSensitive(w, !grey);
2831 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2833 DisplayError("menuEdit.Annotate", 0);
2835 XtSetSensitive(w, !grey);
2840 SetMenuEnables (Enables *enab)
2843 if (!menuBarWidget) return;
2844 while (enab->name != NULL) {
2845 w = XtNameToWidget(menuBarWidget, enab->name);
2847 DisplayError(enab->name, 0);
2849 XtSetSensitive(w, enab->value);
2855 Enables icsEnables[] = {
2856 { "menuFile.Mail Move", False },
2857 { "menuFile.Reload CMail Message", False },
2858 { "menuMode.Machine Black", False },
2859 { "menuMode.Machine White", False },
2860 { "menuMode.Analysis Mode", False },
2861 { "menuMode.Analyze File", False },
2862 { "menuMode.Two Machines", False },
2863 { "menuMode.Machine Match", False },
2865 { "menuEngine.Hint", False },
2866 { "menuEngine.Book", False },
2867 { "menuEngine.Move Now", False },
2868 #ifndef OPTIONSDIALOG
2869 { "menuOptions.Periodic Updates", False },
2870 { "menuOptions.Hide Thinking", False },
2871 { "menuOptions.Ponder Next Move", False },
2874 { "menuEngine.Engine #1 Settings", False },
2875 { "menuEngine.Engine #2 Settings", False },
2876 { "menuEngine.Load Engine", False },
2877 { "menuEdit.Annotate", False },
2878 { "menuOptions.Match", False },
2882 Enables ncpEnables[] = {
2883 { "menuFile.Mail Move", False },
2884 { "menuFile.Reload CMail Message", False },
2885 { "menuMode.Machine White", False },
2886 { "menuMode.Machine Black", False },
2887 { "menuMode.Analysis Mode", False },
2888 { "menuMode.Analyze File", False },
2889 { "menuMode.Two Machines", False },
2890 { "menuMode.Machine Match", False },
2891 { "menuMode.ICS Client", False },
2892 { "menuView.ICStex", False },
2893 { "menuView.ICS Input Box", False },
2894 { "Action", False },
2895 { "menuEdit.Revert", False },
2896 { "menuEdit.Annotate", False },
2897 { "menuEngine.Engine #1 Settings", False },
2898 { "menuEngine.Engine #2 Settings", False },
2899 { "menuEngine.Move Now", False },
2900 { "menuEngine.Retract Move", False },
2901 { "menuOptions.ICS", False },
2902 #ifndef OPTIONSDIALOG
2903 { "menuOptions.Auto Flag", False },
2904 { "menuOptions.Auto Flip View", False },
2905 // { "menuOptions.ICS Alarm", False },
2906 { "menuOptions.Move Sound", False },
2907 { "menuOptions.Hide Thinking", False },
2908 { "menuOptions.Periodic Updates", False },
2909 { "menuOptions.Ponder Next Move", False },
2911 { "menuEngine.Hint", False },
2912 { "menuEngine.Book", False },
2916 Enables gnuEnables[] = {
2917 { "menuMode.ICS Client", False },
2918 { "menuView.ICStex", False },
2919 { "menuView.ICS Input Box", False },
2920 { "menuAction.Accept", False },
2921 { "menuAction.Decline", False },
2922 { "menuAction.Rematch", False },
2923 { "menuAction.Adjourn", False },
2924 { "menuAction.Stop Examining", False },
2925 { "menuAction.Stop Observing", False },
2926 { "menuAction.Upload to Examine", False },
2927 { "menuEdit.Revert", False },
2928 { "menuEdit.Annotate", False },
2929 { "menuOptions.ICS", False },
2931 /* The next two options rely on SetCmailMode being called *after* */
2932 /* SetGNUMode so that when GNU is being used to give hints these */
2933 /* menu options are still available */
2935 { "menuFile.Mail Move", False },
2936 { "menuFile.Reload CMail Message", False },
2937 // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2938 { "menuMode.Machine White", True },
2939 { "menuMode.Machine Black", True },
2940 { "menuMode.Analysis Mode", True },
2941 { "menuMode.Analyze File", True },
2942 { "menuMode.Two Machines", True },
2943 { "menuMode.Machine Match", True },
2944 { "menuEngine.Engine #1 Settings", True },
2945 { "menuEngine.Engine #2 Settings", True },
2946 { "menuEngine.Hint", True },
2947 { "menuEngine.Book", True },
2948 { "menuEngine.Move Now", True },
2949 { "menuEngine.Retract Move", True },
2954 Enables cmailEnables[] = {
2956 { "menuAction.Call Flag", False },
2957 { "menuAction.Draw", True },
2958 { "menuAction.Adjourn", False },
2959 { "menuAction.Abort", False },
2960 { "menuAction.Stop Observing", False },
2961 { "menuAction.Stop Examining", False },
2962 { "menuFile.Mail Move", True },
2963 { "menuFile.Reload CMail Message", True },
2967 Enables trainingOnEnables[] = {
2968 { "menuMode.Edit Comment", False },
2969 { "menuMode.Pause", False },
2970 { "menuEdit.Forward", False },
2971 { "menuEdit.Backward", False },
2972 { "menuEdit.Forward to End", False },
2973 { "menuEdit.Back to Start", False },
2974 { "menuEngine.Move Now", False },
2975 { "menuEdit.Truncate Game", False },
2979 Enables trainingOffEnables[] = {
2980 { "menuMode.Edit Comment", True },
2981 { "menuMode.Pause", True },
2982 { "menuEdit.Forward", True },
2983 { "menuEdit.Backward", True },
2984 { "menuEdit.Forward to End", True },
2985 { "menuEdit.Back to Start", True },
2986 { "menuEngine.Move Now", True },
2987 { "menuEdit.Truncate Game", True },
2991 Enables machineThinkingEnables[] = {
2992 { "menuFile.Load Game", False },
2993 // { "menuFile.Load Next Game", False },
2994 // { "menuFile.Load Previous Game", False },
2995 // { "menuFile.Reload Same Game", False },
2996 { "menuEdit.Paste Game", False },
2997 { "menuFile.Load Position", False },
2998 // { "menuFile.Load Next Position", False },
2999 // { "menuFile.Load Previous Position", False },
3000 // { "menuFile.Reload Same Position", False },
3001 { "menuEdit.Paste Position", False },
3002 { "menuMode.Machine White", False },
3003 { "menuMode.Machine Black", False },
3004 { "menuMode.Two Machines", False },
3005 // { "menuMode.Machine Match", False },
3006 { "menuEngine.Retract Move", False },
3010 Enables userThinkingEnables[] = {
3011 { "menuFile.Load Game", True },
3012 // { "menuFile.Load Next Game", True },
3013 // { "menuFile.Load Previous Game", True },
3014 // { "menuFile.Reload Same Game", True },
3015 { "menuEdit.Paste Game", True },
3016 { "menuFile.Load Position", True },
3017 // { "menuFile.Load Next Position", True },
3018 // { "menuFile.Load Previous Position", True },
3019 // { "menuFile.Reload Same Position", True },
3020 { "menuEdit.Paste Position", True },
3021 { "menuMode.Machine White", True },
3022 { "menuMode.Machine Black", True },
3023 { "menuMode.Two Machines", True },
3024 // { "menuMode.Machine Match", True },
3025 { "menuEngine.Retract Move", True },
3032 SetMenuEnables(icsEnables);
3035 if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3036 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3037 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3045 SetMenuEnables(ncpEnables);
3051 SetMenuEnables(gnuEnables);
3057 SetMenuEnables(cmailEnables);
3061 SetTrainingModeOn ()
3063 SetMenuEnables(trainingOnEnables);
3064 if (appData.showButtonBar) {
3065 XtSetSensitive(buttonBarWidget, False);
3071 SetTrainingModeOff ()
3073 SetMenuEnables(trainingOffEnables);
3074 if (appData.showButtonBar) {
3075 XtSetSensitive(buttonBarWidget, True);
3080 SetUserThinkingEnables ()
3082 if (appData.noChessProgram) return;
3083 SetMenuEnables(userThinkingEnables);
3087 SetMachineThinkingEnables ()
3089 if (appData.noChessProgram) return;
3090 SetMenuEnables(machineThinkingEnables);
3092 case MachinePlaysBlack:
3093 case MachinePlaysWhite:
3094 case TwoMachinesPlay:
3095 XtSetSensitive(XtNameToWidget(menuBarWidget,
3096 ModeToWidgetName(gameMode)), True);
3103 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3104 #define HISTORY_SIZE 64
3105 static char *history[HISTORY_SIZE];
3106 int histIn = 0, histP = 0;
3109 SaveInHistory (char *cmd)
3111 if (history[histIn] != NULL) {
3112 free(history[histIn]);
3113 history[histIn] = NULL;
3115 if (*cmd == NULLCHAR) return;
3116 history[histIn] = StrSave(cmd);
3117 histIn = (histIn + 1) % HISTORY_SIZE;
3118 if (history[histIn] != NULL) {
3119 free(history[histIn]);
3120 history[histIn] = NULL;
3126 PrevInHistory (char *cmd)
3129 if (histP == histIn) {
3130 if (history[histIn] != NULL) free(history[histIn]);
3131 history[histIn] = StrSave(cmd);
3133 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3134 if (newhp == histIn || history[newhp] == NULL) return NULL;
3136 return history[histP];
3142 if (histP == histIn) return NULL;
3143 histP = (histP + 1) % HISTORY_SIZE;
3144 return history[histP];
3146 // end of borrowed code
3148 #define Abs(n) ((n)<0 ? -(n) : (n))
3152 InsertPxlSize (char *pattern, int targetPxlSize)
3154 char *base_fnt_lst, strInt[12], *p, *q;
3155 int alternatives, i, len, strIntLen;
3158 * Replace the "*" (if present) in the pixel-size slot of each
3159 * alternative with the targetPxlSize.
3163 while ((p = strchr(p, ',')) != NULL) {
3167 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3168 strIntLen = strlen(strInt);
3169 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3173 while (alternatives--) {
3174 char *comma = strchr(p, ',');
3175 for (i=0; i<14; i++) {
3176 char *hyphen = strchr(p, '-');
3178 if (comma && hyphen > comma) break;
3179 len = hyphen + 1 - p;
3180 if (i == 7 && *p == '*' && len == 2) {
3182 memcpy(q, strInt, strIntLen);
3192 len = comma + 1 - p;
3199 return base_fnt_lst;
3203 CreateFontSet (char *base_fnt_lst)
3206 char **missing_list;
3210 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3211 &missing_list, &missing_count, &def_string);
3212 if (appData.debugMode) {
3214 XFontStruct **font_struct_list;
3215 char **font_name_list;
3216 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3218 fprintf(debugFP, " got list %s, locale %s\n",
3219 XBaseFontNameListOfFontSet(fntSet),
3220 XLocaleOfFontSet(fntSet));
3221 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3222 for (i = 0; i < count; i++) {
3223 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3226 for (i = 0; i < missing_count; i++) {
3227 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3230 if (fntSet == NULL) {
3231 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3236 #else // not ENABLE_NLS
3238 * Find a font that matches "pattern" that is as close as
3239 * possible to the targetPxlSize. Prefer fonts that are k
3240 * pixels smaller to fonts that are k pixels larger. The
3241 * pattern must be in the X Consortium standard format,
3242 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3243 * The return value should be freed with XtFree when no
3247 FindFont (char *pattern, int targetPxlSize)
3249 char **fonts, *p, *best, *scalable, *scalableTail;
3250 int i, j, nfonts, minerr, err, pxlSize;
3252 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3254 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3255 programName, pattern);
3262 for (i=0; i<nfonts; i++) {
3265 if (*p != '-') continue;
3267 if (*p == NULLCHAR) break;
3268 if (*p++ == '-') j++;
3270 if (j < 7) continue;
3273 scalable = fonts[i];
3276 err = pxlSize - targetPxlSize;
3277 if (Abs(err) < Abs(minerr) ||
3278 (minerr > 0 && err < 0 && -err == minerr)) {
3284 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3285 /* If the error is too big and there is a scalable font,
3286 use the scalable font. */
3287 int headlen = scalableTail - scalable;
3288 p = (char *) XtMalloc(strlen(scalable) + 10);
3289 while (isdigit(*scalableTail)) scalableTail++;
3290 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3292 p = (char *) XtMalloc(strlen(best) + 2);
3293 safeStrCpy(p, best, strlen(best)+1 );
3295 if (appData.debugMode) {
3296 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3297 pattern, targetPxlSize, p);
3299 XFreeFontNames(fonts);
3306 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3307 // must be called before all non-first callse to CreateGCs()
3308 XtReleaseGC(shellWidget, highlineGC);
3309 XtReleaseGC(shellWidget, lightSquareGC);
3310 XtReleaseGC(shellWidget, darkSquareGC);
3311 XtReleaseGC(shellWidget, lineGC);
3312 if (appData.monoMode) {
3313 if (DefaultDepth(xDisplay, xScreen) == 1) {
3314 XtReleaseGC(shellWidget, wbPieceGC);
3316 XtReleaseGC(shellWidget, bwPieceGC);
3319 XtReleaseGC(shellWidget, prelineGC);
3320 XtReleaseGC(shellWidget, jailSquareGC);
3321 XtReleaseGC(shellWidget, wdPieceGC);
3322 XtReleaseGC(shellWidget, wlPieceGC);
3323 XtReleaseGC(shellWidget, wjPieceGC);
3324 XtReleaseGC(shellWidget, bdPieceGC);
3325 XtReleaseGC(shellWidget, blPieceGC);
3326 XtReleaseGC(shellWidget, bjPieceGC);
3331 CreateGCs (int redo)
3333 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3334 | GCBackground | GCFunction | GCPlaneMask;
3335 XGCValues gc_values;
3338 gc_values.plane_mask = AllPlanes;
3339 gc_values.line_width = lineGap;
3340 gc_values.line_style = LineSolid;
3341 gc_values.function = GXcopy;
3344 DeleteGCs(); // called a second time; clean up old GCs first
3345 } else { // [HGM] grid and font GCs created on first call only
3346 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3347 gc_values.background = XWhitePixel(xDisplay, xScreen);
3348 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3349 XSetFont(xDisplay, coordGC, coordFontID);
3351 // [HGM] make font for holdings counts (white on black)
3352 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3353 gc_values.background = XBlackPixel(xDisplay, xScreen);
3354 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3355 XSetFont(xDisplay, countGC, countFontID);
3357 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3358 gc_values.background = XBlackPixel(xDisplay, xScreen);
3359 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3361 if (appData.monoMode) {
3362 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3363 gc_values.background = XWhitePixel(xDisplay, xScreen);
3364 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3366 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3367 gc_values.background = XBlackPixel(xDisplay, xScreen);
3368 lightSquareGC = wbPieceGC
3369 = XtGetGC(shellWidget, value_mask, &gc_values);
3371 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3372 gc_values.background = XWhitePixel(xDisplay, xScreen);
3373 darkSquareGC = bwPieceGC
3374 = XtGetGC(shellWidget, value_mask, &gc_values);
3376 if (DefaultDepth(xDisplay, xScreen) == 1) {
3377 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3378 gc_values.function = GXcopyInverted;
3379 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3380 gc_values.function = GXcopy;
3381 if (XBlackPixel(xDisplay, xScreen) == 1) {
3382 bwPieceGC = darkSquareGC;
3383 wbPieceGC = copyInvertedGC;
3385 bwPieceGC = copyInvertedGC;
3386 wbPieceGC = lightSquareGC;
3390 gc_values.foreground = highlightSquareColor;
3391 gc_values.background = highlightSquareColor;
3392 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3394 gc_values.foreground = premoveHighlightColor;
3395 gc_values.background = premoveHighlightColor;
3396 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3398 gc_values.foreground = lightSquareColor;
3399 gc_values.background = darkSquareColor;
3400 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3402 gc_values.foreground = darkSquareColor;
3403 gc_values.background = lightSquareColor;
3404 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3406 gc_values.foreground = jailSquareColor;
3407 gc_values.background = jailSquareColor;
3408 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3410 gc_values.foreground = whitePieceColor;
3411 gc_values.background = darkSquareColor;
3412 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3414 gc_values.foreground = whitePieceColor;
3415 gc_values.background = lightSquareColor;
3416 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3418 gc_values.foreground = whitePieceColor;
3419 gc_values.background = jailSquareColor;
3420 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3422 gc_values.foreground = blackPieceColor;
3423 gc_values.background = darkSquareColor;
3424 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3426 gc_values.foreground = blackPieceColor;
3427 gc_values.background = lightSquareColor;
3428 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3430 gc_values.foreground = blackPieceColor;
3431 gc_values.background = jailSquareColor;
3432 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3437 loadXIM (XImage *xim, XImage *xmask, char *filename, Pixmap *dest, Pixmap *mask)
3445 fp = fopen(filename, "rb");
3447 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3454 for (y=0; y<h; ++y) {
3455 for (x=0; x<h; ++x) {
3460 XPutPixel(xim, x, y, blackPieceColor);
3462 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3465 XPutPixel(xim, x, y, darkSquareColor);
3467 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3470 XPutPixel(xim, x, y, whitePieceColor);
3472 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3475 XPutPixel(xim, x, y, lightSquareColor);
3477 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3485 /* create Pixmap of piece */
3486 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3488 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3491 /* create Pixmap of clipmask
3492 Note: We assume the white/black pieces have the same
3493 outline, so we make only 6 masks. This is okay
3494 since the XPM clipmask routines do the same. */
3496 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3498 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3501 /* now create the 1-bit version */
3502 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3505 values.foreground = 1;
3506 values.background = 0;
3508 /* Don't use XtGetGC, not read only */
3509 maskGC = XCreateGC(xDisplay, *mask,
3510 GCForeground | GCBackground, &values);
3511 XCopyPlane(xDisplay, temp, *mask, maskGC,
3512 0, 0, squareSize, squareSize, 0, 0, 1);
3513 XFreePixmap(xDisplay, temp);
3518 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3526 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3531 /* The XSynchronize calls were copied from CreatePieces.
3532 Not sure if needed, but can't hurt */
3533 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3536 /* temp needed by loadXIM() */
3537 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3538 0, 0, ss, ss, AllPlanes, XYPixmap);
3540 if (strlen(appData.pixmapDirectory) == 0) {
3544 if (appData.monoMode) {
3545 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3549 fprintf(stderr, _("\nLoading XIMs...\n"));
3551 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3552 fprintf(stderr, "%d", piece+1);
3553 for (kind=0; kind<4; kind++) {
3554 fprintf(stderr, ".");
3555 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3556 ExpandPathName(appData.pixmapDirectory),
3557 piece <= (int) WhiteKing ? "" : "w",
3558 pieceBitmapNames[piece],
3560 ximPieceBitmap[kind][piece] =
3561 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3562 0, 0, ss, ss, AllPlanes, XYPixmap);
3563 if (appData.debugMode)
3564 fprintf(stderr, _("(File:%s:) "), buf);
3565 loadXIM(ximPieceBitmap[kind][piece],
3567 &(xpmPieceBitmap2[kind][piece]),
3568 &(ximMaskPm2[piece]));
3569 if(piece <= (int)WhiteKing)
3570 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3572 fprintf(stderr," ");
3574 /* Load light and dark squares */
3575 /* If the LSQ and DSQ pieces don't exist, we will
3576 draw them with solid squares. */
3577 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3578 if (access(buf, 0) != 0) {
3582 fprintf(stderr, _("light square "));
3584 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3585 0, 0, ss, ss, AllPlanes, XYPixmap);
3586 if (appData.debugMode)
3587 fprintf(stderr, _("(File:%s:) "), buf);
3589 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3590 fprintf(stderr, _("dark square "));
3591 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3592 ExpandPathName(appData.pixmapDirectory), ss);
3593 if (appData.debugMode)
3594 fprintf(stderr, _("(File:%s:) "), buf);
3596 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3597 0, 0, ss, ss, AllPlanes, XYPixmap);
3598 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3599 xpmJailSquare = xpmLightSquare;
3601 fprintf(stderr, _("Done.\n"));
3603 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3606 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3610 CreateXPMBoard (char *s, int kind)
3614 if(!appData.useBitmaps || s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3615 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3616 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3622 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3623 // thisroutine has to be called t free the old piece pixmaps
3625 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3626 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3628 XFreePixmap(xDisplay, xpmLightSquare);
3629 XFreePixmap(xDisplay, xpmDarkSquare);
3638 u_int ss = squareSize;
3640 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3641 XpmColorSymbol symbols[4];
3642 static int redo = False;
3644 if(redo) FreeXPMPieces(); else redo = 1;
3646 /* The XSynchronize calls were copied from CreatePieces.
3647 Not sure if needed, but can't hurt */
3648 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3650 /* Setup translations so piece colors match square colors */
3651 symbols[0].name = "light_piece";
3652 symbols[0].value = appData.whitePieceColor;
3653 symbols[1].name = "dark_piece";
3654 symbols[1].value = appData.blackPieceColor;
3655 symbols[2].name = "light_square";
3656 symbols[2].value = appData.lightSquareColor;
3657 symbols[3].name = "dark_square";
3658 symbols[3].value = appData.darkSquareColor;
3660 attr.valuemask = XpmColorSymbols;
3661 attr.colorsymbols = symbols;
3662 attr.numsymbols = 4;
3664 if (appData.monoMode) {
3665 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3669 if (strlen(appData.pixmapDirectory) == 0) {
3670 XpmPieces* pieces = builtInXpms;
3673 while (pieces->size != squareSize && pieces->size) pieces++;
3674 if (!pieces->size) {
3675 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3678 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3679 for (kind=0; kind<4; kind++) {
3681 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3682 pieces->xpm[piece][kind],
3683 &(xpmPieceBitmap2[kind][piece]),
3684 NULL, &attr)) != 0) {
3685 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3689 if(piece <= (int) WhiteKing)
3690 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3694 xpmJailSquare = xpmLightSquare;
3698 fprintf(stderr, _("\nLoading XPMs...\n"));
3701 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3702 fprintf(stderr, "%d ", piece+1);
3703 for (kind=0; kind<4; kind++) {
3704 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3705 ExpandPathName(appData.pixmapDirectory),
3706 piece > (int) WhiteKing ? "w" : "",
3707 pieceBitmapNames[piece],
3709 if (appData.debugMode) {
3710 fprintf(stderr, _("(File:%s:) "), buf);
3712 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3713 &(xpmPieceBitmap2[kind][piece]),
3714 NULL, &attr)) != 0) {
3715 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3716 // [HGM] missing: read of unorthodox piece failed; substitute King.
3717 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3718 ExpandPathName(appData.pixmapDirectory),
3720 if (appData.debugMode) {
3721 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3723 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3724 &(xpmPieceBitmap2[kind][piece]),
3728 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3733 if(piece <= (int) WhiteKing)
3734 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3737 /* Load light and dark squares */
3738 /* If the LSQ and DSQ pieces don't exist, we will
3739 draw them with solid squares. */
3740 fprintf(stderr, _("light square "));
3741 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3742 if (access(buf, 0) != 0) {
3746 if (appData.debugMode)
3747 fprintf(stderr, _("(File:%s:) "), buf);
3749 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3750 &xpmLightSquare, NULL, &attr)) != 0) {
3751 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3754 fprintf(stderr, _("dark square "));
3755 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3756 ExpandPathName(appData.pixmapDirectory), ss);
3757 if (appData.debugMode) {
3758 fprintf(stderr, _("(File:%s:) "), buf);
3760 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3761 &xpmDarkSquare, NULL, &attr)) != 0) {
3762 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3766 xpmJailSquare = xpmLightSquare;
3767 fprintf(stderr, _("Done.\n"));
3769 oldVariant = -1; // kludge to force re-makig of animation masks
3770 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3773 #endif /* HAVE_LIBXPM */
3776 /* No built-in bitmaps */
3781 u_int ss = squareSize;
3783 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3786 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3787 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3788 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3789 pieceBitmapNames[piece],
3790 ss, kind == SOLID ? 's' : 'o');
3791 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3792 if(piece <= (int)WhiteKing)
3793 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3797 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3801 /* With built-in bitmaps */
3805 BuiltInBits* bib = builtInBits;
3808 u_int ss = squareSize;
3810 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3813 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3815 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3816 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3817 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3818 pieceBitmapNames[piece],
3819 ss, kind == SOLID ? 's' : 'o');
3820 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3821 bib->bits[kind][piece], ss, ss);
3822 if(piece <= (int)WhiteKing)
3823 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3827 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3833 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
3838 char msg[MSG_SIZ], fullname[MSG_SIZ];
3840 if (*appData.bitmapDirectory != NULLCHAR) {
3841 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3842 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3843 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3844 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3845 &w, &h, pm, &x_hot, &y_hot);
3846 fprintf(stderr, "load %s\n", name);
3847 if (errcode != BitmapSuccess) {
3849 case BitmapOpenFailed:
3850 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3852 case BitmapFileInvalid:
3853 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3855 case BitmapNoMemory:
3856 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3860 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3864 fprintf(stderr, _("%s: %s...using built-in\n"),
3866 } else if (w != wreq || h != hreq) {
3868 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3869 programName, fullname, w, h, wreq, hreq);
3875 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3885 if (lineGap == 0) return;
3887 /* [HR] Split this into 2 loops for non-square boards. */
3889 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3890 gridSegments[i].x1 = 0;
3891 gridSegments[i].x2 =
3892 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3893 gridSegments[i].y1 = gridSegments[i].y2
3894 = lineGap / 2 + (i * (squareSize + lineGap));
3897 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3898 gridSegments[j + i].y1 = 0;
3899 gridSegments[j + i].y2 =
3900 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3901 gridSegments[j + i].x1 = gridSegments[j + i].x2
3902 = lineGap / 2 + (j * (squareSize + lineGap));
3907 MenuBarSelect (Widget w, caddr_t addr, caddr_t index)
3909 XtActionProc proc = (XtActionProc) addr;
3911 (proc)(NULL, NULL, NULL, NULL);
3915 MenuEngineSelect (Widget w, caddr_t addr, caddr_t index)
3917 RecentEngineEvent((int) (intptr_t) addr);
3921 AppendEnginesToMenu (Widget menu, char *list)
3929 if(appData.icsActive || appData.recentEngines <= 0) return;
3930 recentEngines = strdup(list);
3932 XtSetArg(args[j], XtNleftMargin, 20); j++;
3933 XtSetArg(args[j], XtNrightMargin, 20); j++;
3935 p = strchr(list, '\n'); if(p == NULL) break;
3936 if(i == 0) XtCreateManagedWidget(_("----"), smeLineObjectClass, menu, args, j); // at least one valid item to add
3938 XtSetArg(args[j], XtNlabel, XtNewString(list));
3939 entry = XtCreateManagedWidget("engine", smeBSBObjectClass, menu, args, j+1);
3940 XtAddCallback(entry, XtNcallback,
3941 (XtCallbackProc) MenuEngineSelect,
3942 (caddr_t) (intptr_t) i);
3943 i++; *p = '\n'; list = p + 1;
3948 CreateMenuBarPopup (Widget parent, String name, Menu *mb)
3955 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3958 XtSetArg(args[j], XtNleftMargin, 20); j++;
3959 XtSetArg(args[j], XtNrightMargin, 20); j++;
3961 while (mi->string != NULL) {
3962 if (strcmp(mi->string, "----") == 0) {
3963 entry = XtCreateManagedWidget(_(mi->string), smeLineObjectClass,
3966 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3967 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3969 XtAddCallback(entry, XtNcallback,
3970 (XtCallbackProc) MenuBarSelect,
3971 (caddr_t) mi->proc);
3975 if(!strcmp(mb->name, "Engine")) AppendEnginesToMenu(menu, appData.recentEngineList);
3979 CreateMenuBar (Menu *mb, int boardWidth)
3981 int i, j, nr = 0, wtot = 0, widths[10];
3984 char menuName[MSG_SIZ];
3989 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3990 XtSetArg(args[j], XtNvSpace, 0); j++;
3991 XtSetArg(args[j], XtNborderWidth, 0); j++;
3992 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3993 formWidget, args, j);
3995 while (mb->name != NULL) {
3996 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3997 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3999 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
4000 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
4001 XtSetArg(args[j], XtNborderWidth, 0); j++;
4002 mb->subMenu = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
4004 CreateMenuBarPopup(menuBar, menuName, mb);
4006 XtSetArg(args[j], XtNwidth, &w); j++;
4007 XtGetValues(mb->subMenu, args, j);
4008 wtot += mb->textWidth = widths[nr++] = w;
4011 while(wtot > boardWidth - 40) {
4013 for(i=0; i<nr; i++) if(widths[i] > wmax) wmax = widths[imax=i];
4017 for(i=0; i<nr; i++) if(widths[i] != ma[i].textWidth) {
4019 XtSetArg(args[j], XtNwidth, widths[i]); j++;
4020 XtSetValues(ma[i].subMenu, args, j);
4026 CreateButtonBar (MenuItem *mi)
4029 Widget button, buttonBar;
4033 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
4035 XtSetArg(args[j], XtNhSpace, 0); j++;
4037 XtSetArg(args[j], XtNborderWidth, 0); j++;
4038 XtSetArg(args[j], XtNvSpace, 0); j++;
4039 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
4040 formWidget, args, j);
4042 while (mi->string != NULL) {
4045 XtSetArg(args[j], XtNinternalWidth, 2); j++;
4046 XtSetArg(args[j], XtNborderWidth, 0); j++;
4048 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
4049 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
4050 buttonBar, args, j);
4051 XtAddCallback(button, XtNcallback,
4052 (XtCallbackProc) MenuBarSelect,
4053 (caddr_t) mi->proc);
4060 CreatePieceMenu (char *name, int color)
4065 ChessSquare selection;
4067 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
4068 boardWidget, args, 0);
4070 for (i = 0; i < PIECE_MENU_SIZE; i++) {
4071 String item = pieceMenuStrings[color][i];
4073 if (strcmp(item, "----") == 0) {
4074 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4077 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4078 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4080 selection = pieceMenuTranslation[color][i];
4081 XtAddCallback(entry, XtNcallback,
4082 (XtCallbackProc) PieceMenuSelect,
4083 (caddr_t) selection);
4084 if (selection == WhitePawn || selection == BlackPawn) {
4085 XtSetArg(args[0], XtNpopupOnEntry, entry);
4086 XtSetValues(menu, args, 1);
4099 ChessSquare selection;
4101 whitePieceMenu = CreatePieceMenu("menuW", 0);
4102 blackPieceMenu = CreatePieceMenu("menuB", 1);
4104 if(appData.pieceMenu) // [HGM] sweep: no idea what this was good for, but it stopped reporting button events outside the window
4105 XtRegisterGrabAction(PieceMenuPopup, True,
4106 (unsigned)(ButtonPressMask|ButtonReleaseMask),
4107 GrabModeAsync, GrabModeAsync);
4109 XtSetArg(args[0], XtNlabel, _("Drop"));
4110 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
4111 boardWidget, args, 1);
4112 for (i = 0; i < DROP_MENU_SIZE; i++) {
4113 String item = dropMenuStrings[i];
4115 if (strcmp(item, "----") == 0) {
4116 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4119 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4120 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4122 selection = dropMenuTranslation[i];
4123 XtAddCallback(entry, XtNcallback,
4124 (XtCallbackProc) DropMenuSelect,
4125 (caddr_t) selection);
4139 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
4140 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
4141 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
4142 dmEnables[i].piece);
4143 XtSetSensitive(entry, p != NULL || !appData.testLegality
4144 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
4145 && !appData.icsActive));
4147 while (p && *p++ == dmEnables[i].piece) count++;
4148 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
4150 XtSetArg(args[j], XtNlabel, label); j++;
4151 XtSetValues(entry, args, j);
4156 PieceMenuPopup (Widget w, XEvent *event, String *params, Cardinal *num_params)
4158 String whichMenu; int menuNr = -2;
4159 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
4160 if (event->type == ButtonRelease)
4161 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4162 else if (event->type == ButtonPress)
4163 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4165 case 0: whichMenu = params[0]; break;
4166 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
4168 case -1: if (errorUp) ErrorPopDown();
4171 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
4175 PieceMenuSelect (Widget w, ChessSquare piece, caddr_t junk)
4177 if (pmFromX < 0 || pmFromY < 0) return;
4178 EditPositionMenuEvent(piece, pmFromX, pmFromY);
4182 DropMenuSelect (Widget w, ChessSquare piece, caddr_t junk)
4184 if (pmFromX < 0 || pmFromY < 0) return;
4185 DropMenuEvent(piece, pmFromX, pmFromY);
4189 WhiteClock (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4191 shiftKey = prms[0][0] & 1;
4196 BlackClock (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4198 shiftKey = prms[0][0] & 1;
4204 * If the user selects on a border boundary, return -1; if off the board,
4205 * return -2. Otherwise map the event coordinate to the square.
4208 EventToSquare (int x, int limit)
4215 if ((x % (squareSize + lineGap)) >= squareSize)
4217 x /= (squareSize + lineGap);
4224 do_flash_delay (unsigned long msec)
4230 drawHighlight (int file, int rank, GC gc)
4234 if (lineGap == 0) return;
4237 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4238 (squareSize + lineGap);
4239 y = lineGap/2 + rank * (squareSize + lineGap);
4241 x = lineGap/2 + file * (squareSize + lineGap);
4242 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4243 (squareSize + lineGap);
4246 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4247 squareSize+lineGap, squareSize+lineGap);
4250 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4251 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4254 SetHighlights (int fromX, int fromY, int toX, int toY)
4256 if (hi1X != fromX || hi1Y != fromY) {
4257 if (hi1X >= 0 && hi1Y >= 0) {
4258 drawHighlight(hi1X, hi1Y, lineGC);
4260 } // [HGM] first erase both, then draw new!
4261 if (hi2X != toX || hi2Y != toY) {
4262 if (hi2X >= 0 && hi2Y >= 0) {
4263 drawHighlight(hi2X, hi2Y, lineGC);
4266 if (hi1X != fromX || hi1Y != fromY) {
4267 if (fromX >= 0 && fromY >= 0) {
4268 drawHighlight(fromX, fromY, highlineGC);
4271 if (hi2X != toX || hi2Y != toY) {
4272 if (toX >= 0 && toY >= 0) {
4273 drawHighlight(toX, toY, highlineGC);
4276 if(toX<0) // clearing the highlights must have damaged arrow
4277 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y); // for now, redraw it (should really be cleared!)
4287 SetHighlights(-1, -1, -1, -1);
4292 SetPremoveHighlights (int fromX, int fromY, int toX, int toY)
4294 if (pm1X != fromX || pm1Y != fromY) {
4295 if (pm1X >= 0 && pm1Y >= 0) {
4296 drawHighlight(pm1X, pm1Y, lineGC);
4298 if (fromX >= 0 && fromY >= 0) {
4299 drawHighlight(fromX, fromY, prelineGC);
4302 if (pm2X != toX || pm2Y != toY) {
4303 if (pm2X >= 0 && pm2Y >= 0) {
4304 drawHighlight(pm2X, pm2Y, lineGC);
4306 if (toX >= 0 && toY >= 0) {
4307 drawHighlight(toX, toY, prelineGC);
4317 ClearPremoveHighlights ()
4319 SetPremoveHighlights(-1, -1, -1, -1);
4323 CutOutSquare (int x, int y, int *x0, int *y0, int kind)
4325 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4326 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4328 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4329 if(textureW[kind] < W*squareSize)
4330 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4332 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4333 if(textureH[kind] < H*squareSize)
4334 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4336 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4341 BlankSquare (int x, int y, int color, ChessSquare piece, Drawable dest, int fac)
4342 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4344 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4345 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4346 squareSize, squareSize, x*fac, y*fac);
4348 if (useImages && useImageSqs) {
4352 pm = xpmLightSquare;
4357 case 2: /* neutral */
4362 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4363 squareSize, squareSize, x*fac, y*fac);
4373 case 2: /* neutral */
4378 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4383 I split out the routines to draw a piece so that I could
4384 make a generic flash routine.
4387 monoDrawPiece_1bit (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4389 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4390 switch (square_color) {
4392 case 2: /* neutral */
4394 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4395 ? *pieceToOutline(piece)
4396 : *pieceToSolid(piece),
4397 dest, bwPieceGC, 0, 0,
4398 squareSize, squareSize, x, y);
4401 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4402 ? *pieceToSolid(piece)
4403 : *pieceToOutline(piece),
4404 dest, wbPieceGC, 0, 0,
4405 squareSize, squareSize, x, y);
4411 monoDrawPiece (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4413 switch (square_color) {
4415 case 2: /* neutral */
4417 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4418 ? *pieceToOutline(piece)
4419 : *pieceToSolid(piece),
4420 dest, bwPieceGC, 0, 0,
4421 squareSize, squareSize, x, y, 1);
4424 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4425 ? *pieceToSolid(piece)
4426 : *pieceToOutline(piece),
4427 dest, wbPieceGC, 0, 0,
4428 squareSize, squareSize, x, y, 1);
4434 colorDrawPiece (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4436 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4437 switch (square_color) {
4439 XCopyPlane(xDisplay, *pieceToSolid(piece),
4440 dest, (int) piece < (int) BlackPawn
4441 ? wlPieceGC : blPieceGC, 0, 0,
4442 squareSize, squareSize, x, y, 1);
4445 XCopyPlane(xDisplay, *pieceToSolid(piece),
4446 dest, (int) piece < (int) BlackPawn
4447 ? wdPieceGC : bdPieceGC, 0, 0,
4448 squareSize, squareSize, x, y, 1);
4450 case 2: /* neutral */
4452 XCopyPlane(xDisplay, *pieceToSolid(piece),
4453 dest, (int) piece < (int) BlackPawn
4454 ? wjPieceGC : bjPieceGC, 0, 0,
4455 squareSize, squareSize, x, y, 1);
4461 colorDrawPieceImage (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4463 int kind, p = piece;
4465 switch (square_color) {
4467 case 2: /* neutral */
4469 if ((int)piece < (int) BlackPawn) {
4477 if ((int)piece < (int) BlackPawn) {
4485 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4486 if(useTexture & square_color+1) {
4487 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4488 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4489 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4490 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4491 XSetClipMask(xDisplay, wlPieceGC, None);
4492 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4494 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4495 dest, wlPieceGC, 0, 0,
4496 squareSize, squareSize, x, y);
4499 typedef void (*DrawFunc)();
4504 if (appData.monoMode) {
4505 if (DefaultDepth(xDisplay, xScreen) == 1) {
4506 return monoDrawPiece_1bit;
4508 return monoDrawPiece;
4512 return colorDrawPieceImage;
4514 return colorDrawPiece;
4518 /* [HR] determine square color depending on chess variant. */
4520 SquareColor (int row, int column)
4524 if (gameInfo.variant == VariantXiangqi) {
4525 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4527 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4529 } else if (row <= 4) {
4535 square_color = ((column + row) % 2) == 1;
4538 /* [hgm] holdings: next line makes all holdings squares light */
4539 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4541 return square_color;
4545 DrawSquare (int row, int column, ChessSquare piece, int do_flash)
4547 int square_color, x, y, direction, font_ascent, font_descent;
4550 XCharStruct overall;
4554 /* Calculate delay in milliseconds (2-delays per complete flash) */
4555 flash_delay = 500 / appData.flashRate;
4558 x = lineGap + ((BOARD_WIDTH-1)-column) *
4559 (squareSize + lineGap);
4560 y = lineGap + row * (squareSize + lineGap);
4562 x = lineGap + column * (squareSize + lineGap);
4563 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4564 (squareSize + lineGap);
4567 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4569 square_color = SquareColor(row, column);
4571 if ( // [HGM] holdings: blank out area between board and holdings
4572 column == BOARD_LEFT-1 || column == BOARD_RGHT
4573 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4574 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4575 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4577 // [HGM] print piece counts next to holdings
4578 string[1] = NULLCHAR;
4579 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4580 string[0] = '0' + piece;
4581 XTextExtents(countFontStruct, string, 1, &direction,
4582 &font_ascent, &font_descent, &overall);
4583 if (appData.monoMode) {
4584 XDrawImageString(xDisplay, xBoardWindow, countGC,
4585 x + squareSize - overall.width - 2,
4586 y + font_ascent + 1, string, 1);
4588 XDrawString(xDisplay, xBoardWindow, countGC,
4589 x + squareSize - overall.width - 2,
4590 y + font_ascent + 1, string, 1);
4593 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4594 string[0] = '0' + piece;
4595 XTextExtents(countFontStruct, string, 1, &direction,
4596 &font_ascent, &font_descent, &overall);
4597 if (appData.monoMode) {
4598 XDrawImageString(xDisplay, xBoardWindow, countGC,
4599 x + 2, y + font_ascent + 1, string, 1);
4601 XDrawString(xDisplay, xBoardWindow, countGC,
4602 x + 2, y + font_ascent + 1, string, 1);
4606 if (piece == EmptySquare || appData.blindfold) {
4607 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4609 drawfunc = ChooseDrawFunc();
4611 if (do_flash && appData.flashCount > 0) {
4612 for (i=0; i<appData.flashCount; ++i) {
4613 drawfunc(piece, square_color, x, y, xBoardWindow);
4614 XSync(xDisplay, False);
4615 do_flash_delay(flash_delay);
4617 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4618 XSync(xDisplay, False);
4619 do_flash_delay(flash_delay);
4622 drawfunc(piece, square_color, x, y, xBoardWindow);
4626 string[1] = NULLCHAR;
4627 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4628 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4629 string[0] = 'a' + column - BOARD_LEFT;
4630 XTextExtents(coordFontStruct, string, 1, &direction,
4631 &font_ascent, &font_descent, &overall);
4632 if (appData.monoMode) {
4633 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4634 x + squareSize - overall.width - 2,
4635 y + squareSize - font_descent - 1, string, 1);
4637 XDrawString(xDisplay, xBoardWindow, coordGC,
4638 x + squareSize - overall.width - 2,
4639 y + squareSize - font_descent - 1, string, 1);
4642 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4643 string[0] = ONE + row;
4644 XTextExtents(coordFontStruct, string, 1, &direction,
4645 &font_ascent, &font_descent, &overall);
4646 if (appData.monoMode) {
4647 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4648 x + 2, y + font_ascent + 1, string, 1);
4650 XDrawString(xDisplay, xBoardWindow, coordGC,
4651 x + 2, y + font_ascent + 1, string, 1);
4654 if(!partnerUp && marker[row][column]) {
4655 if(appData.monoMode) {
4656 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? darkSquareGC : lightSquareGC,
4657 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4658 XDrawArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? lightSquareGC : darkSquareGC,
4659 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4661 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4662 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4667 Fraction (int x, int start, int stop)
4669 double f = ((double) x - start)/(stop - start);
4670 if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
4674 static WindowPlacement wpNew;
4677 CoDrag (Widget sh, WindowPlacement *wp)
4680 int j=0, touch=0, fudge = 2;
4681 GetActualPlacement(sh, wp);
4682 if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
4683 if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
4684 if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
4685 if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
4686 if(!touch ) return; // only windows that touch co-move
4687 if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
4688 int heightInc = wpNew.height - wpMain.height;
4689 double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
4690 double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
4691 wp->y += fracTop * heightInc;
4692 heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
4693 if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
4694 } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
4695 int widthInc = wpNew.width - wpMain.width;
4696 double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
4697 double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
4698 wp->y += fracLeft * widthInc;
4699 widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
4700 if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
4702 wp->x += wpNew.x - wpMain.x;
4703 wp->y += wpNew.y - wpMain.y;
4704 if(touch == 1) wp->x += wpNew.width - wpMain.width; else
4705 if(touch == 3) wp->y += wpNew.height - wpMain.height;
4706 XtSetArg(args[j], XtNx, wp->x); j++;
4707 XtSetArg(args[j], XtNy, wp->y); j++;
4708 XtSetValues(sh, args, j);
4711 static XtIntervalId delayedDragID = 0;
4716 GetActualPlacement(shellWidget, &wpNew);
4717 if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
4718 wpNew.width == wpMain.width && wpNew.height == wpMain.height) // not sized
4719 return; // false alarm
4720 if(EngineOutputIsUp()) CoDrag(engineOutputShell, &wpEngineOutput);
4721 if(MoveHistoryIsUp()) CoDrag(shells[7], &wpMoveHistory);
4722 if(EvalGraphIsUp()) CoDrag(evalGraphShell, &wpEvalGraph);
4723 if(GameListIsUp()) CoDrag(gameListShell, &wpGameList);
4725 XDrawPosition(boardWidget, True, NULL);
4726 delayedDragID = 0; // now drag executed, make sure next DelayedDrag will not cancel timer event (which could now be used by other)
4733 if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
4735 XtAppAddTimeOut(appContext, 50, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
4738 /* Why is this needed on some versions of X? */
4740 EventProc (Widget widget, caddr_t unused, XEvent *event)
4742 if (!XtIsRealized(widget))
4744 switch (event->type) {
4745 case ConfigureNotify: // main window is being dragged: drag attached windows with it
4746 if(appData.useStickyWindows)
4747 DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
4750 if (event->xexpose.count > 0) return; /* no clipping is done */
4751 XDrawPosition(widget, True, NULL);
4752 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4753 flipView = !flipView; partnerUp = !partnerUp;
4754 XDrawPosition(widget, True, NULL);
4755 flipView = !flipView; partnerUp = !partnerUp;
4759 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4767 DrawPosition (int fullRedraw, Board board)
4769 XDrawPosition(boardWidget, fullRedraw, board);
4772 /* Returns 1 if there are "too many" differences between b1 and b2
4773 (i.e. more than 1 move was made) */
4775 too_many_diffs (Board b1, Board b2)
4780 for (i=0; i<BOARD_HEIGHT; ++i) {
4781 for (j=0; j<BOARD_WIDTH; ++j) {
4782 if (b1[i][j] != b2[i][j]) {
4783 if (++c > 4) /* Castling causes 4 diffs */
4791 /* Matrix describing castling maneuvers */
4792 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4793 static int castling_matrix[4][5] = {
4794 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4795 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4796 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4797 { 7, 7, 4, 5, 6 } /* 0-0, black */
4800 /* Checks whether castling occurred. If it did, *rrow and *rcol
4801 are set to the destination (row,col) of the rook that moved.
4803 Returns 1 if castling occurred, 0 if not.
4805 Note: Only handles a max of 1 castling move, so be sure
4806 to call too_many_diffs() first.
4809 check_castle_draw (Board newb, Board oldb, int *rrow, int *rcol)
4814 /* For each type of castling... */
4815 for (i=0; i<4; ++i) {
4816 r = castling_matrix[i];
4818 /* Check the 4 squares involved in the castling move */
4820 for (j=1; j<=4; ++j) {
4821 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4828 /* All 4 changed, so it must be a castling move */
4837 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4839 DrawSeekAxis (int x, int y, int xTo, int yTo)
4841 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4845 DrawSeekBackground (int left, int top, int right, int bottom)
4847 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4851 DrawSeekText (char *buf, int x, int y)
4853 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4857 DrawSeekDot (int x, int y, int colorNr)
4859 int square = colorNr & 0x80;
4862 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4864 XFillRectangle(xDisplay, xBoardWindow, color,
4865 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4867 XFillArc(xDisplay, xBoardWindow, color,
4868 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4871 static int damage[2][BOARD_RANKS][BOARD_FILES];
4874 * event handler for redrawing the board
4877 XDrawPosition (Widget w, int repaint, Board board)
4880 static int lastFlipView = 0;
4881 static int lastBoardValid[2] = {0, 0};
4882 static Board lastBoard[2];
4885 int nr = twoBoards*partnerUp;
4887 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4889 if (board == NULL) {
4890 if (!lastBoardValid[nr]) return;
4891 board = lastBoard[nr];
4893 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4894 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4895 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4900 * It would be simpler to clear the window with XClearWindow()
4901 * but this causes a very distracting flicker.
4904 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4906 if ( lineGap && IsDrawArrowEnabled())
4907 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4908 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4910 /* If too much changes (begin observing new game, etc.), don't
4912 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4914 /* Special check for castling so we don't flash both the king
4915 and the rook (just flash the king). */
4917 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4918 /* Draw rook with NO flashing. King will be drawn flashing later */
4919 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4920 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4924 /* First pass -- Draw (newly) empty squares and repair damage.
4925 This prevents you from having a piece show up twice while it
4926 is flashing on its new square */
4927 for (i = 0; i < BOARD_HEIGHT; i++)
4928 for (j = 0; j < BOARD_WIDTH; j++)
4929 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4930 || damage[nr][i][j]) {
4931 DrawSquare(i, j, board[i][j], 0);
4932 damage[nr][i][j] = False;
4935 /* Second pass -- Draw piece(s) in new position and flash them */
4936 for (i = 0; i < BOARD_HEIGHT; i++)
4937 for (j = 0; j < BOARD_WIDTH; j++)
4938 if (board[i][j] != lastBoard[nr][i][j]) {
4939 DrawSquare(i, j, board[i][j], do_flash);
4943 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4944 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4945 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4947 for (i = 0; i < BOARD_HEIGHT; i++)
4948 for (j = 0; j < BOARD_WIDTH; j++) {
4949 DrawSquare(i, j, board[i][j], 0);
4950 damage[nr][i][j] = False;
4954 CopyBoard(lastBoard[nr], board);
4955 lastBoardValid[nr] = 1;
4956 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4957 lastFlipView = flipView;
4959 /* Draw highlights */
4960 if (pm1X >= 0 && pm1Y >= 0) {
4961 drawHighlight(pm1X, pm1Y, prelineGC);
4963 if (pm2X >= 0 && pm2Y >= 0) {
4964 drawHighlight(pm2X, pm2Y, prelineGC);
4966 if (hi1X >= 0 && hi1Y >= 0) {
4967 drawHighlight(hi1X, hi1Y, highlineGC);
4969 if (hi2X >= 0 && hi2Y >= 0) {
4970 drawHighlight(hi2X, hi2Y, highlineGC);
4972 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4974 /* If piece being dragged around board, must redraw that too */
4977 XSync(xDisplay, False);
4982 * event handler for redrawing the board
4985 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4987 XDrawPosition(w, True, NULL);
4992 * event handler for parsing user moves
4994 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4995 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4996 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4997 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4998 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4999 // and at the end FinishMove() to perform the move after optional promotion popups.
5000 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
5002 HandleUserMove (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5004 if (w != boardWidget || errorExitStatus != -1) return;
5005 if(nprms) shiftKey = !strcmp(prms[0], "1");
5008 if (event->type == ButtonPress) {
5009 XtPopdown(promotionShell);
5010 XtDestroyWidget(promotionShell);
5011 promotionUp = False;
5019 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
5020 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
5021 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
5025 AnimateUserMove (Widget w, XEvent *event, String *params, Cardinal *nParams)
5027 if(!PromoScroll(event->xmotion.x, event->xmotion.y))
5028 DragPieceMove(event->xmotion.x, event->xmotion.y);
5032 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
5033 { // [HGM] pv: walk PV
5034 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
5037 static int savedIndex; /* gross that this is global */
5040 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
5043 XawTextPosition index, dummy;
5046 XawTextGetSelectionPos(w, &index, &dummy);
5047 XtSetArg(arg, XtNstring, &val);
5048 XtGetValues(w, &arg, 1);
5049 ReplaceComment(savedIndex, val);
5050 if(savedIndex != currentMove) ToNrEvent(savedIndex);
5051 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
5055 EditCommentPopUp (int index, char *title, char *text)
5058 if (text == NULL) text = "";
5059 NewCommentPopup(title, text, index);
5068 extern Option boxOptions[];
5078 edit = boxOptions[0].handle;
5080 XtSetArg(args[j], XtNstring, &val); j++;
5081 XtGetValues(edit, args, j);
5083 SendMultiLineToICS(val);
5084 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5085 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5089 ICSInputBoxPopDown ()
5095 CommentPopUp (char *title, char *text)
5097 savedIndex = currentMove; // [HGM] vari
5098 NewCommentPopup(title, text, currentMove);
5107 static char *openName;
5113 (void) (*fileProc)(openFP, 0, openName);
5117 FileNamePopUp (char *label, char *def, char *filter, FileProc proc, char *openMode)
5119 fileProc = proc; /* I can't see a way not */
5120 fileOpenMode = openMode; /* to use globals here */
5121 { // [HGM] use file-selector dialog stolen from Ghostview
5122 int index; // this is not supported yet
5123 if(openFP = XsraSelFile(shellWidget, label, NULL, NULL, _("could not open: "),
5124 (def[0] ? def : NULL), filter, openMode, NULL, &openName))
5125 // [HGM] delay to give expose event opportunity to redraw board after browser-dialog popdown before lengthy load starts
5126 ScheduleDelayedEvent(&DelayedLoad, 50);
5133 if (!filenameUp) return;
5134 XtPopdown(fileNameShell);
5135 XtDestroyWidget(fileNameShell);
5141 FileNameCallback (Widget w, XtPointer client_data, XtPointer call_data)
5146 XtSetArg(args[0], XtNlabel, &name);
5147 XtGetValues(w, args, 1);
5149 if (strcmp(name, _("cancel")) == 0) {
5154 FileNameAction(w, NULL, NULL, NULL);
5158 FileNameAction (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5166 name = XawDialogGetValueString(w = XtParent(w));
5168 if ((name != NULL) && (*name != NULLCHAR)) {
5169 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5170 XtPopdown(w = XtParent(XtParent(w)));
5174 p = strrchr(buf, ' ');
5181 fullname = ExpandPathName(buf);
5183 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5186 f = fopen(fullname, fileOpenMode);
5188 DisplayError(_("Failed to open file"), errno);
5190 (void) (*fileProc)(f, index, buf);
5197 XtPopdown(w = XtParent(XtParent(w)));
5207 Widget dialog, layout;
5209 Dimension bw_width, pw_width;
5211 char *PromoChars = "wglcqrbnkac+=\0";
5214 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5215 XtGetValues(boardWidget, args, j);
5218 XtSetArg(args[j], XtNresizable, True); j++;
5219 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5221 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5222 shellWidget, args, j);
5224 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5225 layoutArgs, XtNumber(layoutArgs));
5228 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5229 XtSetArg(args[j], XtNborderWidth, 0); j++;
5230 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5233 if(gameInfo.variant != VariantShogi) {
5234 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5235 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback, PromoChars + 0);
5236 XawDialogAddButton(dialog, _("General"), PromotionCallback, PromoChars + 1);
5237 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback, PromoChars + 2);
5238 XawDialogAddButton(dialog, _("Captain"), PromotionCallback, PromoChars + 3);
5240 XawDialogAddButton(dialog, _("Queen"), PromotionCallback, PromoChars + 4);
5241 XawDialogAddButton(dialog, _("Rook"), PromotionCallback, PromoChars + 5);
5242 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback, PromoChars + 6);
5243 XawDialogAddButton(dialog, _("Knight"), PromotionCallback, PromoChars + 7);
5245 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5246 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
5247 gameInfo.variant == VariantGiveaway) {
5248 XawDialogAddButton(dialog, _("King"), PromotionCallback, PromoChars + 8);
5250 if(gameInfo.variant == VariantCapablanca ||
5251 gameInfo.variant == VariantGothic ||
5252 gameInfo.variant == VariantCapaRandom) {
5253 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback, PromoChars + 9);
5254 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback, PromoChars + 10);
5256 } else // [HGM] shogi
5258 XawDialogAddButton(dialog, _("Promote"), PromotionCallback, PromoChars + 11);
5259 XawDialogAddButton(dialog, _("Defer"), PromotionCallback, PromoChars + 12);
5261 XawDialogAddButton(dialog, _("cancel"), PromotionCallback, PromoChars + 13);
5263 XtRealizeWidget(promotionShell);
5264 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5267 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5268 XtGetValues(promotionShell, args, j);
5270 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5271 lineGap + squareSize/3 +
5272 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5273 0 : 6*(squareSize + lineGap)), &x, &y);
5276 XtSetArg(args[j], XtNx, x); j++;
5277 XtSetArg(args[j], XtNy, y); j++;
5278 XtSetValues(promotionShell, args, j);
5280 XtPopup(promotionShell, XtGrabNone);
5288 if (!promotionUp) return;
5289 XtPopdown(promotionShell);
5290 XtDestroyWidget(promotionShell);
5291 promotionUp = False;
5295 PromotionCallback (Widget w, XtPointer client_data, XtPointer call_data)
5297 int promoChar = * (const char *) client_data;
5301 if (fromX == -1) return;
5308 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5310 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5311 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5317 ErrorCallback (Widget w, XtPointer client_data, XtPointer call_data)
5319 dialogError = errorUp = False;
5320 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5322 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5329 if (!errorUp) return;
5330 dialogError = errorUp = False;
5331 XtPopdown(errorShell);
5332 XtDestroyWidget(errorShell);
5333 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5337 ErrorPopUp (char *title, char *label, int modal)
5340 Widget dialog, layout;
5344 Dimension bw_width, pw_width;
5345 Dimension pw_height;
5349 XtSetArg(args[i], XtNresizable, True); i++;
5350 XtSetArg(args[i], XtNtitle, title); i++;
5352 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5353 shellUp[0] ? (dialogError = modal = TRUE, shells[0]) : shellWidget, args, i);
5355 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5356 layoutArgs, XtNumber(layoutArgs));
5359 XtSetArg(args[i], XtNlabel, label); i++;
5360 XtSetArg(args[i], XtNborderWidth, 0); i++;
5361 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5364 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5366 XtRealizeWidget(errorShell);
5367 CatchDeleteWindow(errorShell, "ErrorPopDown");
5370 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5371 XtGetValues(boardWidget, args, i);
5373 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5374 XtSetArg(args[i], XtNheight, &pw_height); i++;
5375 XtGetValues(errorShell, args, i);
5378 /* This code seems to tickle an X bug if it is executed too soon
5379 after xboard starts up. The coordinates get transformed as if
5380 the main window was positioned at (0, 0).
5382 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5383 0 - pw_height + squareSize / 3, &x, &y);
5385 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5386 RootWindowOfScreen(XtScreen(boardWidget)),
5387 (bw_width - pw_width) / 2,
5388 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5392 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5395 XtSetArg(args[i], XtNx, x); i++;
5396 XtSetArg(args[i], XtNy, y); i++;
5397 XtSetValues(errorShell, args, i);
5400 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5403 /* Disable all user input other than deleting the window */
5404 static int frozen = 0;
5410 /* Grab by a widget that doesn't accept input */
5411 XtAddGrab(messageWidget, TRUE, FALSE);
5415 /* Undo a FreezeUI */
5419 if (!frozen) return;
5420 XtRemoveGrab(messageWidget);
5425 ModeToWidgetName (GameMode mode)
5428 case BeginningOfGame:
5429 if (appData.icsActive)
5430 return "menuMode.ICS Client";
5431 else if (appData.noChessProgram ||
5432 *appData.cmailGameName != NULLCHAR)
5433 return "menuMode.Edit Game";
5435 return "menuMode.Machine Black";
5436 case MachinePlaysBlack:
5437 return "menuMode.Machine Black";
5438 case MachinePlaysWhite:
5439 return "menuMode.Machine White";
5441 return "menuMode.Analysis Mode";
5443 return "menuMode.Analyze File";
5444 case TwoMachinesPlay:
5445 return "menuMode.Two Machines";
5447 return "menuMode.Edit Game";
5448 case PlayFromGameFile:
5449 return "menuFile.Load Game";
5451 return "menuMode.Edit Position";
5453 return "menuMode.Training";
5454 case IcsPlayingWhite:
5455 case IcsPlayingBlack:
5459 return "menuMode.ICS Client";
5470 static int oldPausing = FALSE;
5471 static GameMode oldmode = (GameMode) -1;
5474 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5476 if (pausing != oldPausing) {
5477 oldPausing = pausing;
5479 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5481 XtSetArg(args[0], XtNleftBitmap, None);
5483 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5486 if (appData.showButtonBar) {
5487 /* Always toggle, don't set. Previous code messes up when
5488 invoked while the button is pressed, as releasing it
5489 toggles the state again. */
5492 XtSetArg(args[0], XtNbackground, &oldbg);
5493 XtSetArg(args[1], XtNforeground, &oldfg);
5494 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5496 XtSetArg(args[0], XtNbackground, oldfg);
5497 XtSetArg(args[1], XtNforeground, oldbg);
5499 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5503 wname = ModeToWidgetName(oldmode);
5504 if (wname != NULL) {
5505 XtSetArg(args[0], XtNleftBitmap, None);
5506 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5508 wname = ModeToWidgetName(gameMode);
5509 if (wname != NULL) {
5510 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5511 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5514 XtSetArg(args[0], XtNleftBitmap, matchMode && matchGame < appData.matchGames ? xMarkPixmap : None);
5515 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Machine Match"), args, 1);
5517 /* Maybe all the enables should be handled here, not just this one */
5518 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5519 gameMode == Training || gameMode == PlayFromGameFile);
5524 * Button/menu procedures
5527 ResetProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5533 LoadGamePopUp (FILE *f, int gameNumber, char *title)
5535 cmailMsgLoaded = FALSE;
5536 if (gameNumber == 0) {
5537 int error = GameListBuild(f);
5539 DisplayError(_("Cannot build game list"), error);
5540 } else if (!ListEmpty(&gameList) &&
5541 ((ListGame *) gameList.tailPred)->number > 1) {
5542 GameListPopUp(f, title);
5548 return LoadGame(f, gameNumber, title, FALSE);
5552 LoadGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5554 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5557 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5561 LoadNextGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5567 LoadPrevGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5573 ReloadGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5579 LoadNextPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5585 LoadPrevPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5591 ReloadPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5597 LoadPositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5599 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5602 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5606 SaveGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5608 FileNamePopUp(_("Save game file name?"),
5609 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5610 appData.oldSaveStyle ? ".game" : ".pgn",
5615 SavePositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5617 FileNamePopUp(_("Save position file name?"),
5618 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5619 appData.oldSaveStyle ? ".pos" : ".fen",
5624 ReloadCmailMsgProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5626 ReloadCmailMsgEvent(FALSE);
5630 MailMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5635 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5636 char *selected_fen_position=NULL;
5639 SendPositionSelection (Widget w, Atom *selection, Atom *target,
5640 Atom *type_return, XtPointer *value_return,
5641 unsigned long *length_return, int *format_return)
5643 char *selection_tmp;
5645 if (!selected_fen_position) return False; /* should never happen */
5646 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5647 /* note: since no XtSelectionDoneProc was registered, Xt will
5648 * automatically call XtFree on the value returned. So have to
5649 * make a copy of it allocated with XtMalloc */
5650 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5651 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5653 *value_return=selection_tmp;
5654 *length_return=strlen(selection_tmp);
5655 *type_return=*target;
5656 *format_return = 8; /* bits per byte */
5658 } else if (*target == XA_TARGETS(xDisplay)) {
5659 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5660 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5661 targets_tmp[1] = XA_STRING;
5662 *value_return = targets_tmp;
5663 *type_return = XA_ATOM;
5666 // This code leads to a read of value_return out of bounds on 64-bit systems.
5667 // Other code which I have seen always sets *format_return to 32 independent of
5668 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
5669 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
5670 *format_return = 8 * sizeof(Atom);
5671 if (*format_return > 32) {
5672 *length_return *= *format_return / 32;
5673 *format_return = 32;
5676 *format_return = 32;
5684 /* note: when called from menu all parameters are NULL, so no clue what the
5685 * Widget which was clicked on was, or what the click event was
5688 CopyPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5691 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5692 * have a notion of a position that is selected but not copied.
5693 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5695 if(gameMode == EditPosition) EditPositionDone(TRUE);
5696 if (selected_fen_position) free(selected_fen_position);
5697 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5698 if (!selected_fen_position) return;
5699 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5701 SendPositionSelection,
5702 NULL/* lose_ownership_proc */ ,
5703 NULL/* transfer_done_proc */);
5704 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5706 SendPositionSelection,
5707 NULL/* lose_ownership_proc */ ,
5708 NULL/* transfer_done_proc */);
5712 CopyFENToClipboard ()
5713 { // wrapper to make call from back-end possible
5714 CopyPositionProc(NULL, NULL, NULL, NULL);
5717 /* function called when the data to Paste is ready */
5719 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
5720 Atom *type, XtPointer value, unsigned long *len, int *format)
5723 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5724 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5725 EditPositionPasteFEN(fenstr);
5729 /* called when Paste Position button is pressed,
5730 * all parameters will be NULL */
5731 void PastePositionProc(w, event, prms, nprms)
5737 XtGetSelectionValue(menuBarWidget,
5738 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5739 /* (XtSelectionCallbackProc) */ PastePositionCB,
5740 NULL, /* client_data passed to PastePositionCB */
5742 /* better to use the time field from the event that triggered the
5743 * call to this function, but that isn't trivial to get
5751 SendGameSelection (Widget w, Atom *selection, Atom *target,
5752 Atom *type_return, XtPointer *value_return,
5753 unsigned long *length_return, int *format_return)
5755 char *selection_tmp;
5757 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5758 FILE* f = fopen(gameCopyFilename, "r");
5761 if (f == NULL) return False;
5765 selection_tmp = XtMalloc(len + 1);
5766 count = fread(selection_tmp, 1, len, f);
5769 XtFree(selection_tmp);
5772 selection_tmp[len] = NULLCHAR;
5773 *value_return = selection_tmp;
5774 *length_return = len;
5775 *type_return = *target;
5776 *format_return = 8; /* bits per byte */
5778 } else if (*target == XA_TARGETS(xDisplay)) {
5779 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5780 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5781 targets_tmp[1] = XA_STRING;
5782 *value_return = targets_tmp;
5783 *type_return = XA_ATOM;
5786 // This code leads to a read of value_return out of bounds on 64-bit systems.
5787 // Other code which I have seen always sets *format_return to 32 independent of
5788 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
5789 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
5790 *format_return = 8 * sizeof(Atom);
5791 if (*format_return > 32) {
5792 *length_return *= *format_return / 32;
5793 *format_return = 32;
5796 *format_return = 32;
5808 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5809 * have a notion of a game that is selected but not copied.
5810 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5812 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5815 NULL/* lose_ownership_proc */ ,
5816 NULL/* transfer_done_proc */);
5817 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5820 NULL/* lose_ownership_proc */ ,
5821 NULL/* transfer_done_proc */);
5824 /* note: when called from menu all parameters are NULL, so no clue what the
5825 * Widget which was clicked on was, or what the click event was
5828 CopyGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5832 ret = SaveGameToFile(gameCopyFilename, FALSE);
5839 CopyGameListProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5841 if(!SaveGameListAsText(fopen(gameCopyFilename, "w"))) return;
5845 /* function called when the data to Paste is ready */
5847 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
5848 Atom *type, XtPointer value, unsigned long *len, int *format)
5851 if (value == NULL || *len == 0) {
5852 return; /* nothing had been selected to copy */
5854 f = fopen(gamePasteFilename, "w");
5856 DisplayError(_("Can't open temp file"), errno);
5859 fwrite(value, 1, *len, f);
5862 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5865 /* called when Paste Game button is pressed,
5866 * all parameters will be NULL */
5868 PasteGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5870 XtGetSelectionValue(menuBarWidget,
5871 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5872 /* (XtSelectionCallbackProc) */ PasteGameCB,
5873 NULL, /* client_data passed to PasteGameCB */
5875 /* better to use the time field from the event that triggered the
5876 * call to this function, but that isn't trivial to get
5887 SaveGameProc(NULL, NULL, NULL, NULL);
5892 QuitProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5898 PauseProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5904 MachineBlackProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5906 MachineBlackEvent();
5910 MachineWhiteProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5912 MachineWhiteEvent();
5916 AnalyzeModeProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5920 if (!first.analysisSupport) {
5921 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5922 DisplayError(buf, 0);
5925 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5926 if (appData.icsActive) {
5927 if (gameMode != IcsObserving) {
5928 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5929 DisplayError(buf, 0);
5931 if (appData.icsEngineAnalyze) {
5932 if (appData.debugMode)
5933 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5939 /* if enable, use want disable icsEngineAnalyze */
5940 if (appData.icsEngineAnalyze) {
5945 appData.icsEngineAnalyze = TRUE;
5946 if (appData.debugMode)
5947 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5949 #ifndef OPTIONSDIALOG
5950 if (!appData.showThinking)
5951 ShowThinkingProc(w,event,prms,nprms);
5958 AnalyzeFileProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5960 if (!first.analysisSupport) {
5962 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5963 DisplayError(buf, 0);
5966 // Reset(FALSE, TRUE);
5967 #ifndef OPTIONSDIALOG
5968 if (!appData.showThinking)
5969 ShowThinkingProc(w,event,prms,nprms);
5972 // FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5973 AnalysisPeriodicEvent(1);
5977 TwoMachinesProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5983 MatchProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5989 IcsClientProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5995 EditGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6001 EditPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6003 EditPositionEvent();
6007 TrainingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6013 EditCommentProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6017 if (PopDown(1)) { // popdown succesful
6019 XtSetArg(args[j], XtNleftBitmap, None); j++;
6020 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
6021 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
6022 } else // was not up
6027 IcsInputBoxProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6029 if (!PopDown(4)) ICSInputBoxPopUp();
6033 AcceptProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6039 DeclineProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6045 RematchProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6051 CallFlagProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6057 DrawProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6063 AbortProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6069 AdjournProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6075 ResignProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6081 AdjuWhiteProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6083 UserAdjudicationEvent(+1);
6087 AdjuBlackProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6089 UserAdjudicationEvent(-1);
6093 AdjuDrawProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6095 UserAdjudicationEvent(0);
6099 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6101 if (shellUp[4] == True)
6106 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6107 { // [HGM] input: let up-arrow recall previous line from history
6114 if (!shellUp[4]) return;
6115 edit = boxOptions[0].handle;
6117 XtSetArg(args[j], XtNstring, &val); j++;
6118 XtGetValues(edit, args, j);
6119 val = PrevInHistory(val);
6120 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6121 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6123 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6124 XawTextReplace(edit, 0, 0, &t);
6125 XawTextSetInsertionPoint(edit, 9999);
6130 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6131 { // [HGM] input: let down-arrow recall next line from history
6136 if (!shellUp[4]) return;
6137 edit = boxOptions[0].handle;
6138 val = NextInHistory();
6139 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6140 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6142 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6143 XawTextReplace(edit, 0, 0, &t);
6144 XawTextSetInsertionPoint(edit, 9999);
6149 StopObservingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6151 StopObservingEvent();
6155 StopExaminingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6157 StopExaminingEvent();
6161 UploadProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6168 ForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6175 BackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6181 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6183 if (!TempBackwardActive) {
6184 TempBackwardActive = True;
6190 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6192 /* Check to see if triggered by a key release event for a repeating key.
6193 * If so the next queued event will be a key press of the same key at the same time */
6194 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
6196 XPeekEvent(xDisplay, &next);
6197 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
6198 next.xkey.keycode == event->xkey.keycode)
6202 TempBackwardActive = False;
6206 ToStartProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6212 ToEndProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6218 RevertProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6224 AnnotateProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6230 TruncateGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6232 TruncateGameEvent();
6236 RetractMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6242 MoveNowProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6248 FlipViewProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6250 flipView = !flipView;
6251 DrawPosition(True, NULL);
6255 PonderNextMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6259 PonderNextMoveEvent(!appData.ponderNextMove);
6260 #ifndef OPTIONSDIALOG
6261 if (appData.ponderNextMove) {
6262 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6264 XtSetArg(args[0], XtNleftBitmap, None);
6266 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6271 #ifndef OPTIONSDIALOG
6273 AlwaysQueenProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6277 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6279 if (appData.alwaysPromoteToQueen) {
6280 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6282 XtSetArg(args[0], XtNleftBitmap, None);
6284 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6289 AnimateDraggingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6293 appData.animateDragging = !appData.animateDragging;
6295 if (appData.animateDragging) {
6296 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6299 XtSetArg(args[0], XtNleftBitmap, None);
6301 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6306 AnimateMovingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6310 appData.animate = !appData.animate;
6312 if (appData.animate) {
6313 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6316 XtSetArg(args[0], XtNleftBitmap, None);
6318 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6323 AutoflagProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6327 appData.autoCallFlag = !appData.autoCallFlag;
6329 if (appData.autoCallFlag) {
6330 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6332 XtSetArg(args[0], XtNleftBitmap, None);
6334 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6339 AutoflipProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6343 appData.autoFlipView = !appData.autoFlipView;
6345 if (appData.autoFlipView) {
6346 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6348 XtSetArg(args[0], XtNleftBitmap, None);
6350 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6355 BlindfoldProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6359 appData.blindfold = !appData.blindfold;
6361 if (appData.blindfold) {
6362 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6364 XtSetArg(args[0], XtNleftBitmap, None);
6366 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6369 DrawPosition(True, NULL);
6373 TestLegalityProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6377 appData.testLegality = !appData.testLegality;
6379 if (appData.testLegality) {
6380 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6382 XtSetArg(args[0], XtNleftBitmap, None);
6384 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6390 FlashMovesProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6394 if (appData.flashCount == 0) {
6395 appData.flashCount = 3;
6397 appData.flashCount = -appData.flashCount;
6400 if (appData.flashCount > 0) {
6401 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6403 XtSetArg(args[0], XtNleftBitmap, None);
6405 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6411 HighlightDraggingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6415 appData.highlightDragging = !appData.highlightDragging;
6417 if (appData.highlightDragging) {
6418 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6420 XtSetArg(args[0], XtNleftBitmap, None);
6422 XtSetValues(XtNameToWidget(menuBarWidget,
6423 "menuOptions.Highlight Dragging"), args, 1);
6428 HighlightLastMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6432 appData.highlightLastMove = !appData.highlightLastMove;
6434 if (appData.highlightLastMove) {
6435 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6437 XtSetArg(args[0], XtNleftBitmap, None);
6439 XtSetValues(XtNameToWidget(menuBarWidget,
6440 "menuOptions.Highlight Last Move"), args, 1);
6444 HighlightArrowProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6448 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6450 if (appData.highlightMoveWithArrow) {
6451 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6453 XtSetArg(args[0], XtNleftBitmap, None);
6455 XtSetValues(XtNameToWidget(menuBarWidget,
6456 "menuOptions.Arrow"), args, 1);
6461 IcsAlarmProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6465 appData.icsAlarm = !appData.icsAlarm;
6467 if (appData.icsAlarm) {
6468 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6470 XtSetArg(args[0], XtNleftBitmap, None);
6472 XtSetValues(XtNameToWidget(menuBarWidget,
6473 "menuOptions.ICS Alarm"), args, 1);
6478 MoveSoundProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6482 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6484 if (appData.ringBellAfterMoves) {
6485 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6487 XtSetArg(args[0], XtNleftBitmap, None);
6489 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6494 OneClickProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6498 appData.oneClick = !appData.oneClick;
6500 if (appData.oneClick) {
6501 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6503 XtSetArg(args[0], XtNleftBitmap, None);
6505 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6510 PeriodicUpdatesProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6514 PeriodicUpdatesEvent(!appData.periodicUpdates);
6516 if (appData.periodicUpdates) {
6517 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6519 XtSetArg(args[0], XtNleftBitmap, None);
6521 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6526 PopupExitMessageProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6530 appData.popupExitMessage = !appData.popupExitMessage;
6532 if (appData.popupExitMessage) {
6533 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6535 XtSetArg(args[0], XtNleftBitmap, None);
6537 XtSetValues(XtNameToWidget(menuBarWidget,
6538 "menuOptions.Popup Exit Message"), args, 1);
6542 PopupMoveErrorsProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6546 appData.popupMoveErrors = !appData.popupMoveErrors;
6548 if (appData.popupMoveErrors) {
6549 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6551 XtSetArg(args[0], XtNleftBitmap, None);
6553 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6559 PremoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6563 appData.premove = !appData.premove;
6565 if (appData.premove) {
6566 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6568 XtSetArg(args[0], XtNleftBitmap, None);
6570 XtSetValues(XtNameToWidget(menuBarWidget,
6571 "menuOptions.Premove"), args, 1);
6576 ShowCoordsProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6580 appData.showCoords = !appData.showCoords;
6582 if (appData.showCoords) {
6583 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6585 XtSetArg(args[0], XtNleftBitmap, None);
6587 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6590 DrawPosition(True, NULL);
6594 ShowThinkingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6596 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6597 ShowThinkingEvent();
6601 HideThinkingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6605 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6606 ShowThinkingEvent();
6608 if (appData.hideThinkingFromHuman) {
6609 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6611 XtSetArg(args[0], XtNleftBitmap, None);
6613 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6619 SaveOnExitProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6623 saveSettingsOnExit = !saveSettingsOnExit;
6625 if (saveSettingsOnExit) {
6626 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6628 XtSetArg(args[0], XtNleftBitmap, None);
6630 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6635 SaveSettingsProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6637 SaveSettings(settingsFileName);
6641 InfoProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6644 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6650 ManProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6654 if (nprms && *nprms > 0)
6658 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6663 HintProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6669 BookProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6675 BugReportProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6678 snprintf(buf, MSG_SIZ, "%s mailto:bug-xboard@gnu.org", appData.sysOpen);
6683 GuideProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6686 snprintf(buf, MSG_SIZ, "%s http://www.gnu.org/software/xboard/user_guide/UserGuide.html", appData.sysOpen);
6691 HomePageProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6694 snprintf(buf, MSG_SIZ, "%s http://www.gnu.org/software/xboard/", appData.sysOpen);
6699 NewsPageProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6702 snprintf(buf, MSG_SIZ, "%s http://www.gnu.org/software/xboard/whats_new/portal.html", appData.sysOpen);
6707 AboutProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6709 char buf[2 * MSG_SIZ];
6711 char *zippy = _(" (with Zippy code)");
6715 snprintf(buf, sizeof(buf),
6717 "Copyright 1991 Digital Equipment Corporation\n"
6718 "Enhancements Copyright 1992-2012 Free Software Foundation\n"
6719 "Enhancements Copyright 2005 Alessandro Scotti\n\n"
6720 "%s is free software and carries NO WARRANTY;"
6721 "see the file COPYING for more information.\n\n"
6722 "Visit XBoard on the web at: http://www.gnu.org/software/xboard/\n"
6723 "Check out the newest features at: http://www.gnu.org/software/xboard/whats_new.html\n\n"
6724 "Report bugs via email at: <bug-xboard@gnu.org>\n\n"
6726 programVersion, zippy, PACKAGE);
6727 ErrorPopUp(_("About XBoard"), buf, FALSE);
6731 DebugProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6733 appData.debugMode = !appData.debugMode;
6737 AboutGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6743 NothingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6749 DisplayMessage (char *message, char *extMessage)
6751 /* display a message in the message widget */
6760 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6765 message = extMessage;
6769 safeStrCpy(lastMsg, message, MSG_SIZ); // [HGM] make available
6771 /* need to test if messageWidget already exists, since this function
6772 can also be called during the startup, if for example a Xresource
6773 is not set up correctly */
6776 XtSetArg(arg, XtNlabel, message);
6777 XtSetValues(messageWidget, &arg, 1);
6784 DisplayTitle (char *text)
6788 char title[MSG_SIZ];
6791 if (text == NULL) text = "";
6793 if (appData.titleInWindow) {
6795 XtSetArg(args[i], XtNlabel, text); i++;
6796 XtSetValues(titleWidget, args, i);
6799 if (*text != NULLCHAR) {
6800 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6801 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6802 } else if (appData.icsActive) {
6803 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6804 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6805 } else if (appData.cmailGameName[0] != NULLCHAR) {
6806 snprintf(icon, sizeof(icon), "%s", "CMail");
6807 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6809 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6810 } else if (gameInfo.variant == VariantGothic) {
6811 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6812 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6815 } else if (gameInfo.variant == VariantFalcon) {
6816 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6817 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6819 } else if (appData.noChessProgram) {
6820 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6821 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6823 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6824 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6827 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6828 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6829 XtSetValues(shellWidget, args, i);
6830 XSync(xDisplay, False);
6835 DisplayError (String message, int error)
6840 if (appData.debugMode || appData.matchMode) {
6841 fprintf(stderr, "%s: %s\n", programName, message);
6844 if (appData.debugMode || appData.matchMode) {
6845 fprintf(stderr, "%s: %s: %s\n",
6846 programName, message, strerror(error));
6848 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6851 ErrorPopUp(_("Error"), message, FALSE);
6856 DisplayMoveError (String message)
6860 DrawPosition(FALSE, NULL);
6861 if (appData.debugMode || appData.matchMode) {
6862 fprintf(stderr, "%s: %s\n", programName, message);
6864 if (appData.popupMoveErrors) {
6865 ErrorPopUp(_("Error"), message, FALSE);
6867 DisplayMessage(message, "");
6873 DisplayFatalError (String message, int error, int status)
6877 errorExitStatus = status;
6879 fprintf(stderr, "%s: %s\n", programName, message);
6881 fprintf(stderr, "%s: %s: %s\n",
6882 programName, message, strerror(error));
6883 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6886 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6887 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6894 DisplayInformation (String message)
6897 ErrorPopUp(_("Information"), message, TRUE);
6901 DisplayNote (String message)
6904 ErrorPopUp(_("Note"), message, FALSE);
6908 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
6914 DisplayIcsInteractionTitle (String message)
6916 if (oldICSInteractionTitle == NULL) {
6917 /* Magic to find the old window title, adapted from vim */
6918 char *wina = getenv("WINDOWID");
6920 Window win = (Window) atoi(wina);
6921 Window root, parent, *children;
6922 unsigned int nchildren;
6923 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6925 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6926 if (!XQueryTree(xDisplay, win, &root, &parent,
6927 &children, &nchildren)) break;
6928 if (children) XFree((void *)children);
6929 if (parent == root || parent == 0) break;
6932 XSetErrorHandler(oldHandler);
6934 if (oldICSInteractionTitle == NULL) {
6935 oldICSInteractionTitle = "xterm";
6938 printf("\033]0;%s\007", message);
6942 char pendingReplyPrefix[MSG_SIZ];
6943 ProcRef pendingReplyPR;
6946 AskQuestionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6949 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6953 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6957 AskQuestionPopDown ()
6959 if (!askQuestionUp) return;
6960 XtPopdown(askQuestionShell);
6961 XtDestroyWidget(askQuestionShell);
6962 askQuestionUp = False;
6966 AskQuestionReplyAction (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6972 reply = XawDialogGetValueString(w = XtParent(w));
6973 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
6974 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
6975 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
6976 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
6977 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
6978 AskQuestionPopDown();
6980 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
6984 AskQuestionCallback (Widget w, XtPointer client_data, XtPointer call_data)
6989 XtSetArg(args[0], XtNlabel, &name);
6990 XtGetValues(w, args, 1);
6992 if (strcmp(name, _("cancel")) == 0) {
6993 AskQuestionPopDown();
6995 AskQuestionReplyAction(w, NULL, NULL, NULL);
7000 AskQuestion (char *title, char *question, char *replyPrefix, ProcRef pr)
7003 Widget popup, layout, dialog, edit;
7009 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7010 pendingReplyPR = pr;
7013 XtSetArg(args[i], XtNresizable, True); i++;
7014 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7015 askQuestionShell = popup =
7016 XtCreatePopupShell(title, transientShellWidgetClass,
7017 shellWidget, args, i);
7020 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7021 layoutArgs, XtNumber(layoutArgs));
7024 XtSetArg(args[i], XtNlabel, question); i++;
7025 XtSetArg(args[i], XtNvalue, ""); i++;
7026 XtSetArg(args[i], XtNborderWidth, 0); i++;
7027 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7030 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7031 (XtPointer) dialog);
7032 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7033 (XtPointer) dialog);
7035 XtRealizeWidget(popup);
7036 CatchDeleteWindow(popup, "AskQuestionPopDown");
7038 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7039 &x, &y, &win_x, &win_y, &mask);
7041 XtSetArg(args[0], XtNx, x - 10);
7042 XtSetArg(args[1], XtNy, y - 30);
7043 XtSetValues(popup, args, 2);
7045 XtPopup(popup, XtGrabExclusive);
7046 askQuestionUp = True;
7048 edit = XtNameToWidget(dialog, "*value");
7049 XtSetKeyboardFocus(popup, edit);
7054 PlaySound (char *name)
7056 if (*name == NULLCHAR) {
7058 } else if (strcmp(name, "$") == 0) {
7059 putc(BELLCHAR, stderr);
7062 char *prefix = "", *sep = "";
7063 if(appData.soundProgram[0] == NULLCHAR) return;
7064 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7065 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7073 PlaySound(appData.soundMove);
7079 PlaySound(appData.soundIcsWin);
7085 PlaySound(appData.soundIcsLoss);
7091 PlaySound(appData.soundIcsDraw);
7095 PlayIcsUnfinishedSound ()
7097 PlaySound(appData.soundIcsUnfinished);
7103 PlaySound(appData.soundIcsAlarm);
7109 PlaySound(appData.soundTell);
7115 system("stty echo");
7122 system("stty -echo");
7127 RunCommand (char *buf)
7133 Colorize (ColorClass cc, int continuation)
7136 int count, outCount, error;
7138 if (textColors[(int)cc].bg > 0) {
7139 if (textColors[(int)cc].fg > 0) {
7140 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7141 textColors[(int)cc].fg, textColors[(int)cc].bg);
7143 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7144 textColors[(int)cc].bg);
7147 if (textColors[(int)cc].fg > 0) {
7148 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7149 textColors[(int)cc].fg);
7151 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7154 count = strlen(buf);
7155 outCount = OutputToProcess(NoProc, buf, count, &error);
7156 if (outCount < count) {
7157 DisplayFatalError(_("Error writing to display"), error, 1);
7160 if (continuation) return;
7163 PlaySound(appData.soundShout);
7166 PlaySound(appData.soundSShout);
7169 PlaySound(appData.soundChannel1);
7172 PlaySound(appData.soundChannel);
7175 PlaySound(appData.soundKibitz);
7178 PlaySound(appData.soundTell);
7180 case ColorChallenge:
7181 PlaySound(appData.soundChallenge);
7184 PlaySound(appData.soundRequest);
7187 PlaySound(appData.soundSeek);
7199 return getpwuid(getuid())->pw_name;
7203 ExpandPathName (char *path)
7205 static char static_buf[4*MSG_SIZ];
7206 char *d, *s, buf[4*MSG_SIZ];
7212 while (*s && isspace(*s))
7221 if (*(s+1) == '/') {
7222 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7226 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7227 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7228 pwd = getpwnam(buf);
7231 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7235 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7236 strcat(d, strchr(s+1, '/'));
7240 safeStrCpy(d, s, 4*MSG_SIZ );
7248 static char host_name[MSG_SIZ];
7250 #if HAVE_GETHOSTNAME
7251 gethostname(host_name, MSG_SIZ);
7253 #else /* not HAVE_GETHOSTNAME */
7254 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7255 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7257 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7259 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7260 #endif /* not HAVE_GETHOSTNAME */
7263 XtIntervalId delayedEventTimerXID = 0;
7264 DelayedEventCallback delayedEventCallback = 0;
7269 delayedEventTimerXID = 0;
7270 delayedEventCallback();
7274 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
7276 if(delayedEventTimerXID && delayedEventCallback == cb)
7277 // [HGM] alive: replace, rather than add or flush identical event
7278 XtRemoveTimeOut(delayedEventTimerXID);
7279 delayedEventCallback = cb;
7280 delayedEventTimerXID =
7281 XtAppAddTimeOut(appContext, millisec,
7282 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7285 DelayedEventCallback
7288 if (delayedEventTimerXID) {
7289 return delayedEventCallback;
7296 CancelDelayedEvent ()
7298 if (delayedEventTimerXID) {
7299 XtRemoveTimeOut(delayedEventTimerXID);
7300 delayedEventTimerXID = 0;
7304 XtIntervalId loadGameTimerXID = 0;
7307 LoadGameTimerRunning ()
7309 return loadGameTimerXID != 0;
7313 StopLoadGameTimer ()
7315 if (loadGameTimerXID != 0) {
7316 XtRemoveTimeOut(loadGameTimerXID);
7317 loadGameTimerXID = 0;
7325 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
7327 loadGameTimerXID = 0;
7332 StartLoadGameTimer (long millisec)
7335 XtAppAddTimeOut(appContext, millisec,
7336 (XtTimerCallbackProc) LoadGameTimerCallback,
7340 XtIntervalId analysisClockXID = 0;
7343 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
7345 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7346 || appData.icsEngineAnalyze) { // [DM]
7347 AnalysisPeriodicEvent(0);
7348 StartAnalysisClock();
7353 StartAnalysisClock ()
7356 XtAppAddTimeOut(appContext, 2000,
7357 (XtTimerCallbackProc) AnalysisClockCallback,
7361 XtIntervalId clockTimerXID = 0;
7364 ClockTimerRunning ()
7366 return clockTimerXID != 0;
7372 if (clockTimerXID != 0) {
7373 XtRemoveTimeOut(clockTimerXID);
7382 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
7389 StartClockTimer (long millisec)
7392 XtAppAddTimeOut(appContext, millisec,
7393 (XtTimerCallbackProc) ClockTimerCallback,
7398 DisplayTimerLabel (Widget w, char *color, long timer, int highlight)
7403 /* check for low time warning */
7404 Pixel foregroundOrWarningColor = timerForegroundPixel;
7407 appData.lowTimeWarning &&
7408 (timer / 1000) < appData.icsAlarmTime)
7409 foregroundOrWarningColor = lowTimeWarningColor;
7411 if (appData.clockMode) {
7412 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7413 XtSetArg(args[0], XtNlabel, buf);
7415 snprintf(buf, MSG_SIZ, "%s ", color);
7416 XtSetArg(args[0], XtNlabel, buf);
7421 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7422 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7424 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7425 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7428 XtSetValues(w, args, 3);
7432 DisplayWhiteClock (long timeRemaining, int highlight)
7436 if(appData.noGUI) return;
7437 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7438 if (highlight && iconPixmap == bIconPixmap) {
7439 iconPixmap = wIconPixmap;
7440 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7441 XtSetValues(shellWidget, args, 1);
7446 DisplayBlackClock (long timeRemaining, int highlight)
7450 if(appData.noGUI) return;
7451 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7452 if (highlight && iconPixmap == wIconPixmap) {
7453 iconPixmap = bIconPixmap;
7454 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7455 XtSetValues(shellWidget, args, 1);
7474 StartChildProcess (char *cmdLine, char *dir, ProcRef *pr)
7478 int to_prog[2], from_prog[2];
7482 if (appData.debugMode) {
7483 fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7486 /* We do NOT feed the cmdLine to the shell; we just
7487 parse it into blank-separated arguments in the
7488 most simple-minded way possible.
7491 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7494 while(*p == ' ') p++;
7496 if(*p == '"' || *p == '\'')
7497 p = strchr(++argv[i-1], *p);
7498 else p = strchr(p, ' ');
7499 if (p == NULL) break;
7504 SetUpChildIO(to_prog, from_prog);
7506 if ((pid = fork()) == 0) {
7508 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7509 close(to_prog[1]); // first close the unused pipe ends
7510 close(from_prog[0]);
7511 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7512 dup2(from_prog[1], 1);
7513 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7514 close(from_prog[1]); // and closing again loses one of the pipes!
7515 if(fileno(stderr) >= 2) // better safe than sorry...
7516 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7518 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7523 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7525 execvp(argv[0], argv);
7527 /* If we get here, exec failed */
7532 /* Parent process */
7534 close(from_prog[1]);
7536 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7539 cp->fdFrom = from_prog[0];
7540 cp->fdTo = to_prog[1];
7545 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7547 AlarmCallBack (int n)
7553 DestroyChildProcess (ProcRef pr, int signalType)
7555 ChildProc *cp = (ChildProc *) pr;
7557 if (cp->kind != CPReal) return;
7559 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7560 signal(SIGALRM, AlarmCallBack);
7562 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7563 kill(cp->pid, SIGKILL); // kill it forcefully
7564 wait((int *) 0); // and wait again
7568 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7570 /* Process is exiting either because of the kill or because of
7571 a quit command sent by the backend; either way, wait for it to die.
7580 InterruptChildProcess (ProcRef pr)
7582 ChildProc *cp = (ChildProc *) pr;
7584 if (cp->kind != CPReal) return;
7585 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7589 OpenTelnet (char *host, char *port, ProcRef *pr)
7591 char cmdLine[MSG_SIZ];
7593 if (port[0] == NULLCHAR) {
7594 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7596 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7598 return StartChildProcess(cmdLine, "", pr);
7602 OpenTCP (char *host, char *port, ProcRef *pr)
7605 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7606 #else /* !OMIT_SOCKETS */
7607 struct addrinfo hints;
7608 struct addrinfo *ais, *ai;
7613 memset(&hints, 0, sizeof(hints));
7614 hints.ai_family = AF_UNSPEC;
7615 hints.ai_socktype = SOCK_STREAM;
7617 error = getaddrinfo(host, port, &hints, &ais);
7619 /* a getaddrinfo error is not an errno, so can't return it */
7620 fprintf(debugFP, "getaddrinfo(%s, %s): %s\n",
7621 host, port, gai_strerror(error));
7625 for (ai = ais; ai != NULL; ai = ai->ai_next) {
7626 if ((s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
7630 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
7643 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7649 #endif /* !OMIT_SOCKETS */
7655 OpenCommPort (char *name, ProcRef *pr)
7660 fd = open(name, 2, 0);
7661 if (fd < 0) return errno;
7663 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7674 OpenLoopback (ProcRef *pr)
7679 SetUpChildIO(to, from);
7681 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7684 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7692 OpenRcmd (char *host, char *user, char *cmd, ProcRef *pr)
7694 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7698 #define INPUT_SOURCE_BUF_SIZE 8192
7707 char buf[INPUT_SOURCE_BUF_SIZE];
7712 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
7714 InputSource *is = (InputSource *) closure;
7719 if (is->lineByLine) {
7720 count = read(is->fd, is->unused,
7721 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7723 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7726 is->unused += count;
7728 while (p < is->unused) {
7729 q = memchr(p, '\n', is->unused - p);
7730 if (q == NULL) break;
7732 (is->func)(is, is->closure, p, q - p, 0);
7736 while (p < is->unused) {
7741 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7746 (is->func)(is, is->closure, is->buf, count, error);
7751 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
7754 ChildProc *cp = (ChildProc *) pr;
7756 is = (InputSource *) calloc(1, sizeof(InputSource));
7757 is->lineByLine = lineByLine;
7761 is->fd = fileno(stdin);
7763 is->kind = cp->kind;
7764 is->fd = cp->fdFrom;
7767 is->unused = is->buf;
7770 is->xid = XtAppAddInput(appContext, is->fd,
7771 (XtPointer) (XtInputReadMask),
7772 (XtInputCallbackProc) DoInputCallback,
7774 is->closure = closure;
7775 return (InputSourceRef) is;
7779 RemoveInputSource (InputSourceRef isr)
7781 InputSource *is = (InputSource *) isr;
7783 if (is->xid == 0) return;
7784 XtRemoveInput(is->xid);
7789 OutputToProcess (ProcRef pr, char *message, int count, int *outError)
7791 static int line = 0;
7792 ChildProc *cp = (ChildProc *) pr;
7797 if (appData.noJoin || !appData.useInternalWrap)
7798 outCount = fwrite(message, 1, count, stdout);
7801 int width = get_term_width();
7802 int len = wrap(NULL, message, count, width, &line);
7803 char *msg = malloc(len);
7807 outCount = fwrite(message, 1, count, stdout);
7810 dbgchk = wrap(msg, message, count, width, &line);
7811 if (dbgchk != len && appData.debugMode)
7812 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7813 outCount = fwrite(msg, 1, dbgchk, stdout);
7819 outCount = write(cp->fdTo, message, count);
7829 /* Output message to process, with "ms" milliseconds of delay
7830 between each character. This is needed when sending the logon
7831 script to ICC, which for some reason doesn't like the
7832 instantaneous send. */
7834 OutputToProcessDelayed (ProcRef pr, char *message, int count, int *outError, long msdelay)
7836 ChildProc *cp = (ChildProc *) pr;
7841 r = write(cp->fdTo, message++, 1);
7854 /**** Animation code by Hugh Fisher, DCS, ANU.
7856 Known problem: if a window overlapping the board is
7857 moved away while a piece is being animated underneath,
7858 the newly exposed area won't be updated properly.
7859 I can live with this.
7861 Known problem: if you look carefully at the animation
7862 of pieces in mono mode, they are being drawn as solid
7863 shapes without interior detail while moving. Fixing
7864 this would be a major complication for minimal return.
7867 /* Masks for XPM pieces. Black and white pieces can have
7868 different shapes, but in the interest of retaining my
7869 sanity pieces must have the same outline on both light
7870 and dark squares, and all pieces must use the same
7871 background square colors/images. */
7873 static int xpmDone = 0;
7876 CreateAnimMasks (int pieceDepth)
7882 unsigned long plane;
7885 /* Need a bitmap just to get a GC with right depth */
7886 buf = XCreatePixmap(xDisplay, xBoardWindow,
7888 values.foreground = 1;
7889 values.background = 0;
7890 /* Don't use XtGetGC, not read only */
7891 maskGC = XCreateGC(xDisplay, buf,
7892 GCForeground | GCBackground, &values);
7893 XFreePixmap(xDisplay, buf);
7895 buf = XCreatePixmap(xDisplay, xBoardWindow,
7896 squareSize, squareSize, pieceDepth);
7897 values.foreground = XBlackPixel(xDisplay, xScreen);
7898 values.background = XWhitePixel(xDisplay, xScreen);
7899 bufGC = XCreateGC(xDisplay, buf,
7900 GCForeground | GCBackground, &values);
7902 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7903 /* Begin with empty mask */
7904 if(!xpmDone) // [HGM] pieces: keep using existing
7905 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7906 squareSize, squareSize, 1);
7907 XSetFunction(xDisplay, maskGC, GXclear);
7908 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7909 0, 0, squareSize, squareSize);
7911 /* Take a copy of the piece */
7916 XSetFunction(xDisplay, bufGC, GXcopy);
7917 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7919 0, 0, squareSize, squareSize, 0, 0);
7921 /* XOR the background (light) over the piece */
7922 XSetFunction(xDisplay, bufGC, GXxor);
7924 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7925 0, 0, squareSize, squareSize, 0, 0);
7927 XSetForeground(xDisplay, bufGC, lightSquareColor);
7928 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7931 /* We now have an inverted piece image with the background
7932 erased. Construct mask by just selecting all the non-zero
7933 pixels - no need to reconstruct the original image. */
7934 XSetFunction(xDisplay, maskGC, GXor);
7936 /* Might be quicker to download an XImage and create bitmap
7937 data from it rather than this N copies per piece, but it
7938 only takes a fraction of a second and there is a much
7939 longer delay for loading the pieces. */
7940 for (n = 0; n < pieceDepth; n ++) {
7941 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7942 0, 0, squareSize, squareSize,
7948 XFreePixmap(xDisplay, buf);
7949 XFreeGC(xDisplay, bufGC);
7950 XFreeGC(xDisplay, maskGC);
7954 InitAnimState (AnimState *anim, XWindowAttributes *info)
7959 /* Each buffer is square size, same depth as window */
7960 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
7961 squareSize, squareSize, info->depth);
7962 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
7963 squareSize, squareSize, info->depth);
7965 /* Create a plain GC for blitting */
7966 mask = GCForeground | GCBackground | GCFunction |
7967 GCPlaneMask | GCGraphicsExposures;
7968 values.foreground = XBlackPixel(xDisplay, xScreen);
7969 values.background = XWhitePixel(xDisplay, xScreen);
7970 values.function = GXcopy;
7971 values.plane_mask = AllPlanes;
7972 values.graphics_exposures = False;
7973 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
7975 /* Piece will be copied from an existing context at
7976 the start of each new animation/drag. */
7977 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
7979 /* Outline will be a read-only copy of an existing */
7980 anim->outlineGC = None;
7986 XWindowAttributes info;
7988 if (xpmDone && gameInfo.variant == oldVariant) return;
7989 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
7990 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
7992 InitAnimState(&game, &info);
7993 InitAnimState(&player, &info);
7995 /* For XPM pieces, we need bitmaps to use as masks. */
7997 CreateAnimMasks(info.depth), xpmDone = 1;
8002 static Boolean frameWaiting;
8005 FrameAlarm (int sig)
8007 frameWaiting = False;
8008 /* In case System-V style signals. Needed?? */
8009 signal(SIGALRM, FrameAlarm);
8013 FrameDelay (int time)
8015 struct itimerval delay;
8017 XSync(xDisplay, False);
8020 frameWaiting = True;
8021 signal(SIGALRM, FrameAlarm);
8022 delay.it_interval.tv_sec =
8023 delay.it_value.tv_sec = time / 1000;
8024 delay.it_interval.tv_usec =
8025 delay.it_value.tv_usec = (time % 1000) * 1000;
8026 setitimer(ITIMER_REAL, &delay, NULL);
8027 while (frameWaiting) pause();
8028 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8029 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8030 setitimer(ITIMER_REAL, &delay, NULL);
8037 FrameDelay (int time)
8039 XSync(xDisplay, False);
8041 usleep(time * 1000);
8052 /* Convert board position to corner of screen rect and color */
8055 ScreenSquare (int column, int row, XPoint *pt, int *color)
8058 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8059 pt->y = lineGap + row * (squareSize + lineGap);
8061 pt->x = lineGap + column * (squareSize + lineGap);
8062 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8064 *color = SquareColor(row, column);
8067 /* Convert window coords to square */
8070 BoardSquare (int x, int y, int *column, int *row)
8072 *column = EventToSquare(x, BOARD_WIDTH);
8073 if (flipView && *column >= 0)
8074 *column = BOARD_WIDTH - 1 - *column;
8075 *row = EventToSquare(y, BOARD_HEIGHT);
8076 if (!flipView && *row >= 0)
8077 *row = BOARD_HEIGHT - 1 - *row;
8082 #undef Max /* just in case */
8084 #define Max(a, b) ((a) > (b) ? (a) : (b))
8085 #define Min(a, b) ((a) < (b) ? (a) : (b))
8088 SetRect (XRectangle *rect, int x, int y, int width, int height)
8092 rect->width = width;
8093 rect->height = height;
8096 /* Test if two frames overlap. If they do, return
8097 intersection rect within old and location of
8098 that rect within new. */
8101 Intersect ( XPoint *old, XPoint *new, int size, XRectangle *area, XPoint *pt)
8103 if (old->x > new->x + size || new->x > old->x + size ||
8104 old->y > new->y + size || new->y > old->y + size) {
8107 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8108 size - abs(old->x - new->x), size - abs(old->y - new->y));
8109 pt->x = Max(old->x - new->x, 0);
8110 pt->y = Max(old->y - new->y, 0);
8115 /* For two overlapping frames, return the rect(s)
8116 in the old that do not intersect with the new. */
8119 CalcUpdateRects (XPoint *old, XPoint *new, int size, XRectangle update[], int *nUpdates)
8123 /* If old = new (shouldn't happen) then nothing to draw */
8124 if (old->x == new->x && old->y == new->y) {
8128 /* Work out what bits overlap. Since we know the rects
8129 are the same size we don't need a full intersect calc. */
8131 /* Top or bottom edge? */
8132 if (new->y > old->y) {
8133 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8135 } else if (old->y > new->y) {
8136 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8137 size, old->y - new->y);
8140 /* Left or right edge - don't overlap any update calculated above. */
8141 if (new->x > old->x) {
8142 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8143 new->x - old->x, size - abs(new->y - old->y));
8145 } else if (old->x > new->x) {
8146 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8147 old->x - new->x, size - abs(new->y - old->y));
8154 /* Generate a series of frame coords from start->mid->finish.
8155 The movement rate doubles until the half way point is
8156 reached, then halves back down to the final destination,
8157 which gives a nice slow in/out effect. The algorithmn
8158 may seem to generate too many intermediates for short
8159 moves, but remember that the purpose is to attract the
8160 viewers attention to the piece about to be moved and
8161 then to where it ends up. Too few frames would be less
8165 Tween (XPoint *start, XPoint *mid, XPoint *finish, int factor, XPoint frames[], int *nFrames)
8167 int fraction, n, count;
8171 /* Slow in, stepping 1/16th, then 1/8th, ... */
8173 for (n = 0; n < factor; n++)
8175 for (n = 0; n < factor; n++) {
8176 frames[count].x = start->x + (mid->x - start->x) / fraction;
8177 frames[count].y = start->y + (mid->y - start->y) / fraction;
8179 fraction = fraction / 2;
8183 frames[count] = *mid;
8186 /* Slow out, stepping 1/2, then 1/4, ... */
8188 for (n = 0; n < factor; n++) {
8189 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8190 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8192 fraction = fraction * 2;
8197 /* Draw a piece on the screen without disturbing what's there */
8200 SelectGCMask (ChessSquare piece, GC *clip, GC *outline, Pixmap *mask)
8204 /* Bitmap for piece being moved. */
8205 if (appData.monoMode) {
8206 *mask = *pieceToSolid(piece);
8207 } else if (useImages) {
8209 *mask = xpmMask[piece];
8211 *mask = ximMaskPm[piece];
8214 *mask = *pieceToSolid(piece);
8217 /* GC for piece being moved. Square color doesn't matter, but
8218 since it gets modified we make a copy of the original. */
8220 if (appData.monoMode)
8225 if (appData.monoMode)
8230 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8232 /* Outline only used in mono mode and is not modified */
8234 *outline = bwPieceGC;
8236 *outline = wbPieceGC;
8240 OverlayPiece (ChessSquare piece, GC clip, GC outline, Drawable dest)
8245 /* Draw solid rectangle which will be clipped to shape of piece */
8246 XFillRectangle(xDisplay, dest, clip,
8247 0, 0, squareSize, squareSize);
8248 if (appData.monoMode)
8249 /* Also draw outline in contrasting color for black
8250 on black / white on white cases */
8251 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8252 0, 0, squareSize, squareSize, 0, 0, 1);
8254 /* Copy the piece */
8259 if(appData.upsideDown && flipView) kind ^= 2;
8260 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8262 0, 0, squareSize, squareSize,
8267 /* Animate the movement of a single piece */
8270 BeginAnimation (AnimState *anim, ChessSquare piece, int startColor, XPoint *start)
8274 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8275 /* The old buffer is initialised with the start square (empty) */
8276 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8277 anim->prevFrame = *start;
8279 /* The piece will be drawn using its own bitmap as a matte */
8280 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8281 XSetClipMask(xDisplay, anim->pieceGC, mask);
8285 AnimationFrame (AnimState *anim, XPoint *frame, ChessSquare piece)
8287 XRectangle updates[4];
8292 /* Save what we are about to draw into the new buffer */
8293 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8294 frame->x, frame->y, squareSize, squareSize,
8297 /* Erase bits of the previous frame */
8298 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8299 /* Where the new frame overlapped the previous,
8300 the contents in newBuf are wrong. */
8301 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8302 overlap.x, overlap.y,
8303 overlap.width, overlap.height,
8305 /* Repaint the areas in the old that don't overlap new */
8306 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8307 for (i = 0; i < count; i++)
8308 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8309 updates[i].x - anim->prevFrame.x,
8310 updates[i].y - anim->prevFrame.y,
8311 updates[i].width, updates[i].height,
8312 updates[i].x, updates[i].y);
8314 /* Easy when no overlap */
8315 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8316 0, 0, squareSize, squareSize,
8317 anim->prevFrame.x, anim->prevFrame.y);
8320 /* Save this frame for next time round */
8321 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8322 0, 0, squareSize, squareSize,
8324 anim->prevFrame = *frame;
8326 /* Draw piece over original screen contents, not current,
8327 and copy entire rect. Wipes out overlapping piece images. */
8328 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8329 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8330 0, 0, squareSize, squareSize,
8331 frame->x, frame->y);
8335 EndAnimation (AnimState *anim, XPoint *finish)
8337 XRectangle updates[4];
8342 /* The main code will redraw the final square, so we
8343 only need to erase the bits that don't overlap. */
8344 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8345 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8346 for (i = 0; i < count; i++)
8347 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8348 updates[i].x - anim->prevFrame.x,
8349 updates[i].y - anim->prevFrame.y,
8350 updates[i].width, updates[i].height,
8351 updates[i].x, updates[i].y);
8353 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8354 0, 0, squareSize, squareSize,
8355 anim->prevFrame.x, anim->prevFrame.y);
8360 FrameSequence (AnimState *anim, ChessSquare piece, int startColor, XPoint *start, XPoint *finish, XPoint frames[], int nFrames)
8364 BeginAnimation(anim, piece, startColor, start);
8365 for (n = 0; n < nFrames; n++) {
8366 AnimationFrame(anim, &(frames[n]), piece);
8367 FrameDelay(appData.animSpeed);
8369 EndAnimation(anim, finish);
8373 AnimateAtomicCapture (Board board, int fromX, int fromY, int toX, int toY)
8376 ChessSquare piece = board[fromY][toY];
8377 board[fromY][toY] = EmptySquare;
8378 DrawPosition(FALSE, board);
8380 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8381 y = lineGap + toY * (squareSize + lineGap);
8383 x = lineGap + toX * (squareSize + lineGap);
8384 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8386 for(i=1; i<4*kFactor; i++) {
8387 int r = squareSize * 9 * i/(20*kFactor - 5);
8388 XFillArc(xDisplay, xBoardWindow, highlineGC,
8389 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8390 FrameDelay(appData.animSpeed);
8392 board[fromY][toY] = piece;
8395 /* Main control logic for deciding what to animate and how */
8398 AnimateMove (Board board, int fromX, int fromY, int toX, int toY)
8402 XPoint start, finish, mid;
8403 XPoint frames[kFactor * 2 + 1];
8404 int nFrames, startColor, endColor;
8406 /* Are we animating? */
8407 if (!appData.animate || appData.blindfold)
8410 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8411 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8412 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8414 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8415 piece = board[fromY][fromX];
8416 if (piece >= EmptySquare) return;
8421 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8424 ScreenSquare(fromX, fromY, &start, &startColor);
8425 ScreenSquare(toX, toY, &finish, &endColor);
8428 /* Knight: make straight movement then diagonal */
8429 if (abs(toY - fromY) < abs(toX - fromX)) {
8430 mid.x = start.x + (finish.x - start.x) / 2;
8434 mid.y = start.y + (finish.y - start.y) / 2;
8437 mid.x = start.x + (finish.x - start.x) / 2;
8438 mid.y = start.y + (finish.y - start.y) / 2;
8441 /* Don't use as many frames for very short moves */
8442 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8443 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8445 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8446 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8447 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8449 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8450 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8453 /* Be sure end square is redrawn */
8454 damage[0][toY][toX] = True;
8458 DragPieceBegin (int x, int y, Boolean instantly)
8460 int boardX, boardY, color;
8463 /* Are we animating? */
8464 if (!appData.animateDragging || appData.blindfold)
8467 /* Figure out which square we start in and the
8468 mouse position relative to top left corner. */
8469 BoardSquare(x, y, &boardX, &boardY);
8470 player.startBoardX = boardX;
8471 player.startBoardY = boardY;
8472 ScreenSquare(boardX, boardY, &corner, &color);
8473 player.startSquare = corner;
8474 player.startColor = color;
8475 /* As soon as we start dragging, the piece will jump slightly to
8476 be centered over the mouse pointer. */
8477 player.mouseDelta.x = squareSize/2;
8478 player.mouseDelta.y = squareSize/2;
8479 /* Initialise animation */
8480 player.dragPiece = PieceForSquare(boardX, boardY);
8482 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8483 player.dragActive = True;
8484 BeginAnimation(&player, player.dragPiece, color, &corner);
8485 /* Mark this square as needing to be redrawn. Note that
8486 we don't remove the piece though, since logically (ie
8487 as seen by opponent) the move hasn't been made yet. */
8488 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8489 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8490 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8491 corner.x, corner.y, squareSize, squareSize,
8492 0, 0); // [HGM] zh: unstack in stead of grab
8493 if(gatingPiece != EmptySquare) {
8494 /* Kludge alert: When gating we want the introduced
8495 piece to appear on the from square. To generate an
8496 image of it, we draw it on the board, copy the image,
8497 and draw the original piece again. */
8498 ChessSquare piece = boards[currentMove][boardY][boardX];
8499 DrawSquare(boardY, boardX, gatingPiece, 0);
8500 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8501 corner.x, corner.y, squareSize, squareSize, 0, 0);
8502 DrawSquare(boardY, boardX, piece, 0);
8504 damage[0][boardY][boardX] = True;
8506 player.dragActive = False;
8511 ChangeDragPiece (ChessSquare piece)
8514 player.dragPiece = piece;
8515 /* The piece will be drawn using its own bitmap as a matte */
8516 SelectGCMask(piece, &player.pieceGC, &player.outlineGC, &mask);
8517 XSetClipMask(xDisplay, player.pieceGC, mask);
8521 DragPieceMove (int x, int y)
8525 /* Are we animating? */
8526 if (!appData.animateDragging || appData.blindfold)
8530 if (! player.dragActive)
8532 /* Move piece, maintaining same relative position
8533 of mouse within square */
8534 corner.x = x - player.mouseDelta.x;
8535 corner.y = y - player.mouseDelta.y;
8536 AnimationFrame(&player, &corner, player.dragPiece);
8538 if (appData.highlightDragging) {
8540 BoardSquare(x, y, &boardX, &boardY);
8541 SetHighlights(fromX, fromY, boardX, boardY);
8547 DragPieceEnd (int x, int y)
8549 int boardX, boardY, color;
8552 /* Are we animating? */
8553 if (!appData.animateDragging || appData.blindfold)
8557 if (! player.dragActive)
8559 /* Last frame in sequence is square piece is
8560 placed on, which may not match mouse exactly. */
8561 BoardSquare(x, y, &boardX, &boardY);
8562 ScreenSquare(boardX, boardY, &corner, &color);
8563 EndAnimation(&player, &corner);
8565 /* Be sure end square is redrawn */
8566 damage[0][boardY][boardX] = True;
8568 /* This prevents weird things happening with fast successive
8569 clicks which on my Sun at least can cause motion events
8570 without corresponding press/release. */
8571 player.dragActive = False;
8574 /* Handle expose event while piece being dragged */
8579 if (!player.dragActive || appData.blindfold)
8582 /* What we're doing: logically, the move hasn't been made yet,
8583 so the piece is still in it's original square. But visually
8584 it's being dragged around the board. So we erase the square
8585 that the piece is on and draw it at the last known drag point. */
8586 BlankSquare(player.startSquare.x, player.startSquare.y,
8587 player.startColor, EmptySquare, xBoardWindow, 1);
8588 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8589 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8592 #include <sys/ioctl.h>
8596 int fd, default_width;
8599 default_width = 79; // this is FICS default anyway...
8601 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8603 if (!ioctl(fd, TIOCGSIZE, &win))
8604 default_width = win.ts_cols;
8605 #elif defined(TIOCGWINSZ)
8607 if (!ioctl(fd, TIOCGWINSZ, &win))
8608 default_width = win.ws_col;
8610 return default_width;
8616 static int old_width = 0;
8617 int new_width = get_term_width();
8619 if (old_width != new_width)
8620 ics_printf("set width %d\n", new_width);
8621 old_width = new_width;
8625 NotifyFrontendLogin ()
8630 /* [AS] Arrow highlighting support */
8632 static double A_WIDTH = 5; /* Width of arrow body */
8634 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8635 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8646 return (int) (x + 0.5);
8650 SquareToPos (int rank, int file, int *x, int *y)
8653 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8654 *y = lineGap + rank * (squareSize + lineGap);
8656 *x = lineGap + file * (squareSize + lineGap);
8657 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8661 /* Draw an arrow between two points using current settings */
8663 DrawArrowBetweenPoints (int s_x, int s_y, int d_x, int d_y)
8666 double dx, dy, j, k, x, y;
8669 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8671 arrow[0].x = s_x + A_WIDTH + 0.5;
8674 arrow[1].x = s_x + A_WIDTH + 0.5;
8675 arrow[1].y = d_y - h;
8677 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8678 arrow[2].y = d_y - h;
8683 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8684 arrow[5].y = d_y - h;
8686 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8687 arrow[4].y = d_y - h;
8689 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8692 else if( d_y == s_y ) {
8693 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8696 arrow[0].y = s_y + A_WIDTH + 0.5;
8698 arrow[1].x = d_x - w;
8699 arrow[1].y = s_y + A_WIDTH + 0.5;
8701 arrow[2].x = d_x - w;
8702 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8707 arrow[5].x = d_x - w;
8708 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8710 arrow[4].x = d_x - w;
8711 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8714 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8717 /* [AS] Needed a lot of paper for this! :-) */
8718 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8719 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8721 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8723 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8728 arrow[0].x = Round(x - j);
8729 arrow[0].y = Round(y + j*dx);
8731 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8732 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8735 x = (double) d_x - k;
8736 y = (double) d_y - k*dy;
8739 x = (double) d_x + k;
8740 y = (double) d_y + k*dy;
8743 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8745 arrow[6].x = Round(x - j);
8746 arrow[6].y = Round(y + j*dx);
8748 arrow[2].x = Round(arrow[6].x + 2*j);
8749 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8751 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8752 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8757 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8758 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8761 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8762 if(appData.monoMode) arrow[7] = arrow[0], XDrawLines(xDisplay, xBoardWindow, darkSquareGC, arrow, 8, CoordModeOrigin);
8763 // Polygon( hdc, arrow, 7 );
8767 ArrowDamage (int s_col, int s_row, int d_col, int d_row)
8770 hor = 64*s_col + 32; vert = 64*s_row + 32;
8771 for(i=0; i<= 64; i++) {
8772 damage[0][vert+6>>6][hor+6>>6] = True;
8773 damage[0][vert-6>>6][hor+6>>6] = True;
8774 damage[0][vert+6>>6][hor-6>>6] = True;
8775 damage[0][vert-6>>6][hor-6>>6] = True;
8776 hor += d_col - s_col; vert += d_row - s_row;
8780 /* [AS] Draw an arrow between two squares */
8782 DrawArrowBetweenSquares (int s_col, int s_row, int d_col, int d_row)
8784 int s_x, s_y, d_x, d_y;
8786 if( s_col == d_col && s_row == d_row ) {
8790 /* Get source and destination points */
8791 SquareToPos( s_row, s_col, &s_x, &s_y);
8792 SquareToPos( d_row, d_col, &d_x, &d_y);
8795 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8797 else if( d_y < s_y ) {
8798 d_y += squareSize / 2 + squareSize / 4;
8801 d_y += squareSize / 2;
8805 d_x += squareSize / 2 - squareSize / 4;
8807 else if( d_x < s_x ) {
8808 d_x += squareSize / 2 + squareSize / 4;
8811 d_x += squareSize / 2;
8814 s_x += squareSize / 2;
8815 s_y += squareSize / 2;
8818 A_WIDTH = squareSize / 14.; //[HGM] make float
8820 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
8821 ArrowDamage(s_col, s_row, d_col, d_row);
8825 IsDrawArrowEnabled ()
8827 return appData.highlightMoveWithArrow && squareSize >= 32;
8831 DrawArrowHighlight (int fromX, int fromY, int toX,int toY)
8833 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
8834 DrawArrowBetweenSquares(fromX, fromY, toX, toY);
8838 UpdateLogos (int displ)
8840 return; // no logos in XBoard yet