2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
145 # if HAVE_LIBREADLINE /* add gnu-readline support */
146 #include <readline/readline.h>
147 #include <readline/history.h>
150 #include <X11/Intrinsic.h>
151 #include <X11/StringDefs.h>
152 #include <X11/Shell.h>
153 #include <X11/cursorfont.h>
154 #include <X11/Xatom.h>
155 #include <X11/Xmu/Atoms.h>
157 #include <X11/Xaw3d/Dialog.h>
158 #include <X11/Xaw3d/Form.h>
159 #include <X11/Xaw3d/List.h>
160 #include <X11/Xaw3d/Label.h>
161 #include <X11/Xaw3d/SimpleMenu.h>
162 #include <X11/Xaw3d/SmeBSB.h>
163 #include <X11/Xaw3d/SmeLine.h>
164 #include <X11/Xaw3d/Box.h>
165 #include <X11/Xaw3d/MenuButton.h>
166 #include <X11/Xaw3d/Text.h>
167 #include <X11/Xaw3d/AsciiText.h>
169 #include <X11/Xaw/Dialog.h>
170 #include <X11/Xaw/Form.h>
171 #include <X11/Xaw/List.h>
172 #include <X11/Xaw/Label.h>
173 #include <X11/Xaw/SimpleMenu.h>
174 #include <X11/Xaw/SmeBSB.h>
175 #include <X11/Xaw/SmeLine.h>
176 #include <X11/Xaw/Box.h>
177 #include <X11/Xaw/MenuButton.h>
178 #include <X11/Xaw/Text.h>
179 #include <X11/Xaw/AsciiText.h>
182 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
187 #include "pixmaps/pixmaps.h"
188 #define IMAGE_EXT "xpm"
190 #define IMAGE_EXT "xim"
191 #include "bitmaps/bitmaps.h"
194 #include "bitmaps/icon_white.bm"
195 #include "bitmaps/icon_black.bm"
196 #include "bitmaps/checkmark.bm"
198 #include "frontend.h"
200 #include "backendz.h"
204 #include "xgamelist.h"
205 #include "xhistory.h"
206 #include "xedittags.h"
209 // must be moved to xengineoutput.h
211 void EngineOutputProc P((Widget w, XEvent *event,
212 String *prms, Cardinal *nprms));
213 void EvalGraphProc P((Widget w, XEvent *event,
214 String *prms, Cardinal *nprms));
221 #define usleep(t) _sleep2(((t)+500)/1000)
225 # define _(s) gettext (s)
226 # define N_(s) gettext_noop (s)
242 int main P((int argc, char **argv));
243 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
244 char *init_path, char *mode, int (*show_entry)(), char **name_return));
245 RETSIGTYPE CmailSigHandler P((int sig));
246 RETSIGTYPE IntSigHandler P((int sig));
247 RETSIGTYPE TermSizeSigHandler P((int sig));
248 void CreateGCs P((void));
249 void CreateXIMPieces P((void));
250 void CreateXPMPieces P((void));
251 void CreatePieces P((void));
252 void CreatePieceMenus P((void));
253 Widget CreateMenuBar P((Menu *mb));
254 Widget CreateButtonBar P ((MenuItem *mi));
255 char *FindFont P((char *pattern, int targetPxlSize));
256 void PieceMenuPopup P((Widget w, XEvent *event,
257 String *params, Cardinal *num_params));
258 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
259 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
260 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
261 u_int wreq, u_int hreq));
262 void CreateGrid P((void));
263 int EventToSquare P((int x, int limit));
264 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
265 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
266 void HandleUserMove P((Widget w, XEvent *event,
267 String *prms, Cardinal *nprms));
268 void AnimateUserMove P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void HandlePV P((Widget w, XEvent * event,
271 String * params, Cardinal * nParams));
272 void SelectPV P((Widget w, XEvent * event,
273 String * params, Cardinal * nParams));
274 void StopPV P((Widget w, XEvent * event,
275 String * params, Cardinal * nParams));
276 void WhiteClock P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void BlackClock P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void DrawPositionProc P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
284 void CommentClick P((Widget w, XEvent * event,
285 String * params, Cardinal * nParams));
286 void CommentPopUp P((char *title, char *label));
287 void CommentPopDown P((void));
288 void CommentCallback P((Widget w, XtPointer client_data,
289 XtPointer call_data));
290 void ICSInputBoxPopUp P((void));
291 void ICSInputBoxPopDown P((void));
292 void FileNamePopUp P((char *label, char *def,
293 FileProc proc, char *openMode));
294 void FileNamePopDown P((void));
295 void FileNameCallback P((Widget w, XtPointer client_data,
296 XtPointer call_data));
297 void FileNameAction P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionReplyAction P((Widget w, XEvent *event,
300 String *prms, Cardinal *nprms));
301 void AskQuestionProc P((Widget w, XEvent *event,
302 String *prms, Cardinal *nprms));
303 void AskQuestionPopDown P((void));
304 void PromotionPopDown P((void));
305 void PromotionCallback P((Widget w, XtPointer client_data,
306 XtPointer call_data));
307 void EditCommentPopDown P((void));
308 void EditCommentCallback P((Widget w, XtPointer client_data,
309 XtPointer call_data));
310 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
311 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
312 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
315 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
317 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
319 void LoadPositionProc P((Widget w, XEvent *event,
320 String *prms, Cardinal *nprms));
321 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
323 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
325 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
327 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
329 void PastePositionProc P((Widget w, XEvent *event, String *prms,
331 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void SavePositionProc P((Widget w, XEvent *event,
335 String *prms, Cardinal *nprms));
336 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
337 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
339 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
340 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
343 void MachineWhiteProc P((Widget w, XEvent *event,
344 String *prms, Cardinal *nprms));
345 void AnalyzeModeProc P((Widget w, XEvent *event,
346 String *prms, Cardinal *nprms));
347 void AnalyzeFileProc P((Widget w, XEvent *event,
348 String *prms, Cardinal *nprms));
349 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
351 void IcsClientProc P((Widget w, XEvent *event, String *prms,
353 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void EditPositionProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void EditCommentProc P((Widget w, XEvent *event,
358 String *prms, Cardinal *nprms));
359 void IcsInputBoxProc P((Widget w, XEvent *event,
360 String *prms, Cardinal *nprms));
361 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void StopObservingProc P((Widget w, XEvent *event, String *prms,
377 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
379 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
388 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
390 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
393 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
395 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
397 void AutocommProc P((Widget w, XEvent *event, String *prms,
399 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void AutobsProc P((Widget w, XEvent *event, String *prms,
403 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
408 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
411 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
413 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
415 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
419 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
421 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
423 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
425 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
427 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
431 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
433 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
435 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
437 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void DisplayMove P((int moveNumber));
449 void DisplayTitle P((char *title));
450 void ICSInitScript P((void));
451 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
452 void ErrorPopUp P((char *title, char *text, int modal));
453 void ErrorPopDown P((void));
454 static char *ExpandPathName P((char *path));
455 static void CreateAnimVars P((void));
456 static void DragPieceMove P((int x, int y));
457 static void DrawDragPiece P((void));
458 char *ModeToWidgetName P((GameMode mode));
459 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void GameListOptionsPopDown P(());
468 void ShufflePopDown P(());
469 void EnginePopDown P(());
470 void UciPopDown P(());
471 void TimeControlPopDown P(());
472 void NewVariantPopDown P(());
473 void SettingsPopDown P(());
474 void update_ics_width P(());
475 int get_term_width P(());
476 int CopyMemoProc P(());
478 # if HAVE_LIBREADLINE /* add gnu-readline support */
479 static void ReadlineCompleteHandler P((char *));
483 * XBoard depends on Xt R4 or higher
485 int xtVersion = XtSpecificationRelease;
490 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
491 jailSquareColor, highlightSquareColor, premoveHighlightColor;
492 Pixel lowTimeWarningColor;
493 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
494 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
495 wjPieceGC, bjPieceGC, prelineGC, countGC;
496 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
497 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
498 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
499 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
500 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
501 ICSInputShell, fileNameShell, askQuestionShell;
502 Widget historyShell, evalGraphShell, gameListShell;
503 int hOffset; // [HGM] dual
504 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
505 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
506 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
507 Font clockFontID, coordFontID, countFontID;
508 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
509 XtAppContext appContext;
511 char *oldICSInteractionTitle;
515 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
517 # if HAVE_LIBREADLINE /* gnu readline support */
518 static char* readline_buffer;
519 static int readline_complete=0;
520 extern int sending_ICS_login;
521 extern int sending_ICS_password;
524 Position commentX = -1, commentY = -1;
525 Dimension commentW, commentH;
526 typedef unsigned int BoardSize;
528 Boolean chessProgram;
530 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
531 int squareSize, smallLayout = 0, tinyLayout = 0,
532 marginW, marginH, // [HGM] for run-time resizing
533 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
534 ICSInputBoxUp = False, askQuestionUp = False,
535 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
536 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
537 Pixel timerForegroundPixel, timerBackgroundPixel;
538 Pixel buttonForegroundPixel, buttonBackgroundPixel;
539 char *chessDir, *programName, *programVersion,
540 *gameCopyFilename, *gamePasteFilename;
541 Boolean alwaysOnTop = False;
542 Boolean saveSettingsOnExit;
543 char *settingsFileName;
544 char *icsTextMenuString;
546 char *firstChessProgramNames;
547 char *secondChessProgramNames;
549 WindowPlacement wpMain;
550 WindowPlacement wpConsole;
551 WindowPlacement wpComment;
552 WindowPlacement wpMoveHistory;
553 WindowPlacement wpEvalGraph;
554 WindowPlacement wpEngineOutput;
555 WindowPlacement wpGameList;
556 WindowPlacement wpTags;
560 Pixmap pieceBitmap[2][(int)BlackPawn];
561 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
562 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
563 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
564 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
565 int useImages, useImageSqs;
566 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
567 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
568 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
569 XImage *ximLightSquare, *ximDarkSquare;
572 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
573 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
575 #define White(piece) ((int)(piece) < (int)BlackPawn)
577 /* Variables for doing smooth animation. This whole thing
578 would be much easier if the board was double-buffered,
579 but that would require a fairly major rewrite. */
584 GC blitGC, pieceGC, outlineGC;
585 XPoint startSquare, prevFrame, mouseDelta;
589 int startBoardX, startBoardY;
592 /* There can be two pieces being animated at once: a player
593 can begin dragging a piece before the remote opponent has moved. */
595 static AnimState game, player;
597 /* Bitmaps for use as masks when drawing XPM pieces.
598 Need one for each black and white piece. */
599 static Pixmap xpmMask[BlackKing + 1];
601 /* This magic number is the number of intermediate frames used
602 in each half of the animation. For short moves it's reduced
603 by 1. The total number of frames will be factor * 2 + 1. */
606 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
608 MenuItem fileMenu[] = {
609 {N_("New Game"), ResetProc},
610 {N_("New Shuffle Game ..."), ShuffleMenuProc},
611 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
612 {"----", NothingProc},
613 {N_("Load Game"), LoadGameProc},
614 {N_("Load Next Game"), LoadNextGameProc},
615 {N_("Load Previous Game"), LoadPrevGameProc},
616 {N_("Reload Same Game"), ReloadGameProc},
617 {N_("Save Game"), SaveGameProc},
618 {"----", NothingProc},
619 {N_("Copy Game"), CopyGameProc},
620 {N_("Paste Game"), PasteGameProc},
621 {"----", NothingProc},
622 {N_("Load Position"), LoadPositionProc},
623 {N_("Load Next Position"), LoadNextPositionProc},
624 {N_("Load Previous Position"), LoadPrevPositionProc},
625 {N_("Reload Same Position"), ReloadPositionProc},
626 {N_("Save Position"), SavePositionProc},
627 {"----", NothingProc},
628 {N_("Copy Position"), CopyPositionProc},
629 {N_("Paste Position"), PastePositionProc},
630 {"----", NothingProc},
631 {N_("Mail Move"), MailMoveProc},
632 {N_("Reload CMail Message"), ReloadCmailMsgProc},
633 {"----", NothingProc},
634 {N_("Exit"), QuitProc},
638 MenuItem modeMenu[] = {
639 {N_("Machine White"), MachineWhiteProc},
640 {N_("Machine Black"), MachineBlackProc},
641 {N_("Two Machines"), TwoMachinesProc},
642 {N_("Analysis Mode"), AnalyzeModeProc},
643 {N_("Analyze File"), AnalyzeFileProc },
644 {N_("ICS Client"), IcsClientProc},
645 {N_("Edit Game"), EditGameProc},
646 {N_("Edit Position"), EditPositionProc},
647 {N_("Training"), TrainingProc},
648 {"----", NothingProc},
649 {N_("Show Engine Output"), EngineOutputProc},
650 {N_("Show Evaluation Graph"), EvalGraphProc},
651 {N_("Show Game List"), ShowGameListProc},
652 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
653 {"----", NothingProc},
654 {N_("Edit Tags"), EditTagsProc},
655 {N_("Edit Comment"), EditCommentProc},
656 {N_("ICS Input Box"), IcsInputBoxProc},
657 {N_("Pause"), PauseProc},
661 MenuItem actionMenu[] = {
662 {N_("Accept"), AcceptProc},
663 {N_("Decline"), DeclineProc},
664 {N_("Rematch"), RematchProc},
665 {"----", NothingProc},
666 {N_("Call Flag"), CallFlagProc},
667 {N_("Draw"), DrawProc},
668 {N_("Adjourn"), AdjournProc},
669 {N_("Abort"), AbortProc},
670 {N_("Resign"), ResignProc},
671 {"----", NothingProc},
672 {N_("Stop Observing"), StopObservingProc},
673 {N_("Stop Examining"), StopExaminingProc},
674 {N_("Upload to Examine"), UploadProc},
675 {"----", NothingProc},
676 {N_("Adjudicate to White"), AdjuWhiteProc},
677 {N_("Adjudicate to Black"), AdjuBlackProc},
678 {N_("Adjudicate Draw"), AdjuDrawProc},
682 MenuItem stepMenu[] = {
683 {N_("Backward"), BackwardProc},
684 {N_("Forward"), ForwardProc},
685 {N_("Back to Start"), ToStartProc},
686 {N_("Forward to End"), ToEndProc},
687 {N_("Revert"), RevertProc},
688 {N_("Annotate"), AnnotateProc},
689 {N_("Truncate Game"), TruncateGameProc},
690 {"----", NothingProc},
691 {N_("Move Now"), MoveNowProc},
692 {N_("Retract Move"), RetractMoveProc},
696 MenuItem optionsMenu[] = {
697 {N_("Flip View"), FlipViewProc},
698 {"----", NothingProc},
699 {N_("Adjudications ..."), EngineMenuProc},
700 {N_("General Settings ..."), UciMenuProc},
701 {N_("Engine #1 Settings ..."), FirstSettingsProc},
702 {N_("Engine #2 Settings ..."), SecondSettingsProc},
703 {N_("Time Control ..."), TimeControlProc},
704 {N_("Game List ..."), GameListOptionsPopUp},
705 {"----", NothingProc},
706 {N_("Always Queen"), AlwaysQueenProc},
707 {N_("Animate Dragging"), AnimateDraggingProc},
708 {N_("Animate Moving"), AnimateMovingProc},
709 {N_("Auto Comment"), AutocommProc},
710 {N_("Auto Flag"), AutoflagProc},
711 {N_("Auto Flip View"), AutoflipProc},
712 {N_("Auto Observe"), AutobsProc},
713 {N_("Auto Raise Board"), AutoraiseProc},
714 {N_("Auto Save"), AutosaveProc},
715 {N_("Blindfold"), BlindfoldProc},
716 {N_("Flash Moves"), FlashMovesProc},
717 {N_("Get Move List"), GetMoveListProc},
719 {N_("Highlight Dragging"), HighlightDraggingProc},
721 {N_("Highlight Last Move"), HighlightLastMoveProc},
722 {N_("Move Sound"), MoveSoundProc},
723 {N_("ICS Alarm"), IcsAlarmProc},
724 {N_("Old Save Style"), OldSaveStyleProc},
725 {N_("Periodic Updates"), PeriodicUpdatesProc},
726 {N_("Ponder Next Move"), PonderNextMoveProc},
727 {N_("Popup Exit Message"), PopupExitMessageProc},
728 {N_("Popup Move Errors"), PopupMoveErrorsProc},
729 {N_("Premove"), PremoveProc},
730 {N_("Quiet Play"), QuietPlayProc},
731 {N_("Show Coords"), ShowCoordsProc},
732 {N_("Hide Thinking"), HideThinkingProc},
733 {N_("Test Legality"), TestLegalityProc},
734 {"----", NothingProc},
735 {N_("Save Settings Now"), SaveSettingsProc},
736 {N_("Save Settings on Exit"), SaveOnExitProc},
740 MenuItem helpMenu[] = {
741 {N_("Info XBoard"), InfoProc},
742 {N_("Man XBoard"), ManProc},
743 {"----", NothingProc},
744 {N_("Hint"), HintProc},
745 {N_("Book"), BookProc},
746 {"----", NothingProc},
747 {N_("About XBoard"), AboutProc},
752 {N_("File"), fileMenu},
753 {N_("Mode"), modeMenu},
754 {N_("Action"), actionMenu},
755 {N_("Step"), stepMenu},
756 {N_("Options"), optionsMenu},
757 {N_("Help"), helpMenu},
761 #define PAUSE_BUTTON N_("P")
762 MenuItem buttonBar[] = {
765 {PAUSE_BUTTON, PauseProc},
771 #define PIECE_MENU_SIZE 18
772 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
773 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
774 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
775 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
776 N_("Empty square"), N_("Clear board") },
777 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
778 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
779 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
780 N_("Empty square"), N_("Clear board") }
782 /* must be in same order as PieceMenuStrings! */
783 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
784 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
785 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
786 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
787 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
788 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
789 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
790 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
791 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
794 #define DROP_MENU_SIZE 6
795 String dropMenuStrings[DROP_MENU_SIZE] = {
796 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
798 /* must be in same order as PieceMenuStrings! */
799 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
800 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
801 WhiteRook, WhiteQueen
809 DropMenuEnables dmEnables[] = {
827 { XtNborderWidth, 0 },
828 { XtNdefaultDistance, 0 },
832 { XtNborderWidth, 0 },
833 { XtNresizable, (XtArgVal) True },
837 { XtNborderWidth, 0 },
843 { XtNjustify, (XtArgVal) XtJustifyRight },
844 { XtNlabel, (XtArgVal) "..." },
845 { XtNresizable, (XtArgVal) True },
846 { XtNresize, (XtArgVal) False }
849 Arg messageArgs[] = {
850 { XtNjustify, (XtArgVal) XtJustifyLeft },
851 { XtNlabel, (XtArgVal) "..." },
852 { XtNresizable, (XtArgVal) True },
853 { XtNresize, (XtArgVal) False }
857 { XtNborderWidth, 0 },
858 { XtNjustify, (XtArgVal) XtJustifyLeft }
861 XtResource clientResources[] = {
862 { "flashCount", "flashCount", XtRInt, sizeof(int),
863 XtOffset(AppDataPtr, flashCount), XtRImmediate,
864 (XtPointer) FLASH_COUNT },
867 XrmOptionDescRec shellOptions[] = {
868 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
869 { "-flash", "flashCount", XrmoptionNoArg, "3" },
870 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
873 XtActionsRec boardActions[] = {
874 { "DrawPosition", DrawPositionProc },
875 { "HandleUserMove", HandleUserMove },
876 { "AnimateUserMove", AnimateUserMove },
877 { "HandlePV", HandlePV },
878 { "SelectPV", SelectPV },
879 { "StopPV", StopPV },
880 { "FileNameAction", FileNameAction },
881 { "AskQuestionProc", AskQuestionProc },
882 { "AskQuestionReplyAction", AskQuestionReplyAction },
883 { "PieceMenuPopup", PieceMenuPopup },
884 { "WhiteClock", WhiteClock },
885 { "BlackClock", BlackClock },
886 { "Iconify", Iconify },
887 { "ResetProc", ResetProc },
888 { "NewVariantProc", NewVariantProc },
889 { "LoadGameProc", LoadGameProc },
890 { "LoadNextGameProc", LoadNextGameProc },
891 { "LoadPrevGameProc", LoadPrevGameProc },
892 { "LoadSelectedProc", LoadSelectedProc },
893 { "SetFilterProc", SetFilterProc },
894 { "ReloadGameProc", ReloadGameProc },
895 { "LoadPositionProc", LoadPositionProc },
896 { "LoadNextPositionProc", LoadNextPositionProc },
897 { "LoadPrevPositionProc", LoadPrevPositionProc },
898 { "ReloadPositionProc", ReloadPositionProc },
899 { "CopyPositionProc", CopyPositionProc },
900 { "PastePositionProc", PastePositionProc },
901 { "CopyGameProc", CopyGameProc },
902 { "PasteGameProc", PasteGameProc },
903 { "SaveGameProc", SaveGameProc },
904 { "SavePositionProc", SavePositionProc },
905 { "MailMoveProc", MailMoveProc },
906 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
907 { "QuitProc", QuitProc },
908 { "MachineWhiteProc", MachineWhiteProc },
909 { "MachineBlackProc", MachineBlackProc },
910 { "AnalysisModeProc", AnalyzeModeProc },
911 { "AnalyzeFileProc", AnalyzeFileProc },
912 { "TwoMachinesProc", TwoMachinesProc },
913 { "IcsClientProc", IcsClientProc },
914 { "EditGameProc", EditGameProc },
915 { "EditPositionProc", EditPositionProc },
916 { "TrainingProc", EditPositionProc },
917 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
918 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
919 { "ShowGameListProc", ShowGameListProc },
920 { "ShowMoveListProc", HistoryShowProc},
921 { "EditTagsProc", EditCommentProc },
922 { "EditCommentProc", EditCommentProc },
923 { "IcsAlarmProc", IcsAlarmProc },
924 { "IcsInputBoxProc", IcsInputBoxProc },
925 { "PauseProc", PauseProc },
926 { "AcceptProc", AcceptProc },
927 { "DeclineProc", DeclineProc },
928 { "RematchProc", RematchProc },
929 { "CallFlagProc", CallFlagProc },
930 { "DrawProc", DrawProc },
931 { "AdjournProc", AdjournProc },
932 { "AbortProc", AbortProc },
933 { "ResignProc", ResignProc },
934 { "AdjuWhiteProc", AdjuWhiteProc },
935 { "AdjuBlackProc", AdjuBlackProc },
936 { "AdjuDrawProc", AdjuDrawProc },
937 { "EnterKeyProc", EnterKeyProc },
938 { "UpKeyProc", UpKeyProc },
939 { "DownKeyProc", DownKeyProc },
940 { "StopObservingProc", StopObservingProc },
941 { "StopExaminingProc", StopExaminingProc },
942 { "UploadProc", UploadProc },
943 { "BackwardProc", BackwardProc },
944 { "ForwardProc", ForwardProc },
945 { "ToStartProc", ToStartProc },
946 { "ToEndProc", ToEndProc },
947 { "RevertProc", RevertProc },
948 { "AnnotateProc", AnnotateProc },
949 { "TruncateGameProc", TruncateGameProc },
950 { "MoveNowProc", MoveNowProc },
951 { "RetractMoveProc", RetractMoveProc },
952 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
953 { "UciMenuProc", (XtActionProc) UciMenuProc },
954 { "TimeControlProc", (XtActionProc) TimeControlProc },
955 { "AlwaysQueenProc", AlwaysQueenProc },
956 { "AnimateDraggingProc", AnimateDraggingProc },
957 { "AnimateMovingProc", AnimateMovingProc },
958 { "AutoflagProc", AutoflagProc },
959 { "AutoflipProc", AutoflipProc },
960 { "AutobsProc", AutobsProc },
961 { "AutoraiseProc", AutoraiseProc },
962 { "AutosaveProc", AutosaveProc },
963 { "BlindfoldProc", BlindfoldProc },
964 { "FlashMovesProc", FlashMovesProc },
965 { "FlipViewProc", FlipViewProc },
966 { "GetMoveListProc", GetMoveListProc },
968 { "HighlightDraggingProc", HighlightDraggingProc },
970 { "HighlightLastMoveProc", HighlightLastMoveProc },
971 { "IcsAlarmProc", IcsAlarmProc },
972 { "MoveSoundProc", MoveSoundProc },
973 { "OldSaveStyleProc", OldSaveStyleProc },
974 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
975 { "PonderNextMoveProc", PonderNextMoveProc },
976 { "PopupExitMessageProc", PopupExitMessageProc },
977 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
978 { "PremoveProc", PremoveProc },
979 { "QuietPlayProc", QuietPlayProc },
980 { "ShowCoordsProc", ShowCoordsProc },
981 { "ShowThinkingProc", ShowThinkingProc },
982 { "HideThinkingProc", HideThinkingProc },
983 { "TestLegalityProc", TestLegalityProc },
984 { "SaveSettingsProc", SaveSettingsProc },
985 { "SaveOnExitProc", SaveOnExitProc },
986 { "InfoProc", InfoProc },
987 { "ManProc", ManProc },
988 { "HintProc", HintProc },
989 { "BookProc", BookProc },
990 { "AboutGameProc", AboutGameProc },
991 { "AboutProc", AboutProc },
992 { "DebugProc", DebugProc },
993 { "NothingProc", NothingProc },
994 { "CommentClick", (XtActionProc) CommentClick },
995 { "CommentPopDown", (XtActionProc) CommentPopDown },
996 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
997 { "TagsPopDown", (XtActionProc) TagsPopDown },
998 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
999 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1000 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1001 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1002 { "GameListPopDown", (XtActionProc) GameListPopDown },
1003 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1004 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1005 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1006 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1007 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1008 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1009 { "EnginePopDown", (XtActionProc) EnginePopDown },
1010 { "UciPopDown", (XtActionProc) UciPopDown },
1011 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1012 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1013 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1014 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1017 char globalTranslations[] =
1018 ":<Key>F9: ResignProc() \n \
1019 :Ctrl<Key>n: ResetProc() \n \
1020 :Meta<Key>V: NewVariantProc() \n \
1021 :Ctrl<Key>o: LoadGameProc() \n \
1022 :Meta<Key>Next: LoadNextGameProc() \n \
1023 :Meta<Key>Prior: LoadPrevGameProc() \n \
1024 :Ctrl<Key>s: SaveGameProc() \n \
1025 :Ctrl<Key>c: CopyGameProc() \n \
1026 :Ctrl<Key>v: PasteGameProc() \n \
1027 :Ctrl<Key>O: LoadPositionProc() \n \
1028 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1029 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1030 :Ctrl<Key>S: SavePositionProc() \n \
1031 :Ctrl<Key>C: CopyPositionProc() \n \
1032 :Ctrl<Key>V: PastePositionProc() \n \
1033 :Ctrl<Key>q: QuitProc() \n \
1034 :Ctrl<Key>w: MachineWhiteProc() \n \
1035 :Ctrl<Key>b: MachineBlackProc() \n \
1036 :Ctrl<Key>t: TwoMachinesProc() \n \
1037 :Ctrl<Key>a: AnalysisModeProc() \n \
1038 :Ctrl<Key>f: AnalyzeFileProc() \n \
1039 :Ctrl<Key>e: EditGameProc() \n \
1040 :Ctrl<Key>E: EditPositionProc() \n \
1041 :Meta<Key>O: EngineOutputProc() \n \
1042 :Meta<Key>E: EvalGraphProc() \n \
1043 :Meta<Key>G: ShowGameListProc() \n \
1044 :Meta<Key>H: ShowMoveListProc() \n \
1045 :<Key>Pause: PauseProc() \n \
1046 :<Key>F3: AcceptProc() \n \
1047 :<Key>F4: DeclineProc() \n \
1048 :<Key>F12: RematchProc() \n \
1049 :<Key>F5: CallFlagProc() \n \
1050 :<Key>F6: DrawProc() \n \
1051 :<Key>F7: AdjournProc() \n \
1052 :<Key>F8: AbortProc() \n \
1053 :<Key>F10: StopObservingProc() \n \
1054 :<Key>F11: StopExaminingProc() \n \
1055 :Meta Ctrl<Key>F12: DebugProc() \n \
1056 :Meta<Key>End: ToEndProc() \n \
1057 :Meta<Key>Right: ForwardProc() \n \
1058 :Meta<Key>Home: ToStartProc() \n \
1059 :Meta<Key>Left: BackwardProc() \n \
1060 :Ctrl<Key>m: MoveNowProc() \n \
1061 :Ctrl<Key>x: RetractMoveProc() \n \
1062 :Meta<Key>J: EngineMenuProc() \n \
1063 :Meta<Key>U: UciMenuProc() \n \
1064 :Meta<Key>T: TimeControlProc() \n \
1065 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1066 :Ctrl<Key>F: AutoflagProc() \n \
1067 :Ctrl<Key>A: AnimateMovingProc() \n \
1068 :Ctrl<Key>P: PonderNextMoveProc() \n \
1069 :Ctrl<Key>L: TestLegalityProc() \n \
1070 :Ctrl<Key>H: HideThinkingProc() \n \
1071 :<Key>-: Iconify() \n \
1072 :<Key>F1: ManProc() \n \
1073 :<Key>F2: FlipViewProc() \n \
1074 <KeyDown>.: BackwardProc() \n \
1075 <KeyUp>.: ForwardProc() \n \
1076 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1077 \"Send to chess program:\",,1) \n \
1078 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1079 \"Send to second chess program:\",,2) \n";
1081 char boardTranslations[] =
1082 "<Btn1Down>: HandleUserMove() \n \
1083 <Btn1Up>: HandleUserMove() \n \
1084 <Btn1Motion>: AnimateUserMove() \n \
1085 <Btn3Motion>: HandlePV() \n \
1086 <Btn3Up>: PieceMenuPopup(menuB) \n \
1087 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1088 PieceMenuPopup(menuB) \n \
1089 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1090 PieceMenuPopup(menuW) \n \
1091 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1092 PieceMenuPopup(menuW) \n \
1093 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1094 PieceMenuPopup(menuB) \n";
1096 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1097 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1099 char ICSInputTranslations[] =
1100 "<Key>Up: UpKeyProc() \n "
1101 "<Key>Down: DownKeyProc() \n "
1102 "<Key>Return: EnterKeyProc() \n";
1104 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1105 // as the widget is destroyed before the up-click can call extend-end
1106 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1108 String xboardResources[] = {
1109 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1110 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1111 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1116 /* Max possible square size */
1117 #define MAXSQSIZE 256
1119 static int xpm_avail[MAXSQSIZE];
1121 #ifdef HAVE_DIR_STRUCT
1123 /* Extract piece size from filename */
1125 xpm_getsize(name, len, ext)
1136 if ((p=strchr(name, '.')) == NULL ||
1137 StrCaseCmp(p+1, ext) != 0)
1143 while (*p && isdigit(*p))
1150 /* Setup xpm_avail */
1152 xpm_getavail(dirname, ext)
1160 for (i=0; i<MAXSQSIZE; ++i)
1163 if (appData.debugMode)
1164 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1166 dir = opendir(dirname);
1169 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1170 programName, dirname);
1174 while ((ent=readdir(dir)) != NULL) {
1175 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1176 if (i > 0 && i < MAXSQSIZE)
1186 xpm_print_avail(fp, ext)
1192 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1193 for (i=1; i<MAXSQSIZE; ++i) {
1199 /* Return XPM piecesize closest to size */
1201 xpm_closest_to(dirname, size, ext)
1207 int sm_diff = MAXSQSIZE;
1211 xpm_getavail(dirname, ext);
1213 if (appData.debugMode)
1214 xpm_print_avail(stderr, ext);
1216 for (i=1; i<MAXSQSIZE; ++i) {
1219 diff = (diff<0) ? -diff : diff;
1220 if (diff < sm_diff) {
1228 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1234 #else /* !HAVE_DIR_STRUCT */
1235 /* If we are on a system without a DIR struct, we can't
1236 read the directory, so we can't collect a list of
1237 filenames, etc., so we can't do any size-fitting. */
1239 xpm_closest_to(dirname, size, ext)
1244 fprintf(stderr, _("\
1245 Warning: No DIR structure found on this system --\n\
1246 Unable to autosize for XPM/XIM pieces.\n\
1247 Please report this error to frankm@hiwaay.net.\n\
1248 Include system type & operating system in message.\n"));
1251 #endif /* HAVE_DIR_STRUCT */
1253 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1254 "magenta", "cyan", "white" };
1258 TextColors textColors[(int)NColorClasses];
1260 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1262 parse_color(str, which)
1266 char *p, buf[100], *d;
1269 if (strlen(str) > 99) /* watch bounds on buf */
1274 for (i=0; i<which; ++i) {
1281 /* Could be looking at something like:
1283 .. in which case we want to stop on a comma also */
1284 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1288 return -1; /* Use default for empty field */
1291 if (which == 2 || isdigit(*p))
1294 while (*p && isalpha(*p))
1299 for (i=0; i<8; ++i) {
1300 if (!StrCaseCmp(buf, cnames[i]))
1301 return which? (i+40) : (i+30);
1303 if (!StrCaseCmp(buf, "default")) return -1;
1305 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1310 parse_cpair(cc, str)
1314 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1315 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1320 /* bg and attr are optional */
1321 textColors[(int)cc].bg = parse_color(str, 1);
1322 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1323 textColors[(int)cc].attr = 0;
1329 /* Arrange to catch delete-window events */
1330 Atom wm_delete_window;
1332 CatchDeleteWindow(Widget w, String procname)
1335 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1336 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1337 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1344 XtSetArg(args[0], XtNiconic, False);
1345 XtSetValues(shellWidget, args, 1);
1347 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1350 //---------------------------------------------------------------------------------------------------------
1351 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1354 #define CW_USEDEFAULT (1<<31)
1355 #define ICS_TEXT_MENU_SIZE 90
1356 #define DEBUG_FILE "xboard.debug"
1357 #define SetCurrentDirectory chdir
1358 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1362 // these two must some day move to frontend.h, when they are implemented
1363 Boolean GameListIsUp();
1365 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1368 // front-end part of option handling
1370 // [HGM] This platform-dependent table provides the location for storing the color info
1371 extern char *crWhite, * crBlack;
1375 &appData.whitePieceColor,
1376 &appData.blackPieceColor,
1377 &appData.lightSquareColor,
1378 &appData.darkSquareColor,
1379 &appData.highlightSquareColor,
1380 &appData.premoveHighlightColor,
1381 &appData.lowTimeWarningColor,
1392 // [HGM] font: keep a font for each square size, even non-stndard ones
1393 #define NUM_SIZES 18
1394 #define MAX_SIZE 130
1395 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1396 char *fontTable[NUM_FONTS][MAX_SIZE];
1399 ParseFont(char *name, int number)
1400 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1402 if(sscanf(name, "size%d:", &size)) {
1403 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1404 // defer processing it until we know if it matches our board size
1405 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1406 fontTable[number][size] = strdup(strchr(name, ':')+1);
1407 fontValid[number][size] = True;
1412 case 0: // CLOCK_FONT
1413 appData.clockFont = strdup(name);
1415 case 1: // MESSAGE_FONT
1416 appData.font = strdup(name);
1418 case 2: // COORD_FONT
1419 appData.coordFont = strdup(name);
1424 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1429 { // only 2 fonts currently
1430 appData.clockFont = CLOCK_FONT_NAME;
1431 appData.coordFont = COORD_FONT_NAME;
1432 appData.font = DEFAULT_FONT_NAME;
1437 { // no-op, until we identify the code for this already in XBoard and move it here
1441 ParseColor(int n, char *name)
1442 { // in XBoard, just copy the color-name string
1443 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1447 ParseTextAttribs(ColorClass cc, char *s)
1449 (&appData.colorShout)[cc] = strdup(s);
1453 ParseBoardSize(void *addr, char *name)
1455 appData.boardSize = strdup(name);
1460 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1464 SetCommPortDefaults()
1465 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1468 // [HGM] args: these three cases taken out to stay in front-end
1470 SaveFontArg(FILE *f, ArgDescriptor *ad)
1473 int i, n = (int)ad->argLoc;
1475 case 0: // CLOCK_FONT
1476 name = appData.clockFont;
1478 case 1: // MESSAGE_FONT
1479 name = appData.font;
1481 case 2: // COORD_FONT
1482 name = appData.coordFont;
1487 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1488 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1489 fontTable[n][squareSize] = strdup(name);
1490 fontValid[n][squareSize] = True;
1493 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1494 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1499 { // nothing to do, as the sounds are at all times represented by their text-string names already
1503 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1504 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1505 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1509 SaveColor(FILE *f, ArgDescriptor *ad)
1510 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1511 if(colorVariable[(int)ad->argLoc])
1512 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1516 SaveBoardSize(FILE *f, char *name, void *addr)
1517 { // wrapper to shield back-end from BoardSize & sizeInfo
1518 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1522 ParseCommPortSettings(char *s)
1523 { // no such option in XBoard (yet)
1526 extern Widget engineOutputShell;
1527 extern Widget tagsShell, editTagsShell;
1529 GetActualPlacement(Widget wg, WindowPlacement *wp)
1539 XtSetArg(args[i], XtNx, &x); i++;
1540 XtSetArg(args[i], XtNy, &y); i++;
1541 XtSetArg(args[i], XtNwidth, &w); i++;
1542 XtSetArg(args[i], XtNheight, &h); i++;
1543 XtGetValues(wg, args, i);
1552 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1553 // In XBoard this will have to wait until awareness of window parameters is implemented
1554 GetActualPlacement(shellWidget, &wpMain);
1555 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1556 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1557 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1558 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1559 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1560 else GetActualPlacement(editShell, &wpComment);
1561 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1562 else GetActualPlacement(editTagsShell, &wpTags);
1566 PrintCommPortSettings(FILE *f, char *name)
1567 { // This option does not exist in XBoard
1571 MySearchPath(char *installDir, char *name, char *fullname)
1572 { // just append installDir and name. Perhaps ExpandPath should be used here?
1573 name = ExpandPathName(name);
1574 if(name && name[0] == '/')
1575 safeStrCpy(fullname, name, MSG_SIZ );
1577 sprintf(fullname, "%s%c%s", installDir, '/', name);
1583 MyGetFullPathName(char *name, char *fullname)
1584 { // should use ExpandPath?
1585 name = ExpandPathName(name);
1586 safeStrCpy(fullname, name, MSG_SIZ );
1591 EnsureOnScreen(int *x, int *y, int minX, int minY)
1598 { // [HGM] args: allows testing if main window is realized from back-end
1599 return xBoardWindow != 0;
1603 PopUpStartupDialog()
1604 { // start menu not implemented in XBoard
1608 ConvertToLine(int argc, char **argv)
1610 static char line[128*1024], buf[1024];
1614 for(i=1; i<argc; i++)
1616 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1617 && argv[i][0] != '{' )
1618 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1620 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1621 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1624 line[strlen(line)-1] = NULLCHAR;
1628 //--------------------------------------------------------------------------------------------
1630 extern Boolean twoBoards, partnerUp;
1633 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1635 #define BoardSize int
1636 void InitDrawingSizes(BoardSize boardSize, int flags)
1637 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1638 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1640 XtGeometryResult gres;
1643 if(!formWidget) return;
1646 * Enable shell resizing.
1648 shellArgs[0].value = (XtArgVal) &w;
1649 shellArgs[1].value = (XtArgVal) &h;
1650 XtGetValues(shellWidget, shellArgs, 2);
1652 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1653 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1654 XtSetValues(shellWidget, &shellArgs[2], 4);
1656 XtSetArg(args[0], XtNdefaultDistance, &sep);
1657 XtGetValues(formWidget, args, 1);
1659 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1660 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1662 hOffset = boardWidth + 10;
1663 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1664 secondSegments[i] = gridSegments[i];
1665 secondSegments[i].x1 += hOffset;
1666 secondSegments[i].x2 += hOffset;
1669 XtSetArg(args[0], XtNwidth, boardWidth);
1670 XtSetArg(args[1], XtNheight, boardHeight);
1671 XtSetValues(boardWidget, args, 2);
1673 timerWidth = (boardWidth - sep) / 2;
1674 XtSetArg(args[0], XtNwidth, timerWidth);
1675 XtSetValues(whiteTimerWidget, args, 1);
1676 XtSetValues(blackTimerWidget, args, 1);
1678 XawFormDoLayout(formWidget, False);
1680 if (appData.titleInWindow) {
1682 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1683 XtSetArg(args[i], XtNheight, &h); i++;
1684 XtGetValues(titleWidget, args, i);
1686 w = boardWidth - 2*bor;
1688 XtSetArg(args[0], XtNwidth, &w);
1689 XtGetValues(menuBarWidget, args, 1);
1690 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1693 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1694 if (gres != XtGeometryYes && appData.debugMode) {
1696 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1697 programName, gres, w, h, wr, hr);
1701 XawFormDoLayout(formWidget, True);
1704 * Inhibit shell resizing.
1706 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1707 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1708 shellArgs[4].value = shellArgs[2].value = w;
1709 shellArgs[5].value = shellArgs[3].value = h;
1710 XtSetValues(shellWidget, &shellArgs[0], 6);
1712 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1715 for(i=0; i<4; i++) {
1717 for(p=0; p<=(int)WhiteKing; p++)
1718 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1719 if(gameInfo.variant == VariantShogi) {
1720 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1721 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1722 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1723 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1724 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1727 if(gameInfo.variant == VariantGothic) {
1728 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1732 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1733 for(p=0; p<=(int)WhiteKing; p++)
1734 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1735 if(gameInfo.variant == VariantShogi) {
1736 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1737 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1738 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1739 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1740 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1743 if(gameInfo.variant == VariantGothic) {
1744 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1750 for(i=0; i<2; i++) {
1752 for(p=0; p<=(int)WhiteKing; p++)
1753 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1754 if(gameInfo.variant == VariantShogi) {
1755 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1756 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1757 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1758 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1759 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1762 if(gameInfo.variant == VariantGothic) {
1763 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1779 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1780 XSetWindowAttributes window_attributes;
1782 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1783 XrmValue vFrom, vTo;
1784 XtGeometryResult gres;
1787 int forceMono = False;
1789 srandom(time(0)); // [HGM] book: make random truly random
1791 setbuf(stdout, NULL);
1792 setbuf(stderr, NULL);
1795 # if HAVE_LIBREADLINE
1796 /* install gnu-readline handler */
1797 rl_callback_handler_install("> ", ReadlineCompleteHandler);
1798 rl_readline_name="XBoard";
1801 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1802 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1806 programName = strrchr(argv[0], '/');
1807 if (programName == NULL)
1808 programName = argv[0];
1813 XtSetLanguageProc(NULL, NULL, NULL);
1814 bindtextdomain(PACKAGE, LOCALEDIR);
1815 textdomain(PACKAGE);
1819 XtAppInitialize(&appContext, "XBoard", shellOptions,
1820 XtNumber(shellOptions),
1821 &argc, argv, xboardResources, NULL, 0);
1822 appData.boardSize = "";
1823 InitAppData(ConvertToLine(argc, argv));
1825 if (p == NULL) p = "/tmp";
1826 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1827 gameCopyFilename = (char*) malloc(i);
1828 gamePasteFilename = (char*) malloc(i);
1829 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1830 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1832 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1833 clientResources, XtNumber(clientResources),
1836 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1837 static char buf[MSG_SIZ];
1838 EscapeExpand(buf, appData.initString);
1839 appData.initString = strdup(buf);
1840 EscapeExpand(buf, appData.secondInitString);
1841 appData.secondInitString = strdup(buf);
1842 EscapeExpand(buf, appData.firstComputerString);
1843 appData.firstComputerString = strdup(buf);
1844 EscapeExpand(buf, appData.secondComputerString);
1845 appData.secondComputerString = strdup(buf);
1848 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1851 if (chdir(chessDir) != 0) {
1852 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1858 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1859 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1860 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1861 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1864 setbuf(debugFP, NULL);
1867 /* [HGM,HR] make sure board size is acceptable */
1868 if(appData.NrFiles > BOARD_FILES ||
1869 appData.NrRanks > BOARD_RANKS )
1870 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1873 /* This feature does not work; animation needs a rewrite */
1874 appData.highlightDragging = FALSE;
1878 xDisplay = XtDisplay(shellWidget);
1879 xScreen = DefaultScreen(xDisplay);
1880 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1882 gameInfo.variant = StringToVariant(appData.variant);
1883 InitPosition(FALSE);
1886 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1888 if (isdigit(appData.boardSize[0])) {
1889 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1890 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1891 &fontPxlSize, &smallLayout, &tinyLayout);
1893 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1894 programName, appData.boardSize);
1898 /* Find some defaults; use the nearest known size */
1899 SizeDefaults *szd, *nearest;
1900 int distance = 99999;
1901 nearest = szd = sizeDefaults;
1902 while (szd->name != NULL) {
1903 if (abs(szd->squareSize - squareSize) < distance) {
1905 distance = abs(szd->squareSize - squareSize);
1906 if (distance == 0) break;
1910 if (i < 2) lineGap = nearest->lineGap;
1911 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1912 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1913 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1914 if (i < 6) smallLayout = nearest->smallLayout;
1915 if (i < 7) tinyLayout = nearest->tinyLayout;
1918 SizeDefaults *szd = sizeDefaults;
1919 if (*appData.boardSize == NULLCHAR) {
1920 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1921 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1924 if (szd->name == NULL) szd--;
1925 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1927 while (szd->name != NULL &&
1928 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1929 if (szd->name == NULL) {
1930 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1931 programName, appData.boardSize);
1935 squareSize = szd->squareSize;
1936 lineGap = szd->lineGap;
1937 clockFontPxlSize = szd->clockFontPxlSize;
1938 coordFontPxlSize = szd->coordFontPxlSize;
1939 fontPxlSize = szd->fontPxlSize;
1940 smallLayout = szd->smallLayout;
1941 tinyLayout = szd->tinyLayout;
1942 // [HGM] font: use defaults from settings file if available and not overruled
1944 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1945 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1946 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1947 appData.font = fontTable[MESSAGE_FONT][squareSize];
1948 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1949 appData.coordFont = fontTable[COORD_FONT][squareSize];
1951 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1952 if (strlen(appData.pixmapDirectory) > 0) {
1953 p = ExpandPathName(appData.pixmapDirectory);
1955 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1956 appData.pixmapDirectory);
1959 if (appData.debugMode) {
1960 fprintf(stderr, _("\
1961 XBoard square size (hint): %d\n\
1962 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1964 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1965 if (appData.debugMode) {
1966 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1970 /* [HR] height treated separately (hacked) */
1971 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1972 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1973 if (appData.showJail == 1) {
1974 /* Jail on top and bottom */
1975 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1976 XtSetArg(boardArgs[2], XtNheight,
1977 boardHeight + 2*(lineGap + squareSize));
1978 } else if (appData.showJail == 2) {
1980 XtSetArg(boardArgs[1], XtNwidth,
1981 boardWidth + 2*(lineGap + squareSize));
1982 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1985 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1986 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1990 * Determine what fonts to use.
1992 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1993 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1994 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1995 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1996 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1997 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1998 appData.font = FindFont(appData.font, fontPxlSize);
1999 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2000 countFontStruct = XQueryFont(xDisplay, countFontID);
2001 // appData.font = FindFont(appData.font, fontPxlSize);
2003 xdb = XtDatabase(xDisplay);
2004 XrmPutStringResource(&xdb, "*font", appData.font);
2007 * Detect if there are not enough colors available and adapt.
2009 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2010 appData.monoMode = True;
2013 if (!appData.monoMode) {
2014 vFrom.addr = (caddr_t) appData.lightSquareColor;
2015 vFrom.size = strlen(appData.lightSquareColor);
2016 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2017 if (vTo.addr == NULL) {
2018 appData.monoMode = True;
2021 lightSquareColor = *(Pixel *) vTo.addr;
2024 if (!appData.monoMode) {
2025 vFrom.addr = (caddr_t) appData.darkSquareColor;
2026 vFrom.size = strlen(appData.darkSquareColor);
2027 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2028 if (vTo.addr == NULL) {
2029 appData.monoMode = True;
2032 darkSquareColor = *(Pixel *) vTo.addr;
2035 if (!appData.monoMode) {
2036 vFrom.addr = (caddr_t) appData.whitePieceColor;
2037 vFrom.size = strlen(appData.whitePieceColor);
2038 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2039 if (vTo.addr == NULL) {
2040 appData.monoMode = True;
2043 whitePieceColor = *(Pixel *) vTo.addr;
2046 if (!appData.monoMode) {
2047 vFrom.addr = (caddr_t) appData.blackPieceColor;
2048 vFrom.size = strlen(appData.blackPieceColor);
2049 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2050 if (vTo.addr == NULL) {
2051 appData.monoMode = True;
2054 blackPieceColor = *(Pixel *) vTo.addr;
2058 if (!appData.monoMode) {
2059 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2060 vFrom.size = strlen(appData.highlightSquareColor);
2061 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2062 if (vTo.addr == NULL) {
2063 appData.monoMode = True;
2066 highlightSquareColor = *(Pixel *) vTo.addr;
2070 if (!appData.monoMode) {
2071 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2072 vFrom.size = strlen(appData.premoveHighlightColor);
2073 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2074 if (vTo.addr == NULL) {
2075 appData.monoMode = True;
2078 premoveHighlightColor = *(Pixel *) vTo.addr;
2083 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2086 if (appData.bitmapDirectory == NULL ||
2087 appData.bitmapDirectory[0] == NULLCHAR)
2088 appData.bitmapDirectory = DEF_BITMAP_DIR;
2091 if (appData.lowTimeWarning && !appData.monoMode) {
2092 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2093 vFrom.size = strlen(appData.lowTimeWarningColor);
2094 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2095 if (vTo.addr == NULL)
2096 appData.monoMode = True;
2098 lowTimeWarningColor = *(Pixel *) vTo.addr;
2101 if (appData.monoMode && appData.debugMode) {
2102 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2103 (unsigned long) XWhitePixel(xDisplay, xScreen),
2104 (unsigned long) XBlackPixel(xDisplay, xScreen));
2107 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2108 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2109 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2110 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2111 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2112 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2113 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2114 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2115 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2116 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2118 if (appData.colorize) {
2120 _("%s: can't parse color names; disabling colorization\n"),
2123 appData.colorize = FALSE;
2125 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2126 textColors[ColorNone].attr = 0;
2128 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2134 layoutName = "tinyLayout";
2135 } else if (smallLayout) {
2136 layoutName = "smallLayout";
2138 layoutName = "normalLayout";
2140 /* Outer layoutWidget is there only to provide a name for use in
2141 resources that depend on the layout style */
2143 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2144 layoutArgs, XtNumber(layoutArgs));
2146 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2147 formArgs, XtNumber(formArgs));
2148 XtSetArg(args[0], XtNdefaultDistance, &sep);
2149 XtGetValues(formWidget, args, 1);
2152 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2153 XtSetArg(args[0], XtNtop, XtChainTop);
2154 XtSetArg(args[1], XtNbottom, XtChainTop);
2155 XtSetArg(args[2], XtNright, XtChainLeft);
2156 XtSetValues(menuBarWidget, args, 3);
2158 widgetList[j++] = whiteTimerWidget =
2159 XtCreateWidget("whiteTime", labelWidgetClass,
2160 formWidget, timerArgs, XtNumber(timerArgs));
2161 XtSetArg(args[0], XtNfont, clockFontStruct);
2162 XtSetArg(args[1], XtNtop, XtChainTop);
2163 XtSetArg(args[2], XtNbottom, XtChainTop);
2164 XtSetValues(whiteTimerWidget, args, 3);
2166 widgetList[j++] = blackTimerWidget =
2167 XtCreateWidget("blackTime", labelWidgetClass,
2168 formWidget, timerArgs, XtNumber(timerArgs));
2169 XtSetArg(args[0], XtNfont, clockFontStruct);
2170 XtSetArg(args[1], XtNtop, XtChainTop);
2171 XtSetArg(args[2], XtNbottom, XtChainTop);
2172 XtSetValues(blackTimerWidget, args, 3);
2174 if (appData.titleInWindow) {
2175 widgetList[j++] = titleWidget =
2176 XtCreateWidget("title", labelWidgetClass, formWidget,
2177 titleArgs, XtNumber(titleArgs));
2178 XtSetArg(args[0], XtNtop, XtChainTop);
2179 XtSetArg(args[1], XtNbottom, XtChainTop);
2180 XtSetValues(titleWidget, args, 2);
2183 if (appData.showButtonBar) {
2184 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2185 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2186 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2187 XtSetArg(args[2], XtNtop, XtChainTop);
2188 XtSetArg(args[3], XtNbottom, XtChainTop);
2189 XtSetValues(buttonBarWidget, args, 4);
2192 widgetList[j++] = messageWidget =
2193 XtCreateWidget("message", labelWidgetClass, formWidget,
2194 messageArgs, XtNumber(messageArgs));
2195 XtSetArg(args[0], XtNtop, XtChainTop);
2196 XtSetArg(args[1], XtNbottom, XtChainTop);
2197 XtSetValues(messageWidget, args, 2);
2199 widgetList[j++] = boardWidget =
2200 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2201 XtNumber(boardArgs));
2203 XtManageChildren(widgetList, j);
2205 timerWidth = (boardWidth - sep) / 2;
2206 XtSetArg(args[0], XtNwidth, timerWidth);
2207 XtSetValues(whiteTimerWidget, args, 1);
2208 XtSetValues(blackTimerWidget, args, 1);
2210 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2211 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2212 XtGetValues(whiteTimerWidget, args, 2);
2214 if (appData.showButtonBar) {
2215 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2216 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2217 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2221 * formWidget uses these constraints but they are stored
2225 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2226 XtSetValues(menuBarWidget, args, i);
2227 if (appData.titleInWindow) {
2230 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2231 XtSetValues(whiteTimerWidget, args, i);
2233 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2234 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2235 XtSetValues(blackTimerWidget, args, i);
2237 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2238 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2239 XtSetValues(titleWidget, args, i);
2241 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2242 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2243 XtSetValues(messageWidget, args, i);
2244 if (appData.showButtonBar) {
2246 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2247 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2248 XtSetValues(buttonBarWidget, args, i);
2252 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2253 XtSetValues(whiteTimerWidget, args, i);
2255 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2256 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2257 XtSetValues(blackTimerWidget, args, i);
2259 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2260 XtSetValues(titleWidget, args, i);
2262 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2263 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2264 XtSetValues(messageWidget, args, i);
2265 if (appData.showButtonBar) {
2267 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2268 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2269 XtSetValues(buttonBarWidget, args, i);
2274 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2275 XtSetValues(whiteTimerWidget, args, i);
2277 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2278 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2279 XtSetValues(blackTimerWidget, args, i);
2281 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2282 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2283 XtSetValues(messageWidget, args, i);
2284 if (appData.showButtonBar) {
2286 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2287 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2288 XtSetValues(buttonBarWidget, args, i);
2292 XtSetArg(args[0], XtNfromVert, messageWidget);
2293 XtSetArg(args[1], XtNtop, XtChainTop);
2294 XtSetArg(args[2], XtNbottom, XtChainBottom);
2295 XtSetArg(args[3], XtNleft, XtChainLeft);
2296 XtSetArg(args[4], XtNright, XtChainRight);
2297 XtSetValues(boardWidget, args, 5);
2299 XtRealizeWidget(shellWidget);
2302 XtSetArg(args[0], XtNx, wpMain.x);
2303 XtSetArg(args[1], XtNy, wpMain.y);
2304 XtSetValues(shellWidget, args, 2);
2308 * Correct the width of the message and title widgets.
2309 * It is not known why some systems need the extra fudge term.
2310 * The value "2" is probably larger than needed.
2312 XawFormDoLayout(formWidget, False);
2314 #define WIDTH_FUDGE 2
2316 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2317 XtSetArg(args[i], XtNheight, &h); i++;
2318 XtGetValues(messageWidget, args, i);
2319 if (appData.showButtonBar) {
2321 XtSetArg(args[i], XtNwidth, &w); i++;
2322 XtGetValues(buttonBarWidget, args, i);
2323 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2325 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2328 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2329 if (gres != XtGeometryYes && appData.debugMode) {
2330 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2331 programName, gres, w, h, wr, hr);
2334 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2335 /* The size used for the child widget in layout lags one resize behind
2336 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2338 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2339 if (gres != XtGeometryYes && appData.debugMode) {
2340 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2341 programName, gres, w, h, wr, hr);
2344 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2345 XtSetArg(args[1], XtNright, XtChainRight);
2346 XtSetValues(messageWidget, args, 2);
2348 if (appData.titleInWindow) {
2350 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2351 XtSetArg(args[i], XtNheight, &h); i++;
2352 XtGetValues(titleWidget, args, i);
2354 w = boardWidth - 2*bor;
2356 XtSetArg(args[0], XtNwidth, &w);
2357 XtGetValues(menuBarWidget, args, 1);
2358 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2361 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2362 if (gres != XtGeometryYes && appData.debugMode) {
2364 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2365 programName, gres, w, h, wr, hr);
2368 XawFormDoLayout(formWidget, True);
2370 xBoardWindow = XtWindow(boardWidget);
2372 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2373 // not need to go into InitDrawingSizes().
2377 * Create X checkmark bitmap and initialize option menu checks.
2379 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2380 checkmark_bits, checkmark_width, checkmark_height);
2381 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2382 if (appData.alwaysPromoteToQueen) {
2383 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2386 if (appData.animateDragging) {
2387 XtSetValues(XtNameToWidget(menuBarWidget,
2388 "menuOptions.Animate Dragging"),
2391 if (appData.animate) {
2392 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2395 if (appData.autoComment) {
2396 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2399 if (appData.autoCallFlag) {
2400 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2403 if (appData.autoFlipView) {
2404 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2407 if (appData.autoObserve) {
2408 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2411 if (appData.autoRaiseBoard) {
2412 XtSetValues(XtNameToWidget(menuBarWidget,
2413 "menuOptions.Auto Raise Board"), args, 1);
2415 if (appData.autoSaveGames) {
2416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2419 if (appData.saveGameFile[0] != NULLCHAR) {
2420 /* Can't turn this off from menu */
2421 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2423 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2427 if (appData.blindfold) {
2428 XtSetValues(XtNameToWidget(menuBarWidget,
2429 "menuOptions.Blindfold"), args, 1);
2431 if (appData.flashCount > 0) {
2432 XtSetValues(XtNameToWidget(menuBarWidget,
2433 "menuOptions.Flash Moves"),
2436 if (appData.getMoveList) {
2437 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2441 if (appData.highlightDragging) {
2442 XtSetValues(XtNameToWidget(menuBarWidget,
2443 "menuOptions.Highlight Dragging"),
2447 if (appData.highlightLastMove) {
2448 XtSetValues(XtNameToWidget(menuBarWidget,
2449 "menuOptions.Highlight Last Move"),
2452 if (appData.icsAlarm) {
2453 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2456 if (appData.ringBellAfterMoves) {
2457 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2460 if (appData.oldSaveStyle) {
2461 XtSetValues(XtNameToWidget(menuBarWidget,
2462 "menuOptions.Old Save Style"), args, 1);
2464 if (appData.periodicUpdates) {
2465 XtSetValues(XtNameToWidget(menuBarWidget,
2466 "menuOptions.Periodic Updates"), args, 1);
2468 if (appData.ponderNextMove) {
2469 XtSetValues(XtNameToWidget(menuBarWidget,
2470 "menuOptions.Ponder Next Move"), args, 1);
2472 if (appData.popupExitMessage) {
2473 XtSetValues(XtNameToWidget(menuBarWidget,
2474 "menuOptions.Popup Exit Message"), args, 1);
2476 if (appData.popupMoveErrors) {
2477 XtSetValues(XtNameToWidget(menuBarWidget,
2478 "menuOptions.Popup Move Errors"), args, 1);
2480 if (appData.premove) {
2481 XtSetValues(XtNameToWidget(menuBarWidget,
2482 "menuOptions.Premove"), args, 1);
2484 if (appData.quietPlay) {
2485 XtSetValues(XtNameToWidget(menuBarWidget,
2486 "menuOptions.Quiet Play"), args, 1);
2488 if (appData.showCoords) {
2489 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2492 if (appData.hideThinkingFromHuman) {
2493 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2496 if (appData.testLegality) {
2497 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2500 if (saveSettingsOnExit) {
2501 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2508 ReadBitmap(&wIconPixmap, "icon_white.bm",
2509 icon_white_bits, icon_white_width, icon_white_height);
2510 ReadBitmap(&bIconPixmap, "icon_black.bm",
2511 icon_black_bits, icon_black_width, icon_black_height);
2512 iconPixmap = wIconPixmap;
2514 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2515 XtSetValues(shellWidget, args, i);
2518 * Create a cursor for the board widget.
2520 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2521 XChangeWindowAttributes(xDisplay, xBoardWindow,
2522 CWCursor, &window_attributes);
2525 * Inhibit shell resizing.
2527 shellArgs[0].value = (XtArgVal) &w;
2528 shellArgs[1].value = (XtArgVal) &h;
2529 XtGetValues(shellWidget, shellArgs, 2);
2530 shellArgs[4].value = shellArgs[2].value = w;
2531 shellArgs[5].value = shellArgs[3].value = h;
2532 XtSetValues(shellWidget, &shellArgs[2], 4);
2533 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2534 marginH = h - boardHeight;
2536 CatchDeleteWindow(shellWidget, "QuitProc");
2541 if (appData.bitmapDirectory[0] != NULLCHAR) {
2548 /* Create regular pieces */
2549 if (!useImages) CreatePieces();
2554 if (appData.animate || appData.animateDragging)
2557 XtAugmentTranslations(formWidget,
2558 XtParseTranslationTable(globalTranslations));
2559 XtAugmentTranslations(boardWidget,
2560 XtParseTranslationTable(boardTranslations));
2561 XtAugmentTranslations(whiteTimerWidget,
2562 XtParseTranslationTable(whiteTranslations));
2563 XtAugmentTranslations(blackTimerWidget,
2564 XtParseTranslationTable(blackTranslations));
2566 /* Why is the following needed on some versions of X instead
2567 * of a translation? */
2568 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2569 (XtEventHandler) EventProc, NULL);
2572 /* [AS] Restore layout */
2573 if( wpMoveHistory.visible ) {
2577 if( wpEvalGraph.visible )
2582 if( wpEngineOutput.visible ) {
2583 EngineOutputPopUp();
2588 if (errorExitStatus == -1) {
2589 if (appData.icsActive) {
2590 /* We now wait until we see "login:" from the ICS before
2591 sending the logon script (problems with timestamp otherwise) */
2592 /*ICSInitScript();*/
2593 if (appData.icsInputBox) ICSInputBoxPopUp();
2597 signal(SIGWINCH, TermSizeSigHandler);
2599 signal(SIGINT, IntSigHandler);
2600 signal(SIGTERM, IntSigHandler);
2601 if (*appData.cmailGameName != NULLCHAR) {
2602 signal(SIGUSR1, CmailSigHandler);
2605 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2607 XtSetKeyboardFocus(shellWidget, formWidget);
2609 XtAppMainLoop(appContext);
2610 if (appData.debugMode) fclose(debugFP); // [DM] debug
2617 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2618 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2620 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2621 unlink(gameCopyFilename);
2622 unlink(gamePasteFilename);
2624 # if HAVE_LIBREADLINE
2625 /* remove gnu-readline handler. */
2626 rl_callback_handler_remove();
2632 RETSIGTYPE TermSizeSigHandler(int sig)
2645 CmailSigHandler(sig)
2651 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2653 /* Activate call-back function CmailSigHandlerCallBack() */
2654 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2656 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2660 CmailSigHandlerCallBack(isr, closure, message, count, error)
2668 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2670 /**** end signal code ****/
2676 /* try to open the icsLogon script, either in the location given
2677 * or in the users HOME directory
2684 f = fopen(appData.icsLogon, "r");
2687 homedir = getenv("HOME");
2688 if (homedir != NULL)
2690 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2691 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2692 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2693 f = fopen(buf, "r");
2698 ProcessICSInitScript(f);
2700 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2709 EditCommentPopDown();
2724 if (!menuBarWidget) return;
2725 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2727 DisplayError("menuStep.Revert", 0);
2729 XtSetSensitive(w, !grey);
2731 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2733 DisplayError("menuStep.Annotate", 0);
2735 XtSetSensitive(w, !grey);
2740 SetMenuEnables(enab)
2744 if (!menuBarWidget) return;
2745 while (enab->name != NULL) {
2746 w = XtNameToWidget(menuBarWidget, enab->name);
2748 DisplayError(enab->name, 0);
2750 XtSetSensitive(w, enab->value);
2756 Enables icsEnables[] = {
2757 { "menuFile.Mail Move", False },
2758 { "menuFile.Reload CMail Message", False },
2759 { "menuMode.Machine Black", False },
2760 { "menuMode.Machine White", False },
2761 { "menuMode.Analysis Mode", False },
2762 { "menuMode.Analyze File", False },
2763 { "menuMode.Two Machines", False },
2765 { "menuHelp.Hint", False },
2766 { "menuHelp.Book", False },
2767 { "menuStep.Move Now", False },
2768 { "menuOptions.Periodic Updates", False },
2769 { "menuOptions.Hide Thinking", False },
2770 { "menuOptions.Ponder Next Move", False },
2772 { "menuStep.Annotate", False },
2776 Enables ncpEnables[] = {
2777 { "menuFile.Mail Move", False },
2778 { "menuFile.Reload CMail Message", False },
2779 { "menuMode.Machine White", False },
2780 { "menuMode.Machine Black", False },
2781 { "menuMode.Analysis Mode", False },
2782 { "menuMode.Analyze File", False },
2783 { "menuMode.Two Machines", False },
2784 { "menuMode.ICS Client", False },
2785 { "menuMode.ICS Input Box", False },
2786 { "Action", False },
2787 { "menuStep.Revert", False },
2788 { "menuStep.Annotate", False },
2789 { "menuStep.Move Now", False },
2790 { "menuStep.Retract Move", False },
2791 { "menuOptions.Auto Comment", False },
2792 { "menuOptions.Auto Flag", False },
2793 { "menuOptions.Auto Flip View", False },
2794 { "menuOptions.Auto Observe", False },
2795 { "menuOptions.Auto Raise Board", False },
2796 { "menuOptions.Get Move List", False },
2797 { "menuOptions.ICS Alarm", False },
2798 { "menuOptions.Move Sound", False },
2799 { "menuOptions.Quiet Play", False },
2800 { "menuOptions.Hide Thinking", False },
2801 { "menuOptions.Periodic Updates", False },
2802 { "menuOptions.Ponder Next Move", False },
2803 { "menuHelp.Hint", False },
2804 { "menuHelp.Book", False },
2808 Enables gnuEnables[] = {
2809 { "menuMode.ICS Client", False },
2810 { "menuMode.ICS Input Box", False },
2811 { "menuAction.Accept", False },
2812 { "menuAction.Decline", False },
2813 { "menuAction.Rematch", False },
2814 { "menuAction.Adjourn", False },
2815 { "menuAction.Stop Examining", False },
2816 { "menuAction.Stop Observing", False },
2817 { "menuAction.Upload to Examine", False },
2818 { "menuStep.Revert", False },
2819 { "menuStep.Annotate", False },
2820 { "menuOptions.Auto Comment", False },
2821 { "menuOptions.Auto Observe", False },
2822 { "menuOptions.Auto Raise Board", False },
2823 { "menuOptions.Get Move List", False },
2824 { "menuOptions.Premove", False },
2825 { "menuOptions.Quiet Play", False },
2827 /* The next two options rely on SetCmailMode being called *after* */
2828 /* SetGNUMode so that when GNU is being used to give hints these */
2829 /* menu options are still available */
2831 { "menuFile.Mail Move", False },
2832 { "menuFile.Reload CMail Message", False },
2836 Enables cmailEnables[] = {
2838 { "menuAction.Call Flag", False },
2839 { "menuAction.Draw", True },
2840 { "menuAction.Adjourn", False },
2841 { "menuAction.Abort", False },
2842 { "menuAction.Stop Observing", False },
2843 { "menuAction.Stop Examining", False },
2844 { "menuFile.Mail Move", True },
2845 { "menuFile.Reload CMail Message", True },
2849 Enables trainingOnEnables[] = {
2850 { "menuMode.Edit Comment", False },
2851 { "menuMode.Pause", False },
2852 { "menuStep.Forward", False },
2853 { "menuStep.Backward", False },
2854 { "menuStep.Forward to End", False },
2855 { "menuStep.Back to Start", False },
2856 { "menuStep.Move Now", False },
2857 { "menuStep.Truncate Game", False },
2861 Enables trainingOffEnables[] = {
2862 { "menuMode.Edit Comment", True },
2863 { "menuMode.Pause", True },
2864 { "menuStep.Forward", True },
2865 { "menuStep.Backward", True },
2866 { "menuStep.Forward to End", True },
2867 { "menuStep.Back to Start", True },
2868 { "menuStep.Move Now", True },
2869 { "menuStep.Truncate Game", True },
2873 Enables machineThinkingEnables[] = {
2874 { "menuFile.Load Game", False },
2875 { "menuFile.Load Next Game", False },
2876 { "menuFile.Load Previous Game", False },
2877 { "menuFile.Reload Same Game", False },
2878 { "menuFile.Paste Game", False },
2879 { "menuFile.Load Position", False },
2880 { "menuFile.Load Next Position", False },
2881 { "menuFile.Load Previous Position", False },
2882 { "menuFile.Reload Same Position", False },
2883 { "menuFile.Paste Position", False },
2884 { "menuMode.Machine White", False },
2885 { "menuMode.Machine Black", False },
2886 { "menuMode.Two Machines", False },
2887 { "menuStep.Retract Move", False },
2891 Enables userThinkingEnables[] = {
2892 { "menuFile.Load Game", True },
2893 { "menuFile.Load Next Game", True },
2894 { "menuFile.Load Previous Game", True },
2895 { "menuFile.Reload Same Game", True },
2896 { "menuFile.Paste Game", True },
2897 { "menuFile.Load Position", True },
2898 { "menuFile.Load Next Position", True },
2899 { "menuFile.Load Previous Position", True },
2900 { "menuFile.Reload Same Position", True },
2901 { "menuFile.Paste Position", True },
2902 { "menuMode.Machine White", True },
2903 { "menuMode.Machine Black", True },
2904 { "menuMode.Two Machines", True },
2905 { "menuStep.Retract Move", True },
2911 SetMenuEnables(icsEnables);
2914 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2915 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2922 SetMenuEnables(ncpEnables);
2928 SetMenuEnables(gnuEnables);
2934 SetMenuEnables(cmailEnables);
2940 SetMenuEnables(trainingOnEnables);
2941 if (appData.showButtonBar) {
2942 XtSetSensitive(buttonBarWidget, False);
2948 SetTrainingModeOff()
2950 SetMenuEnables(trainingOffEnables);
2951 if (appData.showButtonBar) {
2952 XtSetSensitive(buttonBarWidget, True);
2957 SetUserThinkingEnables()
2959 if (appData.noChessProgram) return;
2960 SetMenuEnables(userThinkingEnables);
2964 SetMachineThinkingEnables()
2966 if (appData.noChessProgram) return;
2967 SetMenuEnables(machineThinkingEnables);
2969 case MachinePlaysBlack:
2970 case MachinePlaysWhite:
2971 case TwoMachinesPlay:
2972 XtSetSensitive(XtNameToWidget(menuBarWidget,
2973 ModeToWidgetName(gameMode)), True);
2980 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2981 #define HISTORY_SIZE 64
\r
2982 static char *history[HISTORY_SIZE];
\r
2983 int histIn = 0, histP = 0;
\r
2986 SaveInHistory(char *cmd)
\r
2988 if (history[histIn] != NULL) {
\r
2989 free(history[histIn]);
\r
2990 history[histIn] = NULL;
\r
2992 if (*cmd == NULLCHAR) return;
\r
2993 history[histIn] = StrSave(cmd);
\r
2994 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2995 if (history[histIn] != NULL) {
\r
2996 free(history[histIn]);
\r
2997 history[histIn] = NULL;
\r
3003 PrevInHistory(char *cmd)
\r
3006 if (histP == histIn) {
\r
3007 if (history[histIn] != NULL) free(history[histIn]);
\r
3008 history[histIn] = StrSave(cmd);
\r
3010 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
3011 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3013 return history[histP];
\r
3019 if (histP == histIn) return NULL;
\r
3020 histP = (histP + 1) % HISTORY_SIZE;
\r
3021 return history[histP];
\r
3023 // end of borrowed code
\r
3025 #define Abs(n) ((n)<0 ? -(n) : (n))
3028 * Find a font that matches "pattern" that is as close as
3029 * possible to the targetPxlSize. Prefer fonts that are k
3030 * pixels smaller to fonts that are k pixels larger. The
3031 * pattern must be in the X Consortium standard format,
3032 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3033 * The return value should be freed with XtFree when no
3037 FindFont(pattern, targetPxlSize)
3041 char **fonts, *p, *best, *scalable, *scalableTail;
3042 int i, j, nfonts, minerr, err, pxlSize;
3045 char **missing_list;
3047 char *def_string, *base_fnt_lst, strInt[3];
3049 XFontStruct **fnt_list;
3051 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3052 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3053 p = strstr(pattern, "--");
3054 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3055 strcat(base_fnt_lst, strInt);
3056 strcat(base_fnt_lst, strchr(p + 2, '-'));
3058 if ((fntSet = XCreateFontSet(xDisplay,
3062 &def_string)) == NULL) {
3064 fprintf(stderr, _("Unable to create font set.\n"));
3068 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3070 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3072 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3073 programName, pattern);
3081 for (i=0; i<nfonts; i++) {
3084 if (*p != '-') continue;
3086 if (*p == NULLCHAR) break;
3087 if (*p++ == '-') j++;
3089 if (j < 7) continue;
3092 scalable = fonts[i];
3095 err = pxlSize - targetPxlSize;
3096 if (Abs(err) < Abs(minerr) ||
3097 (minerr > 0 && err < 0 && -err == minerr)) {
3103 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3104 /* If the error is too big and there is a scalable font,
3105 use the scalable font. */
3106 int headlen = scalableTail - scalable;
3107 p = (char *) XtMalloc(strlen(scalable) + 10);
3108 while (isdigit(*scalableTail)) scalableTail++;
3109 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3111 p = (char *) XtMalloc(strlen(best) + 2);
3112 safeStrCpy(p, best, strlen(best)+1 );
3114 if (appData.debugMode) {
3115 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3116 pattern, targetPxlSize, p);
3119 if (missing_count > 0)
3120 XFreeStringList(missing_list);
3121 XFreeFontSet(xDisplay, fntSet);
3123 XFreeFontNames(fonts);
3130 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3131 | GCBackground | GCFunction | GCPlaneMask;
3132 XGCValues gc_values;
3135 gc_values.plane_mask = AllPlanes;
3136 gc_values.line_width = lineGap;
3137 gc_values.line_style = LineSolid;
3138 gc_values.function = GXcopy;
3140 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3141 gc_values.background = XBlackPixel(xDisplay, xScreen);
3142 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3144 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3145 gc_values.background = XWhitePixel(xDisplay, xScreen);
3146 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3147 XSetFont(xDisplay, coordGC, coordFontID);
3149 // [HGM] make font for holdings counts (white on black0
3150 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3151 gc_values.background = XBlackPixel(xDisplay, xScreen);
3152 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3153 XSetFont(xDisplay, countGC, countFontID);
3155 if (appData.monoMode) {
3156 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3157 gc_values.background = XWhitePixel(xDisplay, xScreen);
3158 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3160 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3161 gc_values.background = XBlackPixel(xDisplay, xScreen);
3162 lightSquareGC = wbPieceGC
3163 = XtGetGC(shellWidget, value_mask, &gc_values);
3165 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3166 gc_values.background = XWhitePixel(xDisplay, xScreen);
3167 darkSquareGC = bwPieceGC
3168 = XtGetGC(shellWidget, value_mask, &gc_values);
3170 if (DefaultDepth(xDisplay, xScreen) == 1) {
3171 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3172 gc_values.function = GXcopyInverted;
3173 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3174 gc_values.function = GXcopy;
3175 if (XBlackPixel(xDisplay, xScreen) == 1) {
3176 bwPieceGC = darkSquareGC;
3177 wbPieceGC = copyInvertedGC;
3179 bwPieceGC = copyInvertedGC;
3180 wbPieceGC = lightSquareGC;
3184 gc_values.foreground = highlightSquareColor;
3185 gc_values.background = highlightSquareColor;
3186 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3188 gc_values.foreground = premoveHighlightColor;
3189 gc_values.background = premoveHighlightColor;
3190 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3192 gc_values.foreground = lightSquareColor;
3193 gc_values.background = darkSquareColor;
3194 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3196 gc_values.foreground = darkSquareColor;
3197 gc_values.background = lightSquareColor;
3198 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3200 gc_values.foreground = jailSquareColor;
3201 gc_values.background = jailSquareColor;
3202 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3204 gc_values.foreground = whitePieceColor;
3205 gc_values.background = darkSquareColor;
3206 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3208 gc_values.foreground = whitePieceColor;
3209 gc_values.background = lightSquareColor;
3210 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3212 gc_values.foreground = whitePieceColor;
3213 gc_values.background = jailSquareColor;
3214 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3216 gc_values.foreground = blackPieceColor;
3217 gc_values.background = darkSquareColor;
3218 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3220 gc_values.foreground = blackPieceColor;
3221 gc_values.background = lightSquareColor;
3222 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3224 gc_values.foreground = blackPieceColor;
3225 gc_values.background = jailSquareColor;
3226 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3230 void loadXIM(xim, xmask, filename, dest, mask)
3243 fp = fopen(filename, "rb");
3245 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3252 for (y=0; y<h; ++y) {
3253 for (x=0; x<h; ++x) {
3258 XPutPixel(xim, x, y, blackPieceColor);
3260 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3263 XPutPixel(xim, x, y, darkSquareColor);
3265 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3268 XPutPixel(xim, x, y, whitePieceColor);
3270 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3273 XPutPixel(xim, x, y, lightSquareColor);
3275 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3281 /* create Pixmap of piece */
3282 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3284 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3287 /* create Pixmap of clipmask
3288 Note: We assume the white/black pieces have the same
3289 outline, so we make only 6 masks. This is okay
3290 since the XPM clipmask routines do the same. */
3292 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3294 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3297 /* now create the 1-bit version */
3298 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3301 values.foreground = 1;
3302 values.background = 0;
3304 /* Don't use XtGetGC, not read only */
3305 maskGC = XCreateGC(xDisplay, *mask,
3306 GCForeground | GCBackground, &values);
3307 XCopyPlane(xDisplay, temp, *mask, maskGC,
3308 0, 0, squareSize, squareSize, 0, 0, 1);
3309 XFreePixmap(xDisplay, temp);
3314 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3316 void CreateXIMPieces()
3321 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3326 /* The XSynchronize calls were copied from CreatePieces.
3327 Not sure if needed, but can't hurt */
3328 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3331 /* temp needed by loadXIM() */
3332 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3333 0, 0, ss, ss, AllPlanes, XYPixmap);
3335 if (strlen(appData.pixmapDirectory) == 0) {
3339 if (appData.monoMode) {
3340 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3344 fprintf(stderr, _("\nLoading XIMs...\n"));
3346 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3347 fprintf(stderr, "%d", piece+1);
3348 for (kind=0; kind<4; kind++) {
3349 fprintf(stderr, ".");
3350 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3351 ExpandPathName(appData.pixmapDirectory),
3352 piece <= (int) WhiteKing ? "" : "w",
3353 pieceBitmapNames[piece],
3355 ximPieceBitmap[kind][piece] =
3356 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3357 0, 0, ss, ss, AllPlanes, XYPixmap);
3358 if (appData.debugMode)
3359 fprintf(stderr, _("(File:%s:) "), buf);
3360 loadXIM(ximPieceBitmap[kind][piece],
3362 &(xpmPieceBitmap2[kind][piece]),
3363 &(ximMaskPm2[piece]));
3364 if(piece <= (int)WhiteKing)
3365 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3367 fprintf(stderr," ");
3369 /* Load light and dark squares */
3370 /* If the LSQ and DSQ pieces don't exist, we will
3371 draw them with solid squares. */
3372 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3373 if (access(buf, 0) != 0) {
3377 fprintf(stderr, _("light square "));
3379 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3380 0, 0, ss, ss, AllPlanes, XYPixmap);
3381 if (appData.debugMode)
3382 fprintf(stderr, _("(File:%s:) "), buf);
3384 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3385 fprintf(stderr, _("dark square "));
3386 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3387 ExpandPathName(appData.pixmapDirectory), ss);
3388 if (appData.debugMode)
3389 fprintf(stderr, _("(File:%s:) "), buf);
3391 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3392 0, 0, ss, ss, AllPlanes, XYPixmap);
3393 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3394 xpmJailSquare = xpmLightSquare;
3396 fprintf(stderr, _("Done.\n"));
3398 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3402 void CreateXPMPieces()
3406 u_int ss = squareSize;
3408 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3409 XpmColorSymbol symbols[4];
3411 /* The XSynchronize calls were copied from CreatePieces.
3412 Not sure if needed, but can't hurt */
3413 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3415 /* Setup translations so piece colors match square colors */
3416 symbols[0].name = "light_piece";
3417 symbols[0].value = appData.whitePieceColor;
3418 symbols[1].name = "dark_piece";
3419 symbols[1].value = appData.blackPieceColor;
3420 symbols[2].name = "light_square";
3421 symbols[2].value = appData.lightSquareColor;
3422 symbols[3].name = "dark_square";
3423 symbols[3].value = appData.darkSquareColor;
3425 attr.valuemask = XpmColorSymbols;
3426 attr.colorsymbols = symbols;
3427 attr.numsymbols = 4;
3429 if (appData.monoMode) {
3430 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3434 if (strlen(appData.pixmapDirectory) == 0) {
3435 XpmPieces* pieces = builtInXpms;
3438 while (pieces->size != squareSize && pieces->size) pieces++;
3439 if (!pieces->size) {
3440 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3443 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3444 for (kind=0; kind<4; kind++) {
3446 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3447 pieces->xpm[piece][kind],
3448 &(xpmPieceBitmap2[kind][piece]),
3449 NULL, &attr)) != 0) {
3450 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3454 if(piece <= (int) WhiteKing)
3455 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3459 xpmJailSquare = xpmLightSquare;
3463 fprintf(stderr, _("\nLoading XPMs...\n"));
3466 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3467 fprintf(stderr, "%d ", piece+1);
3468 for (kind=0; kind<4; kind++) {
3469 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3470 ExpandPathName(appData.pixmapDirectory),
3471 piece > (int) WhiteKing ? "w" : "",
3472 pieceBitmapNames[piece],
3474 if (appData.debugMode) {
3475 fprintf(stderr, _("(File:%s:) "), buf);
3477 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3478 &(xpmPieceBitmap2[kind][piece]),
3479 NULL, &attr)) != 0) {
3480 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3481 // [HGM] missing: read of unorthodox piece failed; substitute King.
3482 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3483 ExpandPathName(appData.pixmapDirectory),
3485 if (appData.debugMode) {
3486 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3488 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3489 &(xpmPieceBitmap2[kind][piece]),
3493 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3498 if(piece <= (int) WhiteKing)
3499 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3502 /* Load light and dark squares */
3503 /* If the LSQ and DSQ pieces don't exist, we will
3504 draw them with solid squares. */
3505 fprintf(stderr, _("light square "));
3506 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3507 if (access(buf, 0) != 0) {
3511 if (appData.debugMode)
3512 fprintf(stderr, _("(File:%s:) "), buf);
3514 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3515 &xpmLightSquare, NULL, &attr)) != 0) {
3516 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3519 fprintf(stderr, _("dark square "));
3520 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3521 ExpandPathName(appData.pixmapDirectory), ss);
3522 if (appData.debugMode) {
3523 fprintf(stderr, _("(File:%s:) "), buf);
3525 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3526 &xpmDarkSquare, NULL, &attr)) != 0) {
3527 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3531 xpmJailSquare = xpmLightSquare;
3532 fprintf(stderr, _("Done.\n"));
3534 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3537 #endif /* HAVE_LIBXPM */
3540 /* No built-in bitmaps */
3545 u_int ss = squareSize;
3547 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3550 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3551 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3552 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3553 pieceBitmapNames[piece],
3554 ss, kind == SOLID ? 's' : 'o');
3555 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3556 if(piece <= (int)WhiteKing)
3557 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3561 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3565 /* With built-in bitmaps */
3568 BuiltInBits* bib = builtInBits;
3571 u_int ss = squareSize;
3573 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3576 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3578 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3579 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3580 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3581 pieceBitmapNames[piece],
3582 ss, kind == SOLID ? 's' : 'o');
3583 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3584 bib->bits[kind][piece], ss, ss);
3585 if(piece <= (int)WhiteKing)
3586 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3590 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3595 void ReadBitmap(pm, name, bits, wreq, hreq)
3598 unsigned char bits[];
3604 char msg[MSG_SIZ], fullname[MSG_SIZ];
3606 if (*appData.bitmapDirectory != NULLCHAR) {
3607 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3608 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3609 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3610 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3611 &w, &h, pm, &x_hot, &y_hot);
3612 fprintf(stderr, "load %s\n", name);
3613 if (errcode != BitmapSuccess) {
3615 case BitmapOpenFailed:
3616 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3618 case BitmapFileInvalid:
3619 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3621 case BitmapNoMemory:
3622 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3626 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3630 fprintf(stderr, _("%s: %s...using built-in\n"),
3632 } else if (w != wreq || h != hreq) {
3634 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3635 programName, fullname, w, h, wreq, hreq);
3641 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3650 if (lineGap == 0) return;
3652 /* [HR] Split this into 2 loops for non-square boards. */
3654 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3655 gridSegments[i].x1 = 0;
3656 gridSegments[i].x2 =
3657 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3658 gridSegments[i].y1 = gridSegments[i].y2
3659 = lineGap / 2 + (i * (squareSize + lineGap));
3662 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3663 gridSegments[j + i].y1 = 0;
3664 gridSegments[j + i].y2 =
3665 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3666 gridSegments[j + i].x1 = gridSegments[j + i].x2
3667 = lineGap / 2 + (j * (squareSize + lineGap));
3671 static void MenuBarSelect(w, addr, index)
3676 XtActionProc proc = (XtActionProc) addr;
3678 (proc)(NULL, NULL, NULL, NULL);
3681 void CreateMenuBarPopup(parent, name, mb)
3691 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3694 XtSetArg(args[j], XtNleftMargin, 20); j++;
3695 XtSetArg(args[j], XtNrightMargin, 20); j++;
3697 while (mi->string != NULL) {
3698 if (strcmp(mi->string, "----") == 0) {
3699 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3702 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3703 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3705 XtAddCallback(entry, XtNcallback,
3706 (XtCallbackProc) MenuBarSelect,
3707 (caddr_t) mi->proc);
3713 Widget CreateMenuBar(mb)
3717 Widget anchor, menuBar;
3719 char menuName[MSG_SIZ];
3722 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3723 XtSetArg(args[j], XtNvSpace, 0); j++;
3724 XtSetArg(args[j], XtNborderWidth, 0); j++;
3725 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3726 formWidget, args, j);
3728 while (mb->name != NULL) {
3729 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3730 strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
3732 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3735 shortName[0] = _(mb->name)[0];
3736 shortName[1] = NULLCHAR;
3737 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3740 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3743 XtSetArg(args[j], XtNborderWidth, 0); j++;
3744 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3746 CreateMenuBarPopup(menuBar, menuName, mb);
3752 Widget CreateButtonBar(mi)
3756 Widget button, buttonBar;
3760 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3762 XtSetArg(args[j], XtNhSpace, 0); j++;
3764 XtSetArg(args[j], XtNborderWidth, 0); j++;
3765 XtSetArg(args[j], XtNvSpace, 0); j++;
3766 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3767 formWidget, args, j);
3769 while (mi->string != NULL) {
3772 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3773 XtSetArg(args[j], XtNborderWidth, 0); j++;
3775 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3776 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3777 buttonBar, args, j);
3778 XtAddCallback(button, XtNcallback,
3779 (XtCallbackProc) MenuBarSelect,
3780 (caddr_t) mi->proc);
3787 CreatePieceMenu(name, color)
3794 ChessSquare selection;
3796 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3797 boardWidget, args, 0);
3799 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3800 String item = pieceMenuStrings[color][i];
3802 if (strcmp(item, "----") == 0) {
3803 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3806 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3807 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3809 selection = pieceMenuTranslation[color][i];
3810 XtAddCallback(entry, XtNcallback,
3811 (XtCallbackProc) PieceMenuSelect,
3812 (caddr_t) selection);
3813 if (selection == WhitePawn || selection == BlackPawn) {
3814 XtSetArg(args[0], XtNpopupOnEntry, entry);
3815 XtSetValues(menu, args, 1);
3828 ChessSquare selection;
3830 whitePieceMenu = CreatePieceMenu("menuW", 0);
3831 blackPieceMenu = CreatePieceMenu("menuB", 1);
3833 XtRegisterGrabAction(PieceMenuPopup, True,
3834 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3835 GrabModeAsync, GrabModeAsync);
3837 XtSetArg(args[0], XtNlabel, _("Drop"));
3838 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3839 boardWidget, args, 1);
3840 for (i = 0; i < DROP_MENU_SIZE; i++) {
3841 String item = dropMenuStrings[i];
3843 if (strcmp(item, "----") == 0) {
3844 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3847 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3848 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3850 selection = dropMenuTranslation[i];
3851 XtAddCallback(entry, XtNcallback,
3852 (XtCallbackProc) DropMenuSelect,
3853 (caddr_t) selection);
3858 void SetupDropMenu()
3866 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3867 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3868 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3869 dmEnables[i].piece);
3870 XtSetSensitive(entry, p != NULL || !appData.testLegality
3871 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3872 && !appData.icsActive));
3874 while (p && *p++ == dmEnables[i].piece) count++;
3875 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3877 XtSetArg(args[j], XtNlabel, label); j++;
3878 XtSetValues(entry, args, j);
3882 void PieceMenuPopup(w, event, params, num_params)
3886 Cardinal *num_params;
3888 String whichMenu; int menuNr;
3889 if (event->type == ButtonRelease)
3890 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3891 else if (event->type == ButtonPress)
3892 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3894 case 0: whichMenu = params[0]; break;
3895 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3897 case -1: if (errorUp) ErrorPopDown();
3900 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3903 static void PieceMenuSelect(w, piece, junk)
3908 if (pmFromX < 0 || pmFromY < 0) return;
3909 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3912 static void DropMenuSelect(w, piece, junk)
3917 if (pmFromX < 0 || pmFromY < 0) return;
3918 DropMenuEvent(piece, pmFromX, pmFromY);
3921 void WhiteClock(w, event, prms, nprms)
3927 if (gameMode == EditPosition || gameMode == IcsExamining) {
3928 SetWhiteToPlayEvent();
3929 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3934 void BlackClock(w, event, prms, nprms)
3940 if (gameMode == EditPosition || gameMode == IcsExamining) {
3941 SetBlackToPlayEvent();
3942 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3949 * If the user selects on a border boundary, return -1; if off the board,
3950 * return -2. Otherwise map the event coordinate to the square.
3952 int EventToSquare(x, limit)
3960 if ((x % (squareSize + lineGap)) >= squareSize)
3962 x /= (squareSize + lineGap);
3968 static void do_flash_delay(msec)
3974 static void drawHighlight(file, rank, gc)
3980 if (lineGap == 0 || appData.blindfold) return;
3983 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3984 (squareSize + lineGap);
3985 y = lineGap/2 + rank * (squareSize + lineGap);
3987 x = lineGap/2 + file * (squareSize + lineGap);
3988 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3989 (squareSize + lineGap);
3992 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3993 squareSize+lineGap, squareSize+lineGap);
3996 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3997 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4000 SetHighlights(fromX, fromY, toX, toY)
4001 int fromX, fromY, toX, toY;
4003 if (hi1X != fromX || hi1Y != fromY) {
4004 if (hi1X >= 0 && hi1Y >= 0) {
4005 drawHighlight(hi1X, hi1Y, lineGC);
4007 } // [HGM] first erase both, then draw new!
4008 if (hi2X != toX || hi2Y != toY) {
4009 if (hi2X >= 0 && hi2Y >= 0) {
4010 drawHighlight(hi2X, hi2Y, lineGC);
4013 if (hi1X != fromX || hi1Y != fromY) {
4014 if (fromX >= 0 && fromY >= 0) {
4015 drawHighlight(fromX, fromY, highlineGC);
4018 if (hi2X != toX || hi2Y != toY) {
4019 if (toX >= 0 && toY >= 0) {
4020 drawHighlight(toX, toY, highlineGC);
4032 SetHighlights(-1, -1, -1, -1);
4037 SetPremoveHighlights(fromX, fromY, toX, toY)
4038 int fromX, fromY, toX, toY;
4040 if (pm1X != fromX || pm1Y != fromY) {
4041 if (pm1X >= 0 && pm1Y >= 0) {
4042 drawHighlight(pm1X, pm1Y, lineGC);
4044 if (fromX >= 0 && fromY >= 0) {
4045 drawHighlight(fromX, fromY, prelineGC);
4048 if (pm2X != toX || pm2Y != toY) {
4049 if (pm2X >= 0 && pm2Y >= 0) {
4050 drawHighlight(pm2X, pm2Y, lineGC);
4052 if (toX >= 0 && toY >= 0) {
4053 drawHighlight(toX, toY, prelineGC);
4063 ClearPremoveHighlights()
4065 SetPremoveHighlights(-1, -1, -1, -1);
4068 static void BlankSquare(x, y, color, piece, dest)
4073 if (useImages && useImageSqs) {
4077 pm = xpmLightSquare;
4082 case 2: /* neutral */
4087 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4088 squareSize, squareSize, x, y);
4098 case 2: /* neutral */
4103 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4108 I split out the routines to draw a piece so that I could
4109 make a generic flash routine.
4111 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4113 int square_color, x, y;
4116 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4117 switch (square_color) {
4119 case 2: /* neutral */
4121 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4122 ? *pieceToOutline(piece)
4123 : *pieceToSolid(piece),
4124 dest, bwPieceGC, 0, 0,
4125 squareSize, squareSize, x, y);
4128 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4129 ? *pieceToSolid(piece)
4130 : *pieceToOutline(piece),
4131 dest, wbPieceGC, 0, 0,
4132 squareSize, squareSize, x, y);
4137 static void monoDrawPiece(piece, square_color, x, y, dest)
4139 int square_color, x, y;
4142 switch (square_color) {
4144 case 2: /* neutral */
4146 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4147 ? *pieceToOutline(piece)
4148 : *pieceToSolid(piece),
4149 dest, bwPieceGC, 0, 0,
4150 squareSize, squareSize, x, y, 1);
4153 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4154 ? *pieceToSolid(piece)
4155 : *pieceToOutline(piece),
4156 dest, wbPieceGC, 0, 0,
4157 squareSize, squareSize, x, y, 1);
4162 static void colorDrawPiece(piece, square_color, x, y, dest)
4164 int square_color, x, y;
4167 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4168 switch (square_color) {
4170 XCopyPlane(xDisplay, *pieceToSolid(piece),
4171 dest, (int) piece < (int) BlackPawn
4172 ? wlPieceGC : blPieceGC, 0, 0,
4173 squareSize, squareSize, x, y, 1);
4176 XCopyPlane(xDisplay, *pieceToSolid(piece),
4177 dest, (int) piece < (int) BlackPawn
4178 ? wdPieceGC : bdPieceGC, 0, 0,
4179 squareSize, squareSize, x, y, 1);
4181 case 2: /* neutral */
4183 XCopyPlane(xDisplay, *pieceToSolid(piece),
4184 dest, (int) piece < (int) BlackPawn
4185 ? wjPieceGC : bjPieceGC, 0, 0,
4186 squareSize, squareSize, x, y, 1);
4191 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4193 int square_color, x, y;
4198 switch (square_color) {
4200 case 2: /* neutral */
4202 if ((int)piece < (int) BlackPawn) {
4210 if ((int)piece < (int) BlackPawn) {
4218 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4219 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4220 dest, wlPieceGC, 0, 0,
4221 squareSize, squareSize, x, y);
4224 typedef void (*DrawFunc)();
4226 DrawFunc ChooseDrawFunc()
4228 if (appData.monoMode) {
4229 if (DefaultDepth(xDisplay, xScreen) == 1) {
4230 return monoDrawPiece_1bit;
4232 return monoDrawPiece;
4236 return colorDrawPieceImage;
4238 return colorDrawPiece;
4242 /* [HR] determine square color depending on chess variant. */
4243 static int SquareColor(row, column)
4248 if (gameInfo.variant == VariantXiangqi) {
4249 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4251 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4253 } else if (row <= 4) {
4259 square_color = ((column + row) % 2) == 1;
4262 /* [hgm] holdings: next line makes all holdings squares light */
4263 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4265 return square_color;
4268 void DrawSquare(row, column, piece, do_flash)
4269 int row, column, do_flash;
4272 int square_color, x, y, direction, font_ascent, font_descent;
4275 XCharStruct overall;
4279 /* Calculate delay in milliseconds (2-delays per complete flash) */
4280 flash_delay = 500 / appData.flashRate;
4283 x = lineGap + ((BOARD_WIDTH-1)-column) *
4284 (squareSize + lineGap);
4285 y = lineGap + row * (squareSize + lineGap);
4287 x = lineGap + column * (squareSize + lineGap);
4288 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4289 (squareSize + lineGap);
4292 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4294 square_color = SquareColor(row, column);
4296 if ( // [HGM] holdings: blank out area between board and holdings
4297 column == BOARD_LEFT-1 || column == BOARD_RGHT
4298 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4299 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4300 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4302 // [HGM] print piece counts next to holdings
4303 string[1] = NULLCHAR;
4304 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4305 string[0] = '0' + piece;
4306 XTextExtents(countFontStruct, string, 1, &direction,
4307 &font_ascent, &font_descent, &overall);
4308 if (appData.monoMode) {
4309 XDrawImageString(xDisplay, xBoardWindow, countGC,
4310 x + squareSize - overall.width - 2,
4311 y + font_ascent + 1, string, 1);
4313 XDrawString(xDisplay, xBoardWindow, countGC,
4314 x + squareSize - overall.width - 2,
4315 y + font_ascent + 1, string, 1);
4318 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4319 string[0] = '0' + piece;
4320 XTextExtents(countFontStruct, string, 1, &direction,
4321 &font_ascent, &font_descent, &overall);
4322 if (appData.monoMode) {
4323 XDrawImageString(xDisplay, xBoardWindow, countGC,
4324 x + 2, y + font_ascent + 1, string, 1);
4326 XDrawString(xDisplay, xBoardWindow, countGC,
4327 x + 2, y + font_ascent + 1, string, 1);
4331 if (piece == EmptySquare || appData.blindfold) {
4332 BlankSquare(x, y, square_color, piece, xBoardWindow);
4334 drawfunc = ChooseDrawFunc();
4335 if (do_flash && appData.flashCount > 0) {
4336 for (i=0; i<appData.flashCount; ++i) {
4338 drawfunc(piece, square_color, x, y, xBoardWindow);
4339 XSync(xDisplay, False);
4340 do_flash_delay(flash_delay);
4342 BlankSquare(x, y, square_color, piece, xBoardWindow);
4343 XSync(xDisplay, False);
4344 do_flash_delay(flash_delay);
4347 drawfunc(piece, square_color, x, y, xBoardWindow);
4351 string[1] = NULLCHAR;
4352 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4353 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4354 string[0] = 'a' + column - BOARD_LEFT;
4355 XTextExtents(coordFontStruct, string, 1, &direction,
4356 &font_ascent, &font_descent, &overall);
4357 if (appData.monoMode) {
4358 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4359 x + squareSize - overall.width - 2,
4360 y + squareSize - font_descent - 1, string, 1);
4362 XDrawString(xDisplay, xBoardWindow, coordGC,
4363 x + squareSize - overall.width - 2,
4364 y + squareSize - font_descent - 1, string, 1);
4367 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4368 string[0] = ONE + row;
4369 XTextExtents(coordFontStruct, string, 1, &direction,
4370 &font_ascent, &font_descent, &overall);
4371 if (appData.monoMode) {
4372 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4373 x + 2, y + font_ascent + 1, string, 1);
4375 XDrawString(xDisplay, xBoardWindow, coordGC,
4376 x + 2, y + font_ascent + 1, string, 1);
4379 if(!partnerUp && marker[row][column]) {
4380 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4381 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4386 /* Why is this needed on some versions of X? */
4387 void EventProc(widget, unused, event)
4392 if (!XtIsRealized(widget))
4395 switch (event->type) {
4397 if (event->xexpose.count > 0) return; /* no clipping is done */
4398 XDrawPosition(widget, True, NULL);
4399 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4400 flipView = !flipView; partnerUp = !partnerUp;
4401 XDrawPosition(widget, True, NULL);
4402 flipView = !flipView; partnerUp = !partnerUp;
4406 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4413 void DrawPosition(fullRedraw, board)
4414 /*Boolean*/int fullRedraw;
4417 XDrawPosition(boardWidget, fullRedraw, board);
4420 /* Returns 1 if there are "too many" differences between b1 and b2
4421 (i.e. more than 1 move was made) */
4422 static int too_many_diffs(b1, b2)
4428 for (i=0; i<BOARD_HEIGHT; ++i) {
4429 for (j=0; j<BOARD_WIDTH; ++j) {
4430 if (b1[i][j] != b2[i][j]) {
4431 if (++c > 4) /* Castling causes 4 diffs */
4440 /* Matrix describing castling maneuvers */
4441 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4442 static int castling_matrix[4][5] = {
4443 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4444 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4445 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4446 { 7, 7, 4, 5, 6 } /* 0-0, black */
4449 /* Checks whether castling occurred. If it did, *rrow and *rcol
4450 are set to the destination (row,col) of the rook that moved.
4452 Returns 1 if castling occurred, 0 if not.
4454 Note: Only handles a max of 1 castling move, so be sure
4455 to call too_many_diffs() first.
4457 static int check_castle_draw(newb, oldb, rrow, rcol)
4464 /* For each type of castling... */
4465 for (i=0; i<4; ++i) {
4466 r = castling_matrix[i];
4468 /* Check the 4 squares involved in the castling move */
4470 for (j=1; j<=4; ++j) {
4471 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4478 /* All 4 changed, so it must be a castling move */
4487 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4488 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4490 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4493 void DrawSeekBackground( int left, int top, int right, int bottom )
4495 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4498 void DrawSeekText(char *buf, int x, int y)
4500 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4503 void DrawSeekDot(int x, int y, int colorNr)
4505 int square = colorNr & 0x80;
4508 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4510 XFillRectangle(xDisplay, xBoardWindow, color,
4511 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4513 XFillArc(xDisplay, xBoardWindow, color,
4514 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4517 static int damage[2][BOARD_RANKS][BOARD_FILES];
4520 * event handler for redrawing the board
4522 void XDrawPosition(w, repaint, board)
4524 /*Boolean*/int repaint;
4528 static int lastFlipView = 0;
4529 static int lastBoardValid[2] = {0, 0};
4530 static Board lastBoard[2];
4533 int nr = twoBoards*partnerUp;
4535 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4537 if (board == NULL) {
4538 if (!lastBoardValid[nr]) return;
4539 board = lastBoard[nr];
4541 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4542 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4543 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4548 * It would be simpler to clear the window with XClearWindow()
4549 * but this causes a very distracting flicker.
4552 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4554 /* If too much changes (begin observing new game, etc.), don't
4556 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4558 /* Special check for castling so we don't flash both the king
4559 and the rook (just flash the king). */
4561 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4562 /* Draw rook with NO flashing. King will be drawn flashing later */
4563 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4564 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4568 /* First pass -- Draw (newly) empty squares and repair damage.
4569 This prevents you from having a piece show up twice while it
4570 is flashing on its new square */
4571 for (i = 0; i < BOARD_HEIGHT; i++)
4572 for (j = 0; j < BOARD_WIDTH; j++)
4573 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4574 || damage[nr][i][j]) {
4575 DrawSquare(i, j, board[i][j], 0);
4576 damage[nr][i][j] = False;
4579 /* Second pass -- Draw piece(s) in new position and flash them */
4580 for (i = 0; i < BOARD_HEIGHT; i++)
4581 for (j = 0; j < BOARD_WIDTH; j++)
4582 if (board[i][j] != lastBoard[nr][i][j]) {
4583 DrawSquare(i, j, board[i][j], do_flash);
4587 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4588 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4589 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4591 for (i = 0; i < BOARD_HEIGHT; i++)
4592 for (j = 0; j < BOARD_WIDTH; j++) {
4593 DrawSquare(i, j, board[i][j], 0);
4594 damage[nr][i][j] = False;
4598 CopyBoard(lastBoard[nr], board);
4599 lastBoardValid[nr] = 1;
4600 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4601 lastFlipView = flipView;
4603 /* Draw highlights */
4604 if (pm1X >= 0 && pm1Y >= 0) {
4605 drawHighlight(pm1X, pm1Y, prelineGC);
4607 if (pm2X >= 0 && pm2Y >= 0) {
4608 drawHighlight(pm2X, pm2Y, prelineGC);
4610 if (hi1X >= 0 && hi1Y >= 0) {
4611 drawHighlight(hi1X, hi1Y, highlineGC);
4613 if (hi2X >= 0 && hi2Y >= 0) {
4614 drawHighlight(hi2X, hi2Y, highlineGC);
4617 /* If piece being dragged around board, must redraw that too */
4620 XSync(xDisplay, False);
4625 * event handler for redrawing the board
4627 void DrawPositionProc(w, event, prms, nprms)
4633 XDrawPosition(w, True, NULL);
4638 * event handler for parsing user moves
4640 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4641 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4642 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4643 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4644 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4645 // and at the end FinishMove() to perform the move after optional promotion popups.
4646 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4647 void HandleUserMove(w, event, prms, nprms)
4653 if (w != boardWidget || errorExitStatus != -1) return;
4656 if (event->type == ButtonPress) {
4657 XtPopdown(promotionShell);
4658 XtDestroyWidget(promotionShell);
4659 promotionUp = False;
4667 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4668 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4669 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4672 void AnimateUserMove (Widget w, XEvent * event,
4673 String * params, Cardinal * nParams)
4675 DragPieceMove(event->xmotion.x, event->xmotion.y);
4678 void HandlePV (Widget w, XEvent * event,
4679 String * params, Cardinal * nParams)
4680 { // [HGM] pv: walk PV
4681 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4684 Widget CommentCreate(name, text, mutable, callback, lines)
4686 int /*Boolean*/ mutable;
4687 XtCallbackProc callback;
4691 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4696 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4697 XtGetValues(boardWidget, args, j);
4700 XtSetArg(args[j], XtNresizable, True); j++;
4703 XtCreatePopupShell(name, topLevelShellWidgetClass,
4704 shellWidget, args, j);
4707 XtCreatePopupShell(name, transientShellWidgetClass,
4708 shellWidget, args, j);
4711 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4712 layoutArgs, XtNumber(layoutArgs));
4714 XtCreateManagedWidget("form", formWidgetClass, layout,
4715 formArgs, XtNumber(formArgs));
4719 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4720 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4722 XtSetArg(args[j], XtNstring, text); j++;
4723 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4724 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4725 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4726 XtSetArg(args[j], XtNright, XtChainRight); j++;
4727 XtSetArg(args[j], XtNresizable, True); j++;
4728 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4729 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4730 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4731 XtSetArg(args[j], XtNautoFill, True); j++;
4732 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4734 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4735 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4739 XtSetArg(args[j], XtNfromVert, edit); j++;
4740 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4741 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4742 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4743 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4745 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4746 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4749 XtSetArg(args[j], XtNfromVert, edit); j++;
4750 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4751 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4752 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4753 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4754 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4756 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4757 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4760 XtSetArg(args[j], XtNfromVert, edit); j++;
4761 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4762 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4763 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4764 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4765 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4767 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4768 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4771 XtSetArg(args[j], XtNfromVert, edit); j++;
4772 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4773 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4774 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4775 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4777 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4778 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4781 XtSetArg(args[j], XtNfromVert, edit); j++;
4782 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4783 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4784 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4785 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4786 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4788 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4789 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4792 XtRealizeWidget(shell);
4794 if (commentX == -1) {
4797 Dimension pw_height;
4798 Dimension ew_height;
4801 XtSetArg(args[j], XtNheight, &ew_height); j++;
4802 XtGetValues(edit, args, j);
4805 XtSetArg(args[j], XtNheight, &pw_height); j++;
4806 XtGetValues(shell, args, j);
4807 commentH = pw_height + (lines - 1) * ew_height;
4808 commentW = bw_width - 16;
4810 XSync(xDisplay, False);
4812 /* This code seems to tickle an X bug if it is executed too soon
4813 after xboard starts up. The coordinates get transformed as if
4814 the main window was positioned at (0, 0).
4816 XtTranslateCoords(shellWidget,
4817 (bw_width - commentW) / 2, 0 - commentH / 2,
4818 &commentX, &commentY);
4820 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4821 RootWindowOfScreen(XtScreen(shellWidget)),
4822 (bw_width - commentW) / 2, 0 - commentH / 2,
4827 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4830 if(wpComment.width > 0) {
4831 commentX = wpComment.x;
4832 commentY = wpComment.y;
4833 commentW = wpComment.width;
4834 commentH = wpComment.height;
4838 XtSetArg(args[j], XtNheight, commentH); j++;
4839 XtSetArg(args[j], XtNwidth, commentW); j++;
4840 XtSetArg(args[j], XtNx, commentX); j++;
4841 XtSetArg(args[j], XtNy, commentY); j++;
4842 XtSetValues(shell, args, j);
4843 XtSetKeyboardFocus(shell, edit);
4848 /* Used for analysis window and ICS input window */
4849 Widget MiscCreate(name, text, mutable, callback, lines)
4851 int /*Boolean*/ mutable;
4852 XtCallbackProc callback;
4856 Widget shell, layout, form, edit;
4858 Dimension bw_width, pw_height, ew_height, w, h;
4864 XtSetArg(args[j], XtNresizable, True); j++;
4867 XtCreatePopupShell(name, topLevelShellWidgetClass,
4868 shellWidget, args, j);
4871 XtCreatePopupShell(name, transientShellWidgetClass,
4872 shellWidget, args, j);
4875 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4876 layoutArgs, XtNumber(layoutArgs));
4878 XtCreateManagedWidget("form", formWidgetClass, layout,
4879 formArgs, XtNumber(formArgs));
4883 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4884 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4886 XtSetArg(args[j], XtNstring, text); j++;
4887 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4888 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4889 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4890 XtSetArg(args[j], XtNright, XtChainRight); j++;
4891 XtSetArg(args[j], XtNresizable, True); j++;
4892 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4893 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4894 XtSetArg(args[j], XtNautoFill, True); j++;
4895 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4897 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4899 XtRealizeWidget(shell);
4902 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4903 XtGetValues(boardWidget, args, j);
4906 XtSetArg(args[j], XtNheight, &ew_height); j++;
4907 XtGetValues(edit, args, j);
4910 XtSetArg(args[j], XtNheight, &pw_height); j++;
4911 XtGetValues(shell, args, j);
4912 h = pw_height + (lines - 1) * ew_height;
4915 XSync(xDisplay, False);
4917 /* This code seems to tickle an X bug if it is executed too soon
4918 after xboard starts up. The coordinates get transformed as if
4919 the main window was positioned at (0, 0).
4921 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4923 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4924 RootWindowOfScreen(XtScreen(shellWidget)),
4925 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4929 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4932 XtSetArg(args[j], XtNheight, h); j++;
4933 XtSetArg(args[j], XtNwidth, w); j++;
4934 XtSetArg(args[j], XtNx, x); j++;
4935 XtSetArg(args[j], XtNy, y); j++;
4936 XtSetValues(shell, args, j);
4942 static int savedIndex; /* gross that this is global */
4944 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4947 XawTextPosition index, dummy;
4950 XawTextGetSelectionPos(w, &index, &dummy);
4951 XtSetArg(arg, XtNstring, &val);
4952 XtGetValues(w, &arg, 1);
4953 ReplaceComment(savedIndex, val);
4954 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4955 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4958 void EditCommentPopUp(index, title, text)
4967 if (text == NULL) text = "";
4969 if (editShell == NULL) {
4971 CommentCreate(title, text, True, EditCommentCallback, 4);
4972 XtRealizeWidget(editShell);
4973 CatchDeleteWindow(editShell, "EditCommentPopDown");
4975 edit = XtNameToWidget(editShell, "*form.text");
4977 XtSetArg(args[j], XtNstring, text); j++;
4978 XtSetValues(edit, args, j);
4980 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4981 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4982 XtSetValues(editShell, args, j);
4985 XtPopup(editShell, XtGrabNone);
4989 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4990 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4994 void EditCommentCallback(w, client_data, call_data)
4996 XtPointer client_data, call_data;
5004 XtSetArg(args[j], XtNlabel, &name); j++;
5005 XtGetValues(w, args, j);
5007 if (strcmp(name, _("ok")) == 0) {
5008 edit = XtNameToWidget(editShell, "*form.text");
5010 XtSetArg(args[j], XtNstring, &val); j++;
5011 XtGetValues(edit, args, j);
5012 ReplaceComment(savedIndex, val);
5013 EditCommentPopDown();
5014 } else if (strcmp(name, _("cancel")) == 0) {
5015 EditCommentPopDown();
5016 } else if (strcmp(name, _("clear")) == 0) {
5017 edit = XtNameToWidget(editShell, "*form.text");
5018 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5019 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5023 void EditCommentPopDown()
5028 if (!editUp) return;
5030 XtSetArg(args[j], XtNx, &commentX); j++;
5031 XtSetArg(args[j], XtNy, &commentY); j++;
5032 XtSetArg(args[j], XtNheight, &commentH); j++;
5033 XtSetArg(args[j], XtNwidth, &commentW); j++;
5034 XtGetValues(editShell, args, j);
5035 XtPopdown(editShell);
5038 XtSetArg(args[j], XtNleftBitmap, None); j++;
5039 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5043 void ICSInputBoxPopUp()
5048 char *title = _("ICS Input");
5051 if (ICSInputShell == NULL) {
5052 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5053 tr = XtParseTranslationTable(ICSInputTranslations);
5054 edit = XtNameToWidget(ICSInputShell, "*form.text");
5055 XtOverrideTranslations(edit, tr);
5056 XtRealizeWidget(ICSInputShell);
5057 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5060 edit = XtNameToWidget(ICSInputShell, "*form.text");
5062 XtSetArg(args[j], XtNstring, ""); j++;
5063 XtSetValues(edit, args, j);
5065 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5066 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5067 XtSetValues(ICSInputShell, args, j);
5070 XtPopup(ICSInputShell, XtGrabNone);
5071 XtSetKeyboardFocus(ICSInputShell, edit);
5073 ICSInputBoxUp = True;
5075 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5076 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5080 void ICSInputSendText()
5087 edit = XtNameToWidget(ICSInputShell, "*form.text");
5089 XtSetArg(args[j], XtNstring, &val); j++;
5090 XtGetValues(edit, args, j);
5092 SendMultiLineToICS(val);
5093 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5094 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5097 void ICSInputBoxPopDown()
5102 if (!ICSInputBoxUp) return;
5104 XtPopdown(ICSInputShell);
5105 ICSInputBoxUp = False;
5107 XtSetArg(args[j], XtNleftBitmap, None); j++;
5108 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5112 void CommentPopUp(title, text)
5119 savedIndex = currentMove; // [HGM] vari
5120 if (commentShell == NULL) {
5122 CommentCreate(title, text, False, CommentCallback, 4);
5123 XtRealizeWidget(commentShell);
5124 CatchDeleteWindow(commentShell, "CommentPopDown");
5126 edit = XtNameToWidget(commentShell, "*form.text");
5128 XtSetArg(args[j], XtNstring, text); j++;
5129 XtSetValues(edit, args, j);
5131 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5132 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5133 XtSetValues(commentShell, args, j);
5136 XtPopup(commentShell, XtGrabNone);
5137 XSync(xDisplay, False);
5142 void CommentCallback(w, client_data, call_data)
5144 XtPointer client_data, call_data;
5151 XtSetArg(args[j], XtNlabel, &name); j++;
5152 XtGetValues(w, args, j);
5154 if (strcmp(name, _("close")) == 0) {
5156 } else if (strcmp(name, _("edit")) == 0) {
5163 void CommentPopDown()
5168 if (!commentUp) return;
5170 XtSetArg(args[j], XtNx, &commentX); j++;
5171 XtSetArg(args[j], XtNy, &commentY); j++;
5172 XtSetArg(args[j], XtNwidth, &commentW); j++;
5173 XtSetArg(args[j], XtNheight, &commentH); j++;
5174 XtGetValues(commentShell, args, j);
5175 XtPopdown(commentShell);
5176 XSync(xDisplay, False);
5180 void FileNamePopUp(label, def, proc, openMode)
5186 fileProc = proc; /* I can't see a way not */
5187 fileOpenMode = openMode; /* to use globals here */
5188 { // [HGM] use file-selector dialog stolen from Ghostview
5190 int index; // this is not supported yet
5192 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5193 def, openMode, NULL, &name))
5194 (void) (*fileProc)(f, index=0, name);
5198 void FileNamePopDown()
5200 if (!filenameUp) return;
5201 XtPopdown(fileNameShell);
5202 XtDestroyWidget(fileNameShell);
5207 void FileNameCallback(w, client_data, call_data)
5209 XtPointer client_data, call_data;
5214 XtSetArg(args[0], XtNlabel, &name);
5215 XtGetValues(w, args, 1);
5217 if (strcmp(name, _("cancel")) == 0) {
5222 FileNameAction(w, NULL, NULL, NULL);
5225 void FileNameAction(w, event, prms, nprms)
5237 name = XawDialogGetValueString(w = XtParent(w));
5239 if ((name != NULL) && (*name != NULLCHAR)) {
5240 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5241 XtPopdown(w = XtParent(XtParent(w)));
5245 p = strrchr(buf, ' ');
5252 fullname = ExpandPathName(buf);
5254 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5257 f = fopen(fullname, fileOpenMode);
5259 DisplayError(_("Failed to open file"), errno);
5261 (void) (*fileProc)(f, index, buf);
5268 XtPopdown(w = XtParent(XtParent(w)));
5274 void PromotionPopUp()
5277 Widget dialog, layout;
5279 Dimension bw_width, pw_width;
5283 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5284 XtGetValues(boardWidget, args, j);
5287 XtSetArg(args[j], XtNresizable, True); j++;
5288 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5290 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5291 shellWidget, args, j);
5293 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5294 layoutArgs, XtNumber(layoutArgs));
5297 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5298 XtSetArg(args[j], XtNborderWidth, 0); j++;
5299 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5302 if(gameInfo.variant != VariantShogi) {
5303 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5304 (XtPointer) dialog);
5305 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5306 (XtPointer) dialog);
5307 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5308 (XtPointer) dialog);
5309 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5310 (XtPointer) dialog);
5311 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5312 gameInfo.variant == VariantGiveaway) {
5313 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5314 (XtPointer) dialog);
5316 if(gameInfo.variant == VariantCapablanca ||
5317 gameInfo.variant == VariantGothic ||
5318 gameInfo.variant == VariantCapaRandom) {
5319 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5320 (XtPointer) dialog);
5321 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5322 (XtPointer) dialog);
5324 } else // [HGM] shogi
5326 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5327 (XtPointer) dialog);
5328 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5329 (XtPointer) dialog);
5331 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5332 (XtPointer) dialog);
5334 XtRealizeWidget(promotionShell);
5335 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5338 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5339 XtGetValues(promotionShell, args, j);
5341 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5342 lineGap + squareSize/3 +
5343 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5344 0 : 6*(squareSize + lineGap)), &x, &y);
5347 XtSetArg(args[j], XtNx, x); j++;
5348 XtSetArg(args[j], XtNy, y); j++;
5349 XtSetValues(promotionShell, args, j);
5351 XtPopup(promotionShell, XtGrabNone);
5356 void PromotionPopDown()
5358 if (!promotionUp) return;
5359 XtPopdown(promotionShell);
5360 XtDestroyWidget(promotionShell);
5361 promotionUp = False;
5364 void PromotionCallback(w, client_data, call_data)
5366 XtPointer client_data, call_data;
5372 XtSetArg(args[0], XtNlabel, &name);
5373 XtGetValues(w, args, 1);
5377 if (fromX == -1) return;
5379 if (strcmp(name, _("cancel")) == 0) {
5383 } else if (strcmp(name, _("Knight")) == 0) {
5385 } else if (strcmp(name, _("Promote")) == 0) {
5387 } else if (strcmp(name, _("Defer")) == 0) {
5390 promoChar = ToLower(name[0]);
5393 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5395 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5396 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5401 void ErrorCallback(w, client_data, call_data)
5403 XtPointer client_data, call_data;
5406 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5408 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5414 if (!errorUp) return;
5416 XtPopdown(errorShell);
5417 XtDestroyWidget(errorShell);
5418 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5421 void ErrorPopUp(title, label, modal)
5422 char *title, *label;
5426 Widget dialog, layout;
5430 Dimension bw_width, pw_width;
5431 Dimension pw_height;
5435 XtSetArg(args[i], XtNresizable, True); i++;
5436 XtSetArg(args[i], XtNtitle, title); i++;
5438 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5439 shellWidget, args, i);
5441 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5442 layoutArgs, XtNumber(layoutArgs));
5445 XtSetArg(args[i], XtNlabel, label); i++;
5446 XtSetArg(args[i], XtNborderWidth, 0); i++;
5447 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5450 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5452 XtRealizeWidget(errorShell);
5453 CatchDeleteWindow(errorShell, "ErrorPopDown");
5456 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5457 XtGetValues(boardWidget, args, i);
5459 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5460 XtSetArg(args[i], XtNheight, &pw_height); i++;
5461 XtGetValues(errorShell, args, i);
5464 /* This code seems to tickle an X bug if it is executed too soon
5465 after xboard starts up. The coordinates get transformed as if
5466 the main window was positioned at (0, 0).
5468 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5469 0 - pw_height + squareSize / 3, &x, &y);
5471 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5472 RootWindowOfScreen(XtScreen(boardWidget)),
5473 (bw_width - pw_width) / 2,
5474 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5478 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5481 XtSetArg(args[i], XtNx, x); i++;
5482 XtSetArg(args[i], XtNy, y); i++;
5483 XtSetValues(errorShell, args, i);
5486 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5489 /* Disable all user input other than deleting the window */
5490 static int frozen = 0;
5494 /* Grab by a widget that doesn't accept input */
5495 XtAddGrab(messageWidget, TRUE, FALSE);
5499 /* Undo a FreezeUI */
5502 if (!frozen) return;
5503 XtRemoveGrab(messageWidget);
5507 char *ModeToWidgetName(mode)
5511 case BeginningOfGame:
5512 if (appData.icsActive)
5513 return "menuMode.ICS Client";
5514 else if (appData.noChessProgram ||
5515 *appData.cmailGameName != NULLCHAR)
5516 return "menuMode.Edit Game";
5518 return "menuMode.Machine Black";
5519 case MachinePlaysBlack:
5520 return "menuMode.Machine Black";
5521 case MachinePlaysWhite:
5522 return "menuMode.Machine White";
5524 return "menuMode.Analysis Mode";
5526 return "menuMode.Analyze File";
5527 case TwoMachinesPlay:
5528 return "menuMode.Two Machines";
5530 return "menuMode.Edit Game";
5531 case PlayFromGameFile:
5532 return "menuFile.Load Game";
5534 return "menuMode.Edit Position";
5536 return "menuMode.Training";
5537 case IcsPlayingWhite:
5538 case IcsPlayingBlack:
5542 return "menuMode.ICS Client";
5549 void ModeHighlight()
5552 static int oldPausing = FALSE;
5553 static GameMode oldmode = (GameMode) -1;
5556 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5558 if (pausing != oldPausing) {
5559 oldPausing = pausing;
5561 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5563 XtSetArg(args[0], XtNleftBitmap, None);
5565 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5568 if (appData.showButtonBar) {
5569 /* Always toggle, don't set. Previous code messes up when
5570 invoked while the button is pressed, as releasing it
5571 toggles the state again. */
5574 XtSetArg(args[0], XtNbackground, &oldbg);
5575 XtSetArg(args[1], XtNforeground, &oldfg);
5576 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5578 XtSetArg(args[0], XtNbackground, oldfg);
5579 XtSetArg(args[1], XtNforeground, oldbg);
5581 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5585 wname = ModeToWidgetName(oldmode);
5586 if (wname != NULL) {
5587 XtSetArg(args[0], XtNleftBitmap, None);
5588 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5590 wname = ModeToWidgetName(gameMode);
5591 if (wname != NULL) {
5592 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5593 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5597 /* Maybe all the enables should be handled here, not just this one */
5598 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5599 gameMode == Training || gameMode == PlayFromGameFile);
5604 * Button/menu procedures
5606 void ResetProc(w, event, prms, nprms)
5615 int LoadGamePopUp(f, gameNumber, title)
5620 cmailMsgLoaded = FALSE;
5621 if (gameNumber == 0) {
5622 int error = GameListBuild(f);
5624 DisplayError(_("Cannot build game list"), error);
5625 } else if (!ListEmpty(&gameList) &&
5626 ((ListGame *) gameList.tailPred)->number > 1) {
5627 GameListPopUp(f, title);
5633 return LoadGame(f, gameNumber, title, FALSE);
5636 void LoadGameProc(w, event, prms, nprms)
5642 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5645 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5648 void LoadNextGameProc(w, event, prms, nprms)
5657 void LoadPrevGameProc(w, event, prms, nprms)
5666 void ReloadGameProc(w, event, prms, nprms)
5675 void LoadNextPositionProc(w, event, prms, nprms)
5684 void LoadPrevPositionProc(w, event, prms, nprms)
5693 void ReloadPositionProc(w, event, prms, nprms)
5702 void LoadPositionProc(w, event, prms, nprms)
5708 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5711 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5714 void SaveGameProc(w, event, prms, nprms)
5720 FileNamePopUp(_("Save game file name?"),
5721 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5725 void SavePositionProc(w, event, prms, nprms)
5731 FileNamePopUp(_("Save position file name?"),
5732 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5736 void ReloadCmailMsgProc(w, event, prms, nprms)
5742 ReloadCmailMsgEvent(FALSE);
5745 void MailMoveProc(w, event, prms, nprms)
5754 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5755 char *selected_fen_position=NULL;
5758 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5759 Atom *type_return, XtPointer *value_return,
5760 unsigned long *length_return, int *format_return)
5762 char *selection_tmp;
5764 if (!selected_fen_position) return False; /* should never happen */
5765 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5766 /* note: since no XtSelectionDoneProc was registered, Xt will
5767 * automatically call XtFree on the value returned. So have to
5768 * make a copy of it allocated with XtMalloc */
5769 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5770 safeStrCpy(selection_tmp, selected_fen_position, sizeof(selection_tmp)/sizeof(selection_tmp[0]) );
5772 *value_return=selection_tmp;
5773 *length_return=strlen(selection_tmp);
5774 *type_return=*target;
5775 *format_return = 8; /* bits per byte */
5777 } else if (*target == XA_TARGETS(xDisplay)) {
5778 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5779 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5780 targets_tmp[1] = XA_STRING;
5781 *value_return = targets_tmp;
5782 *type_return = XA_ATOM;
5784 *format_return = 8 * sizeof(Atom);
5785 if (*format_return > 32) {
5786 *length_return *= *format_return / 32;
5787 *format_return = 32;
5795 /* note: when called from menu all parameters are NULL, so no clue what the
5796 * Widget which was clicked on was, or what the click event was
5798 void CopyPositionProc(w, event, prms, nprms)
5805 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5806 * have a notion of a position that is selected but not copied.
5807 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5809 if(gameMode == EditPosition) EditPositionDone(TRUE);
5810 if (selected_fen_position) free(selected_fen_position);
5811 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5812 if (!selected_fen_position) return;
5813 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5815 SendPositionSelection,
5816 NULL/* lose_ownership_proc */ ,
5817 NULL/* transfer_done_proc */);
5818 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5820 SendPositionSelection,
5821 NULL/* lose_ownership_proc */ ,
5822 NULL/* transfer_done_proc */);
5825 /* function called when the data to Paste is ready */
5827 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5828 Atom *type, XtPointer value, unsigned long *len, int *format)
5831 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5832 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5833 EditPositionPasteFEN(fenstr);
5837 /* called when Paste Position button is pressed,
5838 * all parameters will be NULL */
5839 void PastePositionProc(w, event, prms, nprms)
5845 XtGetSelectionValue(menuBarWidget,
5846 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5847 /* (XtSelectionCallbackProc) */ PastePositionCB,
5848 NULL, /* client_data passed to PastePositionCB */
5850 /* better to use the time field from the event that triggered the
5851 * call to this function, but that isn't trivial to get
5859 SendGameSelection(Widget w, Atom *selection, Atom *target,
5860 Atom *type_return, XtPointer *value_return,
5861 unsigned long *length_return, int *format_return)
5863 char *selection_tmp;
5865 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5866 FILE* f = fopen(gameCopyFilename, "r");
5869 if (f == NULL) return False;
5873 selection_tmp = XtMalloc(len + 1);
5874 count = fread(selection_tmp, 1, len, f);
5876 XtFree(selection_tmp);
5879 selection_tmp[len] = NULLCHAR;
5880 *value_return = selection_tmp;
5881 *length_return = len;
5882 *type_return = *target;
5883 *format_return = 8; /* bits per byte */
5885 } else if (*target == XA_TARGETS(xDisplay)) {
5886 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5887 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5888 targets_tmp[1] = XA_STRING;
5889 *value_return = targets_tmp;
5890 *type_return = XA_ATOM;
5892 *format_return = 8 * sizeof(Atom);
5893 if (*format_return > 32) {
5894 *length_return *= *format_return / 32;
5895 *format_return = 32;
5903 /* note: when called from menu all parameters are NULL, so no clue what the
5904 * Widget which was clicked on was, or what the click event was
5906 void CopyGameProc(w, event, prms, nprms)
5914 ret = SaveGameToFile(gameCopyFilename, FALSE);
5918 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5919 * have a notion of a game that is selected but not copied.
5920 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5922 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5925 NULL/* lose_ownership_proc */ ,
5926 NULL/* transfer_done_proc */);
5927 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5930 NULL/* lose_ownership_proc */ ,
5931 NULL/* transfer_done_proc */);
5934 /* function called when the data to Paste is ready */
5936 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5937 Atom *type, XtPointer value, unsigned long *len, int *format)
5940 if (value == NULL || *len == 0) {
5941 return; /* nothing had been selected to copy */
5943 f = fopen(gamePasteFilename, "w");
5945 DisplayError(_("Can't open temp file"), errno);
5948 fwrite(value, 1, *len, f);
5951 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5954 /* called when Paste Game button is pressed,
5955 * all parameters will be NULL */
5956 void PasteGameProc(w, event, prms, nprms)
5962 XtGetSelectionValue(menuBarWidget,
5963 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5964 /* (XtSelectionCallbackProc) */ PasteGameCB,
5965 NULL, /* client_data passed to PasteGameCB */
5967 /* better to use the time field from the event that triggered the
5968 * call to this function, but that isn't trivial to get
5978 SaveGameProc(NULL, NULL, NULL, NULL);
5982 void QuitProc(w, event, prms, nprms)
5991 void PauseProc(w, event, prms, nprms)
6001 void MachineBlackProc(w, event, prms, nprms)
6007 MachineBlackEvent();
6010 void MachineWhiteProc(w, event, prms, nprms)
6016 MachineWhiteEvent();
6019 void AnalyzeModeProc(w, event, prms, nprms)
6027 if (!first.analysisSupport) {
6028 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6029 DisplayError(buf, 0);
6032 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6033 if (appData.icsActive) {
6034 if (gameMode != IcsObserving) {
6035 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6036 DisplayError(buf, 0);
6038 if (appData.icsEngineAnalyze) {
6039 if (appData.debugMode)
6040 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6046 /* if enable, use want disable icsEngineAnalyze */
6047 if (appData.icsEngineAnalyze) {
6052 appData.icsEngineAnalyze = TRUE;
6053 if (appData.debugMode)
6054 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6056 if (!appData.showThinking)
6057 ShowThinkingProc(w,event,prms,nprms);
6062 void AnalyzeFileProc(w, event, prms, nprms)
6068 if (!first.analysisSupport) {
6070 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6071 DisplayError(buf, 0);
6076 if (!appData.showThinking)
6077 ShowThinkingProc(w,event,prms,nprms);
6080 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6081 AnalysisPeriodicEvent(1);
6084 void TwoMachinesProc(w, event, prms, nprms)
6093 void IcsClientProc(w, event, prms, nprms)
6102 void EditGameProc(w, event, prms, nprms)
6111 void EditPositionProc(w, event, prms, nprms)
6117 EditPositionEvent();
6120 void TrainingProc(w, event, prms, nprms)
6129 void EditCommentProc(w, event, prms, nprms)
6136 EditCommentPopDown();
6142 void IcsInputBoxProc(w, event, prms, nprms)
6148 if (ICSInputBoxUp) {
6149 ICSInputBoxPopDown();
6155 void AcceptProc(w, event, prms, nprms)
6164 void DeclineProc(w, event, prms, nprms)
6173 void RematchProc(w, event, prms, nprms)
6182 void CallFlagProc(w, event, prms, nprms)
6191 void DrawProc(w, event, prms, nprms)
6200 void AbortProc(w, event, prms, nprms)
6209 void AdjournProc(w, event, prms, nprms)
6218 void ResignProc(w, event, prms, nprms)
6227 void AdjuWhiteProc(w, event, prms, nprms)
6233 UserAdjudicationEvent(+1);
6236 void AdjuBlackProc(w, event, prms, nprms)
6242 UserAdjudicationEvent(-1);
6245 void AdjuDrawProc(w, event, prms, nprms)
6251 UserAdjudicationEvent(0);
6254 void EnterKeyProc(w, event, prms, nprms)
6260 if (ICSInputBoxUp == True)
6264 void UpKeyProc(w, event, prms, nprms)
6269 { // [HGM] input: let up-arrow recall previous line from history
6276 if (!ICSInputBoxUp) return;
6277 edit = XtNameToWidget(ICSInputShell, "*form.text");
6279 XtSetArg(args[j], XtNstring, &val); j++;
6280 XtGetValues(edit, args, j);
6281 val = PrevInHistory(val);
6282 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6283 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6285 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6286 XawTextReplace(edit, 0, 0, &t);
6287 XawTextSetInsertionPoint(edit, 9999);
6291 void DownKeyProc(w, event, prms, nprms)
6296 { // [HGM] input: let down-arrow recall next line from history
6301 if (!ICSInputBoxUp) return;
6302 edit = XtNameToWidget(ICSInputShell, "*form.text");
6303 val = NextInHistory();
6304 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6305 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6307 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6308 XawTextReplace(edit, 0, 0, &t);
6309 XawTextSetInsertionPoint(edit, 9999);
6313 void StopObservingProc(w, event, prms, nprms)
6319 StopObservingEvent();
6322 void StopExaminingProc(w, event, prms, nprms)
6328 StopExaminingEvent();
6331 void UploadProc(w, event, prms, nprms)
6341 void ForwardProc(w, event, prms, nprms)
6351 void BackwardProc(w, event, prms, nprms)
6360 void ToStartProc(w, event, prms, nprms)
6369 void ToEndProc(w, event, prms, nprms)
6378 void RevertProc(w, event, prms, nprms)
6387 void AnnotateProc(w, event, prms, nprms)
6396 void TruncateGameProc(w, event, prms, nprms)
6402 TruncateGameEvent();
6404 void RetractMoveProc(w, event, prms, nprms)
6413 void MoveNowProc(w, event, prms, nprms)
6423 void AlwaysQueenProc(w, event, prms, nprms)
6431 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6433 if (appData.alwaysPromoteToQueen) {
6434 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6436 XtSetArg(args[0], XtNleftBitmap, None);
6438 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6442 void AnimateDraggingProc(w, event, prms, nprms)
6450 appData.animateDragging = !appData.animateDragging;
6452 if (appData.animateDragging) {
6453 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6456 XtSetArg(args[0], XtNleftBitmap, None);
6458 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6462 void AnimateMovingProc(w, event, prms, nprms)
6470 appData.animate = !appData.animate;
6472 if (appData.animate) {
6473 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6476 XtSetArg(args[0], XtNleftBitmap, None);
6478 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6482 void AutocommProc(w, event, prms, nprms)
6490 appData.autoComment = !appData.autoComment;
6492 if (appData.autoComment) {
6493 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6495 XtSetArg(args[0], XtNleftBitmap, None);
6497 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6502 void AutoflagProc(w, event, prms, nprms)
6510 appData.autoCallFlag = !appData.autoCallFlag;
6512 if (appData.autoCallFlag) {
6513 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6515 XtSetArg(args[0], XtNleftBitmap, None);
6517 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6521 void AutoflipProc(w, event, prms, nprms)
6529 appData.autoFlipView = !appData.autoFlipView;
6531 if (appData.autoFlipView) {
6532 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6534 XtSetArg(args[0], XtNleftBitmap, None);
6536 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6540 void AutobsProc(w, event, prms, nprms)
6548 appData.autoObserve = !appData.autoObserve;
6550 if (appData.autoObserve) {
6551 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6553 XtSetArg(args[0], XtNleftBitmap, None);
6555 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6559 void AutoraiseProc(w, event, prms, nprms)
6567 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6569 if (appData.autoRaiseBoard) {
6570 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6572 XtSetArg(args[0], XtNleftBitmap, None);
6574 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6578 void AutosaveProc(w, event, prms, nprms)
6586 appData.autoSaveGames = !appData.autoSaveGames;
6588 if (appData.autoSaveGames) {
6589 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6591 XtSetArg(args[0], XtNleftBitmap, None);
6593 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6597 void BlindfoldProc(w, event, prms, nprms)
6605 appData.blindfold = !appData.blindfold;
6607 if (appData.blindfold) {
6608 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6610 XtSetArg(args[0], XtNleftBitmap, None);
6612 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6615 DrawPosition(True, NULL);
6618 void TestLegalityProc(w, event, prms, nprms)
6626 appData.testLegality = !appData.testLegality;
6628 if (appData.testLegality) {
6629 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6631 XtSetArg(args[0], XtNleftBitmap, None);
6633 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6638 void FlashMovesProc(w, event, prms, nprms)
6646 if (appData.flashCount == 0) {
6647 appData.flashCount = 3;
6649 appData.flashCount = -appData.flashCount;
6652 if (appData.flashCount > 0) {
6653 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6655 XtSetArg(args[0], XtNleftBitmap, None);
6657 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6661 void FlipViewProc(w, event, prms, nprms)
6667 flipView = !flipView;
6668 DrawPosition(True, NULL);
6671 void GetMoveListProc(w, event, prms, nprms)
6679 appData.getMoveList = !appData.getMoveList;
6681 if (appData.getMoveList) {
6682 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6685 XtSetArg(args[0], XtNleftBitmap, None);
6687 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6692 void HighlightDraggingProc(w, event, prms, nprms)
6700 appData.highlightDragging = !appData.highlightDragging;
6702 if (appData.highlightDragging) {
6703 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6705 XtSetArg(args[0], XtNleftBitmap, None);
6707 XtSetValues(XtNameToWidget(menuBarWidget,
6708 "menuOptions.Highlight Dragging"), args, 1);
6712 void HighlightLastMoveProc(w, event, prms, nprms)
6720 appData.highlightLastMove = !appData.highlightLastMove;
6722 if (appData.highlightLastMove) {
6723 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6725 XtSetArg(args[0], XtNleftBitmap, None);
6727 XtSetValues(XtNameToWidget(menuBarWidget,
6728 "menuOptions.Highlight Last Move"), args, 1);
6731 void IcsAlarmProc(w, event, prms, nprms)
6739 appData.icsAlarm = !appData.icsAlarm;
6741 if (appData.icsAlarm) {
6742 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6744 XtSetArg(args[0], XtNleftBitmap, None);
6746 XtSetValues(XtNameToWidget(menuBarWidget,
6747 "menuOptions.ICS Alarm"), args, 1);
6750 void MoveSoundProc(w, event, prms, nprms)
6758 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6760 if (appData.ringBellAfterMoves) {
6761 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6763 XtSetArg(args[0], XtNleftBitmap, None);
6765 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6770 void OldSaveStyleProc(w, event, prms, nprms)
6778 appData.oldSaveStyle = !appData.oldSaveStyle;
6780 if (appData.oldSaveStyle) {
6781 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6783 XtSetArg(args[0], XtNleftBitmap, None);
6785 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6789 void PeriodicUpdatesProc(w, event, prms, nprms)
6797 PeriodicUpdatesEvent(!appData.periodicUpdates);
6799 if (appData.periodicUpdates) {
6800 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6802 XtSetArg(args[0], XtNleftBitmap, None);
6804 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6808 void PonderNextMoveProc(w, event, prms, nprms)
6816 PonderNextMoveEvent(!appData.ponderNextMove);
6818 if (appData.ponderNextMove) {
6819 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6821 XtSetArg(args[0], XtNleftBitmap, None);
6823 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6827 void PopupExitMessageProc(w, event, prms, nprms)
6835 appData.popupExitMessage = !appData.popupExitMessage;
6837 if (appData.popupExitMessage) {
6838 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6840 XtSetArg(args[0], XtNleftBitmap, None);
6842 XtSetValues(XtNameToWidget(menuBarWidget,
6843 "menuOptions.Popup Exit Message"), args, 1);
6846 void PopupMoveErrorsProc(w, event, prms, nprms)
6854 appData.popupMoveErrors = !appData.popupMoveErrors;
6856 if (appData.popupMoveErrors) {
6857 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6859 XtSetArg(args[0], XtNleftBitmap, None);
6861 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6865 void PremoveProc(w, event, prms, nprms)
6873 appData.premove = !appData.premove;
6875 if (appData.premove) {
6876 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6878 XtSetArg(args[0], XtNleftBitmap, None);
6880 XtSetValues(XtNameToWidget(menuBarWidget,
6881 "menuOptions.Premove"), args, 1);
6884 void QuietPlayProc(w, event, prms, nprms)
6892 appData.quietPlay = !appData.quietPlay;
6894 if (appData.quietPlay) {
6895 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6897 XtSetArg(args[0], XtNleftBitmap, None);
6899 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6903 void ShowCoordsProc(w, event, prms, nprms)
6911 appData.showCoords = !appData.showCoords;
6913 if (appData.showCoords) {
6914 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6916 XtSetArg(args[0], XtNleftBitmap, None);
6918 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6921 DrawPosition(True, NULL);
6924 void ShowThinkingProc(w, event, prms, nprms)
6930 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6931 ShowThinkingEvent();
6934 void HideThinkingProc(w, event, prms, nprms)
6942 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6943 ShowThinkingEvent();
6945 if (appData.hideThinkingFromHuman) {
6946 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6948 XtSetArg(args[0], XtNleftBitmap, None);
6950 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6954 void SaveOnExitProc(w, event, prms, nprms)
6962 saveSettingsOnExit = !saveSettingsOnExit;
6964 if (saveSettingsOnExit) {
6965 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6967 XtSetArg(args[0], XtNleftBitmap, None);
6969 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6973 void SaveSettingsProc(w, event, prms, nprms)
6979 SaveSettings(settingsFileName);
6982 void InfoProc(w, event, prms, nprms)
6989 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6994 void ManProc(w, event, prms, nprms)
7002 if (nprms && *nprms > 0)
7006 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7010 void HintProc(w, event, prms, nprms)
7019 void BookProc(w, event, prms, nprms)
7028 void AboutProc(w, event, prms, nprms)
7036 char *zippy = " (with Zippy code)";
7040 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7041 programVersion, zippy,
7042 "Copyright 1991 Digital Equipment Corporation",
7043 "Enhancements Copyright 1992-2009 Free Software Foundation",
7044 "Enhancements Copyright 2005 Alessandro Scotti",
7045 PACKAGE, " is free software and carries NO WARRANTY;",
7046 "see the file COPYING for more information.");
7047 ErrorPopUp(_("About XBoard"), buf, FALSE);
7050 void DebugProc(w, event, prms, nprms)
7056 appData.debugMode = !appData.debugMode;
7059 void AboutGameProc(w, event, prms, nprms)
7068 void NothingProc(w, event, prms, nprms)
7077 void Iconify(w, event, prms, nprms)
7086 XtSetArg(args[0], XtNiconic, True);
7087 XtSetValues(shellWidget, args, 1);
7090 void DisplayMessage(message, extMessage)
7091 char *message, *extMessage;
7093 /* display a message in the message widget */
7102 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7107 message = extMessage;
7111 /* need to test if messageWidget already exists, since this function
7112 can also be called during the startup, if for example a Xresource
7113 is not set up correctly */
7116 XtSetArg(arg, XtNlabel, message);
7117 XtSetValues(messageWidget, &arg, 1);
7123 void DisplayTitle(text)
7128 char title[MSG_SIZ];
7131 if (text == NULL) text = "";
7133 if (appData.titleInWindow) {
7135 XtSetArg(args[i], XtNlabel, text); i++;
7136 XtSetValues(titleWidget, args, i);
7139 if (*text != NULLCHAR) {
7140 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7141 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7142 } else if (appData.icsActive) {
7143 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7144 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7145 } else if (appData.cmailGameName[0] != NULLCHAR) {
7146 snprintf(icon, sizeof(icon), "%s", "CMail");
7147 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7149 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7150 } else if (gameInfo.variant == VariantGothic) {
7151 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7152 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7155 } else if (gameInfo.variant == VariantFalcon) {
7156 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7157 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7159 } else if (appData.noChessProgram) {
7160 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7161 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7163 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7164 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7167 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7168 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7169 XtSetValues(shellWidget, args, i);
7174 DisplayError(message, error)
7181 if (appData.debugMode || appData.matchMode) {
7182 fprintf(stderr, "%s: %s\n", programName, message);
7185 if (appData.debugMode || appData.matchMode) {
7186 fprintf(stderr, "%s: %s: %s\n",
7187 programName, message, strerror(error));
7189 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7192 ErrorPopUp(_("Error"), message, FALSE);
7196 void DisplayMoveError(message)
7201 DrawPosition(FALSE, NULL);
7202 if (appData.debugMode || appData.matchMode) {
7203 fprintf(stderr, "%s: %s\n", programName, message);
7205 if (appData.popupMoveErrors) {
7206 ErrorPopUp(_("Error"), message, FALSE);
7208 DisplayMessage(message, "");
7213 void DisplayFatalError(message, error, status)
7219 errorExitStatus = status;
7221 fprintf(stderr, "%s: %s\n", programName, message);
7223 fprintf(stderr, "%s: %s: %s\n",
7224 programName, message, strerror(error));
7225 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7228 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7229 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7235 void DisplayInformation(message)
7239 ErrorPopUp(_("Information"), message, TRUE);
7242 void DisplayNote(message)
7246 ErrorPopUp(_("Note"), message, FALSE);
7250 NullXErrorCheck(dpy, error_event)
7252 XErrorEvent *error_event;
7257 void DisplayIcsInteractionTitle(message)
7260 if (oldICSInteractionTitle == NULL) {
7261 /* Magic to find the old window title, adapted from vim */
7262 char *wina = getenv("WINDOWID");
7264 Window win = (Window) atoi(wina);
7265 Window root, parent, *children;
7266 unsigned int nchildren;
7267 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7269 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7270 if (!XQueryTree(xDisplay, win, &root, &parent,
7271 &children, &nchildren)) break;
7272 if (children) XFree((void *)children);
7273 if (parent == root || parent == 0) break;
7276 XSetErrorHandler(oldHandler);
7278 if (oldICSInteractionTitle == NULL) {
7279 oldICSInteractionTitle = "xterm";
7282 printf("\033]0;%s\007", message);
7286 char pendingReplyPrefix[MSG_SIZ];
7287 ProcRef pendingReplyPR;
7289 void AskQuestionProc(w, event, prms, nprms)
7296 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7300 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7303 void AskQuestionPopDown()
7305 if (!askQuestionUp) return;
7306 XtPopdown(askQuestionShell);
7307 XtDestroyWidget(askQuestionShell);
7308 askQuestionUp = False;
7311 void AskQuestionReplyAction(w, event, prms, nprms)
7321 reply = XawDialogGetValueString(w = XtParent(w));
7322 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7323 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7324 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7325 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7326 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7327 AskQuestionPopDown();
7329 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7332 void AskQuestionCallback(w, client_data, call_data)
7334 XtPointer client_data, call_data;
7339 XtSetArg(args[0], XtNlabel, &name);
7340 XtGetValues(w, args, 1);
7342 if (strcmp(name, _("cancel")) == 0) {
7343 AskQuestionPopDown();
7345 AskQuestionReplyAction(w, NULL, NULL, NULL);
7349 void AskQuestion(title, question, replyPrefix, pr)
7350 char *title, *question, *replyPrefix;
7354 Widget popup, layout, dialog, edit;
7360 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7361 pendingReplyPR = pr;
7364 XtSetArg(args[i], XtNresizable, True); i++;
7365 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7366 askQuestionShell = popup =
7367 XtCreatePopupShell(title, transientShellWidgetClass,
7368 shellWidget, args, i);
7371 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7372 layoutArgs, XtNumber(layoutArgs));
7375 XtSetArg(args[i], XtNlabel, question); i++;
7376 XtSetArg(args[i], XtNvalue, ""); i++;
7377 XtSetArg(args[i], XtNborderWidth, 0); i++;
7378 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7381 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7382 (XtPointer) dialog);
7383 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7384 (XtPointer) dialog);
7386 XtRealizeWidget(popup);
7387 CatchDeleteWindow(popup, "AskQuestionPopDown");
7389 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7390 &x, &y, &win_x, &win_y, &mask);
7392 XtSetArg(args[0], XtNx, x - 10);
7393 XtSetArg(args[1], XtNy, y - 30);
7394 XtSetValues(popup, args, 2);
7396 XtPopup(popup, XtGrabExclusive);
7397 askQuestionUp = True;
7399 edit = XtNameToWidget(dialog, "*value");
7400 XtSetKeyboardFocus(popup, edit);
7408 if (*name == NULLCHAR) {
7410 } else if (strcmp(name, "$") == 0) {
7411 putc(BELLCHAR, stderr);
7414 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7422 PlaySound(appData.soundMove);
7428 PlaySound(appData.soundIcsWin);
7434 PlaySound(appData.soundIcsLoss);
7440 PlaySound(appData.soundIcsDraw);
7444 PlayIcsUnfinishedSound()
7446 PlaySound(appData.soundIcsUnfinished);
7452 PlaySound(appData.soundIcsAlarm);
7458 system("stty echo");
7464 system("stty -echo");
7468 Colorize(cc, continuation)
7473 int count, outCount, error;
7475 if (textColors[(int)cc].bg > 0) {
7476 if (textColors[(int)cc].fg > 0) {
7477 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7478 textColors[(int)cc].fg, textColors[(int)cc].bg);
7480 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7481 textColors[(int)cc].bg);
7484 if (textColors[(int)cc].fg > 0) {
7485 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7486 textColors[(int)cc].fg);
7488 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7491 count = strlen(buf);
7492 outCount = OutputToProcess(NoProc, buf, count, &error);
7493 if (outCount < count) {
7494 DisplayFatalError(_("Error writing to display"), error, 1);
7497 if (continuation) return;
7500 PlaySound(appData.soundShout);
7503 PlaySound(appData.soundSShout);
7506 PlaySound(appData.soundChannel1);
7509 PlaySound(appData.soundChannel);
7512 PlaySound(appData.soundKibitz);
7515 PlaySound(appData.soundTell);
7517 case ColorChallenge:
7518 PlaySound(appData.soundChallenge);
7521 PlaySound(appData.soundRequest);
7524 PlaySound(appData.soundSeek);
7535 return getpwuid(getuid())->pw_name;
7539 ExpandPathName(path)
7542 static char static_buf[4*MSG_SIZ];
7543 char *d, *s, buf[4*MSG_SIZ];
7549 while (*s && isspace(*s))
7558 if (*(s+1) == '/') {
7559 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7563 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7564 *strchr(buf, '/') = 0;
7565 pwd = getpwnam(buf);
7568 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7572 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7573 strcat(d, strchr(s+1, '/'));
7577 safeStrCpy(d, s, 4*MSG_SIZ );
7584 static char host_name[MSG_SIZ];
7586 #if HAVE_GETHOSTNAME
7587 gethostname(host_name, MSG_SIZ);
7589 #else /* not HAVE_GETHOSTNAME */
7590 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7591 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7593 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7595 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7596 #endif /* not HAVE_GETHOSTNAME */
7599 XtIntervalId delayedEventTimerXID = 0;
7600 DelayedEventCallback delayedEventCallback = 0;
7605 delayedEventTimerXID = 0;
7606 delayedEventCallback();
7610 ScheduleDelayedEvent(cb, millisec)
7611 DelayedEventCallback cb; long millisec;
7613 if(delayedEventTimerXID && delayedEventCallback == cb)
7614 // [HGM] alive: replace, rather than add or flush identical event
7615 XtRemoveTimeOut(delayedEventTimerXID);
7616 delayedEventCallback = cb;
7617 delayedEventTimerXID =
7618 XtAppAddTimeOut(appContext, millisec,
7619 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7622 DelayedEventCallback
7625 if (delayedEventTimerXID) {
7626 return delayedEventCallback;
7633 CancelDelayedEvent()
7635 if (delayedEventTimerXID) {
7636 XtRemoveTimeOut(delayedEventTimerXID);
7637 delayedEventTimerXID = 0;
7641 XtIntervalId loadGameTimerXID = 0;
7643 int LoadGameTimerRunning()
7645 return loadGameTimerXID != 0;
7648 int StopLoadGameTimer()
7650 if (loadGameTimerXID != 0) {
7651 XtRemoveTimeOut(loadGameTimerXID);
7652 loadGameTimerXID = 0;
7660 LoadGameTimerCallback(arg, id)
7664 loadGameTimerXID = 0;
7669 StartLoadGameTimer(millisec)
7673 XtAppAddTimeOut(appContext, millisec,
7674 (XtTimerCallbackProc) LoadGameTimerCallback,
7678 XtIntervalId analysisClockXID = 0;
7681 AnalysisClockCallback(arg, id)
7685 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7686 || appData.icsEngineAnalyze) { // [DM]
7687 AnalysisPeriodicEvent(0);
7688 StartAnalysisClock();
7693 StartAnalysisClock()
7696 XtAppAddTimeOut(appContext, 2000,
7697 (XtTimerCallbackProc) AnalysisClockCallback,
7701 XtIntervalId clockTimerXID = 0;
7703 int ClockTimerRunning()
7705 return clockTimerXID != 0;
7708 int StopClockTimer()
7710 if (clockTimerXID != 0) {
7711 XtRemoveTimeOut(clockTimerXID);
7720 ClockTimerCallback(arg, id)
7729 StartClockTimer(millisec)
7733 XtAppAddTimeOut(appContext, millisec,
7734 (XtTimerCallbackProc) ClockTimerCallback,
7739 DisplayTimerLabel(w, color, timer, highlight)
7748 /* check for low time warning */
7749 Pixel foregroundOrWarningColor = timerForegroundPixel;
7752 appData.lowTimeWarning &&
7753 (timer / 1000) < appData.icsAlarmTime)
7754 foregroundOrWarningColor = lowTimeWarningColor;
7756 if (appData.clockMode) {
7757 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7758 XtSetArg(args[0], XtNlabel, buf);
7760 snprintf(buf, MSG_SIZ, "%s ", color);
7761 XtSetArg(args[0], XtNlabel, buf);
7766 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7767 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7769 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7770 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7773 XtSetValues(w, args, 3);
7777 DisplayWhiteClock(timeRemaining, highlight)
7783 if(appData.noGUI) return;
7784 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7785 if (highlight && iconPixmap == bIconPixmap) {
7786 iconPixmap = wIconPixmap;
7787 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7788 XtSetValues(shellWidget, args, 1);
7793 DisplayBlackClock(timeRemaining, highlight)
7799 if(appData.noGUI) return;
7800 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7801 if (highlight && iconPixmap == wIconPixmap) {
7802 iconPixmap = bIconPixmap;
7803 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7804 XtSetValues(shellWidget, args, 1);
7822 int StartChildProcess(cmdLine, dir, pr)
7829 int to_prog[2], from_prog[2];
7833 if (appData.debugMode) {
7834 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7837 /* We do NOT feed the cmdLine to the shell; we just
7838 parse it into blank-separated arguments in the
7839 most simple-minded way possible.
7842 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7845 while(*p == ' ') p++;
7847 if(*p == '"' || *p == '\'')
7848 p = strchr(++argv[i-1], *p);
7849 else p = strchr(p, ' ');
7850 if (p == NULL) break;
7855 SetUpChildIO(to_prog, from_prog);
7857 if ((pid = fork()) == 0) {
7859 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7860 close(to_prog[1]); // first close the unused pipe ends
7861 close(from_prog[0]);
7862 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7863 dup2(from_prog[1], 1);
7864 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7865 close(from_prog[1]); // and closing again loses one of the pipes!
7866 if(fileno(stderr) >= 2) // better safe than sorry...
7867 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7869 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7874 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7876 execvp(argv[0], argv);
7878 /* If we get here, exec failed */
7883 /* Parent process */
7885 close(from_prog[1]);
7887 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7890 cp->fdFrom = from_prog[0];
7891 cp->fdTo = to_prog[1];
7896 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7897 static RETSIGTYPE AlarmCallBack(int n)
7903 DestroyChildProcess(pr, signalType)
7907 ChildProc *cp = (ChildProc *) pr;
7909 if (cp->kind != CPReal) return;
7911 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7912 signal(SIGALRM, AlarmCallBack);
7914 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7915 kill(cp->pid, SIGKILL); // kill it forcefully
7916 wait((int *) 0); // and wait again
7920 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7922 /* Process is exiting either because of the kill or because of
7923 a quit command sent by the backend; either way, wait for it to die.
7932 InterruptChildProcess(pr)
7935 ChildProc *cp = (ChildProc *) pr;
7937 if (cp->kind != CPReal) return;
7938 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7941 int OpenTelnet(host, port, pr)
7946 char cmdLine[MSG_SIZ];
7948 if (port[0] == NULLCHAR) {
7949 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7951 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7953 return StartChildProcess(cmdLine, "", pr);
7956 int OpenTCP(host, port, pr)
7962 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7963 #else /* !OMIT_SOCKETS */
7965 struct sockaddr_in sa;
7967 unsigned short uport;
7970 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7974 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7975 sa.sin_family = AF_INET;
7976 sa.sin_addr.s_addr = INADDR_ANY;
7977 uport = (unsigned short) 0;
7978 sa.sin_port = htons(uport);
7979 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7983 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7984 if (!(hp = gethostbyname(host))) {
7986 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7987 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7988 hp->h_addrtype = AF_INET;
7990 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7991 hp->h_addr_list[0] = (char *) malloc(4);
7992 hp->h_addr_list[0][0] = b0;
7993 hp->h_addr_list[0][1] = b1;
7994 hp->h_addr_list[0][2] = b2;
7995 hp->h_addr_list[0][3] = b3;
8000 sa.sin_family = hp->h_addrtype;
8001 uport = (unsigned short) atoi(port);
8002 sa.sin_port = htons(uport);
8003 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8005 if (connect(s, (struct sockaddr *) &sa,
8006 sizeof(struct sockaddr_in)) < 0) {
8010 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8017 #endif /* !OMIT_SOCKETS */
8022 int OpenCommPort(name, pr)
8029 fd = open(name, 2, 0);
8030 if (fd < 0) return errno;
8032 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8042 int OpenLoopback(pr)
8048 SetUpChildIO(to, from);
8050 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8053 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8060 int OpenRcmd(host, user, cmd, pr)
8061 char *host, *user, *cmd;
8064 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8068 #define INPUT_SOURCE_BUF_SIZE 8192
8077 char buf[INPUT_SOURCE_BUF_SIZE];
8082 DoInputCallback(closure, source, xid)
8087 InputSource *is = (InputSource *) closure;
8092 if (is->lineByLine) {
8093 count = read(is->fd, is->unused,
8094 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8096 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8099 is->unused += count;
8101 while (p < is->unused) {
8102 q = memchr(p, '\n', is->unused - p);
8103 if (q == NULL) break;
8105 (is->func)(is, is->closure, p, q - p, 0);
8109 while (p < is->unused) {
8114 # if HAVE_LIBREADLINE
8115 /* check if input is from stdin, if yes, use gnu-readline */
8116 if( is->fd==fileno(stdin) )
8118 /* to clear the line */
8121 /* read from stdin */
8122 rl_callback_read_char();
8124 /* redisplay the current line, check special case for login and password */
8125 if(sending_ICS_password)
8127 int i; char buf[MSG_SIZ];
8131 /* blank the password */
8132 count = strlen(rl_line_buffer);
8135 printf("PROBLEM with readline\n");
8138 for(i=0;i<count;i++)
8142 printf("\rpassword: %s",buf);
8144 else if (sending_ICS_login)
8146 /* show login prompt */
8147 count = strlen(rl_line_buffer);
8148 printf("\rlogin: %s",rl_line_buffer);
8151 rl_reset_line_state();
8153 if(readline_complete)
8155 /* copy into XBoards buffer */
8156 count = strlen(readline_buffer);
8157 if (count>INPUT_SOURCE_BUF_SIZE-1)
8159 printf("PROBLEM with readline\n");
8160 count = INPUT_SOURCE_BUF_SIZE;
8162 strncpy(is->buf,readline_buffer,count);
8163 is->buf[count]='\n';count++;
8165 /* reset gnu-readline state */
8166 free(readline_buffer);
8167 readline_buffer=NULL;
8168 readline_complete=0;
8174 (is->func)(is, is->closure, is->buf, count, error);
8176 /* are we done with the password? */
8177 if(sending_ICS_password)
8178 sending_ICS_password=0;
8179 if(sending_ICS_login)
8180 sending_ICS_login=0;
8185 /* input not from stdin, use default method */
8186 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8191 (is->func)(is, is->closure, is->buf, count, error);
8193 #else /* no readline support */
8194 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8199 (is->func)(is, is->closure, is->buf, count, error);
8205 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8212 ChildProc *cp = (ChildProc *) pr;
8214 is = (InputSource *) calloc(1, sizeof(InputSource));
8215 is->lineByLine = lineByLine;
8219 is->fd = fileno(stdin);
8221 is->kind = cp->kind;
8222 is->fd = cp->fdFrom;
8225 is->unused = is->buf;
8228 is->xid = XtAppAddInput(appContext, is->fd,
8229 (XtPointer) (XtInputReadMask),
8230 (XtInputCallbackProc) DoInputCallback,
8232 is->closure = closure;
8233 return (InputSourceRef) is;
8237 RemoveInputSource(isr)
8240 InputSource *is = (InputSource *) isr;
8242 if (is->xid == 0) return;
8243 XtRemoveInput(is->xid);
8247 int OutputToProcess(pr, message, count, outError)
8253 static int line = 0;
8254 ChildProc *cp = (ChildProc *) pr;
8260 if (appData.noJoin || !appData.useInternalWrap)
8261 outCount = fwrite(message, 1, count, stdout);
8264 int width = get_term_width();
8265 int len = wrap(NULL, message, count, width, &line);
8266 char *msg = malloc(len);
8270 outCount = fwrite(message, 1, count, stdout);
8273 dbgchk = wrap(msg, message, count, width, &line);
8274 if (dbgchk != len && appData.debugMode)
8275 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8276 outCount = fwrite(msg, 1, dbgchk, stdout);
8281 # if HAVE_LIBREADLINE
8282 /* readline support */
8283 if(strlen(rl_line_buffer))
8284 printf("\n> %s",rl_line_buffer);
8289 outCount = write(cp->fdTo, message, count);
8299 /* Output message to process, with "ms" milliseconds of delay
8300 between each character. This is needed when sending the logon
8301 script to ICC, which for some reason doesn't like the
8302 instantaneous send. */
8303 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8310 ChildProc *cp = (ChildProc *) pr;
8315 r = write(cp->fdTo, message++, 1);
8328 /**** Animation code by Hugh Fisher, DCS, ANU.
8330 Known problem: if a window overlapping the board is
8331 moved away while a piece is being animated underneath,
8332 the newly exposed area won't be updated properly.
8333 I can live with this.
8335 Known problem: if you look carefully at the animation
8336 of pieces in mono mode, they are being drawn as solid
8337 shapes without interior detail while moving. Fixing
8338 this would be a major complication for minimal return.
8341 /* Masks for XPM pieces. Black and white pieces can have
8342 different shapes, but in the interest of retaining my
8343 sanity pieces must have the same outline on both light
8344 and dark squares, and all pieces must use the same
8345 background square colors/images. */
8347 static int xpmDone = 0;
8350 CreateAnimMasks (pieceDepth)
8357 unsigned long plane;
8360 /* Need a bitmap just to get a GC with right depth */
8361 buf = XCreatePixmap(xDisplay, xBoardWindow,
8363 values.foreground = 1;
8364 values.background = 0;
8365 /* Don't use XtGetGC, not read only */
8366 maskGC = XCreateGC(xDisplay, buf,
8367 GCForeground | GCBackground, &values);
8368 XFreePixmap(xDisplay, buf);
8370 buf = XCreatePixmap(xDisplay, xBoardWindow,
8371 squareSize, squareSize, pieceDepth);
8372 values.foreground = XBlackPixel(xDisplay, xScreen);
8373 values.background = XWhitePixel(xDisplay, xScreen);
8374 bufGC = XCreateGC(xDisplay, buf,
8375 GCForeground | GCBackground, &values);
8377 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8378 /* Begin with empty mask */
8379 if(!xpmDone) // [HGM] pieces: keep using existing
8380 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8381 squareSize, squareSize, 1);
8382 XSetFunction(xDisplay, maskGC, GXclear);
8383 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8384 0, 0, squareSize, squareSize);
8386 /* Take a copy of the piece */
8391 XSetFunction(xDisplay, bufGC, GXcopy);
8392 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8394 0, 0, squareSize, squareSize, 0, 0);
8396 /* XOR the background (light) over the piece */
8397 XSetFunction(xDisplay, bufGC, GXxor);
8399 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8400 0, 0, squareSize, squareSize, 0, 0);
8402 XSetForeground(xDisplay, bufGC, lightSquareColor);
8403 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8406 /* We now have an inverted piece image with the background
8407 erased. Construct mask by just selecting all the non-zero
8408 pixels - no need to reconstruct the original image. */
8409 XSetFunction(xDisplay, maskGC, GXor);
8411 /* Might be quicker to download an XImage and create bitmap
8412 data from it rather than this N copies per piece, but it
8413 only takes a fraction of a second and there is a much
8414 longer delay for loading the pieces. */
8415 for (n = 0; n < pieceDepth; n ++) {
8416 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8417 0, 0, squareSize, squareSize,
8423 XFreePixmap(xDisplay, buf);
8424 XFreeGC(xDisplay, bufGC);
8425 XFreeGC(xDisplay, maskGC);
8429 InitAnimState (anim, info)
8431 XWindowAttributes * info;
8436 /* Each buffer is square size, same depth as window */
8437 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8438 squareSize, squareSize, info->depth);
8439 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8440 squareSize, squareSize, info->depth);
8442 /* Create a plain GC for blitting */
8443 mask = GCForeground | GCBackground | GCFunction |
8444 GCPlaneMask | GCGraphicsExposures;
8445 values.foreground = XBlackPixel(xDisplay, xScreen);
8446 values.background = XWhitePixel(xDisplay, xScreen);
8447 values.function = GXcopy;
8448 values.plane_mask = AllPlanes;
8449 values.graphics_exposures = False;
8450 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8452 /* Piece will be copied from an existing context at
8453 the start of each new animation/drag. */
8454 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8456 /* Outline will be a read-only copy of an existing */
8457 anim->outlineGC = None;
8463 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8464 XWindowAttributes info;
8466 if (xpmDone && gameInfo.variant == old) return;
8467 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8468 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8470 InitAnimState(&game, &info);
8471 InitAnimState(&player, &info);
8473 /* For XPM pieces, we need bitmaps to use as masks. */
8475 CreateAnimMasks(info.depth);
8481 static Boolean frameWaiting;
8483 static RETSIGTYPE FrameAlarm (sig)
8486 frameWaiting = False;
8487 /* In case System-V style signals. Needed?? */
8488 signal(SIGALRM, FrameAlarm);
8495 struct itimerval delay;
8497 XSync(xDisplay, False);
8500 frameWaiting = True;
8501 signal(SIGALRM, FrameAlarm);
8502 delay.it_interval.tv_sec =
8503 delay.it_value.tv_sec = time / 1000;
8504 delay.it_interval.tv_usec =
8505 delay.it_value.tv_usec = (time % 1000) * 1000;
8506 setitimer(ITIMER_REAL, &delay, NULL);
8507 while (frameWaiting) pause();
8508 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8509 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8510 setitimer(ITIMER_REAL, &delay, NULL);
8520 XSync(xDisplay, False);
8522 usleep(time * 1000);
8527 /* Convert board position to corner of screen rect and color */
8530 ScreenSquare(column, row, pt, color)
8531 int column; int row; XPoint * pt; int * color;
8534 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8535 pt->y = lineGap + row * (squareSize + lineGap);
8537 pt->x = lineGap + column * (squareSize + lineGap);
8538 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8540 *color = SquareColor(row, column);
8543 /* Convert window coords to square */
8546 BoardSquare(x, y, column, row)
8547 int x; int y; int * column; int * row;
8549 *column = EventToSquare(x, BOARD_WIDTH);
8550 if (flipView && *column >= 0)
8551 *column = BOARD_WIDTH - 1 - *column;
8552 *row = EventToSquare(y, BOARD_HEIGHT);
8553 if (!flipView && *row >= 0)
8554 *row = BOARD_HEIGHT - 1 - *row;
8559 #undef Max /* just in case */
8561 #define Max(a, b) ((a) > (b) ? (a) : (b))
8562 #define Min(a, b) ((a) < (b) ? (a) : (b))
8565 SetRect(rect, x, y, width, height)
8566 XRectangle * rect; int x; int y; int width; int height;
8570 rect->width = width;
8571 rect->height = height;
8574 /* Test if two frames overlap. If they do, return
8575 intersection rect within old and location of
8576 that rect within new. */
8579 Intersect(old, new, size, area, pt)
8580 XPoint * old; XPoint * new;
8581 int size; XRectangle * area; XPoint * pt;
8583 if (old->x > new->x + size || new->x > old->x + size ||
8584 old->y > new->y + size || new->y > old->y + size) {
8587 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8588 size - abs(old->x - new->x), size - abs(old->y - new->y));
8589 pt->x = Max(old->x - new->x, 0);
8590 pt->y = Max(old->y - new->y, 0);
8595 /* For two overlapping frames, return the rect(s)
8596 in the old that do not intersect with the new. */
8599 CalcUpdateRects(old, new, size, update, nUpdates)
8600 XPoint * old; XPoint * new; int size;
8601 XRectangle update[]; int * nUpdates;
8605 /* If old = new (shouldn't happen) then nothing to draw */
8606 if (old->x == new->x && old->y == new->y) {
8610 /* Work out what bits overlap. Since we know the rects
8611 are the same size we don't need a full intersect calc. */
8613 /* Top or bottom edge? */
8614 if (new->y > old->y) {
8615 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8617 } else if (old->y > new->y) {
8618 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8619 size, old->y - new->y);
8622 /* Left or right edge - don't overlap any update calculated above. */
8623 if (new->x > old->x) {
8624 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8625 new->x - old->x, size - abs(new->y - old->y));
8627 } else if (old->x > new->x) {
8628 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8629 old->x - new->x, size - abs(new->y - old->y));
8636 /* Generate a series of frame coords from start->mid->finish.
8637 The movement rate doubles until the half way point is
8638 reached, then halves back down to the final destination,
8639 which gives a nice slow in/out effect. The algorithmn
8640 may seem to generate too many intermediates for short
8641 moves, but remember that the purpose is to attract the
8642 viewers attention to the piece about to be moved and
8643 then to where it ends up. Too few frames would be less
8647 Tween(start, mid, finish, factor, frames, nFrames)
8648 XPoint * start; XPoint * mid;
8649 XPoint * finish; int factor;
8650 XPoint frames[]; int * nFrames;
8652 int fraction, n, count;
8656 /* Slow in, stepping 1/16th, then 1/8th, ... */
8658 for (n = 0; n < factor; n++)
8660 for (n = 0; n < factor; n++) {
8661 frames[count].x = start->x + (mid->x - start->x) / fraction;
8662 frames[count].y = start->y + (mid->y - start->y) / fraction;
8664 fraction = fraction / 2;
8668 frames[count] = *mid;
8671 /* Slow out, stepping 1/2, then 1/4, ... */
8673 for (n = 0; n < factor; n++) {
8674 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8675 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8677 fraction = fraction * 2;
8682 /* Draw a piece on the screen without disturbing what's there */
8685 SelectGCMask(piece, clip, outline, mask)
8686 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8690 /* Bitmap for piece being moved. */
8691 if (appData.monoMode) {
8692 *mask = *pieceToSolid(piece);
8693 } else if (useImages) {
8695 *mask = xpmMask[piece];
8697 *mask = ximMaskPm[piece];
8700 *mask = *pieceToSolid(piece);
8703 /* GC for piece being moved. Square color doesn't matter, but
8704 since it gets modified we make a copy of the original. */
8706 if (appData.monoMode)
8711 if (appData.monoMode)
8716 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8718 /* Outline only used in mono mode and is not modified */
8720 *outline = bwPieceGC;
8722 *outline = wbPieceGC;
8726 OverlayPiece(piece, clip, outline, dest)
8727 ChessSquare piece; GC clip; GC outline; Drawable dest;
8732 /* Draw solid rectangle which will be clipped to shape of piece */
8733 XFillRectangle(xDisplay, dest, clip,
8734 0, 0, squareSize, squareSize);
8735 if (appData.monoMode)
8736 /* Also draw outline in contrasting color for black
8737 on black / white on white cases */
8738 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8739 0, 0, squareSize, squareSize, 0, 0, 1);
8741 /* Copy the piece */
8746 if(appData.upsideDown && flipView) kind ^= 2;
8747 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8749 0, 0, squareSize, squareSize,
8754 /* Animate the movement of a single piece */
8757 BeginAnimation(anim, piece, startColor, start)
8765 /* The old buffer is initialised with the start square (empty) */
8766 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8767 anim->prevFrame = *start;
8769 /* The piece will be drawn using its own bitmap as a matte */
8770 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8771 XSetClipMask(xDisplay, anim->pieceGC, mask);
8775 AnimationFrame(anim, frame, piece)
8780 XRectangle updates[4];
8785 /* Save what we are about to draw into the new buffer */
8786 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8787 frame->x, frame->y, squareSize, squareSize,
8790 /* Erase bits of the previous frame */
8791 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8792 /* Where the new frame overlapped the previous,
8793 the contents in newBuf are wrong. */
8794 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8795 overlap.x, overlap.y,
8796 overlap.width, overlap.height,
8798 /* Repaint the areas in the old that don't overlap new */
8799 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8800 for (i = 0; i < count; i++)
8801 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8802 updates[i].x - anim->prevFrame.x,
8803 updates[i].y - anim->prevFrame.y,
8804 updates[i].width, updates[i].height,
8805 updates[i].x, updates[i].y);
8807 /* Easy when no overlap */
8808 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8809 0, 0, squareSize, squareSize,
8810 anim->prevFrame.x, anim->prevFrame.y);
8813 /* Save this frame for next time round */
8814 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8815 0, 0, squareSize, squareSize,
8817 anim->prevFrame = *frame;
8819 /* Draw piece over original screen contents, not current,
8820 and copy entire rect. Wipes out overlapping piece images. */
8821 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8822 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8823 0, 0, squareSize, squareSize,
8824 frame->x, frame->y);
8828 EndAnimation (anim, finish)
8832 XRectangle updates[4];
8837 /* The main code will redraw the final square, so we
8838 only need to erase the bits that don't overlap. */
8839 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8840 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8841 for (i = 0; i < count; i++)
8842 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8843 updates[i].x - anim->prevFrame.x,
8844 updates[i].y - anim->prevFrame.y,
8845 updates[i].width, updates[i].height,
8846 updates[i].x, updates[i].y);
8848 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8849 0, 0, squareSize, squareSize,
8850 anim->prevFrame.x, anim->prevFrame.y);
8855 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8857 ChessSquare piece; int startColor;
8858 XPoint * start; XPoint * finish;
8859 XPoint frames[]; int nFrames;
8863 BeginAnimation(anim, piece, startColor, start);
8864 for (n = 0; n < nFrames; n++) {
8865 AnimationFrame(anim, &(frames[n]), piece);
8866 FrameDelay(appData.animSpeed);
8868 EndAnimation(anim, finish);
8871 /* Main control logic for deciding what to animate and how */
8874 AnimateMove(board, fromX, fromY, toX, toY)
8883 XPoint start, finish, mid;
8884 XPoint frames[kFactor * 2 + 1];
8885 int nFrames, startColor, endColor;
8887 /* Are we animating? */
8888 if (!appData.animate || appData.blindfold)
8891 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8892 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8893 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8895 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8896 piece = board[fromY][fromX];
8897 if (piece >= EmptySquare) return;
8902 hop = (piece == WhiteKnight || piece == BlackKnight);
8905 if (appData.debugMode) {
8906 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8907 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8908 piece, fromX, fromY, toX, toY); }
8910 ScreenSquare(fromX, fromY, &start, &startColor);
8911 ScreenSquare(toX, toY, &finish, &endColor);
8914 /* Knight: make diagonal movement then straight */
8915 if (abs(toY - fromY) < abs(toX - fromX)) {
8916 mid.x = start.x + (finish.x - start.x) / 2;
8920 mid.y = start.y + (finish.y - start.y) / 2;
8923 mid.x = start.x + (finish.x - start.x) / 2;
8924 mid.y = start.y + (finish.y - start.y) / 2;
8927 /* Don't use as many frames for very short moves */
8928 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8929 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8931 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8932 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8934 /* Be sure end square is redrawn */
8935 damage[0][toY][toX] = True;
8939 DragPieceBegin(x, y)
8942 int boardX, boardY, color;
8945 /* Are we animating? */
8946 if (!appData.animateDragging || appData.blindfold)
8949 /* Figure out which square we start in and the
8950 mouse position relative to top left corner. */
8951 BoardSquare(x, y, &boardX, &boardY);
8952 player.startBoardX = boardX;
8953 player.startBoardY = boardY;
8954 ScreenSquare(boardX, boardY, &corner, &color);
8955 player.startSquare = corner;
8956 player.startColor = color;
8957 /* As soon as we start dragging, the piece will jump slightly to
8958 be centered over the mouse pointer. */
8959 player.mouseDelta.x = squareSize/2;
8960 player.mouseDelta.y = squareSize/2;
8961 /* Initialise animation */
8962 player.dragPiece = PieceForSquare(boardX, boardY);
8964 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8965 player.dragActive = True;
8966 BeginAnimation(&player, player.dragPiece, color, &corner);
8967 /* Mark this square as needing to be redrawn. Note that
8968 we don't remove the piece though, since logically (ie
8969 as seen by opponent) the move hasn't been made yet. */
8970 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8971 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8972 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8973 corner.x, corner.y, squareSize, squareSize,
8974 0, 0); // [HGM] zh: unstack in stead of grab
8975 damage[0][boardY][boardX] = True;
8977 player.dragActive = False;
8987 /* Are we animating? */
8988 if (!appData.animateDragging || appData.blindfold)
8992 if (! player.dragActive)
8994 /* Move piece, maintaining same relative position
8995 of mouse within square */
8996 corner.x = x - player.mouseDelta.x;
8997 corner.y = y - player.mouseDelta.y;
8998 AnimationFrame(&player, &corner, player.dragPiece);
9000 if (appData.highlightDragging) {
9002 BoardSquare(x, y, &boardX, &boardY);
9003 SetHighlights(fromX, fromY, boardX, boardY);
9012 int boardX, boardY, color;
9015 /* Are we animating? */
9016 if (!appData.animateDragging || appData.blindfold)
9020 if (! player.dragActive)
9022 /* Last frame in sequence is square piece is
9023 placed on, which may not match mouse exactly. */
9024 BoardSquare(x, y, &boardX, &boardY);
9025 ScreenSquare(boardX, boardY, &corner, &color);
9026 EndAnimation(&player, &corner);
9028 /* Be sure end square is redrawn */
9029 damage[0][boardY][boardX] = True;
9031 /* This prevents weird things happening with fast successive
9032 clicks which on my Sun at least can cause motion events
9033 without corresponding press/release. */
9034 player.dragActive = False;
9037 /* Handle expose event while piece being dragged */
9042 if (!player.dragActive || appData.blindfold)
9045 /* What we're doing: logically, the move hasn't been made yet,
9046 so the piece is still in it's original square. But visually
9047 it's being dragged around the board. So we erase the square
9048 that the piece is on and draw it at the last known drag point. */
9049 BlankSquare(player.startSquare.x, player.startSquare.y,
9050 player.startColor, EmptySquare, xBoardWindow);
9051 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9052 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9055 #include <sys/ioctl.h>
9056 int get_term_width()
9058 int fd, default_width;
9061 default_width = 79; // this is FICS default anyway...
9063 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9065 if (!ioctl(fd, TIOCGSIZE, &win))
9066 default_width = win.ts_cols;
9067 #elif defined(TIOCGWINSZ)
9069 if (!ioctl(fd, TIOCGWINSZ, &win))
9070 default_width = win.ws_col;
9072 return default_width;
9078 static int old_width = 0;
9079 int new_width = get_term_width();
9081 if (old_width != new_width)
9082 ics_printf("set width %d\n", new_width);
9083 old_width = new_width;
9086 void NotifyFrontendLogin()
9091 # if HAVE_LIBREADLINE
9093 ReadlineCompleteHandler(char* ptr)
9095 /* make gnu-readline keep the history */
9096 readline_buffer = ptr;
9097 readline_complete = 1;
9099 if (ptr && *ptr && !sending_ICS_password && !sending_ICS_login)