PageRenderTime 74ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 2ms

/xboard-4.5.2a/xboard.c

#
C | 9144 lines | 7958 code | 806 blank | 380 comment | 1103 complexity | 3223cfc3085b0c66253d8eceeb9a6be2 MD5 | raw file
Possible License(s): GPL-3.0, MPL-2.0-no-copyleft-exception
  1. /*
  2. * xboard.c -- X front end for XBoard
  3. *
  4. * Copyright 1991 by Digital Equipment Corporation, Maynard,
  5. * Massachusetts.
  6. *
  7. * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
  8. * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
  9. *
  10. * The following terms apply to Digital Equipment Corporation's copyright
  11. * interest in XBoard:
  12. * ------------------------------------------------------------------------
  13. * All Rights Reserved
  14. *
  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.
  22. *
  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
  29. * SOFTWARE.
  30. * ------------------------------------------------------------------------
  31. *
  32. * The following terms apply to the enhanced version of XBoard
  33. * distributed by the Free Software Foundation:
  34. * ------------------------------------------------------------------------
  35. *
  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.
  40. *
  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.
  45. *
  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/. *
  48. *
  49. *------------------------------------------------------------------------
  50. ** See the file ChangeLog for a revision history. */
  51. #define HIGHDRAG 1
  52. #include "config.h"
  53. #include <stdio.h>
  54. #include <ctype.h>
  55. #include <signal.h>
  56. #include <errno.h>
  57. #include <sys/types.h>
  58. #include <sys/stat.h>
  59. #include <pwd.h>
  60. #include <math.h>
  61. #if !OMIT_SOCKETS
  62. # if HAVE_SYS_SOCKET_H
  63. # include <sys/socket.h>
  64. # include <netinet/in.h>
  65. # include <netdb.h>
  66. # else /* not HAVE_SYS_SOCKET_H */
  67. # if HAVE_LAN_SOCKET_H
  68. # include <lan/socket.h>
  69. # include <lan/in.h>
  70. # include <lan/netdb.h>
  71. # else /* not HAVE_LAN_SOCKET_H */
  72. # define OMIT_SOCKETS 1
  73. # endif /* not HAVE_LAN_SOCKET_H */
  74. # endif /* not HAVE_SYS_SOCKET_H */
  75. #endif /* !OMIT_SOCKETS */
  76. #if STDC_HEADERS
  77. # include <stdlib.h>
  78. # include <string.h>
  79. #else /* not STDC_HEADERS */
  80. extern char *getenv();
  81. # if HAVE_STRING_H
  82. # include <string.h>
  83. # else /* not HAVE_STRING_H */
  84. # include <strings.h>
  85. # endif /* not HAVE_STRING_H */
  86. #endif /* not STDC_HEADERS */
  87. #if HAVE_SYS_FCNTL_H
  88. # include <sys/fcntl.h>
  89. #else /* not HAVE_SYS_FCNTL_H */
  90. # if HAVE_FCNTL_H
  91. # include <fcntl.h>
  92. # endif /* HAVE_FCNTL_H */
  93. #endif /* not HAVE_SYS_FCNTL_H */
  94. #if HAVE_SYS_SYSTEMINFO_H
  95. # include <sys/systeminfo.h>
  96. #endif /* HAVE_SYS_SYSTEMINFO_H */
  97. #if TIME_WITH_SYS_TIME
  98. # include <sys/time.h>
  99. # include <time.h>
  100. #else
  101. # if HAVE_SYS_TIME_H
  102. # include <sys/time.h>
  103. # else
  104. # include <time.h>
  105. # endif
  106. #endif
  107. #if HAVE_UNISTD_H
  108. # include <unistd.h>
  109. #endif
  110. #if HAVE_SYS_WAIT_H
  111. # include <sys/wait.h>
  112. #endif
  113. #if HAVE_DIRENT_H
  114. # include <dirent.h>
  115. # define NAMLEN(dirent) strlen((dirent)->d_name)
  116. # define HAVE_DIR_STRUCT
  117. #else
  118. # define dirent direct
  119. # define NAMLEN(dirent) (dirent)->d_namlen
  120. # if HAVE_SYS_NDIR_H
  121. # include <sys/ndir.h>
  122. # define HAVE_DIR_STRUCT
  123. # endif
  124. # if HAVE_SYS_DIR_H
  125. # include <sys/dir.h>
  126. # define HAVE_DIR_STRUCT
  127. # endif
  128. # if HAVE_NDIR_H
  129. # include <ndir.h>
  130. # define HAVE_DIR_STRUCT
  131. # endif
  132. #endif
  133. #include <X11/Intrinsic.h>
  134. #include <X11/StringDefs.h>
  135. #include <X11/Shell.h>
  136. #include <X11/cursorfont.h>
  137. #include <X11/Xatom.h>
  138. #include <X11/Xmu/Atoms.h>
  139. #if USE_XAW3D
  140. #include <X11/Xaw3d/Dialog.h>
  141. #include <X11/Xaw3d/Form.h>
  142. #include <X11/Xaw3d/List.h>
  143. #include <X11/Xaw3d/Label.h>
  144. #include <X11/Xaw3d/SimpleMenu.h>
  145. #include <X11/Xaw3d/SmeBSB.h>
  146. #include <X11/Xaw3d/SmeLine.h>
  147. #include <X11/Xaw3d/Box.h>
  148. #include <X11/Xaw3d/MenuButton.h>
  149. #include <X11/Xaw3d/Text.h>
  150. #include <X11/Xaw3d/AsciiText.h>
  151. #else
  152. #include <X11/Xaw/Dialog.h>
  153. #include <X11/Xaw/Form.h>
  154. #include <X11/Xaw/List.h>
  155. #include <X11/Xaw/Label.h>
  156. #include <X11/Xaw/SimpleMenu.h>
  157. #include <X11/Xaw/SmeBSB.h>
  158. #include <X11/Xaw/SmeLine.h>
  159. #include <X11/Xaw/Box.h>
  160. #include <X11/Xaw/MenuButton.h>
  161. #include <X11/Xaw/Text.h>
  162. #include <X11/Xaw/AsciiText.h>
  163. #endif
  164. // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
  165. #include "common.h"
  166. #if HAVE_LIBXPM
  167. #include <X11/xpm.h>
  168. #include "pixmaps/pixmaps.h"
  169. #define IMAGE_EXT "xpm"
  170. #else
  171. #define IMAGE_EXT "xim"
  172. #include "bitmaps/bitmaps.h"
  173. #endif
  174. #include "bitmaps/icon_white.bm"
  175. #include "bitmaps/icon_black.bm"
  176. #include "bitmaps/checkmark.bm"
  177. #include "frontend.h"
  178. #include "backend.h"
  179. #include "backendz.h"
  180. #include "moves.h"
  181. #include "xboard.h"
  182. #include "childio.h"
  183. #include "xgamelist.h"
  184. #include "xhistory.h"
  185. #include "xedittags.h"
  186. #include "gettext.h"
  187. // must be moved to xengineoutput.h
  188. void EngineOutputProc P((Widget w, XEvent *event,
  189. String *prms, Cardinal *nprms));
  190. void EvalGraphProc P((Widget w, XEvent *event,
  191. String *prms, Cardinal *nprms));
  192. #ifdef __EMX__
  193. #ifndef HAVE_USLEEP
  194. #define HAVE_USLEEP
  195. #endif
  196. #define usleep(t) _sleep2(((t)+500)/1000)
  197. #endif
  198. #ifdef ENABLE_NLS
  199. # define _(s) gettext (s)
  200. # define N_(s) gettext_noop (s)
  201. #else
  202. # define _(s) (s)
  203. # define N_(s) s
  204. #endif
  205. typedef struct {
  206. String string;
  207. String ref;
  208. XtActionProc proc;
  209. } MenuItem;
  210. typedef struct {
  211. String name;
  212. String ref;
  213. MenuItem *mi;
  214. } Menu;
  215. int main P((int argc, char **argv));
  216. FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
  217. char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return));
  218. RETSIGTYPE CmailSigHandler P((int sig));
  219. RETSIGTYPE IntSigHandler P((int sig));
  220. RETSIGTYPE TermSizeSigHandler P((int sig));
  221. void CreateGCs P((int redo));
  222. void CreateAnyPieces P((void));
  223. void CreateXIMPieces P((void));
  224. void CreateXPMPieces P((void));
  225. void CreateXPMBoard P((char *s, int n));
  226. void CreatePieces P((void));
  227. void CreatePieceMenus P((void));
  228. Widget CreateMenuBar P((Menu *mb));
  229. Widget CreateButtonBar P ((MenuItem *mi));
  230. char *FindFont P((char *pattern, int targetPxlSize));
  231. void PieceMenuPopup P((Widget w, XEvent *event,
  232. String *params, Cardinal *num_params));
  233. static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
  234. static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
  235. void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
  236. u_int wreq, u_int hreq));
  237. void CreateGrid P((void));
  238. int EventToSquare P((int x, int limit));
  239. void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
  240. void EventProc P((Widget widget, caddr_t unused, XEvent *event));
  241. void HandleUserMove P((Widget w, XEvent *event,
  242. String *prms, Cardinal *nprms));
  243. void AnimateUserMove P((Widget w, XEvent * event,
  244. String * params, Cardinal * nParams));
  245. void HandlePV P((Widget w, XEvent * event,
  246. String * params, Cardinal * nParams));
  247. void SelectPV P((Widget w, XEvent * event,
  248. String * params, Cardinal * nParams));
  249. void StopPV P((Widget w, XEvent * event,
  250. String * params, Cardinal * nParams));
  251. void WhiteClock P((Widget w, XEvent *event,
  252. String *prms, Cardinal *nprms));
  253. void BlackClock P((Widget w, XEvent *event,
  254. String *prms, Cardinal *nprms));
  255. void DrawPositionProc P((Widget w, XEvent *event,
  256. String *prms, Cardinal *nprms));
  257. void XDrawPosition P((Widget w, /*Boolean*/int repaint,
  258. Board board));
  259. void CommentClick P((Widget w, XEvent * event,
  260. String * params, Cardinal * nParams));
  261. void CommentPopUp P((char *title, char *label));
  262. void CommentPopDown P((void));
  263. void CommentCallback P((Widget w, XtPointer client_data,
  264. XtPointer call_data));
  265. void ICSInputBoxPopUp P((void));
  266. void ICSInputBoxPopDown P((void));
  267. void FileNamePopUp P((char *label, char *def, char *filter,
  268. FileProc proc, char *openMode));
  269. void FileNamePopDown P((void));
  270. void FileNameCallback P((Widget w, XtPointer client_data,
  271. XtPointer call_data));
  272. void FileNameAction P((Widget w, XEvent *event,
  273. String *prms, Cardinal *nprms));
  274. void AskQuestionReplyAction P((Widget w, XEvent *event,
  275. String *prms, Cardinal *nprms));
  276. void AskQuestionProc P((Widget w, XEvent *event,
  277. String *prms, Cardinal *nprms));
  278. void AskQuestionPopDown P((void));
  279. void PromotionPopDown P((void));
  280. void PromotionCallback P((Widget w, XtPointer client_data,
  281. XtPointer call_data));
  282. void EditCommentPopDown P((void));
  283. void EditCommentCallback P((Widget w, XtPointer client_data,
  284. XtPointer call_data));
  285. void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
  286. void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  287. void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  288. void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
  289. Cardinal *nprms));
  290. void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
  291. Cardinal *nprms));
  292. void ReloadGameProc P((Widget w, XEvent *event, String *prms,
  293. Cardinal *nprms));
  294. void LoadPositionProc P((Widget w, XEvent *event,
  295. String *prms, Cardinal *nprms));
  296. void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
  297. Cardinal *nprms));
  298. void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
  299. Cardinal *nprms));
  300. void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
  301. Cardinal *nprms));
  302. void CopyPositionProc P((Widget w, XEvent *event, String *prms,
  303. Cardinal *nprms));
  304. void PastePositionProc P((Widget w, XEvent *event, String *prms,
  305. Cardinal *nprms));
  306. void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  307. void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  308. void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  309. void SavePositionProc P((Widget w, XEvent *event,
  310. String *prms, Cardinal *nprms));
  311. void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  312. void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
  313. Cardinal *nprms));
  314. void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  315. void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  316. void MachineBlackProc P((Widget w, XEvent *event, String *prms,
  317. Cardinal *nprms));
  318. void MachineWhiteProc P((Widget w, XEvent *event,
  319. String *prms, Cardinal *nprms));
  320. void AnalyzeModeProc P((Widget w, XEvent *event,
  321. String *prms, Cardinal *nprms));
  322. void AnalyzeFileProc P((Widget w, XEvent *event,
  323. String *prms, Cardinal *nprms));
  324. void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
  325. Cardinal *nprms));
  326. void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  327. void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  328. void IcsClientProc P((Widget w, XEvent *event, String *prms,
  329. Cardinal *nprms));
  330. void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  331. void EditPositionProc P((Widget w, XEvent *event,
  332. String *prms, Cardinal *nprms));
  333. void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  334. void EditCommentProc P((Widget w, XEvent *event,
  335. String *prms, Cardinal *nprms));
  336. void IcsInputBoxProc P((Widget w, XEvent *event,
  337. String *prms, Cardinal *nprms));
  338. void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  339. void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  340. void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  341. void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  342. void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  343. void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  344. void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  345. void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  346. void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  347. void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  348. void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  349. void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  350. void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  351. void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  352. void StopObservingProc P((Widget w, XEvent *event, String *prms,
  353. Cardinal *nprms));
  354. void StopExaminingProc P((Widget w, XEvent *event, String *prms,
  355. Cardinal *nprms));
  356. void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  357. void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  358. void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  359. void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  360. void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  361. void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  362. void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  363. void TruncateGameProc P((Widget w, XEvent *event, String *prms,
  364. Cardinal *nprms));
  365. void RetractMoveProc P((Widget w, XEvent *event, String *prms,
  366. Cardinal *nprms));
  367. void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  368. void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
  369. Cardinal *nprms));
  370. void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
  371. Cardinal *nprms));
  372. void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
  373. Cardinal *nprms));
  374. void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  375. void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  376. void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  377. void FlashMovesProc P((Widget w, XEvent *event, String *prms,
  378. Cardinal *nprms));
  379. void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  380. void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
  381. Cardinal *nprms));
  382. void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
  383. Cardinal *nprms));
  384. void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
  385. Cardinal *nprms));
  386. void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  387. //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  388. void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  389. void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
  390. Cardinal *nprms));
  391. void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
  392. Cardinal *nprms));
  393. void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
  394. Cardinal *nprms));
  395. void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
  396. Cardinal *nprms));
  397. //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  398. void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
  399. Cardinal *nprms));
  400. void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
  401. Cardinal *nprms));
  402. void HideThinkingProc P((Widget w, XEvent *event, String *prms,
  403. Cardinal *nprms));
  404. void TestLegalityProc P((Widget w, XEvent *event, String *prms,
  405. Cardinal *nprms));
  406. void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  407. void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  408. void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  409. void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  410. void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  411. void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  412. void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  413. void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  414. void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  415. void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  416. void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  417. void DisplayMove P((int moveNumber));
  418. void DisplayTitle P((char *title));
  419. void ICSInitScript P((void));
  420. int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
  421. void ErrorPopUp P((char *title, char *text, int modal));
  422. void ErrorPopDown P((void));
  423. static char *ExpandPathName P((char *path));
  424. static void CreateAnimVars P((void));
  425. static void DragPieceMove P((int x, int y));
  426. static void DrawDragPiece P((void));
  427. char *ModeToWidgetName P((GameMode mode));
  428. void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  429. void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  430. void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  431. void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  432. void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  433. void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  434. void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  435. void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  436. void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  437. void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  438. void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  439. void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  440. void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  441. void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  442. void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
  443. void GameListOptionsPopDown P(());
  444. void ShufflePopDown P(());
  445. void TimeControlPopDown P(());
  446. void GenericPopDown P(());
  447. void update_ics_width P(());
  448. int get_term_width P(());
  449. int CopyMemoProc P(());
  450. void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
  451. Boolean IsDrawArrowEnabled P(());
  452. /*
  453. * XBoard depends on Xt R4 or higher
  454. */
  455. int xtVersion = XtSpecificationRelease;
  456. int xScreen;
  457. Display *xDisplay;
  458. Window xBoardWindow;
  459. Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
  460. jailSquareColor, highlightSquareColor, premoveHighlightColor;
  461. Pixel lowTimeWarningColor;
  462. GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
  463. bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
  464. wjPieceGC, bjPieceGC, prelineGC, countGC;
  465. Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
  466. Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
  467. whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
  468. commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
  469. menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
  470. ICSInputShell, fileNameShell, askQuestionShell;
  471. Widget historyShell, evalGraphShell, gameListShell;
  472. int hOffset; // [HGM] dual
  473. XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
  474. XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
  475. XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
  476. Font clockFontID, coordFontID, countFontID;
  477. XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
  478. XtAppContext appContext;
  479. char *layoutName;
  480. char *oldICSInteractionTitle;
  481. FileProc fileProc;
  482. char *fileOpenMode;
  483. char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
  484. Position commentX = -1, commentY = -1;
  485. Dimension commentW, commentH;
  486. typedef unsigned int BoardSize;
  487. BoardSize boardSize;
  488. Boolean chessProgram;
  489. int minX, minY; // [HGM] placement: volatile limits on upper-left corner
  490. int squareSize, smallLayout = 0, tinyLayout = 0,
  491. marginW, marginH, // [HGM] for run-time resizing
  492. fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
  493. ICSInputBoxUp = False, askQuestionUp = False,
  494. filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
  495. editUp = False, errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
  496. Pixel timerForegroundPixel, timerBackgroundPixel;
  497. Pixel buttonForegroundPixel, buttonBackgroundPixel;
  498. char *chessDir, *programName, *programVersion,
  499. *gameCopyFilename, *gamePasteFilename;
  500. Boolean alwaysOnTop = False;
  501. Boolean saveSettingsOnExit;
  502. char *settingsFileName;
  503. char *icsTextMenuString;
  504. char *icsNames;
  505. char *firstChessProgramNames;
  506. char *secondChessProgramNames;
  507. WindowPlacement wpMain;
  508. WindowPlacement wpConsole;
  509. WindowPlacement wpComment;
  510. WindowPlacement wpMoveHistory;
  511. WindowPlacement wpEvalGraph;
  512. WindowPlacement wpEngineOutput;
  513. WindowPlacement wpGameList;
  514. WindowPlacement wpTags;
  515. #define SOLID 0
  516. #define OUTLINE 1
  517. Pixmap pieceBitmap[2][(int)BlackPawn];
  518. Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
  519. Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
  520. Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
  521. Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
  522. Pixmap xpmBoardBitmap[2];
  523. int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
  524. XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
  525. Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
  526. Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
  527. XImage *ximLightSquare, *ximDarkSquare;
  528. XImage *xim_Cross;
  529. #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
  530. #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
  531. #define White(piece) ((int)(piece) < (int)BlackPawn)
  532. /* Variables for doing smooth animation. This whole thing
  533. would be much easier if the board was double-buffered,
  534. but that would require a fairly major rewrite. */
  535. typedef struct {
  536. Pixmap saveBuf;
  537. Pixmap newBuf;
  538. GC blitGC, pieceGC, outlineGC;
  539. XPoint startSquare, prevFrame, mouseDelta;
  540. int startColor;
  541. int dragPiece;
  542. Boolean dragActive;
  543. int startBoardX, startBoardY;
  544. } AnimState;
  545. /* There can be two pieces being animated at once: a player
  546. can begin dragging a piece before the remote opponent has moved. */
  547. static AnimState game, player;
  548. /* Bitmaps for use as masks when drawing XPM pieces.
  549. Need one for each black and white piece. */
  550. static Pixmap xpmMask[BlackKing + 1];
  551. /* This magic number is the number of intermediate frames used
  552. in each half of the animation. For short moves it's reduced
  553. by 1. The total number of frames will be factor * 2 + 1. */
  554. #define kFactor 4
  555. SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
  556. MenuItem fileMenu[] = {
  557. {N_("New Game Ctrl+N"), "New Game", ResetProc},
  558. {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
  559. {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
  560. {"----", NULL, NothingProc},
  561. {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
  562. {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
  563. // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
  564. // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
  565. // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
  566. {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
  567. {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
  568. {"----", NULL, NothingProc},
  569. // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
  570. {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
  571. {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
  572. {"----", NULL, NothingProc},
  573. {N_("Mail Move"), "Mail Move", MailMoveProc},
  574. {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
  575. {"----", NULL, NothingProc},
  576. {N_("Quit Ctr+Q"), "Exit", QuitProc},
  577. {NULL, NULL, NULL}
  578. };
  579. MenuItem editMenu[] = {
  580. {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
  581. {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
  582. {"----", NULL, NothingProc},
  583. {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
  584. {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
  585. {"----", NULL, NothingProc},
  586. {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
  587. {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
  588. {N_("Edit Tags"), "Edit Tags", EditTagsProc},
  589. {N_("Edit Comment"), "Edit Comment", EditCommentProc},
  590. {"----", NULL, NothingProc},
  591. {N_("Revert Home"), "Revert", RevertProc},
  592. {N_("Annotate"), "Annotate", AnnotateProc},
  593. {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
  594. {"----", NULL, NothingProc},
  595. {N_("Backward Alt+Left"), "Backward", BackwardProc},
  596. {N_("Forward Alt+Right"), "Forward", ForwardProc},
  597. {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
  598. {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
  599. {NULL, NULL, NULL}
  600. };
  601. MenuItem viewMenu[] = {
  602. {N_("Flip View F2"), "Flip View", FlipViewProc},
  603. {"----", NULL, NothingProc},
  604. {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
  605. {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
  606. {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
  607. {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
  608. {N_("ICS text menu"), "ICStex", IcsTextProc},
  609. {"----", NULL, NothingProc},
  610. {N_("Tags"), "Show Tags", EditTagsProc},
  611. {N_("Comments"), "Show Comments", EditCommentProc},
  612. {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
  613. {"----", NULL, NothingProc},
  614. {N_("Board..."), "Board Options", BoardOptionsProc},
  615. {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
  616. {NULL, NULL, NULL}
  617. };
  618. MenuItem modeMenu[] = {
  619. {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
  620. {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
  621. {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
  622. {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
  623. {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
  624. {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
  625. {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
  626. {N_("Training"), "Training", TrainingProc},
  627. {N_("ICS Client"), "ICS Client", IcsClientProc},
  628. {"----", NULL, NothingProc},
  629. {N_("Machine Match"), "Machine Match", MatchProc},
  630. {N_("Pause Pause"), "Pause", PauseProc},
  631. {NULL, NULL, NULL}
  632. };
  633. MenuItem actionMenu[] = {
  634. {N_("Accept F3"), "Accept", AcceptProc},
  635. {N_("Decline F4"), "Decline", DeclineProc},
  636. {N_("Rematch F12"), "Rematch", RematchProc},
  637. {"----", NULL, NothingProc},
  638. {N_("Call Flag F5"), "Call Flag", CallFlagProc},
  639. {N_("Draw F6"), "Draw", DrawProc},
  640. {N_("Adjourn F7"), "Adjourn", AdjournProc},
  641. {N_("Abort F8"),"Abort", AbortProc},
  642. {N_("Resign F9"), "Resign", ResignProc},
  643. {"----", NULL, NothingProc},
  644. {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
  645. {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
  646. {N_("Upload to Examine"), "Upload to Examine", UploadProc},
  647. {"----", NULL, NothingProc},
  648. {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
  649. {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
  650. {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
  651. {NULL, NULL, NULL}
  652. };
  653. MenuItem engineMenu[] = {
  654. {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
  655. {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
  656. {"----", NULL, NothingProc},
  657. {N_("Hint"), "Hint", HintProc},
  658. {N_("Book"), "Book", BookProc},
  659. {"----", NULL, NothingProc},
  660. {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
  661. {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
  662. {NULL, NULL, NULL}
  663. };
  664. MenuItem optionsMenu[] = {
  665. #define OPTIONSDIALOG
  666. #ifdef OPTIONSDIALOG
  667. {N_("General ..."), "General", OptionsProc},
  668. #endif
  669. {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
  670. {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
  671. {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
  672. {N_("ICS ..."), "ICS", IcsOptionsProc},
  673. {N_("Match ..."), "Match", MatchOptionsProc},
  674. {N_("Load Game ..."), "Load Game", LoadOptionsProc},
  675. {N_("Save Game ..."), "Save Game", SaveOptionsProc},
  676. // {N_(" ..."), "", OptionsProc},
  677. {N_("Game List ..."), "Game List", GameListOptionsPopUp},
  678. {N_("Sounds ..."), "Sounds", SoundOptionsProc},
  679. {"----", NULL, NothingProc},
  680. #ifndef OPTIONSDIALOG
  681. {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
  682. {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
  683. {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
  684. {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
  685. {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
  686. {N_("Blindfold"), "Blindfold", BlindfoldProc},
  687. {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
  688. #if HIGHDRAG
  689. {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
  690. #endif
  691. {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
  692. {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
  693. {N_("Move Sound"), "Move Sound", MoveSoundProc},
  694. // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
  695. {N_("One-Click Moving"), "OneClick", OneClickProc},
  696. {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
  697. {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
  698. {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
  699. {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
  700. // {N_("Premove"), "Premove", PremoveProc},
  701. {N_("Show Coords"), "Show Coords", ShowCoordsProc},
  702. {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
  703. {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
  704. {"----", NULL, NothingProc},
  705. #endif
  706. {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
  707. {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
  708. {NULL, NULL, NULL}
  709. };
  710. MenuItem helpMenu[] = {
  711. {N_("Info XBoard"), "Info XBoard", InfoProc},
  712. {N_("Man XBoard F1"), "Man XBoard", ManProc},
  713. {"----", NULL, NothingProc},
  714. {N_("About XBoard"), "About XBoard", AboutProc},
  715. {NULL, NULL, NULL}
  716. };
  717. Menu menuBar[] = {
  718. {N_("File"), "File", fileMenu},
  719. {N_("Edit"), "Edit", editMenu},
  720. {N_("View"), "View", viewMenu},
  721. {N_("Mode"), "Mode", modeMenu},
  722. {N_("Action"), "Action", actionMenu},
  723. {N_("Engine"), "Engine", engineMenu},
  724. {N_("Options"), "Options", optionsMenu},
  725. {N_("Help"), "Help", helpMenu},
  726. {NULL, NULL, NULL}
  727. };
  728. #define PAUSE_BUTTON "P"
  729. MenuItem buttonBar[] = {
  730. {"<<", "<<", ToStartProc},
  731. {"<", "<", BackwardProc},
  732. {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
  733. {">", ">", ForwardProc},
  734. {">>", ">>", ToEndProc},
  735. {NULL, NULL, NULL}
  736. };
  737. #define PIECE_MENU_SIZE 18
  738. String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
  739. { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
  740. N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
  741. N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
  742. N_("Empty square"), N_("Clear board") },
  743. { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
  744. N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
  745. N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
  746. N_("Empty square"), N_("Clear board") }
  747. };
  748. /* must be in same order as PieceMenuStrings! */
  749. ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
  750. { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
  751. WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
  752. WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
  753. PromotePiece, DemotePiece, EmptySquare, ClearBoard },
  754. { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
  755. BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
  756. BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
  757. PromotePiece, DemotePiece, EmptySquare, ClearBoard },
  758. };
  759. #define DROP_MENU_SIZE 6
  760. String dropMenuStrings[DROP_MENU_SIZE] = {
  761. "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
  762. };
  763. /* must be in same order as PieceMenuStrings! */
  764. ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
  765. (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
  766. WhiteRook, WhiteQueen
  767. };
  768. typedef struct {
  769. char piece;
  770. char* widget;
  771. } DropMenuEnables;
  772. DropMenuEnables dmEnables[] = {
  773. { 'P', "Pawn" },
  774. { 'N', "Knight" },
  775. { 'B', "Bishop" },
  776. { 'R', "Rook" },
  777. { 'Q', "Queen" }
  778. };
  779. Arg shellArgs[] = {
  780. { XtNwidth, 0 },
  781. { XtNheight, 0 },
  782. { XtNminWidth, 0 },
  783. { XtNminHeight, 0 },
  784. { XtNmaxWidth, 0 },
  785. { XtNmaxHeight, 0 }
  786. };
  787. Arg layoutArgs[] = {
  788. { XtNborderWidth, 0 },
  789. { XtNdefaultDistance, 0 },
  790. };
  791. Arg formArgs[] = {
  792. { XtNborderWidth, 0 },
  793. { XtNresizable, (XtArgVal) True },
  794. };
  795. Arg boardArgs[] = {
  796. { XtNborderWidth, 0 },
  797. { XtNwidth, 0 },
  798. { XtNheight, 0 }
  799. };
  800. Arg titleArgs[] = {
  801. { XtNjustify, (XtArgVal) XtJustifyRight },
  802. { XtNlabel, (XtArgVal) "..." },
  803. { XtNresizable, (XtArgVal) True },
  804. { XtNresize, (XtArgVal) False }
  805. };
  806. Arg messageArgs[] = {
  807. { XtNjustify, (XtArgVal) XtJustifyLeft },
  808. { XtNlabel, (XtArgVal) "..." },
  809. { XtNresizable, (XtArgVal) True },
  810. { XtNresize, (XtArgVal) False }
  811. };
  812. Arg timerArgs[] = {
  813. { XtNborderWidth, 0 },
  814. { XtNjustify, (XtArgVal) XtJustifyLeft }
  815. };
  816. XtResource clientResources[] = {
  817. { "flashCount", "flashCount", XtRInt, sizeof(int),
  818. XtOffset(AppDataPtr, flashCount), XtRImmediate,
  819. (XtPointer) FLASH_COUNT },
  820. };
  821. XrmOptionDescRec shellOptions[] = {
  822. { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
  823. { "-flash", "flashCount", XrmoptionNoArg, "3" },
  824. { "-xflash", "flashCount", XrmoptionNoArg, "0" },
  825. };
  826. XtActionsRec boardActions[] = {
  827. { "DrawPosition", DrawPositionProc },
  828. { "HandleUserMove", HandleUserMove },
  829. { "AnimateUserMove", AnimateUserMove },
  830. { "HandlePV", HandlePV },
  831. { "SelectPV", SelectPV },
  832. { "StopPV", StopPV },
  833. { "FileNameAction", FileNameAction },
  834. { "AskQuestionProc", AskQuestionProc },
  835. { "AskQuestionReplyAction", AskQuestionReplyAction },
  836. { "PieceMenuPopup", PieceMenuPopup },
  837. { "WhiteClock", WhiteClock },
  838. { "BlackClock", BlackClock },
  839. { "Iconify", Iconify },
  840. { "ResetProc", ResetProc },
  841. { "NewVariantProc", NewVariantProc },
  842. { "LoadGameProc", LoadGameProc },
  843. { "LoadNextGameProc", LoadNextGameProc },
  844. { "LoadPrevGameProc", LoadPrevGameProc },
  845. { "LoadSelectedProc", LoadSelectedProc },
  846. { "SetFilterProc", SetFilterProc },
  847. { "ReloadGameProc", ReloadGameProc },
  848. { "LoadPositionProc", LoadPositionProc },
  849. { "LoadNextPositionProc", LoadNextPositionProc },
  850. { "LoadPrevPositionProc", LoadPrevPositionProc },
  851. { "ReloadPositionProc", ReloadPositionProc },
  852. { "CopyPositionProc", CopyPositionProc },
  853. { "PastePositionProc", PastePositionProc },
  854. { "CopyGameProc", CopyGameProc },
  855. { "PasteGameProc", PasteGameProc },
  856. { "SaveGameProc", SaveGameProc },
  857. { "SavePositionProc", SavePositionProc },
  858. { "MailMoveProc", MailMoveProc },
  859. { "ReloadCmailMsgProc", ReloadCmailMsgProc },
  860. { "QuitProc", QuitProc },
  861. { "MachineWhiteProc", MachineWhiteProc },
  862. { "MachineBlackProc", MachineBlackProc },
  863. { "AnalysisModeProc", AnalyzeModeProc },
  864. { "AnalyzeFileProc", AnalyzeFileProc },
  865. { "TwoMachinesProc", TwoMachinesProc },
  866. { "IcsClientProc", IcsClientProc },
  867. { "EditGameProc", EditGameProc },
  868. { "EditPositionProc", EditPositionProc },
  869. { "TrainingProc", EditPositionProc },
  870. { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
  871. { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
  872. { "ShowGameListProc", ShowGameListProc },
  873. { "ShowMoveListProc", HistoryShowProc},
  874. { "EditTagsProc", EditCommentProc },
  875. { "EditCommentProc", EditCommentProc },
  876. { "IcsInputBoxProc", IcsInputBoxProc },
  877. { "PauseProc", PauseProc },
  878. { "AcceptProc", AcceptProc },
  879. { "DeclineProc", DeclineProc },
  880. { "RematchProc", RematchProc },
  881. { "CallFlagProc", CallFlagProc },
  882. { "DrawProc", DrawProc },
  883. { "AdjournProc", AdjournProc },
  884. { "AbortProc", AbortProc },
  885. { "ResignProc", ResignProc },
  886. { "AdjuWhiteProc", AdjuWhiteProc },
  887. { "AdjuBlackProc", AdjuBlackProc },
  888. { "AdjuDrawProc", AdjuDrawProc },
  889. { "EnterKeyProc", EnterKeyProc },
  890. { "UpKeyProc", UpKeyProc },
  891. { "DownKeyProc", DownKeyProc },
  892. { "StopObservingProc", StopObservingProc },
  893. { "StopExaminingProc", StopExaminingProc },
  894. { "UploadProc", UploadProc },
  895. { "BackwardProc", BackwardProc },
  896. { "ForwardProc", ForwardProc },
  897. { "ToStartProc", ToStartProc },
  898. { "ToEndProc", ToEndProc },
  899. { "RevertProc", RevertProc },
  900. { "AnnotateProc", AnnotateProc },
  901. { "TruncateGameProc", TruncateGameProc },
  902. { "MoveNowProc", MoveNowProc },
  903. { "RetractMoveProc", RetractMoveProc },
  904. { "EngineMenuProc", (XtActionProc) EngineMenuProc },
  905. { "UciMenuProc", (XtActionProc) UciMenuProc },
  906. { "TimeControlProc", (XtActionProc) TimeControlProc },
  907. { "FlipViewProc", FlipViewProc },
  908. { "PonderNextMoveProc", PonderNextMoveProc },
  909. #ifndef OPTIONSDIALOG
  910. { "AlwaysQueenProc", AlwaysQueenProc },
  911. { "AnimateDraggingProc", AnimateDraggingProc },
  912. { "AnimateMovingProc", AnimateMovingProc },
  913. { "AutoflagProc", AutoflagProc },
  914. { "AutoflipProc", AutoflipProc },
  915. { "BlindfoldProc", BlindfoldProc },
  916. { "FlashMovesProc", FlashMovesProc },
  917. #if HIGHDRAG
  918. { "HighlightDraggingProc", HighlightDraggingProc },
  919. #endif
  920. { "HighlightLastMoveProc", HighlightLastMoveProc },
  921. // { "IcsAlarmProc", IcsAlarmProc },
  922. { "MoveSoundProc", MoveSoundProc },
  923. { "PeriodicUpdatesProc", PeriodicUpdatesProc },
  924. { "PopupExitMessageProc", PopupExitMessageProc },
  925. { "PopupMoveErrorsProc", PopupMoveErrorsProc },
  926. // { "PremoveProc", PremoveProc },
  927. { "ShowCoordsProc", ShowCoordsProc },
  928. { "ShowThinkingProc", ShowThinkingProc },
  929. { "HideThinkingProc", HideThinkingProc },
  930. { "TestLegalityProc", TestLegalityProc },
  931. #endif
  932. { "SaveSettingsProc", SaveSettingsProc },
  933. { "SaveOnExitProc", SaveOnExitProc },
  934. { "InfoProc", InfoProc },
  935. { "ManProc", ManProc },
  936. { "HintProc", HintProc },
  937. { "BookProc", BookProc },
  938. { "AboutGameProc", AboutGameProc },
  939. { "AboutProc", AboutProc },
  940. { "DebugProc", DebugProc },
  941. { "NothingProc", NothingProc },
  942. { "CommentClick", (XtActionProc) CommentClick },
  943. { "CommentPopDown", (XtActionProc) CommentPopDown },
  944. { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
  945. { "TagsPopDown", (XtActionProc) TagsPopDown },
  946. { "ErrorPopDown", (XtActionProc) ErrorPopDown },
  947. { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
  948. { "FileNamePopDown", (XtActionProc) FileNamePopDown },
  949. { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
  950. { "GameListPopDown", (XtActionProc) GameListPopDown },
  951. { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
  952. { "PromotionPopDown", (XtActionProc) PromotionPopDown },
  953. { "HistoryPopDown", (XtActionProc) HistoryPopDown },
  954. { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
  955. { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
  956. { "ShufflePopDown", (XtActionProc) ShufflePopDown },
  957. { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
  958. { "GenericPopDown", (XtActionProc) GenericPopDown },
  959. { "CopyMemoProc", (XtActionProc) CopyMemoProc },
  960. };
  961. char globalTranslations[] =
  962. ":<Key>F9: ResignProc() \n \
  963. :Ctrl<Key>n: ResetProc() \n \
  964. :Meta<Key>V: NewVariantProc() \n \
  965. :Ctrl<Key>o: LoadGameProc() \n \
  966. :Meta<Key>Next: LoadNextGameProc() \n \
  967. :Meta<Key>Prior: LoadPrevGameProc() \n \
  968. :Ctrl<Key>s: SaveGameProc() \n \
  969. :Ctrl<Key>c: CopyGameProc() \n \
  970. :Ctrl<Key>v: PasteGameProc() \n \
  971. :Ctrl<Key>O: LoadPositionProc() \n \
  972. :Shift<Key>Next: LoadNextPositionProc() \n \
  973. :Shift<Key>Prior: LoadPrevPositionProc() \n \
  974. :Ctrl<Key>S: SavePositionProc() \n \
  975. :Ctrl<Key>C: CopyPositionProc() \n \
  976. :Ctrl<Key>V: PastePositionProc() \n \
  977. :Ctrl<Key>q: QuitProc() \n \
  978. :Ctrl<Key>w: MachineWhiteProc() \n \
  979. :Ctrl<Key>b: MachineBlackProc() \n \
  980. :Ctrl<Key>t: TwoMachinesProc() \n \
  981. :Ctrl<Key>a: AnalysisModeProc() \n \
  982. :Ctrl<Key>f: AnalyzeFileProc() \n \
  983. :Ctrl<Key>e: EditGameProc() \n \
  984. :Ctrl<Key>E: EditPositionProc() \n \
  985. :Meta<Key>O: EngineOutputProc() \n \
  986. :Meta<Key>E: EvalGraphProc() \n \
  987. :Meta<Key>G: ShowGameListProc() \n \
  988. :Meta<Key>H: ShowMoveListProc() \n \
  989. :<Key>Pause: PauseProc() \n \
  990. :<Key>F3: AcceptProc() \n \
  991. :<Key>F4: DeclineProc() \n \
  992. :<Key>F12: RematchProc() \n \
  993. :<Key>F5: CallFlagProc() \n \
  994. :<Key>F6: DrawProc() \n \
  995. :<Key>F7: AdjournProc() \n \
  996. :<Key>F8: AbortProc() \n \
  997. :<Key>F10: StopObservingProc() \n \
  998. :<Key>F11: StopExaminingProc() \n \
  999. :Meta Ctrl<Key>F12: DebugProc() \n \
  1000. :Meta<Key>End: ToEndProc() \n \
  1001. :Meta<Key>Right: ForwardProc() \n \
  1002. :Meta<Key>Home: ToStartProc() \n \
  1003. :Meta<Key>Left: BackwardProc() \n \
  1004. :<Key>Home: RevertProc() \n \
  1005. :<Key>End: TruncateGameProc() \n \
  1006. :Ctrl<Key>m: MoveNowProc() \n \
  1007. :Ctrl<Key>x: RetractMoveProc() \n \
  1008. :Meta<Key>J: EngineMenuProc() \n \
  1009. :Meta<Key>U: UciMenuProc() \n \
  1010. :Meta<Key>T: TimeControlProc() \n \
  1011. :Ctrl<Key>P: PonderNextMoveProc() \n "
  1012. #ifndef OPTIONSDIALOG
  1013. "\
  1014. :Ctrl<Key>Q: AlwaysQueenProc() \n \
  1015. :Ctrl<Key>F: AutoflagProc() \n \
  1016. :Ctrl<Key>A: AnimateMovingProc() \n \
  1017. :Ctrl<Key>L: TestLegalityProc() \n \
  1018. :Ctrl<Key>H: HideThinkingProc() \n "
  1019. #endif
  1020. "\
  1021. :<Key>-: Iconify() \n \
  1022. :<Key>F1: ManProc() \n \
  1023. :<Key>F2: FlipViewProc() \n \
  1024. <KeyDown>.: BackwardProc() \n \
  1025. <KeyUp>.: ForwardProc() \n \
  1026. Shift<Key>1: AskQuestionProc(\"Direct command\",\
  1027. \"Send to chess program:\",,1) \n \
  1028. Shift<Key>2: AskQuestionProc(\"Direct command\",\
  1029. \"Send to second chess program:\",,2) \n";
  1030. char boardTranslations[] =
  1031. "<Btn1Down>: HandleUserMove(0) \n \
  1032. Shift<Btn1Up>: HandleUserMove(1) \n \
  1033. <Btn1Up>: HandleUserMove(0) \n \
  1034. <Btn1Motion>: AnimateUserMove() \n \
  1035. <Btn3Motion>: HandlePV() \n \
  1036. <Btn3Up>: PieceMenuPopup(menuB) \n \
  1037. Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
  1038. PieceMenuPopup(menuB) \n \
  1039. Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
  1040. PieceMenuPopup(menuW) \n \
  1041. Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
  1042. PieceMenuPopup(menuW) \n \
  1043. Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
  1044. PieceMenuPopup(menuB) \n";
  1045. char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
  1046. char blackTranslations[] = "<BtnDown>: BlackClock()\n";
  1047. char ICSInputTranslations[] =
  1048. "<Key>Up: UpKeyProc() \n "
  1049. "<Key>Down: DownKeyProc() \n "
  1050. "<Key>Return: EnterKeyProc() \n";
  1051. // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
  1052. // as the widget is destroyed before the up-click can call extend-end
  1053. char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
  1054. String xboardResources[] = {
  1055. "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
  1056. "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
  1057. "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
  1058. NULL
  1059. };
  1060. /* Max possible square size */
  1061. #define MAXSQSIZE 256
  1062. static int xpm_avail[MAXSQSIZE];
  1063. #ifdef HAVE_DIR_STRUCT
  1064. /* Extract piece size from filename */
  1065. static int
  1066. xpm_getsize(name, len, ext)
  1067. char *name;
  1068. int len;
  1069. char *ext;
  1070. {
  1071. char *p, *d;
  1072. char buf[10];
  1073. if (len < 4)
  1074. return 0;
  1075. if ((p=strchr(name, '.')) == NULL ||
  1076. StrCaseCmp(p+1, ext) != 0)
  1077. return 0;
  1078. p = name + 3;
  1079. d = buf;
  1080. while (*p && isdigit(*p))
  1081. *(d++) = *(p++);
  1082. *d = 0;
  1083. return atoi(buf);
  1084. }
  1085. /* Setup xpm_avail */
  1086. static int
  1087. xpm_getavail(dirname, ext)
  1088. char *dirname;
  1089. char *ext;
  1090. {
  1091. DIR *dir;
  1092. struct dirent *ent;
  1093. int i;
  1094. for (i=0; i<MAXSQSIZE; ++i)
  1095. xpm_avail[i] = 0;
  1096. if (appData.debugMode)
  1097. fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
  1098. dir = opendir(dirname);
  1099. if (!dir)
  1100. {
  1101. fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
  1102. programName, dirname);
  1103. exit(1);
  1104. }
  1105. while ((ent=readdir(dir)) != NULL) {
  1106. i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
  1107. if (i > 0 && i < MAXSQSIZE)
  1108. xpm_avail[i] = 1;
  1109. }
  1110. closedir(dir);
  1111. return 0;
  1112. }
  1113. void
  1114. xpm_print_avail(fp, ext)
  1115. FILE *fp;
  1116. char *ext;
  1117. {
  1118. int i;
  1119. fprintf(fp, _("Available `%s' sizes:\n"), ext);
  1120. for (i=1; i<MAXSQSIZE; ++i) {
  1121. if (xpm_avail[i])
  1122. printf("%d\n", i);
  1123. }
  1124. }
  1125. /* Return XPM piecesize closest to size */
  1126. int
  1127. xpm_closest_to(dirname, size, ext)
  1128. char *dirname;
  1129. int size;
  1130. char *ext;
  1131. {
  1132. int i;
  1133. int sm_diff = MAXSQSIZE;
  1134. int sm_index = 0;
  1135. int diff;
  1136. xpm_getavail(dirname, ext);
  1137. if (appData.debugMode)
  1138. xpm_print_avail(stderr, ext);
  1139. for (i=1; i<MAXSQSIZE; ++i) {
  1140. if (xpm_avail[i]) {
  1141. diff = size - i;
  1142. diff = (diff<0) ? -diff : diff;
  1143. if (diff < sm_diff) {
  1144. sm_diff = diff;
  1145. sm_index = i;
  1146. }
  1147. }
  1148. }
  1149. if (!sm_index) {
  1150. fprintf(stderr, _("Error: No `%s' files!\n"), ext);
  1151. exit(1);
  1152. }
  1153. return sm_index;
  1154. }
  1155. #else /* !HAVE_DIR_STRUCT */
  1156. /* If we are on a system without a DIR struct, we can't
  1157. read the directory, so we can't collect a list of
  1158. filenames, etc., so we can't do any size-fitting. */
  1159. int
  1160. xpm_closest_to(dirname, size, ext)
  1161. char *dirname;
  1162. int size;
  1163. char *ext;
  1164. {
  1165. fprintf(stderr, _("\
  1166. Warning: No DIR structure found on this system --\n\
  1167. Unable to autosize for XPM/XIM pieces.\n\
  1168. Please report this error to frankm@hiwaay.net.\n\
  1169. Include system type & operating system in message.\n"));
  1170. return size;
  1171. }
  1172. #endif /* HAVE_DIR_STRUCT */
  1173. static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
  1174. "magenta", "cyan", "white" };
  1175. typedef struct {
  1176. int attr, bg, fg;
  1177. } TextColors;
  1178. TextColors textColors[(int)NColorClasses];
  1179. /* String is: "fg, bg, attr". Which is 0, 1, 2 */
  1180. static int
  1181. parse_color(str, which)
  1182. char *str;
  1183. int which;
  1184. {
  1185. char *p, buf[100], *d;
  1186. int i;
  1187. if (strlen(str) > 99) /* watch bounds on buf */
  1188. return -1;
  1189. p = str;
  1190. d = buf;
  1191. for (i=0; i<which; ++i) {
  1192. p = strchr(p, ',');
  1193. if (!p)
  1194. return -1;
  1195. ++p;
  1196. }
  1197. /* Could be looking at something like:
  1198. black, , 1
  1199. .. in which case we want to stop on a comma also */
  1200. while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
  1201. ++p;
  1202. if (*p == ',') {
  1203. return -1; /* Use default for empty field */
  1204. }
  1205. if (which == 2 || isdigit(*p))
  1206. return atoi(p);
  1207. while (*p && isalpha(*p))
  1208. *(d++) = *(p++);
  1209. *d = 0;
  1210. for (i=0; i<8; ++i) {
  1211. if (!StrCaseCmp(buf, cnames[i]))
  1212. return which? (i+40) : (i+30);
  1213. }
  1214. if (!StrCaseCmp(buf, "default")) return -1;
  1215. fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
  1216. return -2;
  1217. }
  1218. static int
  1219. parse_cpair(cc, str)
  1220. ColorClass cc;
  1221. char *str;
  1222. {
  1223. if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
  1224. fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
  1225. programName, str);
  1226. return -1;
  1227. }
  1228. /* bg and attr are optional */
  1229. textColors[(int)cc].bg = parse_color(str, 1);
  1230. if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
  1231. textColors[(int)cc].attr = 0;
  1232. }
  1233. return 0;
  1234. }
  1235. /* Arrange to catch delete-window events */
  1236. Atom wm_delete_window;
  1237. void
  1238. CatchDeleteWindow(Widget w, String procname)
  1239. {
  1240. char buf[MSG_SIZ];
  1241. XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
  1242. snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
  1243. XtAugmentTranslations(w, XtParseTranslationTable(buf));
  1244. }
  1245. void
  1246. BoardToTop()
  1247. {
  1248. Arg args[16];
  1249. XtSetArg(args[0], XtNiconic, False);
  1250. XtSetValues(shellWidget, args, 1);
  1251. XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
  1252. }
  1253. //---------------------------------------------------------------------------------------------------------
  1254. // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
  1255. #define XBOARD True
  1256. #define JAWS_ARGS
  1257. #define CW_USEDEFAULT (1<<31)
  1258. #define ICS_TEXT_MENU_SIZE 90
  1259. #define DEBUG_FILE "xboard.debug"
  1260. #define SetCurrentDirectory chdir
  1261. #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
  1262. #define OPTCHAR "-"
  1263. #define SEPCHAR " "
  1264. // these two must some day move to frontend.h, when they are implemented
  1265. Boolean GameListIsUp();
  1266. // The option definition and parsing code common to XBoard and WinBoard is collected in this file
  1267. #include "args.h"
  1268. // front-end part of option handling
  1269. // [HGM] This platform-dependent table provides the location for storing the color info
  1270. extern char *crWhite, * crBlack;
  1271. void *
  1272. colorVariable[] = {
  1273. &appData.whitePieceColor,
  1274. &appData.blackPieceColor,
  1275. &appData.lightSquareColor,
  1276. &appData.darkSquareColor,
  1277. &appData.highlightSquareColor,
  1278. &appData.premoveHighlightColor,
  1279. &appData.lowTimeWarningColor,
  1280. NULL,
  1281. NULL,
  1282. NULL,
  1283. NULL,
  1284. NULL,
  1285. &crWhite,
  1286. &crBlack,
  1287. NULL
  1288. };
  1289. // [HGM] font: keep a font for each square size, even non-stndard ones
  1290. #define NUM_SIZES 18
  1291. #define MAX_SIZE 130
  1292. Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
  1293. char *fontTable[NUM_FONTS][MAX_SIZE];
  1294. void
  1295. ParseFont(char *name, int number)
  1296. { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
  1297. int size;
  1298. if(sscanf(name, "size%d:", &size)) {
  1299. // [HGM] font: font is meant for specific boardSize (likely from settings file);
  1300. // defer processing it until we know if it matches our board size
  1301. if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
  1302. fontTable[number][size] = strdup(strchr(name, ':')+1);
  1303. fontValid[number][size] = True;
  1304. }
  1305. return;
  1306. }
  1307. switch(number) {
  1308. case 0: // CLOCK_FONT
  1309. appData.clockFont = strdup(name);
  1310. break;
  1311. case 1: // MESSAGE_FONT
  1312. appData.font = strdup(name);
  1313. break;
  1314. case 2: // COORD_FONT
  1315. appData.coordFont = strdup(name);
  1316. break;
  1317. default:
  1318. return;
  1319. }
  1320. fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
  1321. }
  1322. void
  1323. SetFontDefaults()
  1324. { // only 2 fonts currently
  1325. appData.clockFont = CLOCK_FONT_NAME;
  1326. appData.coordFont = COORD_FONT_NAME;
  1327. appData.font = DEFAULT_FONT_NAME;
  1328. }
  1329. void
  1330. CreateFonts()
  1331. { // no-op, until we identify the code for this already in XBoard and move it here
  1332. }
  1333. void
  1334. ParseColor(int n, char *name)
  1335. { // in XBoard, just copy the color-name string
  1336. if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
  1337. }
  1338. void
  1339. ParseTextAttribs(ColorClass cc, char *s)
  1340. {
  1341. (&appData.colorShout)[cc] = strdup(s);
  1342. }
  1343. void
  1344. ParseBoardSize(void *addr, char *name)
  1345. {
  1346. appData.boardSize = strdup(name);
  1347. }
  1348. void
  1349. LoadAllSounds()
  1350. { // In XBoard the sound-playing program takes care of obtaining the actual sound
  1351. }
  1352. void
  1353. SetCommPortDefaults()
  1354. { // for now, this is a no-op, as the corresponding option does not exist in XBoard
  1355. }
  1356. // [HGM] args: these three cases taken out to stay in front-end
  1357. void
  1358. SaveFontArg(FILE *f, ArgDescriptor *ad)
  1359. {
  1360. char *name;
  1361. int i, n = (int)(intptr_t)ad->argLoc;
  1362. switch(n) {
  1363. case 0: // CLOCK_FONT
  1364. name = appData.clockFont;
  1365. break;
  1366. case 1: // MESSAGE_FONT
  1367. name = appData.font;
  1368. break;
  1369. case 2: // COORD_FONT
  1370. name = appData.coordFont;
  1371. break;
  1372. default:
  1373. return;
  1374. }
  1375. for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
  1376. if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
  1377. fontTable[n][squareSize] = strdup(name);
  1378. fontValid[n][squareSize] = True;
  1379. break;
  1380. }
  1381. for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
  1382. fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
  1383. }
  1384. void
  1385. ExportSounds()
  1386. { // nothing to do, as the sounds are at all times represented by their text-string names already
  1387. }
  1388. void
  1389. SaveAttribsArg(FILE *f, ArgDescriptor *ad)
  1390. { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
  1391. fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
  1392. }
  1393. void
  1394. SaveColor(FILE *f, ArgDescriptor *ad)
  1395. { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
  1396. if(colorVariable[(int)(intptr_t)ad->argLoc])
  1397. fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
  1398. }
  1399. void
  1400. SaveBoardSize(FILE *f, char *name, void *addr)
  1401. { // wrapper to shield back-end from BoardSize & sizeInfo
  1402. fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
  1403. }
  1404. void
  1405. ParseCommPortSettings(char *s)
  1406. { // no such option in XBoard (yet)
  1407. }
  1408. extern Widget engineOutputShell;
  1409. extern Widget tagsShell, editTagsShell;
  1410. void
  1411. GetActualPlacement(Widget wg, WindowPlacement *wp)
  1412. {
  1413. Arg args[16];
  1414. Dimension w, h;
  1415. Position x, y;
  1416. int i;
  1417. if(!wg) return;
  1418. i = 0;
  1419. XtSetArg(args[i], XtNx, &x); i++;
  1420. XtSetArg(args[i], XtNy, &y); i++;
  1421. XtSetArg(args[i], XtNwidth, &w); i++;
  1422. XtSetArg(args[i], XtNheight, &h); i++;
  1423. XtGetValues(wg, args, i);
  1424. wp->x = x - 4;
  1425. wp->y = y - 23;
  1426. wp->height = h;
  1427. wp->width = w;
  1428. }
  1429. void
  1430. GetWindowCoords()
  1431. { // wrapper to shield use of window handles from back-end (make addressible by number?)
  1432. // In XBoard this will have to wait until awareness of window parameters is implemented
  1433. GetActualPlacement(shellWidget, &wpMain);
  1434. if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
  1435. if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
  1436. if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
  1437. if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
  1438. if(commentShell) GetActualPlacement(commentShell, &wpComment);
  1439. else GetActualPlacement(editShell, &wpComment);
  1440. if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
  1441. else GetActualPlacement(editTagsShell, &wpTags);
  1442. }
  1443. void
  1444. PrintCommPortSettings(FILE *f, char *name)
  1445. { // This option does not exist in XBoard
  1446. }
  1447. int
  1448. MySearchPath(char *installDir, char *name, char *fullname)
  1449. { // just append installDir and name. Perhaps ExpandPath should be used here?
  1450. name = ExpandPathName(name);
  1451. if(name && name[0] == '/')
  1452. safeStrCpy(fullname, name, MSG_SIZ );
  1453. else {
  1454. sprintf(fullname, "%s%c%s", installDir, '/', name);
  1455. }
  1456. return 1;
  1457. }
  1458. int
  1459. MyGetFullPathName(char *name, char *fullname)
  1460. { // should use ExpandPath?
  1461. name = ExpandPathName(name);
  1462. safeStrCpy(fullname, name, MSG_SIZ );
  1463. return 1;
  1464. }
  1465. void
  1466. EnsureOnScreen(int *x, int *y, int minX, int minY)
  1467. {
  1468. return;
  1469. }
  1470. int
  1471. MainWindowUp()
  1472. { // [HGM] args: allows testing if main window is realized from back-end
  1473. return xBoardWindow != 0;
  1474. }
  1475. void
  1476. PopUpStartupDialog()
  1477. { // start menu not implemented in XBoard
  1478. }
  1479. char *
  1480. ConvertToLine(int argc, char **argv)
  1481. {
  1482. static char line[128*1024], buf[1024];
  1483. int i;
  1484. line[0] = NULLCHAR;
  1485. for(i=1; i<argc; i++)
  1486. {
  1487. if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
  1488. && argv[i][0] != '{' )
  1489. snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
  1490. else
  1491. snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
  1492. strncat(line, buf, 128*1024 - strlen(line) - 1 );
  1493. }
  1494. line[strlen(line)-1] = NULLCHAR;
  1495. return line;
  1496. }
  1497. //--------------------------------------------------------------------------------------------
  1498. extern Boolean twoBoards, partnerUp;
  1499. #ifdef IDSIZES
  1500. // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
  1501. #else
  1502. #define BoardSize int
  1503. void InitDrawingSizes(BoardSize boardSize, int flags)
  1504. { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
  1505. Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
  1506. Arg args[16];
  1507. XtGeometryResult gres;
  1508. int i;
  1509. if(!formWidget) return;
  1510. /*
  1511. * Enable shell resizing.
  1512. */
  1513. shellArgs[0].value = (XtArgVal) &w;
  1514. shellArgs[1].value = (XtArgVal) &h;
  1515. XtGetValues(shellWidget, shellArgs, 2);
  1516. shellArgs[4].value = 3*w; shellArgs[2].value = 10;
  1517. shellArgs[5].value = 2*h; shellArgs[3].value = 10;
  1518. XtSetValues(shellWidget, &shellArgs[2], 4);
  1519. XtSetArg(args[0], XtNdefaultDistance, &sep);
  1520. XtGetValues(formWidget, args, 1);
  1521. if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
  1522. boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
  1523. boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
  1524. CreateGrid();
  1525. hOffset = boardWidth + 10;
  1526. for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
  1527. secondSegments[i] = gridSegments[i];
  1528. secondSegments[i].x1 += hOffset;
  1529. secondSegments[i].x2 += hOffset;
  1530. }
  1531. XtSetArg(args[0], XtNwidth, boardWidth);
  1532. XtSetArg(args[1], XtNheight, boardHeight);
  1533. XtSetValues(boardWidget, args, 2);
  1534. timerWidth = (boardWidth - sep) / 2;
  1535. XtSetArg(args[0], XtNwidth, timerWidth);
  1536. XtSetValues(whiteTimerWidget, args, 1);
  1537. XtSetValues(blackTimerWidget, args, 1);
  1538. XawFormDoLayout(formWidget, False);
  1539. if (appData.titleInWindow) {
  1540. i = 0;
  1541. XtSetArg(args[i], XtNborderWidth, &bor); i++;
  1542. XtSetArg(args[i], XtNheight, &h); i++;
  1543. XtGetValues(titleWidget, args, i);
  1544. if (smallLayout) {
  1545. w = boardWidth - 2*bor;
  1546. } else {
  1547. XtSetArg(args[0], XtNwidth, &w);
  1548. XtGetValues(menuBarWidget, args, 1);
  1549. w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
  1550. }
  1551. gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
  1552. if (gres != XtGeometryYes && appData.debugMode) {
  1553. fprintf(stderr,
  1554. _("%s: titleWidget geometry error %d %d %d %d %d\n"),
  1555. programName, gres, w, h, wr, hr);
  1556. }
  1557. }
  1558. XawFormDoLayout(formWidget, True);
  1559. /*
  1560. * Inhibit shell resizing.
  1561. */
  1562. shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
  1563. shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
  1564. shellArgs[4].value = shellArgs[2].value = w;
  1565. shellArgs[5].value = shellArgs[3].value = h;
  1566. XtSetValues(shellWidget, &shellArgs[0], 6);
  1567. // [HGM] pieces: tailor piece bitmaps to needs of specific variant
  1568. // (only for xpm)
  1569. if(useImages) {
  1570. for(i=0; i<4; i++) {
  1571. int p;
  1572. for(p=0; p<=(int)WhiteKing; p++)
  1573. xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
  1574. if(gameInfo.variant == VariantShogi) {
  1575. xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
  1576. xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
  1577. xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
  1578. xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
  1579. xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
  1580. }
  1581. #ifdef GOTHIC
  1582. if(gameInfo.variant == VariantGothic) {
  1583. xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
  1584. }
  1585. #endif
  1586. if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
  1587. xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
  1588. xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
  1589. }
  1590. #if !HAVE_LIBXPM
  1591. // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
  1592. for(p=0; p<=(int)WhiteKing; p++)
  1593. ximMaskPm[p] = ximMaskPm2[p]; // defaults
  1594. if(gameInfo.variant == VariantShogi) {
  1595. ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
  1596. ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
  1597. ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
  1598. ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
  1599. ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
  1600. }
  1601. #ifdef GOTHIC
  1602. if(gameInfo.variant == VariantGothic) {
  1603. ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
  1604. }
  1605. #endif
  1606. if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
  1607. ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
  1608. ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
  1609. }
  1610. #endif
  1611. }
  1612. } else {
  1613. for(i=0; i<2; i++) {
  1614. int p;
  1615. for(p=0; p<=(int)WhiteKing; p++)
  1616. pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
  1617. if(gameInfo.variant == VariantShogi) {
  1618. pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
  1619. pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
  1620. pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
  1621. pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
  1622. pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
  1623. }
  1624. #ifdef GOTHIC
  1625. if(gameInfo.variant == VariantGothic) {
  1626. pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
  1627. }
  1628. #endif
  1629. if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
  1630. pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
  1631. pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
  1632. }
  1633. }
  1634. }
  1635. #if HAVE_LIBXPM
  1636. CreateAnimVars();
  1637. #endif
  1638. }
  1639. #endif
  1640. void ParseIcsTextColors()
  1641. { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
  1642. if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
  1643. parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
  1644. parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
  1645. parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
  1646. parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
  1647. parse_cpair(ColorTell, appData.colorTell) < 0 ||
  1648. parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
  1649. parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
  1650. parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
  1651. parse_cpair(ColorNormal, appData.colorNormal) < 0)
  1652. {
  1653. if (appData.colorize) {
  1654. fprintf(stderr,
  1655. _("%s: can't parse color names; disabling colorization\n"),
  1656. programName);
  1657. }
  1658. appData.colorize = FALSE;
  1659. }
  1660. }
  1661. int MakeColors()
  1662. { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
  1663. XrmValue vFrom, vTo;
  1664. int forceMono = False;
  1665. if (!appData.monoMode) {
  1666. vFrom.addr = (caddr_t) appData.lightSquareColor;
  1667. vFrom.size = strlen(appData.lightSquareColor);
  1668. XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
  1669. if (vTo.addr == NULL) {
  1670. appData.monoMode = True;
  1671. forceMono = True;
  1672. } else {
  1673. lightSquareColor = *(Pixel *) vTo.addr;
  1674. }
  1675. }
  1676. if (!appData.monoMode) {
  1677. vFrom.addr = (caddr_t) appData.darkSquareColor;
  1678. vFrom.size = strlen(appData.darkSquareColor);
  1679. XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
  1680. if (vTo.addr == NULL) {
  1681. appData.monoMode = True;
  1682. forceMono = True;
  1683. } else {
  1684. darkSquareColor = *(Pixel *) vTo.addr;
  1685. }
  1686. }
  1687. if (!appData.monoMode) {
  1688. vFrom.addr = (caddr_t) appData.whitePieceColor;
  1689. vFrom.size = strlen(appData.whitePieceColor);
  1690. XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
  1691. if (vTo.addr == NULL) {
  1692. appData.monoMode = True;
  1693. forceMono = True;
  1694. } else {
  1695. whitePieceColor = *(Pixel *) vTo.addr;
  1696. }
  1697. }
  1698. if (!appData.monoMode) {
  1699. vFrom.addr = (caddr_t) appData.blackPieceColor;
  1700. vFrom.size = strlen(appData.blackPieceColor);
  1701. XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
  1702. if (vTo.addr == NULL) {
  1703. appData.monoMode = True;
  1704. forceMono = True;
  1705. } else {
  1706. blackPieceColor = *(Pixel *) vTo.addr;
  1707. }
  1708. }
  1709. if (!appData.monoMode) {
  1710. vFrom.addr = (caddr_t) appData.highlightSquareColor;
  1711. vFrom.size = strlen(appData.highlightSquareColor);
  1712. XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
  1713. if (vTo.addr == NULL) {
  1714. appData.monoMode = True;
  1715. forceMono = True;
  1716. } else {
  1717. highlightSquareColor = *(Pixel *) vTo.addr;
  1718. }
  1719. }
  1720. if (!appData.monoMode) {
  1721. vFrom.addr = (caddr_t) appData.premoveHighlightColor;
  1722. vFrom.size = strlen(appData.premoveHighlightColor);
  1723. XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
  1724. if (vTo.addr == NULL) {
  1725. appData.monoMode = True;
  1726. forceMono = True;
  1727. } else {
  1728. premoveHighlightColor = *(Pixel *) vTo.addr;
  1729. }
  1730. }
  1731. return forceMono;
  1732. }
  1733. void
  1734. CreateAnyPieces()
  1735. { // [HGM] taken out of main
  1736. #if HAVE_LIBXPM
  1737. if (appData.monoMode && // [HGM] no sense to go on to certain doom
  1738. (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
  1739. appData.bitmapDirectory = DEF_BITMAP_DIR;
  1740. if (appData.bitmapDirectory[0] != NULLCHAR) {
  1741. CreatePieces();
  1742. } else {
  1743. CreateXPMPieces();
  1744. CreateXPMBoard(appData.liteBackTextureFile, 1);
  1745. CreateXPMBoard(appData.darkBackTextureFile, 0);
  1746. }
  1747. #else
  1748. CreateXIMPieces();
  1749. /* Create regular pieces */
  1750. if (!useImages) CreatePieces();
  1751. #endif
  1752. }
  1753. int
  1754. main(argc, argv)
  1755. int argc;
  1756. char **argv;
  1757. {
  1758. int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
  1759. XSetWindowAttributes window_attributes;
  1760. Arg args[16];
  1761. Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
  1762. XrmValue vFrom, vTo;
  1763. XtGeometryResult gres;
  1764. char *p;
  1765. XrmDatabase xdb;
  1766. int forceMono = False;
  1767. srandom(time(0)); // [HGM] book: make random truly random
  1768. setbuf(stdout, NULL);
  1769. setbuf(stderr, NULL);
  1770. debugFP = stderr;
  1771. if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
  1772. printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
  1773. exit(0);
  1774. }
  1775. programName = strrchr(argv[0], '/');
  1776. if (programName == NULL)
  1777. programName = argv[0];
  1778. else
  1779. programName++;
  1780. #ifdef ENABLE_NLS
  1781. XtSetLanguageProc(NULL, NULL, NULL);
  1782. bindtextdomain(PACKAGE, LOCALEDIR);
  1783. textdomain(PACKAGE);
  1784. #endif
  1785. shellWidget =
  1786. XtAppInitialize(&appContext, "XBoard", shellOptions,
  1787. XtNumber(shellOptions),
  1788. &argc, argv, xboardResources, NULL, 0);
  1789. appData.boardSize = "";
  1790. InitAppData(ConvertToLine(argc, argv));
  1791. p = getenv("HOME");
  1792. if (p == NULL) p = "/tmp";
  1793. i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
  1794. gameCopyFilename = (char*) malloc(i);
  1795. gamePasteFilename = (char*) malloc(i);
  1796. snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
  1797. snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
  1798. XtGetApplicationResources(shellWidget, (XtPointer) &appData,
  1799. clientResources, XtNumber(clientResources),
  1800. NULL, 0);
  1801. { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
  1802. static char buf[MSG_SIZ];
  1803. EscapeExpand(buf, appData.initString);
  1804. appData.initString = strdup(buf);
  1805. EscapeExpand(buf, appData.secondInitString);
  1806. appData.secondInitString = strdup(buf);
  1807. EscapeExpand(buf, appData.firstComputerString);
  1808. appData.firstComputerString = strdup(buf);
  1809. EscapeExpand(buf, appData.secondComputerString);
  1810. appData.secondComputerString = strdup(buf);
  1811. }
  1812. if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
  1813. chessDir = ".";
  1814. } else {
  1815. if (chdir(chessDir) != 0) {
  1816. fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
  1817. perror(chessDir);
  1818. exit(1);
  1819. }
  1820. }
  1821. if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
  1822. /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
  1823. if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
  1824. printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
  1825. exit(errno);
  1826. }
  1827. setbuf(debugFP, NULL);
  1828. }
  1829. /* [HGM,HR] make sure board size is acceptable */
  1830. if(appData.NrFiles > BOARD_FILES ||
  1831. appData.NrRanks > BOARD_RANKS )
  1832. DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
  1833. #if !HIGHDRAG
  1834. /* This feature does not work; animation needs a rewrite */
  1835. appData.highlightDragging = FALSE;
  1836. #endif
  1837. InitBackEnd1();
  1838. xDisplay = XtDisplay(shellWidget);
  1839. xScreen = DefaultScreen(xDisplay);
  1840. wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
  1841. gameInfo.variant = StringToVariant(appData.variant);
  1842. InitPosition(FALSE);
  1843. #ifdef IDSIZE
  1844. InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
  1845. #else
  1846. if (isdigit(appData.boardSize[0])) {
  1847. i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
  1848. &lineGap, &clockFontPxlSize, &coordFontPxlSize,
  1849. &fontPxlSize, &smallLayout, &tinyLayout);
  1850. if (i == 0) {
  1851. fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
  1852. programName, appData.boardSize);
  1853. exit(2);
  1854. }
  1855. if (i < 7) {
  1856. /* Find some defaults; use the nearest known size */
  1857. SizeDefaults *szd, *nearest;
  1858. int distance = 99999;
  1859. nearest = szd = sizeDefaults;
  1860. while (szd->name != NULL) {
  1861. if (abs(szd->squareSize - squareSize) < distance) {
  1862. nearest = szd;
  1863. distance = abs(szd->squareSize - squareSize);
  1864. if (distance == 0) break;
  1865. }
  1866. szd++;
  1867. }
  1868. if (i < 2) lineGap = nearest->lineGap;
  1869. if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
  1870. if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
  1871. if (i < 5) fontPxlSize = nearest->fontPxlSize;
  1872. if (i < 6) smallLayout = nearest->smallLayout;
  1873. if (i < 7) tinyLayout = nearest->tinyLayout;
  1874. }
  1875. } else {
  1876. SizeDefaults *szd = sizeDefaults;
  1877. if (*appData.boardSize == NULLCHAR) {
  1878. while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
  1879. DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
  1880. szd++;
  1881. }
  1882. if (szd->name == NULL) szd--;
  1883. appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
  1884. } else {
  1885. while (szd->name != NULL &&
  1886. StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
  1887. if (szd->name == NULL) {
  1888. fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
  1889. programName, appData.boardSize);
  1890. exit(2);
  1891. }
  1892. }
  1893. squareSize = szd->squareSize;
  1894. lineGap = szd->lineGap;
  1895. clockFontPxlSize = szd->clockFontPxlSize;
  1896. coordFontPxlSize = szd->coordFontPxlSize;
  1897. fontPxlSize = szd->fontPxlSize;
  1898. smallLayout = szd->smallLayout;
  1899. tinyLayout = szd->tinyLayout;
  1900. // [HGM] font: use defaults from settings file if available and not overruled
  1901. }
  1902. if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
  1903. appData.clockFont = fontTable[CLOCK_FONT][squareSize];
  1904. if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
  1905. appData.font = fontTable[MESSAGE_FONT][squareSize];
  1906. if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
  1907. appData.coordFont = fontTable[COORD_FONT][squareSize];
  1908. /* Now, using squareSize as a hint, find a good XPM/XIM set size */
  1909. if (strlen(appData.pixmapDirectory) > 0) {
  1910. p = ExpandPathName(appData.pixmapDirectory);
  1911. if (!p) {
  1912. fprintf(stderr, _("Error expanding path name \"%s\"\n"),
  1913. appData.pixmapDirectory);
  1914. exit(1);
  1915. }
  1916. if (appData.debugMode) {
  1917. fprintf(stderr, _("\
  1918. XBoard square size (hint): %d\n\
  1919. %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
  1920. }
  1921. squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
  1922. if (appData.debugMode) {
  1923. fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
  1924. }
  1925. }
  1926. defaultLineGap = lineGap;
  1927. if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
  1928. /* [HR] height treated separately (hacked) */
  1929. boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
  1930. boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
  1931. if (appData.showJail == 1) {
  1932. /* Jail on top and bottom */
  1933. XtSetArg(boardArgs[1], XtNwidth, boardWidth);
  1934. XtSetArg(boardArgs[2], XtNheight,
  1935. boardHeight + 2*(lineGap + squareSize));
  1936. } else if (appData.showJail == 2) {
  1937. /* Jail on sides */
  1938. XtSetArg(boardArgs[1], XtNwidth,
  1939. boardWidth + 2*(lineGap + squareSize));
  1940. XtSetArg(boardArgs[2], XtNheight, boardHeight);
  1941. } else {
  1942. /* No jail */
  1943. XtSetArg(boardArgs[1], XtNwidth, boardWidth);
  1944. XtSetArg(boardArgs[2], XtNheight, boardHeight);
  1945. }
  1946. /*
  1947. * Determine what fonts to use.
  1948. */
  1949. appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
  1950. clockFontID = XLoadFont(xDisplay, appData.clockFont);
  1951. clockFontStruct = XQueryFont(xDisplay, clockFontID);
  1952. appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
  1953. coordFontID = XLoadFont(xDisplay, appData.coordFont);
  1954. coordFontStruct = XQueryFont(xDisplay, coordFontID);
  1955. appData.font = FindFont(appData.font, fontPxlSize);
  1956. countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
  1957. countFontStruct = XQueryFont(xDisplay, countFontID);
  1958. // appData.font = FindFont(appData.font, fontPxlSize);
  1959. xdb = XtDatabase(xDisplay);
  1960. XrmPutStringResource(&xdb, "*font", appData.font);
  1961. /*
  1962. * Detect if there are not enough colors available and adapt.
  1963. */
  1964. if (DefaultDepth(xDisplay, xScreen) <= 2) {
  1965. appData.monoMode = True;
  1966. }
  1967. forceMono = MakeColors();
  1968. if (forceMono) {
  1969. fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
  1970. programName);
  1971. appData.monoMode = True;
  1972. }
  1973. if (appData.lowTimeWarning && !appData.monoMode) {
  1974. vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
  1975. vFrom.size = strlen(appData.lowTimeWarningColor);
  1976. XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
  1977. if (vTo.addr == NULL)
  1978. appData.monoMode = True;
  1979. else
  1980. lowTimeWarningColor = *(Pixel *) vTo.addr;
  1981. }
  1982. if (appData.monoMode && appData.debugMode) {
  1983. fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
  1984. (unsigned long) XWhitePixel(xDisplay, xScreen),
  1985. (unsigned long) XBlackPixel(xDisplay, xScreen));
  1986. }
  1987. ParseIcsTextColors();
  1988. textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
  1989. textColors[ColorNone].attr = 0;
  1990. XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
  1991. /*
  1992. * widget hierarchy
  1993. */
  1994. if (tinyLayout) {
  1995. layoutName = "tinyLayout";
  1996. } else if (smallLayout) {
  1997. layoutName = "smallLayout";
  1998. } else {
  1999. layoutName = "normalLayout";
  2000. }
  2001. /* Outer layoutWidget is there only to provide a name for use in
  2002. resources that depend on the layout style */
  2003. layoutWidget =
  2004. XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
  2005. layoutArgs, XtNumber(layoutArgs));
  2006. formWidget =
  2007. XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
  2008. formArgs, XtNumber(formArgs));
  2009. XtSetArg(args[0], XtNdefaultDistance, &sep);
  2010. XtGetValues(formWidget, args, 1);
  2011. j = 0;
  2012. widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
  2013. XtSetArg(args[0], XtNtop, XtChainTop);
  2014. XtSetArg(args[1], XtNbottom, XtChainTop);
  2015. XtSetArg(args[2], XtNright, XtChainLeft);
  2016. XtSetValues(menuBarWidget, args, 3);
  2017. widgetList[j++] = whiteTimerWidget =
  2018. XtCreateWidget("whiteTime", labelWidgetClass,
  2019. formWidget, timerArgs, XtNumber(timerArgs));
  2020. XtSetArg(args[0], XtNfont, clockFontStruct);
  2021. XtSetArg(args[1], XtNtop, XtChainTop);
  2022. XtSetArg(args[2], XtNbottom, XtChainTop);
  2023. XtSetValues(whiteTimerWidget, args, 3);
  2024. widgetList[j++] = blackTimerWidget =
  2025. XtCreateWidget("blackTime", labelWidgetClass,
  2026. formWidget, timerArgs, XtNumber(timerArgs));
  2027. XtSetArg(args[0], XtNfont, clockFontStruct);
  2028. XtSetArg(args[1], XtNtop, XtChainTop);
  2029. XtSetArg(args[2], XtNbottom, XtChainTop);
  2030. XtSetValues(blackTimerWidget, args, 3);
  2031. if (appData.titleInWindow) {
  2032. widgetList[j++] = titleWidget =
  2033. XtCreateWidget("title", labelWidgetClass, formWidget,
  2034. titleArgs, XtNumber(titleArgs));
  2035. XtSetArg(args[0], XtNtop, XtChainTop);
  2036. XtSetArg(args[1], XtNbottom, XtChainTop);
  2037. XtSetValues(titleWidget, args, 2);
  2038. }
  2039. if (appData.showButtonBar) {
  2040. widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
  2041. XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
  2042. XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
  2043. XtSetArg(args[2], XtNtop, XtChainTop);
  2044. XtSetArg(args[3], XtNbottom, XtChainTop);
  2045. XtSetValues(buttonBarWidget, args, 4);
  2046. }
  2047. widgetList[j++] = messageWidget =
  2048. XtCreateWidget("message", labelWidgetClass, formWidget,
  2049. messageArgs, XtNumber(messageArgs));
  2050. XtSetArg(args[0], XtNtop, XtChainTop);
  2051. XtSetArg(args[1], XtNbottom, XtChainTop);
  2052. XtSetValues(messageWidget, args, 2);
  2053. widgetList[j++] = boardWidget =
  2054. XtCreateWidget("board", widgetClass, formWidget, boardArgs,
  2055. XtNumber(boardArgs));
  2056. XtManageChildren(widgetList, j);
  2057. timerWidth = (boardWidth - sep) / 2;
  2058. XtSetArg(args[0], XtNwidth, timerWidth);
  2059. XtSetValues(whiteTimerWidget, args, 1);
  2060. XtSetValues(blackTimerWidget, args, 1);
  2061. XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
  2062. XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
  2063. XtGetValues(whiteTimerWidget, args, 2);
  2064. if (appData.showButtonBar) {
  2065. XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
  2066. XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
  2067. XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
  2068. }
  2069. /*
  2070. * formWidget uses these constraints but they are stored
  2071. * in the children.
  2072. */
  2073. i = 0;
  2074. XtSetArg(args[i], XtNfromHoriz, 0); i++;
  2075. XtSetValues(menuBarWidget, args, i);
  2076. if (appData.titleInWindow) {
  2077. if (smallLayout) {
  2078. i = 0;
  2079. XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
  2080. XtSetValues(whiteTimerWidget, args, i);
  2081. i = 0;
  2082. XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
  2083. XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
  2084. XtSetValues(blackTimerWidget, args, i);
  2085. i = 0;
  2086. XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
  2087. XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
  2088. XtSetValues(titleWidget, args, i);
  2089. i = 0;
  2090. XtSetArg(args[i], XtNfromVert, titleWidget); i++;
  2091. XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
  2092. XtSetValues(messageWidget, args, i);
  2093. if (appData.showButtonBar) {
  2094. i = 0;
  2095. XtSetArg(args[i], XtNfromVert, titleWidget); i++;
  2096. XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
  2097. XtSetValues(buttonBarWidget, args, i);
  2098. }
  2099. } else {
  2100. i = 0;
  2101. XtSetArg(args[i], XtNfromVert, titleWidget); i++;
  2102. XtSetValues(whiteTimerWidget, args, i);
  2103. i = 0;
  2104. XtSetArg(args[i], XtNfromVert, titleWidget); i++;
  2105. XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
  2106. XtSetValues(blackTimerWidget, args, i);
  2107. i = 0;
  2108. XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
  2109. XtSetValues(titleWidget, args, i);
  2110. i = 0;
  2111. XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
  2112. XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
  2113. XtSetValues(messageWidget, args, i);
  2114. if (appData.showButtonBar) {
  2115. i = 0;
  2116. XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
  2117. XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
  2118. XtSetValues(buttonBarWidget, args, i);
  2119. }
  2120. }
  2121. } else {
  2122. i = 0;
  2123. XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
  2124. XtSetValues(whiteTimerWidget, args, i);
  2125. i = 0;
  2126. XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
  2127. XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
  2128. XtSetValues(blackTimerWidget, args, i);
  2129. i = 0;
  2130. XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
  2131. XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
  2132. XtSetValues(messageWidget, args, i);
  2133. if (appData.showButtonBar) {
  2134. i = 0;
  2135. XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
  2136. XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
  2137. XtSetValues(buttonBarWidget, args, i);
  2138. }
  2139. }
  2140. i = 0;
  2141. XtSetArg(args[0], XtNfromVert, messageWidget);
  2142. XtSetArg(args[1], XtNtop, XtChainTop);
  2143. XtSetArg(args[2], XtNbottom, XtChainBottom);
  2144. XtSetArg(args[3], XtNleft, XtChainLeft);
  2145. XtSetArg(args[4], XtNright, XtChainRight);
  2146. XtSetValues(boardWidget, args, 5);
  2147. XtRealizeWidget(shellWidget);
  2148. if(wpMain.x > 0) {
  2149. XtSetArg(args[0], XtNx, wpMain.x);
  2150. XtSetArg(args[1], XtNy, wpMain.y);
  2151. XtSetValues(shellWidget, args, 2);
  2152. }
  2153. /*
  2154. * Correct the width of the message and title widgets.
  2155. * It is not known why some systems need the extra fudge term.
  2156. * The value "2" is probably larger than needed.
  2157. */
  2158. XawFormDoLayout(formWidget, False);
  2159. #define WIDTH_FUDGE 2
  2160. i = 0;
  2161. XtSetArg(args[i], XtNborderWidth, &bor); i++;
  2162. XtSetArg(args[i], XtNheight, &h); i++;
  2163. XtGetValues(messageWidget, args, i);
  2164. if (appData.showButtonBar) {
  2165. i = 0;
  2166. XtSetArg(args[i], XtNwidth, &w); i++;
  2167. XtGetValues(buttonBarWidget, args, i);
  2168. w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
  2169. } else {
  2170. w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
  2171. }
  2172. gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
  2173. if (gres != XtGeometryYes && appData.debugMode) {
  2174. fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
  2175. programName, gres, w, h, wr, hr);
  2176. }
  2177. /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
  2178. /* The size used for the child widget in layout lags one resize behind
  2179. its true size, so we resize a second time, 1 pixel smaller. Yeech! */
  2180. w--;
  2181. gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
  2182. if (gres != XtGeometryYes && appData.debugMode) {
  2183. fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
  2184. programName, gres, w, h, wr, hr);
  2185. }
  2186. /* !! end hack */
  2187. XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
  2188. XtSetArg(args[1], XtNright, XtChainRight);
  2189. XtSetValues(messageWidget, args, 2);
  2190. if (appData.titleInWindow) {
  2191. i = 0;
  2192. XtSetArg(args[i], XtNborderWidth, &bor); i++;
  2193. XtSetArg(args[i], XtNheight, &h); i++;
  2194. XtGetValues(titleWidget, args, i);
  2195. if (smallLayout) {
  2196. w = boardWidth - 2*bor;
  2197. } else {
  2198. XtSetArg(args[0], XtNwidth, &w);
  2199. XtGetValues(menuBarWidget, args, 1);
  2200. w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
  2201. }
  2202. gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
  2203. if (gres != XtGeometryYes && appData.debugMode) {
  2204. fprintf(stderr,
  2205. _("%s: titleWidget geometry error %d %d %d %d %d\n"),
  2206. programName, gres, w, h, wr, hr);
  2207. }
  2208. }
  2209. XawFormDoLayout(formWidget, True);
  2210. xBoardWindow = XtWindow(boardWidget);
  2211. // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
  2212. // not need to go into InitDrawingSizes().
  2213. #endif
  2214. /*
  2215. * Create X checkmark bitmap and initialize option menu checks.
  2216. */
  2217. ReadBitmap(&xMarkPixmap, "checkmark.bm",
  2218. checkmark_bits, checkmark_width, checkmark_height);
  2219. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  2220. #ifndef OPTIONSDIALOG
  2221. if (appData.alwaysPromoteToQueen) {
  2222. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
  2223. args, 1);
  2224. }
  2225. if (appData.animateDragging) {
  2226. XtSetValues(XtNameToWidget(menuBarWidget,
  2227. "menuOptions.Animate Dragging"),
  2228. args, 1);
  2229. }
  2230. if (appData.animate) {
  2231. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
  2232. args, 1);
  2233. }
  2234. if (appData.autoCallFlag) {
  2235. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
  2236. args, 1);
  2237. }
  2238. if (appData.autoFlipView) {
  2239. XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
  2240. args, 1);
  2241. }
  2242. if (appData.blindfold) {
  2243. XtSetValues(XtNameToWidget(menuBarWidget,
  2244. "menuOptions.Blindfold"), args, 1);
  2245. }
  2246. if (appData.flashCount > 0) {
  2247. XtSetValues(XtNameToWidget(menuBarWidget,
  2248. "menuOptions.Flash Moves"),
  2249. args, 1);
  2250. }
  2251. #if HIGHDRAG
  2252. if (appData.highlightDragging) {
  2253. XtSetValues(XtNameToWidget(menuBarWidget,
  2254. "menuOptions.Highlight Dragging"),
  2255. args, 1);
  2256. }
  2257. #endif
  2258. if (appData.highlightLastMove) {
  2259. XtSetValues(XtNameToWidget(menuBarWidget,
  2260. "menuOptions.Highlight Last Move"),
  2261. args, 1);
  2262. }
  2263. if (appData.highlightMoveWithArrow) {
  2264. XtSetValues(XtNameToWidget(menuBarWidget,
  2265. "menuOptions.Arrow"),
  2266. args, 1);
  2267. }
  2268. // if (appData.icsAlarm) {
  2269. // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
  2270. // args, 1);
  2271. // }
  2272. if (appData.ringBellAfterMoves) {
  2273. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
  2274. args, 1);
  2275. }
  2276. if (appData.oneClick) {
  2277. XtSetValues(XtNameToWidget(menuBarWidget,
  2278. "menuOptions.OneClick"), args, 1);
  2279. }
  2280. if (appData.periodicUpdates) {
  2281. XtSetValues(XtNameToWidget(menuBarWidget,
  2282. "menuOptions.Periodic Updates"), args, 1);
  2283. }
  2284. if (appData.ponderNextMove) {
  2285. XtSetValues(XtNameToWidget(menuBarWidget,
  2286. "menuOptions.Ponder Next Move"), args, 1);
  2287. }
  2288. if (appData.popupExitMessage) {
  2289. XtSetValues(XtNameToWidget(menuBarWidget,
  2290. "menuOptions.Popup Exit Message"), args, 1);
  2291. }
  2292. if (appData.popupMoveErrors) {
  2293. XtSetValues(XtNameToWidget(menuBarWidget,
  2294. "menuOptions.Popup Move Errors"), args, 1);
  2295. }
  2296. // if (appData.premove) {
  2297. // XtSetValues(XtNameToWidget(menuBarWidget,
  2298. // "menuOptions.Premove"), args, 1);
  2299. // }
  2300. if (appData.showCoords) {
  2301. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
  2302. args, 1);
  2303. }
  2304. if (appData.hideThinkingFromHuman) {
  2305. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
  2306. args, 1);
  2307. }
  2308. if (appData.testLegality) {
  2309. XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
  2310. args, 1);
  2311. }
  2312. #endif
  2313. if (saveSettingsOnExit) {
  2314. XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
  2315. args, 1);
  2316. }
  2317. /*
  2318. * Create an icon.
  2319. */
  2320. ReadBitmap(&wIconPixmap, "icon_white.bm",
  2321. icon_white_bits, icon_white_width, icon_white_height);
  2322. ReadBitmap(&bIconPixmap, "icon_black.bm",
  2323. icon_black_bits, icon_black_width, icon_black_height);
  2324. iconPixmap = wIconPixmap;
  2325. i = 0;
  2326. XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
  2327. XtSetValues(shellWidget, args, i);
  2328. /*
  2329. * Create a cursor for the board widget.
  2330. */
  2331. window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
  2332. XChangeWindowAttributes(xDisplay, xBoardWindow,
  2333. CWCursor, &window_attributes);
  2334. /*
  2335. * Inhibit shell resizing.
  2336. */
  2337. shellArgs[0].value = (XtArgVal) &w;
  2338. shellArgs[1].value = (XtArgVal) &h;
  2339. XtGetValues(shellWidget, shellArgs, 2);
  2340. shellArgs[4].value = shellArgs[2].value = w;
  2341. shellArgs[5].value = shellArgs[3].value = h;
  2342. XtSetValues(shellWidget, &shellArgs[2], 4);
  2343. marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
  2344. marginH = h - boardHeight;
  2345. CatchDeleteWindow(shellWidget, "QuitProc");
  2346. CreateGCs(False);
  2347. CreateGrid();
  2348. CreateAnyPieces();
  2349. CreatePieceMenus();
  2350. if (appData.animate || appData.animateDragging)
  2351. CreateAnimVars();
  2352. XtAugmentTranslations(formWidget,
  2353. XtParseTranslationTable(globalTranslations));
  2354. XtAugmentTranslations(boardWidget,
  2355. XtParseTranslationTable(boardTranslations));
  2356. XtAugmentTranslations(whiteTimerWidget,
  2357. XtParseTranslationTable(whiteTranslations));
  2358. XtAugmentTranslations(blackTimerWidget,
  2359. XtParseTranslationTable(blackTranslations));
  2360. /* Why is the following needed on some versions of X instead
  2361. * of a translation? */
  2362. XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
  2363. (XtEventHandler) EventProc, NULL);
  2364. /* end why */
  2365. /* [AS] Restore layout */
  2366. if( wpMoveHistory.visible ) {
  2367. HistoryPopUp();
  2368. }
  2369. if( wpEvalGraph.visible )
  2370. {
  2371. EvalGraphPopUp();
  2372. };
  2373. if( wpEngineOutput.visible ) {
  2374. EngineOutputPopUp();
  2375. }
  2376. InitBackEnd2();
  2377. if (errorExitStatus == -1) {
  2378. if (appData.icsActive) {
  2379. /* We now wait until we see "login:" from the ICS before
  2380. sending the logon script (problems with timestamp otherwise) */
  2381. /*ICSInitScript();*/
  2382. if (appData.icsInputBox) ICSInputBoxPopUp();
  2383. }
  2384. #ifdef SIGWINCH
  2385. signal(SIGWINCH, TermSizeSigHandler);
  2386. #endif
  2387. signal(SIGINT, IntSigHandler);
  2388. signal(SIGTERM, IntSigHandler);
  2389. if (*appData.cmailGameName != NULLCHAR) {
  2390. signal(SIGUSR1, CmailSigHandler);
  2391. }
  2392. }
  2393. gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
  2394. InitPosition(TRUE);
  2395. // XtSetKeyboardFocus(shellWidget, formWidget);
  2396. XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
  2397. XtAppMainLoop(appContext);
  2398. if (appData.debugMode) fclose(debugFP); // [DM] debug
  2399. return 0;
  2400. }
  2401. void
  2402. ShutDownFrontEnd()
  2403. {
  2404. if (appData.icsActive && oldICSInteractionTitle != NULL) {
  2405. DisplayIcsInteractionTitle(oldICSInteractionTitle);
  2406. }
  2407. if (saveSettingsOnExit) SaveSettings(settingsFileName);
  2408. unlink(gameCopyFilename);
  2409. unlink(gamePasteFilename);
  2410. }
  2411. RETSIGTYPE TermSizeSigHandler(int sig)
  2412. {
  2413. update_ics_width();
  2414. }
  2415. RETSIGTYPE
  2416. IntSigHandler(sig)
  2417. int sig;
  2418. {
  2419. ExitEvent(sig);
  2420. }
  2421. RETSIGTYPE
  2422. CmailSigHandler(sig)
  2423. int sig;
  2424. {
  2425. int dummy = 0;
  2426. int error;
  2427. signal(SIGUSR1, SIG_IGN); /* suspend handler */
  2428. /* Activate call-back function CmailSigHandlerCallBack() */
  2429. OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
  2430. signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
  2431. }
  2432. void
  2433. CmailSigHandlerCallBack(isr, closure, message, count, error)
  2434. InputSourceRef isr;
  2435. VOIDSTAR closure;
  2436. char *message;
  2437. int count;
  2438. int error;
  2439. {
  2440. BoardToTop();
  2441. ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
  2442. }
  2443. /**** end signal code ****/
  2444. void
  2445. ICSInitScript()
  2446. {
  2447. /* try to open the icsLogon script, either in the location given
  2448. * or in the users HOME directory
  2449. */
  2450. FILE *f;
  2451. char buf[MSG_SIZ];
  2452. char *homedir;
  2453. f = fopen(appData.icsLogon, "r");
  2454. if (f == NULL)
  2455. {
  2456. homedir = getenv("HOME");
  2457. if (homedir != NULL)
  2458. {
  2459. safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
  2460. strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
  2461. strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
  2462. f = fopen(buf, "r");
  2463. }
  2464. }
  2465. if (f != NULL)
  2466. ProcessICSInitScript(f);
  2467. else
  2468. printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
  2469. return;
  2470. }
  2471. void
  2472. ResetFrontEnd()
  2473. {
  2474. CommentPopDown();
  2475. EditCommentPopDown();
  2476. TagsPopDown();
  2477. return;
  2478. }
  2479. typedef struct {
  2480. char *name;
  2481. Boolean value;
  2482. } Enables;
  2483. void
  2484. GreyRevert(grey)
  2485. Boolean grey;
  2486. {
  2487. Widget w;
  2488. if (!menuBarWidget) return;
  2489. w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
  2490. if (w == NULL) {
  2491. DisplayError("menuEdit.Revert", 0);
  2492. } else {
  2493. XtSetSensitive(w, !grey);
  2494. }
  2495. w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
  2496. if (w == NULL) {
  2497. DisplayError("menuEdit.Annotate", 0);
  2498. } else {
  2499. XtSetSensitive(w, !grey);
  2500. }
  2501. }
  2502. void
  2503. SetMenuEnables(enab)
  2504. Enables *enab;
  2505. {
  2506. Widget w;
  2507. if (!menuBarWidget) return;
  2508. while (enab->name != NULL) {
  2509. w = XtNameToWidget(menuBarWidget, enab->name);
  2510. if (w == NULL) {
  2511. DisplayError(enab->name, 0);
  2512. } else {
  2513. XtSetSensitive(w, enab->value);
  2514. }
  2515. enab++;
  2516. }
  2517. }
  2518. Enables icsEnables[] = {
  2519. { "menuFile.Mail Move", False },
  2520. { "menuFile.Reload CMail Message", False },
  2521. { "menuMode.Machine Black", False },
  2522. { "menuMode.Machine White", False },
  2523. { "menuMode.Analysis Mode", False },
  2524. { "menuMode.Analyze File", False },
  2525. { "menuMode.Two Machines", False },
  2526. { "menuMode.Machine Match", False },
  2527. #ifndef ZIPPY
  2528. { "menuEngine.Hint", False },
  2529. { "menuEngine.Book", False },
  2530. { "menuEngine.Move Now", False },
  2531. #ifndef OPTIONSDIALOG
  2532. { "menuOptions.Periodic Updates", False },
  2533. { "menuOptions.Hide Thinking", False },
  2534. { "menuOptions.Ponder Next Move", False },
  2535. #endif
  2536. #endif
  2537. { "menuEngine.Engine #1 Settings", False },
  2538. { "menuEngine.Engine #2 Settings", False },
  2539. { "menuEdit.Annotate", False },
  2540. { NULL, False }
  2541. };
  2542. Enables ncpEnables[] = {
  2543. { "menuFile.Mail Move", False },
  2544. { "menuFile.Reload CMail Message", False },
  2545. { "menuMode.Machine White", False },
  2546. { "menuMode.Machine Black", False },
  2547. { "menuMode.Analysis Mode", False },
  2548. { "menuMode.Analyze File", False },
  2549. { "menuMode.Two Machines", False },
  2550. { "menuMode.Machine Match", False },
  2551. { "menuMode.ICS Client", False },
  2552. { "menuView.ICStex", False },
  2553. { "menuView.ICS Input Box", False },
  2554. { "Action", False },
  2555. { "menuEdit.Revert", False },
  2556. { "menuEdit.Annotate", False },
  2557. { "menuEngine.Engine #1 Settings", False },
  2558. { "menuEngine.Engine #2 Settings", False },
  2559. { "menuEngine.Move Now", False },
  2560. { "menuEngine.Retract Move", False },
  2561. { "menuOptions.ICS", False },
  2562. #ifndef OPTIONSDIALOG
  2563. { "menuOptions.Auto Flag", False },
  2564. { "menuOptions.Auto Flip View", False },
  2565. // { "menuOptions.ICS Alarm", False },
  2566. { "menuOptions.Move Sound", False },
  2567. { "menuOptions.Hide Thinking", False },
  2568. { "menuOptions.Periodic Updates", False },
  2569. { "menuOptions.Ponder Next Move", False },
  2570. #endif
  2571. { "menuEngine.Hint", False },
  2572. { "menuEngine.Book", False },
  2573. { NULL, False }
  2574. };
  2575. Enables gnuEnables[] = {
  2576. { "menuMode.ICS Client", False },
  2577. { "menuView.ICStex", False },
  2578. { "menuView.ICS Input Box", False },
  2579. { "menuAction.Accept", False },
  2580. { "menuAction.Decline", False },
  2581. { "menuAction.Rematch", False },
  2582. { "menuAction.Adjourn", False },
  2583. { "menuAction.Stop Examining", False },
  2584. { "menuAction.Stop Observing", False },
  2585. { "menuAction.Upload to Examine", False },
  2586. { "menuEdit.Revert", False },
  2587. { "menuEdit.Annotate", False },
  2588. { "menuOptions.ICS", False },
  2589. /* The next two options rely on SetCmailMode being called *after* */
  2590. /* SetGNUMode so that when GNU is being used to give hints these */
  2591. /* menu options are still available */
  2592. { "menuFile.Mail Move", False },
  2593. { "menuFile.Reload CMail Message", False },
  2594. { NULL, False }
  2595. };
  2596. Enables cmailEnables[] = {
  2597. { "Action", True },
  2598. { "menuAction.Call Flag", False },
  2599. { "menuAction.Draw", True },
  2600. { "menuAction.Adjourn", False },
  2601. { "menuAction.Abort", False },
  2602. { "menuAction.Stop Observing", False },
  2603. { "menuAction.Stop Examining", False },
  2604. { "menuFile.Mail Move", True },
  2605. { "menuFile.Reload CMail Message", True },
  2606. { NULL, False }
  2607. };
  2608. Enables trainingOnEnables[] = {
  2609. { "menuMode.Edit Comment", False },
  2610. { "menuMode.Pause", False },
  2611. { "menuEdit.Forward", False },
  2612. { "menuEdit.Backward", False },
  2613. { "menuEdit.Forward to End", False },
  2614. { "menuEdit.Back to Start", False },
  2615. { "menuEngine.Move Now", False },
  2616. { "menuEdit.Truncate Game", False },
  2617. { NULL, False }
  2618. };
  2619. Enables trainingOffEnables[] = {
  2620. { "menuMode.Edit Comment", True },
  2621. { "menuMode.Pause", True },
  2622. { "menuEdit.Forward", True },
  2623. { "menuEdit.Backward", True },
  2624. { "menuEdit.Forward to End", True },
  2625. { "menuEdit.Back to Start", True },
  2626. { "menuEngine.Move Now", True },
  2627. { "menuEdit.Truncate Game", True },
  2628. { NULL, False }
  2629. };
  2630. Enables machineThinkingEnables[] = {
  2631. { "menuFile.Load Game", False },
  2632. // { "menuFile.Load Next Game", False },
  2633. // { "menuFile.Load Previous Game", False },
  2634. // { "menuFile.Reload Same Game", False },
  2635. { "menuEdit.Paste Game", False },
  2636. { "menuFile.Load Position", False },
  2637. // { "menuFile.Load Next Position", False },
  2638. // { "menuFile.Load Previous Position", False },
  2639. // { "menuFile.Reload Same Position", False },
  2640. { "menuEdit.Paste Position", False },
  2641. { "menuMode.Machine White", False },
  2642. { "menuMode.Machine Black", False },
  2643. { "menuMode.Two Machines", False },
  2644. { "menuMode.Machine Match", False },
  2645. { "menuEngine.Retract Move", False },
  2646. { NULL, False }
  2647. };
  2648. Enables userThinkingEnables[] = {
  2649. { "menuFile.Load Game", True },
  2650. // { "menuFile.Load Next Game", True },
  2651. // { "menuFile.Load Previous Game", True },
  2652. // { "menuFile.Reload Same Game", True },
  2653. { "menuEdit.Paste Game", True },
  2654. { "menuFile.Load Position", True },
  2655. // { "menuFile.Load Next Position", True },
  2656. // { "menuFile.Load Previous Position", True },
  2657. // { "menuFile.Reload Same Position", True },
  2658. { "menuEdit.Paste Position", True },
  2659. { "menuMode.Machine White", True },
  2660. { "menuMode.Machine Black", True },
  2661. { "menuMode.Two Machines", True },
  2662. { "menuMode.Machine Match", True },
  2663. { "menuEngine.Retract Move", True },
  2664. { NULL, False }
  2665. };
  2666. void SetICSMode()
  2667. {
  2668. SetMenuEnables(icsEnables);
  2669. #if ZIPPY
  2670. if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
  2671. XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
  2672. XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
  2673. }
  2674. #endif
  2675. }
  2676. void
  2677. SetNCPMode()
  2678. {
  2679. SetMenuEnables(ncpEnables);
  2680. }
  2681. void
  2682. SetGNUMode()
  2683. {
  2684. SetMenuEnables(gnuEnables);
  2685. }
  2686. void
  2687. SetCmailMode()
  2688. {
  2689. SetMenuEnables(cmailEnables);
  2690. }
  2691. void
  2692. SetTrainingModeOn()
  2693. {
  2694. SetMenuEnables(trainingOnEnables);
  2695. if (appData.showButtonBar) {
  2696. XtSetSensitive(buttonBarWidget, False);
  2697. }
  2698. CommentPopDown();
  2699. }
  2700. void
  2701. SetTrainingModeOff()
  2702. {
  2703. SetMenuEnables(trainingOffEnables);
  2704. if (appData.showButtonBar) {
  2705. XtSetSensitive(buttonBarWidget, True);
  2706. }
  2707. }
  2708. void
  2709. SetUserThinkingEnables()
  2710. {
  2711. if (appData.noChessProgram) return;
  2712. SetMenuEnables(userThinkingEnables);
  2713. }
  2714. void
  2715. SetMachineThinkingEnables()
  2716. {
  2717. if (appData.noChessProgram) return;
  2718. SetMenuEnables(machineThinkingEnables);
  2719. switch (gameMode) {
  2720. case MachinePlaysBlack:
  2721. case MachinePlaysWhite:
  2722. case TwoMachinesPlay:
  2723. XtSetSensitive(XtNameToWidget(menuBarWidget,
  2724. ModeToWidgetName(gameMode)), True);
  2725. break;
  2726. default:
  2727. break;
  2728. }
  2729. }
  2730. // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
  2731. #define HISTORY_SIZE 64
  2732. static char *history[HISTORY_SIZE];
  2733. int histIn = 0, histP = 0;
  2734. void
  2735. SaveInHistory(char *cmd)
  2736. {
  2737. if (history[histIn] != NULL) {
  2738. free(history[histIn]);
  2739. history[histIn] = NULL;
  2740. }
  2741. if (*cmd == NULLCHAR) return;
  2742. history[histIn] = StrSave(cmd);
  2743. histIn = (histIn + 1) % HISTORY_SIZE;
  2744. if (history[histIn] != NULL) {
  2745. free(history[histIn]);
  2746. history[histIn] = NULL;
  2747. }
  2748. histP = histIn;
  2749. }
  2750. char *
  2751. PrevInHistory(char *cmd)
  2752. {
  2753. int newhp;
  2754. if (histP == histIn) {
  2755. if (history[histIn] != NULL) free(history[histIn]);
  2756. history[histIn] = StrSave(cmd);
  2757. }
  2758. newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
  2759. if (newhp == histIn || history[newhp] == NULL) return NULL;
  2760. histP = newhp;
  2761. return history[histP];
  2762. }
  2763. char *
  2764. NextInHistory()
  2765. {
  2766. if (histP == histIn) return NULL;
  2767. histP = (histP + 1) % HISTORY_SIZE;
  2768. return history[histP];
  2769. }
  2770. // end of borrowed code
  2771. #define Abs(n) ((n)<0 ? -(n) : (n))
  2772. /*
  2773. * Find a font that matches "pattern" that is as close as
  2774. * possible to the targetPxlSize. Prefer fonts that are k
  2775. * pixels smaller to fonts that are k pixels larger. The
  2776. * pattern must be in the X Consortium standard format,
  2777. * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
  2778. * The return value should be freed with XtFree when no
  2779. * longer needed.
  2780. */
  2781. char *
  2782. FindFont(pattern, targetPxlSize)
  2783. char *pattern;
  2784. int targetPxlSize;
  2785. {
  2786. char **fonts, *p, *best, *scalable, *scalableTail;
  2787. int i, j, nfonts, minerr, err, pxlSize;
  2788. #ifdef ENABLE_NLS
  2789. char **missing_list;
  2790. int missing_count;
  2791. char *def_string, *base_fnt_lst, strInt[3];
  2792. XFontSet fntSet;
  2793. XFontStruct **fnt_list;
  2794. base_fnt_lst = calloc(1, strlen(pattern) + 3);
  2795. snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
  2796. p = strstr(pattern, "--");
  2797. strncpy(base_fnt_lst, pattern, p - pattern + 2);
  2798. strcat(base_fnt_lst, strInt);
  2799. strcat(base_fnt_lst, strchr(p + 2, '-'));
  2800. if ((fntSet = XCreateFontSet(xDisplay,
  2801. base_fnt_lst,
  2802. &missing_list,
  2803. &missing_count,
  2804. &def_string)) == NULL) {
  2805. fprintf(stderr, _("Unable to create font set.\n"));
  2806. exit (2);
  2807. }
  2808. nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
  2809. #else
  2810. fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
  2811. if (nfonts < 1) {
  2812. fprintf(stderr, _("%s: no fonts match pattern %s\n"),
  2813. programName, pattern);
  2814. exit(2);
  2815. }
  2816. #endif
  2817. best = fonts[0];
  2818. scalable = NULL;
  2819. minerr = 999999;
  2820. for (i=0; i<nfonts; i++) {
  2821. j = 0;
  2822. p = fonts[i];
  2823. if (*p != '-') continue;
  2824. while (j < 7) {
  2825. if (*p == NULLCHAR) break;
  2826. if (*p++ == '-') j++;
  2827. }
  2828. if (j < 7) continue;
  2829. pxlSize = atoi(p);
  2830. if (pxlSize == 0) {
  2831. scalable = fonts[i];
  2832. scalableTail = p;
  2833. } else {
  2834. err = pxlSize - targetPxlSize;
  2835. if (Abs(err) < Abs(minerr) ||
  2836. (minerr > 0 && err < 0 && -err == minerr)) {
  2837. best = fonts[i];
  2838. minerr = err;
  2839. }
  2840. }
  2841. }
  2842. if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
  2843. /* If the error is too big and there is a scalable font,
  2844. use the scalable font. */
  2845. int headlen = scalableTail - scalable;
  2846. p = (char *) XtMalloc(strlen(scalable) + 10);
  2847. while (isdigit(*scalableTail)) scalableTail++;
  2848. sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
  2849. } else {
  2850. p = (char *) XtMalloc(strlen(best) + 2);
  2851. safeStrCpy(p, best, strlen(best)+1 );
  2852. }
  2853. if (appData.debugMode) {
  2854. fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
  2855. pattern, targetPxlSize, p);
  2856. }
  2857. #ifdef ENABLE_NLS
  2858. if (missing_count > 0)
  2859. XFreeStringList(missing_list);
  2860. XFreeFontSet(xDisplay, fntSet);
  2861. #else
  2862. XFreeFontNames(fonts);
  2863. #endif
  2864. return p;
  2865. }
  2866. void DeleteGCs()
  2867. { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
  2868. // must be called before all non-first callse to CreateGCs()
  2869. XtReleaseGC(shellWidget, highlineGC);
  2870. XtReleaseGC(shellWidget, lightSquareGC);
  2871. XtReleaseGC(shellWidget, darkSquareGC);
  2872. XtReleaseGC(shellWidget, lineGC);
  2873. if (appData.monoMode) {
  2874. if (DefaultDepth(xDisplay, xScreen) == 1) {
  2875. XtReleaseGC(shellWidget, wbPieceGC);
  2876. } else {
  2877. XtReleaseGC(shellWidget, bwPieceGC);
  2878. }
  2879. } else {
  2880. XtReleaseGC(shellWidget, prelineGC);
  2881. XtReleaseGC(shellWidget, jailSquareGC);
  2882. XtReleaseGC(shellWidget, wdPieceGC);
  2883. XtReleaseGC(shellWidget, wlPieceGC);
  2884. XtReleaseGC(shellWidget, wjPieceGC);
  2885. XtReleaseGC(shellWidget, bdPieceGC);
  2886. XtReleaseGC(shellWidget, blPieceGC);
  2887. XtReleaseGC(shellWidget, bjPieceGC);
  2888. }
  2889. }
  2890. void CreateGCs(int redo)
  2891. {
  2892. XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
  2893. | GCBackground | GCFunction | GCPlaneMask;
  2894. XGCValues gc_values;
  2895. GC copyInvertedGC;
  2896. gc_values.plane_mask = AllPlanes;
  2897. gc_values.line_width = lineGap;
  2898. gc_values.line_style = LineSolid;
  2899. gc_values.function = GXcopy;
  2900. if(redo) {
  2901. DeleteGCs(); // called a second time; clean up old GCs first
  2902. } else { // [HGM] grid and font GCs created on first call only
  2903. gc_values.foreground = XBlackPixel(xDisplay, xScreen);
  2904. gc_values.background = XWhitePixel(xDisplay, xScreen);
  2905. coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2906. XSetFont(xDisplay, coordGC, coordFontID);
  2907. // [HGM] make font for holdings counts (white on black)
  2908. gc_values.foreground = XWhitePixel(xDisplay, xScreen);
  2909. gc_values.background = XBlackPixel(xDisplay, xScreen);
  2910. countGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2911. XSetFont(xDisplay, countGC, countFontID);
  2912. }
  2913. gc_values.foreground = XBlackPixel(xDisplay, xScreen);
  2914. gc_values.background = XBlackPixel(xDisplay, xScreen);
  2915. lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2916. if (appData.monoMode) {
  2917. gc_values.foreground = XWhitePixel(xDisplay, xScreen);
  2918. gc_values.background = XWhitePixel(xDisplay, xScreen);
  2919. highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2920. gc_values.foreground = XWhitePixel(xDisplay, xScreen);
  2921. gc_values.background = XBlackPixel(xDisplay, xScreen);
  2922. lightSquareGC = wbPieceGC
  2923. = XtGetGC(shellWidget, value_mask, &gc_values);
  2924. gc_values.foreground = XBlackPixel(xDisplay, xScreen);
  2925. gc_values.background = XWhitePixel(xDisplay, xScreen);
  2926. darkSquareGC = bwPieceGC
  2927. = XtGetGC(shellWidget, value_mask, &gc_values);
  2928. if (DefaultDepth(xDisplay, xScreen) == 1) {
  2929. /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
  2930. gc_values.function = GXcopyInverted;
  2931. copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2932. gc_values.function = GXcopy;
  2933. if (XBlackPixel(xDisplay, xScreen) == 1) {
  2934. bwPieceGC = darkSquareGC;
  2935. wbPieceGC = copyInvertedGC;
  2936. } else {
  2937. bwPieceGC = copyInvertedGC;
  2938. wbPieceGC = lightSquareGC;
  2939. }
  2940. }
  2941. } else {
  2942. gc_values.foreground = highlightSquareColor;
  2943. gc_values.background = highlightSquareColor;
  2944. highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2945. gc_values.foreground = premoveHighlightColor;
  2946. gc_values.background = premoveHighlightColor;
  2947. prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2948. gc_values.foreground = lightSquareColor;
  2949. gc_values.background = darkSquareColor;
  2950. lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2951. gc_values.foreground = darkSquareColor;
  2952. gc_values.background = lightSquareColor;
  2953. darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2954. gc_values.foreground = jailSquareColor;
  2955. gc_values.background = jailSquareColor;
  2956. jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2957. gc_values.foreground = whitePieceColor;
  2958. gc_values.background = darkSquareColor;
  2959. wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2960. gc_values.foreground = whitePieceColor;
  2961. gc_values.background = lightSquareColor;
  2962. wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2963. gc_values.foreground = whitePieceColor;
  2964. gc_values.background = jailSquareColor;
  2965. wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2966. gc_values.foreground = blackPieceColor;
  2967. gc_values.background = darkSquareColor;
  2968. bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2969. gc_values.foreground = blackPieceColor;
  2970. gc_values.background = lightSquareColor;
  2971. blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2972. gc_values.foreground = blackPieceColor;
  2973. gc_values.background = jailSquareColor;
  2974. bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
  2975. }
  2976. }
  2977. void loadXIM(xim, xmask, filename, dest, mask)
  2978. XImage *xim;
  2979. XImage *xmask;
  2980. char *filename;
  2981. Pixmap *dest;
  2982. Pixmap *mask;
  2983. {
  2984. int x, y, w, h, p;
  2985. FILE *fp;
  2986. Pixmap temp;
  2987. XGCValues values;
  2988. GC maskGC;
  2989. fp = fopen(filename, "rb");
  2990. if (!fp) {
  2991. fprintf(stderr, _("%s: error loading XIM!\n"), programName);
  2992. exit(1);
  2993. }
  2994. w = fgetc(fp);
  2995. h = fgetc(fp);
  2996. for (y=0; y<h; ++y) {
  2997. for (x=0; x<h; ++x) {
  2998. p = fgetc(fp);
  2999. switch (p) {
  3000. case 0:
  3001. XPutPixel(xim, x, y, blackPieceColor);
  3002. if (xmask)
  3003. XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
  3004. break;
  3005. case 1:
  3006. XPutPixel(xim, x, y, darkSquareColor);
  3007. if (xmask)
  3008. XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
  3009. break;
  3010. case 2:
  3011. XPutPixel(xim, x, y, whitePieceColor);
  3012. if (xmask)
  3013. XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
  3014. break;
  3015. case 3:
  3016. XPutPixel(xim, x, y, lightSquareColor);
  3017. if (xmask)
  3018. XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
  3019. break;
  3020. }
  3021. }
  3022. }
  3023. fclose(fp);
  3024. /* create Pixmap of piece */
  3025. *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
  3026. w, h, xim->depth);
  3027. XPutImage(xDisplay, *dest, lightSquareGC, xim,
  3028. 0, 0, 0, 0, w, h);
  3029. /* create Pixmap of clipmask
  3030. Note: We assume the white/black pieces have the same
  3031. outline, so we make only 6 masks. This is okay
  3032. since the XPM clipmask routines do the same. */
  3033. if (xmask) {
  3034. temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
  3035. w, h, xim->depth);
  3036. XPutImage(xDisplay, temp, lightSquareGC, xmask,
  3037. 0, 0, 0, 0, w, h);
  3038. /* now create the 1-bit version */
  3039. *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
  3040. w, h, 1);
  3041. values.foreground = 1;
  3042. values.background = 0;
  3043. /* Don't use XtGetGC, not read only */
  3044. maskGC = XCreateGC(xDisplay, *mask,
  3045. GCForeground | GCBackground, &values);
  3046. XCopyPlane(xDisplay, temp, *mask, maskGC,
  3047. 0, 0, squareSize, squareSize, 0, 0, 1);
  3048. XFreePixmap(xDisplay, temp);
  3049. }
  3050. }
  3051. char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
  3052. void CreateXIMPieces()
  3053. {
  3054. int piece, kind;
  3055. char buf[MSG_SIZ];
  3056. u_int ss;
  3057. static char *ximkind[] = { "ll", "ld", "dl", "dd" };
  3058. XImage *ximtemp;
  3059. ss = squareSize;
  3060. /* The XSynchronize calls were copied from CreatePieces.
  3061. Not sure if needed, but can't hurt */
  3062. XSynchronize(xDisplay, True); /* Work-around for xlib/xt
  3063. buffering bug */
  3064. /* temp needed by loadXIM() */
  3065. ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
  3066. 0, 0, ss, ss, AllPlanes, XYPixmap);
  3067. if (strlen(appData.pixmapDirectory) == 0) {
  3068. useImages = 0;
  3069. } else {
  3070. useImages = 1;
  3071. if (appData.monoMode) {
  3072. DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
  3073. 0, 2);
  3074. ExitEvent(2);
  3075. }
  3076. fprintf(stderr, _("\nLoading XIMs...\n"));
  3077. /* Load pieces */
  3078. for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
  3079. fprintf(stderr, "%d", piece+1);
  3080. for (kind=0; kind<4; kind++) {
  3081. fprintf(stderr, ".");
  3082. snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
  3083. ExpandPathName(appData.pixmapDirectory),
  3084. piece <= (int) WhiteKing ? "" : "w",
  3085. pieceBitmapNames[piece],
  3086. ximkind[kind], ss);
  3087. ximPieceBitmap[kind][piece] =
  3088. XGetImage(xDisplay, DefaultRootWindow(xDisplay),
  3089. 0, 0, ss, ss, AllPlanes, XYPixmap);
  3090. if (appData.debugMode)
  3091. fprintf(stderr, _("(File:%s:) "), buf);
  3092. loadXIM(ximPieceBitmap[kind][piece],
  3093. ximtemp, buf,
  3094. &(xpmPieceBitmap2[kind][piece]),
  3095. &(ximMaskPm2[piece]));
  3096. if(piece <= (int)WhiteKing)
  3097. xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
  3098. }
  3099. fprintf(stderr," ");
  3100. }
  3101. /* Load light and dark squares */
  3102. /* If the LSQ and DSQ pieces don't exist, we will
  3103. draw them with solid squares. */
  3104. snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
  3105. if (access(buf, 0) != 0) {
  3106. useImageSqs = 0;
  3107. } else {
  3108. useImageSqs = 1;
  3109. fprintf(stderr, _("light square "));
  3110. ximLightSquare=
  3111. XGetImage(xDisplay, DefaultRootWindow(xDisplay),
  3112. 0, 0, ss, ss, AllPlanes, XYPixmap);
  3113. if (appData.debugMode)
  3114. fprintf(stderr, _("(File:%s:) "), buf);
  3115. loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
  3116. fprintf(stderr, _("dark square "));
  3117. snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
  3118. ExpandPathName(appData.pixmapDirectory), ss);
  3119. if (appData.debugMode)
  3120. fprintf(stderr, _("(File:%s:) "), buf);
  3121. ximDarkSquare=
  3122. XGetImage(xDisplay, DefaultRootWindow(xDisplay),
  3123. 0, 0, ss, ss, AllPlanes, XYPixmap);
  3124. loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
  3125. xpmJailSquare = xpmLightSquare;
  3126. }
  3127. fprintf(stderr, _("Done.\n"));
  3128. }
  3129. XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
  3130. }
  3131. static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
  3132. #if HAVE_LIBXPM
  3133. void CreateXPMBoard(char *s, int kind)
  3134. {
  3135. XpmAttributes attr;
  3136. attr.valuemask = 0;
  3137. if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
  3138. if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
  3139. useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
  3140. }
  3141. }
  3142. void FreeXPMPieces()
  3143. { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
  3144. // thisroutine has to be called t free the old piece pixmaps
  3145. int piece, kind;
  3146. for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
  3147. for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
  3148. if(useImageSqs) {
  3149. XFreePixmap(xDisplay, xpmLightSquare);
  3150. XFreePixmap(xDisplay, xpmDarkSquare);
  3151. }
  3152. }
  3153. void CreateXPMPieces()
  3154. {
  3155. int piece, kind, r;
  3156. char buf[MSG_SIZ];
  3157. u_int ss = squareSize;
  3158. XpmAttributes attr;
  3159. static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
  3160. XpmColorSymbol symbols[4];
  3161. static int redo = False;
  3162. if(redo) FreeXPMPieces(); else redo = 1;
  3163. /* The XSynchronize calls were copied from CreatePieces.
  3164. Not sure if needed, but can't hurt */
  3165. XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
  3166. /* Setup translations so piece colors match square colors */
  3167. symbols[0].name = "light_piece";
  3168. symbols[0].value = appData.whitePieceColor;
  3169. symbols[1].name = "dark_piece";
  3170. symbols[1].value = appData.blackPieceColor;
  3171. symbols[2].name = "light_square";
  3172. symbols[2].value = appData.lightSquareColor;
  3173. symbols[3].name = "dark_square";
  3174. symbols[3].value = appData.darkSquareColor;
  3175. attr.valuemask = XpmColorSymbols;
  3176. attr.colorsymbols = symbols;
  3177. attr.numsymbols = 4;
  3178. if (appData.monoMode) {
  3179. DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
  3180. 0, 2);
  3181. ExitEvent(2);
  3182. }
  3183. if (strlen(appData.pixmapDirectory) == 0) {
  3184. XpmPieces* pieces = builtInXpms;
  3185. useImages = 1;
  3186. /* Load pieces */
  3187. while (pieces->size != squareSize && pieces->size) pieces++;
  3188. if (!pieces->size) {
  3189. fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
  3190. exit(1);
  3191. }
  3192. for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
  3193. for (kind=0; kind<4; kind++) {
  3194. if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
  3195. pieces->xpm[piece][kind],
  3196. &(xpmPieceBitmap2[kind][piece]),
  3197. NULL, &attr)) != 0) {
  3198. fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
  3199. r, buf);
  3200. exit(1);
  3201. }
  3202. if(piece <= (int) WhiteKing)
  3203. xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
  3204. }
  3205. }
  3206. useImageSqs = 0;
  3207. xpmJailSquare = xpmLightSquare;
  3208. } else {
  3209. useImages = 1;
  3210. fprintf(stderr, _("\nLoading XPMs...\n"));
  3211. /* Load pieces */
  3212. for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
  3213. fprintf(stderr, "%d ", piece+1);
  3214. for (kind=0; kind<4; kind++) {
  3215. snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
  3216. ExpandPathName(appData.pixmapDirectory),
  3217. piece > (int) WhiteKing ? "w" : "",
  3218. pieceBitmapNames[piece],
  3219. xpmkind[kind], ss);
  3220. if (appData.debugMode) {
  3221. fprintf(stderr, _("(File:%s:) "), buf);
  3222. }
  3223. if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
  3224. &(xpmPieceBitmap2[kind][piece]),
  3225. NULL, &attr)) != 0) {
  3226. if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
  3227. // [HGM] missing: read of unorthodox piece failed; substitute King.
  3228. snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
  3229. ExpandPathName(appData.pixmapDirectory),
  3230. xpmkind[kind], ss);
  3231. if (appData.debugMode) {
  3232. fprintf(stderr, _("(Replace by File:%s:) "), buf);
  3233. }
  3234. r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
  3235. &(xpmPieceBitmap2[kind][piece]),
  3236. NULL, &attr);
  3237. }
  3238. if (r != 0) {
  3239. fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
  3240. r, buf);
  3241. exit(1);
  3242. }
  3243. }
  3244. if(piece <= (int) WhiteKing)
  3245. xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
  3246. }
  3247. }
  3248. /* Load light and dark squares */
  3249. /* If the LSQ and DSQ pieces don't exist, we will
  3250. draw them with solid squares. */
  3251. fprintf(stderr, _("light square "));
  3252. snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
  3253. if (access(buf, 0) != 0) {
  3254. useImageSqs = 0;
  3255. } else {
  3256. useImageSqs = 1;
  3257. if (appData.debugMode)
  3258. fprintf(stderr, _("(File:%s:) "), buf);
  3259. if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
  3260. &xpmLightSquare, NULL, &attr)) != 0) {
  3261. fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
  3262. exit(1);
  3263. }
  3264. fprintf(stderr, _("dark square "));
  3265. snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
  3266. ExpandPathName(appData.pixmapDirectory), ss);
  3267. if (appData.debugMode) {
  3268. fprintf(stderr, _("(File:%s:) "), buf);
  3269. }
  3270. if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
  3271. &xpmDarkSquare, NULL, &attr)) != 0) {
  3272. fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
  3273. exit(1);
  3274. }
  3275. }
  3276. xpmJailSquare = xpmLightSquare;
  3277. fprintf(stderr, _("Done.\n"));
  3278. }
  3279. oldVariant = -1; // kludge to force re-makig of animation masks
  3280. XSynchronize(xDisplay, False); /* Work-around for xlib/xt
  3281. buffering bug */
  3282. }
  3283. #endif /* HAVE_LIBXPM */
  3284. #if HAVE_LIBXPM
  3285. /* No built-in bitmaps */
  3286. void CreatePieces()
  3287. {
  3288. int piece, kind;
  3289. char buf[MSG_SIZ];
  3290. u_int ss = squareSize;
  3291. XSynchronize(xDisplay, True); /* Work-around for xlib/xt
  3292. buffering bug */
  3293. for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
  3294. for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
  3295. snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
  3296. pieceBitmapNames[piece],
  3297. ss, kind == SOLID ? 's' : 'o');
  3298. ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
  3299. if(piece <= (int)WhiteKing)
  3300. pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
  3301. }
  3302. }
  3303. XSynchronize(xDisplay, False); /* Work-around for xlib/xt
  3304. buffering bug */
  3305. }
  3306. #else
  3307. /* With built-in bitmaps */
  3308. void CreatePieces()
  3309. {
  3310. BuiltInBits* bib = builtInBits;
  3311. int piece, kind;
  3312. char buf[MSG_SIZ];
  3313. u_int ss = squareSize;
  3314. XSynchronize(xDisplay, True); /* Work-around for xlib/xt
  3315. buffering bug */
  3316. while (bib->squareSize != ss && bib->squareSize != 0) bib++;
  3317. for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
  3318. for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
  3319. snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
  3320. pieceBitmapNames[piece],
  3321. ss, kind == SOLID ? 's' : 'o');
  3322. ReadBitmap(&pieceBitmap2[kind][piece], buf,
  3323. bib->bits[kind][piece], ss, ss);
  3324. if(piece <= (int)WhiteKing)
  3325. pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
  3326. }
  3327. }
  3328. XSynchronize(xDisplay, False); /* Work-around for xlib/xt
  3329. buffering bug */
  3330. }
  3331. #endif
  3332. void ReadBitmap(pm, name, bits, wreq, hreq)
  3333. Pixmap *pm;
  3334. String name;
  3335. unsigned char bits[];
  3336. u_int wreq, hreq;
  3337. {
  3338. int x_hot, y_hot;
  3339. u_int w, h;
  3340. int errcode;
  3341. char msg[MSG_SIZ], fullname[MSG_SIZ];
  3342. if (*appData.bitmapDirectory != NULLCHAR) {
  3343. safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
  3344. strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
  3345. strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
  3346. errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
  3347. &w, &h, pm, &x_hot, &y_hot);
  3348. fprintf(stderr, "load %s\n", name);
  3349. if (errcode != BitmapSuccess) {
  3350. switch (errcode) {
  3351. case BitmapOpenFailed:
  3352. snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
  3353. break;
  3354. case BitmapFileInvalid:
  3355. snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
  3356. break;
  3357. case BitmapNoMemory:
  3358. snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
  3359. fullname);
  3360. break;
  3361. default:
  3362. snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
  3363. errcode, fullname);
  3364. break;
  3365. }
  3366. fprintf(stderr, _("%s: %s...using built-in\n"),
  3367. programName, msg);
  3368. } else if (w != wreq || h != hreq) {
  3369. fprintf(stderr,
  3370. _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
  3371. programName, fullname, w, h, wreq, hreq);
  3372. } else {
  3373. return;
  3374. }
  3375. }
  3376. if (bits != NULL) {
  3377. *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
  3378. wreq, hreq);
  3379. }
  3380. }
  3381. void CreateGrid()
  3382. {
  3383. int i, j;
  3384. if (lineGap == 0) return;
  3385. /* [HR] Split this into 2 loops for non-square boards. */
  3386. for (i = 0; i < BOARD_HEIGHT + 1; i++) {
  3387. gridSegments[i].x1 = 0;
  3388. gridSegments[i].x2 =
  3389. lineGap + BOARD_WIDTH * (squareSize + lineGap);
  3390. gridSegments[i].y1 = gridSegments[i].y2
  3391. = lineGap / 2 + (i * (squareSize + lineGap));
  3392. }
  3393. for (j = 0; j < BOARD_WIDTH + 1; j++) {
  3394. gridSegments[j + i].y1 = 0;
  3395. gridSegments[j + i].y2 =
  3396. lineGap + BOARD_HEIGHT * (squareSize + lineGap);
  3397. gridSegments[j + i].x1 = gridSegments[j + i].x2
  3398. = lineGap / 2 + (j * (squareSize + lineGap));
  3399. }
  3400. }
  3401. static void MenuBarSelect(w, addr, index)
  3402. Widget w;
  3403. caddr_t addr;
  3404. caddr_t index;
  3405. {
  3406. XtActionProc proc = (XtActionProc) addr;
  3407. (proc)(NULL, NULL, NULL, NULL);
  3408. }
  3409. void CreateMenuBarPopup(parent, name, mb)
  3410. Widget parent;
  3411. String name;
  3412. Menu *mb;
  3413. {
  3414. int j;
  3415. Widget menu, entry;
  3416. MenuItem *mi;
  3417. Arg args[16];
  3418. menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
  3419. parent, NULL, 0);
  3420. j = 0;
  3421. XtSetArg(args[j], XtNleftMargin, 20); j++;
  3422. XtSetArg(args[j], XtNrightMargin, 20); j++;
  3423. mi = mb->mi;
  3424. while (mi->string != NULL) {
  3425. if (strcmp(mi->string, "----") == 0) {
  3426. entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
  3427. menu, args, j);
  3428. } else {
  3429. XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
  3430. entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
  3431. menu, args, j+1);
  3432. XtAddCallback(entry, XtNcallback,
  3433. (XtCallbackProc) MenuBarSelect,
  3434. (caddr_t) mi->proc);
  3435. }
  3436. mi++;
  3437. }
  3438. }
  3439. Widget CreateMenuBar(mb)
  3440. Menu *mb;
  3441. {
  3442. int j;
  3443. Widget anchor, menuBar;
  3444. Arg args[16];
  3445. char menuName[MSG_SIZ];
  3446. j = 0;
  3447. XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
  3448. XtSetArg(args[j], XtNvSpace, 0); j++;
  3449. XtSetArg(args[j], XtNborderWidth, 0); j++;
  3450. menuBar = XtCreateWidget("menuBar", boxWidgetClass,
  3451. formWidget, args, j);
  3452. while (mb->name != NULL) {
  3453. safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
  3454. strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
  3455. j = 0;
  3456. XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
  3457. if (tinyLayout) {
  3458. char shortName[2];
  3459. shortName[0] = mb->name[0];
  3460. shortName[1] = NULLCHAR;
  3461. XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
  3462. }
  3463. else {
  3464. XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
  3465. }
  3466. XtSetArg(args[j], XtNborderWidth, 0); j++;
  3467. anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
  3468. menuBar, args, j);
  3469. CreateMenuBarPopup(menuBar, menuName, mb);
  3470. mb++;
  3471. }
  3472. return menuBar;
  3473. }
  3474. Widget CreateButtonBar(mi)
  3475. MenuItem *mi;
  3476. {
  3477. int j;
  3478. Widget button, buttonBar;
  3479. Arg args[16];
  3480. j = 0;
  3481. XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
  3482. if (tinyLayout) {
  3483. XtSetArg(args[j], XtNhSpace, 0); j++;
  3484. }
  3485. XtSetArg(args[j], XtNborderWidth, 0); j++;
  3486. XtSetArg(args[j], XtNvSpace, 0); j++;
  3487. buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
  3488. formWidget, args, j);
  3489. while (mi->string != NULL) {
  3490. j = 0;
  3491. if (tinyLayout) {
  3492. XtSetArg(args[j], XtNinternalWidth, 2); j++;
  3493. XtSetArg(args[j], XtNborderWidth, 0); j++;
  3494. }
  3495. XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
  3496. button = XtCreateManagedWidget(mi->string, commandWidgetClass,
  3497. buttonBar, args, j);
  3498. XtAddCallback(button, XtNcallback,
  3499. (XtCallbackProc) MenuBarSelect,
  3500. (caddr_t) mi->proc);
  3501. mi++;
  3502. }
  3503. return buttonBar;
  3504. }
  3505. Widget
  3506. CreatePieceMenu(name, color)
  3507. char *name;
  3508. int color;
  3509. {
  3510. int i;
  3511. Widget entry, menu;
  3512. Arg args[16];
  3513. ChessSquare selection;
  3514. menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
  3515. boardWidget, args, 0);
  3516. for (i = 0; i < PIECE_MENU_SIZE; i++) {
  3517. String item = pieceMenuStrings[color][i];
  3518. if (strcmp(item, "----") == 0) {
  3519. entry = XtCreateManagedWidget(item, smeLineObjectClass,
  3520. menu, NULL, 0);
  3521. } else {
  3522. XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
  3523. entry = XtCreateManagedWidget(item, smeBSBObjectClass,
  3524. menu, args, 1);
  3525. selection = pieceMenuTranslation[color][i];
  3526. XtAddCallback(entry, XtNcallback,
  3527. (XtCallbackProc) PieceMenuSelect,
  3528. (caddr_t) selection);
  3529. if (selection == WhitePawn || selection == BlackPawn) {
  3530. XtSetArg(args[0], XtNpopupOnEntry, entry);
  3531. XtSetValues(menu, args, 1);
  3532. }
  3533. }
  3534. }
  3535. return menu;
  3536. }
  3537. void
  3538. CreatePieceMenus()
  3539. {
  3540. int i;
  3541. Widget entry;
  3542. Arg args[16];
  3543. ChessSquare selection;
  3544. whitePieceMenu = CreatePieceMenu("menuW", 0);
  3545. blackPieceMenu = CreatePieceMenu("menuB", 1);
  3546. XtRegisterGrabAction(PieceMenuPopup, True,
  3547. (unsigned)(ButtonPressMask|ButtonReleaseMask),
  3548. GrabModeAsync, GrabModeAsync);
  3549. XtSetArg(args[0], XtNlabel, _("Drop"));
  3550. dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
  3551. boardWidget, args, 1);
  3552. for (i = 0; i < DROP_MENU_SIZE; i++) {
  3553. String item = dropMenuStrings[i];
  3554. if (strcmp(item, "----") == 0) {
  3555. entry = XtCreateManagedWidget(item, smeLineObjectClass,
  3556. dropMenu, NULL, 0);
  3557. } else {
  3558. XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
  3559. entry = XtCreateManagedWidget(item, smeBSBObjectClass,
  3560. dropMenu, args, 1);
  3561. selection = dropMenuTranslation[i];
  3562. XtAddCallback(entry, XtNcallback,
  3563. (XtCallbackProc) DropMenuSelect,
  3564. (caddr_t) selection);
  3565. }
  3566. }
  3567. }
  3568. void SetupDropMenu()
  3569. {
  3570. int i, j, count;
  3571. char label[32];
  3572. Arg args[16];
  3573. Widget entry;
  3574. char* p;
  3575. for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
  3576. entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
  3577. p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
  3578. dmEnables[i].piece);
  3579. XtSetSensitive(entry, p != NULL || !appData.testLegality
  3580. /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
  3581. && !appData.icsActive));
  3582. count = 0;
  3583. while (p && *p++ == dmEnables[i].piece) count++;
  3584. snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
  3585. j = 0;
  3586. XtSetArg(args[j], XtNlabel, label); j++;
  3587. XtSetValues(entry, args, j);
  3588. }
  3589. }
  3590. void PieceMenuPopup(w, event, params, num_params)
  3591. Widget w;
  3592. XEvent *event;
  3593. String *params;
  3594. Cardinal *num_params;
  3595. {
  3596. String whichMenu; int menuNr;
  3597. if (event->type == ButtonRelease)
  3598. menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
  3599. else if (event->type == ButtonPress)
  3600. menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
  3601. switch(menuNr) {
  3602. case 0: whichMenu = params[0]; break;
  3603. case 1: SetupDropMenu(); whichMenu = "menuD"; break;
  3604. case 2:
  3605. case -1: if (errorUp) ErrorPopDown();
  3606. default: return;
  3607. }
  3608. XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
  3609. }
  3610. static void PieceMenuSelect(w, piece, junk)
  3611. Widget w;
  3612. ChessSquare piece;
  3613. caddr_t junk;
  3614. {
  3615. if (pmFromX < 0 || pmFromY < 0) return;
  3616. EditPositionMenuEvent(piece, pmFromX, pmFromY);
  3617. }
  3618. static void DropMenuSelect(w, piece, junk)
  3619. Widget w;
  3620. ChessSquare piece;
  3621. caddr_t junk;
  3622. {
  3623. if (pmFromX < 0 || pmFromY < 0) return;
  3624. DropMenuEvent(piece, pmFromX, pmFromY);
  3625. }
  3626. void WhiteClock(w, event, prms, nprms)
  3627. Widget w;
  3628. XEvent *event;
  3629. String *prms;
  3630. Cardinal *nprms;
  3631. {
  3632. ClockClick(0);
  3633. }
  3634. void BlackClock(w, event, prms, nprms)
  3635. Widget w;
  3636. XEvent *event;
  3637. String *prms;
  3638. Cardinal *nprms;
  3639. {
  3640. ClockClick(1);
  3641. }
  3642. /*
  3643. * If the user selects on a border boundary, return -1; if off the board,
  3644. * return -2. Otherwise map the event coordinate to the square.
  3645. */
  3646. int EventToSquare(x, limit)
  3647. int x;
  3648. {
  3649. if (x <= 0)
  3650. return -2;
  3651. if (x < lineGap)
  3652. return -1;
  3653. x -= lineGap;
  3654. if ((x % (squareSize + lineGap)) >= squareSize)
  3655. return -1;
  3656. x /= (squareSize + lineGap);
  3657. if (x >= limit)
  3658. return -2;
  3659. return x;
  3660. }
  3661. static void do_flash_delay(msec)
  3662. unsigned long msec;
  3663. {
  3664. TimeDelay(msec);
  3665. }
  3666. static void drawHighlight(file, rank, gc)
  3667. int file, rank;
  3668. GC gc;
  3669. {
  3670. int x, y;
  3671. if (lineGap == 0) return;
  3672. if (flipView) {
  3673. x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
  3674. (squareSize + lineGap);
  3675. y = lineGap/2 + rank * (squareSize + lineGap);
  3676. } else {
  3677. x = lineGap/2 + file * (squareSize + lineGap);
  3678. y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
  3679. (squareSize + lineGap);
  3680. }
  3681. XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
  3682. squareSize+lineGap, squareSize+lineGap);
  3683. }
  3684. int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
  3685. int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
  3686. void
  3687. SetHighlights(fromX, fromY, toX, toY)
  3688. int fromX, fromY, toX, toY;
  3689. {
  3690. if (hi1X != fromX || hi1Y != fromY) {
  3691. if (hi1X >= 0 && hi1Y >= 0) {
  3692. drawHighlight(hi1X, hi1Y, lineGC);
  3693. }
  3694. } // [HGM] first erase both, then draw new!
  3695. if (hi2X != toX || hi2Y != toY) {
  3696. if (hi2X >= 0 && hi2Y >= 0) {
  3697. drawHighlight(hi2X, hi2Y, lineGC);
  3698. }
  3699. }
  3700. if (hi1X != fromX || hi1Y != fromY) {
  3701. if (fromX >= 0 && fromY >= 0) {
  3702. drawHighlight(fromX, fromY, highlineGC);
  3703. }
  3704. }
  3705. if (hi2X != toX || hi2Y != toY) {
  3706. if (toX >= 0 && toY >= 0) {
  3707. drawHighlight(toX, toY, highlineGC);
  3708. }
  3709. }
  3710. hi1X = fromX;
  3711. hi1Y = fromY;
  3712. hi2X = toX;
  3713. hi2Y = toY;
  3714. }
  3715. void
  3716. ClearHighlights()
  3717. {
  3718. SetHighlights(-1, -1, -1, -1);
  3719. }
  3720. void
  3721. SetPremoveHighlights(fromX, fromY, toX, toY)
  3722. int fromX, fromY, toX, toY;
  3723. {
  3724. if (pm1X != fromX || pm1Y != fromY) {
  3725. if (pm1X >= 0 && pm1Y >= 0) {
  3726. drawHighlight(pm1X, pm1Y, lineGC);
  3727. }
  3728. if (fromX >= 0 && fromY >= 0) {
  3729. drawHighlight(fromX, fromY, prelineGC);
  3730. }
  3731. }
  3732. if (pm2X != toX || pm2Y != toY) {
  3733. if (pm2X >= 0 && pm2Y >= 0) {
  3734. drawHighlight(pm2X, pm2Y, lineGC);
  3735. }
  3736. if (toX >= 0 && toY >= 0) {
  3737. drawHighlight(toX, toY, prelineGC);
  3738. }
  3739. }
  3740. pm1X = fromX;
  3741. pm1Y = fromY;
  3742. pm2X = toX;
  3743. pm2Y = toY;
  3744. }
  3745. void
  3746. ClearPremoveHighlights()
  3747. {
  3748. SetPremoveHighlights(-1, -1, -1, -1);
  3749. }
  3750. static int CutOutSquare(x, y, x0, y0, kind)
  3751. int x, y, *x0, *y0, kind;
  3752. {
  3753. int W = BOARD_WIDTH, H = BOARD_HEIGHT;
  3754. int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
  3755. *x0 = 0; *y0 = 0;
  3756. if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
  3757. if(textureW[kind] < W*squareSize)
  3758. *x0 = (textureW[kind] - squareSize) * nx/(W-1);
  3759. else
  3760. *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
  3761. if(textureH[kind] < H*squareSize)
  3762. *y0 = (textureH[kind] - squareSize) * ny/(H-1);
  3763. else
  3764. *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
  3765. return 1;
  3766. }
  3767. static void BlankSquare(x, y, color, piece, dest, fac)
  3768. int x, y, color, fac;
  3769. ChessSquare piece;
  3770. Drawable dest;
  3771. { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
  3772. int x0, y0;
  3773. if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
  3774. XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
  3775. squareSize, squareSize, x*fac, y*fac);
  3776. } else
  3777. if (useImages && useImageSqs) {
  3778. Pixmap pm;
  3779. switch (color) {
  3780. case 1: /* light */
  3781. pm = xpmLightSquare;
  3782. break;
  3783. case 0: /* dark */
  3784. pm = xpmDarkSquare;
  3785. break;
  3786. case 2: /* neutral */
  3787. default:
  3788. pm = xpmJailSquare;
  3789. break;
  3790. }
  3791. XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
  3792. squareSize, squareSize, x*fac, y*fac);
  3793. } else {
  3794. GC gc;
  3795. switch (color) {
  3796. case 1: /* light */
  3797. gc = lightSquareGC;
  3798. break;
  3799. case 0: /* dark */
  3800. gc = darkSquareGC;
  3801. break;
  3802. case 2: /* neutral */
  3803. default:
  3804. gc = jailSquareGC;
  3805. break;
  3806. }
  3807. XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
  3808. }
  3809. }
  3810. /*
  3811. I split out the routines to draw a piece so that I could
  3812. make a generic flash routine.
  3813. */
  3814. static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
  3815. ChessSquare piece;
  3816. int square_color, x, y;
  3817. Drawable dest;
  3818. {
  3819. /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
  3820. switch (square_color) {
  3821. case 1: /* light */
  3822. case 2: /* neutral */
  3823. default:
  3824. XCopyArea(xDisplay, (int) piece < (int) BlackPawn
  3825. ? *pieceToOutline(piece)
  3826. : *pieceToSolid(piece),
  3827. dest, bwPieceGC, 0, 0,
  3828. squareSize, squareSize, x, y);
  3829. break;
  3830. case 0: /* dark */
  3831. XCopyArea(xDisplay, (int) piece < (int) BlackPawn
  3832. ? *pieceToSolid(piece)
  3833. : *pieceToOutline(piece),
  3834. dest, wbPieceGC, 0, 0,
  3835. squareSize, squareSize, x, y);
  3836. break;
  3837. }
  3838. }
  3839. static void monoDrawPiece(piece, square_color, x, y, dest)
  3840. ChessSquare piece;
  3841. int square_color, x, y;
  3842. Drawable dest;
  3843. {
  3844. switch (square_color) {
  3845. case 1: /* light */
  3846. case 2: /* neutral */
  3847. default:
  3848. XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
  3849. ? *pieceToOutline(piece)
  3850. : *pieceToSolid(piece),
  3851. dest, bwPieceGC, 0, 0,
  3852. squareSize, squareSize, x, y, 1);
  3853. break;
  3854. case 0: /* dark */
  3855. XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
  3856. ? *pieceToSolid(piece)
  3857. : *pieceToOutline(piece),
  3858. dest, wbPieceGC, 0, 0,
  3859. squareSize, squareSize, x, y, 1);
  3860. break;
  3861. }
  3862. }
  3863. static void colorDrawPiece(piece, square_color, x, y, dest)
  3864. ChessSquare piece;
  3865. int square_color, x, y;
  3866. Drawable dest;
  3867. {
  3868. if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
  3869. switch (square_color) {
  3870. case 1: /* light */
  3871. XCopyPlane(xDisplay, *pieceToSolid(piece),
  3872. dest, (int) piece < (int) BlackPawn
  3873. ? wlPieceGC : blPieceGC, 0, 0,
  3874. squareSize, squareSize, x, y, 1);
  3875. break;
  3876. case 0: /* dark */
  3877. XCopyPlane(xDisplay, *pieceToSolid(piece),
  3878. dest, (int) piece < (int) BlackPawn
  3879. ? wdPieceGC : bdPieceGC, 0, 0,
  3880. squareSize, squareSize, x, y, 1);
  3881. break;
  3882. case 2: /* neutral */
  3883. default:
  3884. XCopyPlane(xDisplay, *pieceToSolid(piece),
  3885. dest, (int) piece < (int) BlackPawn
  3886. ? wjPieceGC : bjPieceGC, 0, 0,
  3887. squareSize, squareSize, x, y, 1);
  3888. break;
  3889. }
  3890. }
  3891. static void colorDrawPieceImage(piece, square_color, x, y, dest)
  3892. ChessSquare piece;
  3893. int square_color, x, y;
  3894. Drawable dest;
  3895. {
  3896. int kind, p = piece;
  3897. switch (square_color) {
  3898. case 1: /* light */
  3899. case 2: /* neutral */
  3900. default:
  3901. if ((int)piece < (int) BlackPawn) {
  3902. kind = 0;
  3903. } else {
  3904. kind = 2;
  3905. piece -= BlackPawn;
  3906. }
  3907. break;
  3908. case 0: /* dark */
  3909. if ((int)piece < (int) BlackPawn) {
  3910. kind = 1;
  3911. } else {
  3912. kind = 3;
  3913. piece -= BlackPawn;
  3914. }
  3915. break;
  3916. }
  3917. if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
  3918. if(useTexture & square_color+1) {
  3919. BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
  3920. XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
  3921. XSetClipOrigin(xDisplay, wlPieceGC, x, y);
  3922. XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
  3923. XSetClipMask(xDisplay, wlPieceGC, None);
  3924. XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
  3925. } else
  3926. XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
  3927. dest, wlPieceGC, 0, 0,
  3928. squareSize, squareSize, x, y);
  3929. }
  3930. typedef void (*DrawFunc)();
  3931. DrawFunc ChooseDrawFunc()
  3932. {
  3933. if (appData.monoMode) {
  3934. if (DefaultDepth(xDisplay, xScreen) == 1) {
  3935. return monoDrawPiece_1bit;
  3936. } else {
  3937. return monoDrawPiece;
  3938. }
  3939. } else {
  3940. if (useImages)
  3941. return colorDrawPieceImage;
  3942. else
  3943. return colorDrawPiece;
  3944. }
  3945. }
  3946. /* [HR] determine square color depending on chess variant. */
  3947. static int SquareColor(row, column)
  3948. int row, column;
  3949. {
  3950. int square_color;
  3951. if (gameInfo.variant == VariantXiangqi) {
  3952. if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
  3953. square_color = 1;
  3954. } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
  3955. square_color = 0;
  3956. } else if (row <= 4) {
  3957. square_color = 0;
  3958. } else {
  3959. square_color = 1;
  3960. }
  3961. } else {
  3962. square_color = ((column + row) % 2) == 1;
  3963. }
  3964. /* [hgm] holdings: next line makes all holdings squares light */
  3965. if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
  3966. return square_color;
  3967. }
  3968. void DrawSquare(row, column, piece, do_flash)
  3969. int row, column, do_flash;
  3970. ChessSquare piece;
  3971. {
  3972. int square_color, x, y, direction, font_ascent, font_descent;
  3973. int i;
  3974. char string[2];
  3975. XCharStruct overall;
  3976. DrawFunc drawfunc;
  3977. int flash_delay;
  3978. /* Calculate delay in milliseconds (2-delays per complete flash) */
  3979. flash_delay = 500 / appData.flashRate;
  3980. if (flipView) {
  3981. x = lineGap + ((BOARD_WIDTH-1)-column) *
  3982. (squareSize + lineGap);
  3983. y = lineGap + row * (squareSize + lineGap);
  3984. } else {
  3985. x = lineGap + column * (squareSize + lineGap);
  3986. y = lineGap + ((BOARD_HEIGHT-1)-row) *
  3987. (squareSize + lineGap);
  3988. }
  3989. if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
  3990. square_color = SquareColor(row, column);
  3991. if ( // [HGM] holdings: blank out area between board and holdings
  3992. column == BOARD_LEFT-1 || column == BOARD_RGHT
  3993. || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
  3994. || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
  3995. BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
  3996. // [HGM] print piece counts next to holdings
  3997. string[1] = NULLCHAR;
  3998. if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
  3999. string[0] = '0' + piece;
  4000. XTextExtents(countFontStruct, string, 1, &direction,
  4001. &font_ascent, &font_descent, &overall);
  4002. if (appData.monoMode) {
  4003. XDrawImageString(xDisplay, xBoardWindow, countGC,
  4004. x + squareSize - overall.width - 2,
  4005. y + font_ascent + 1, string, 1);
  4006. } else {
  4007. XDrawString(xDisplay, xBoardWindow, countGC,
  4008. x + squareSize - overall.width - 2,
  4009. y + font_ascent + 1, string, 1);
  4010. }
  4011. }
  4012. if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
  4013. string[0] = '0' + piece;
  4014. XTextExtents(countFontStruct, string, 1, &direction,
  4015. &font_ascent, &font_descent, &overall);
  4016. if (appData.monoMode) {
  4017. XDrawImageString(xDisplay, xBoardWindow, countGC,
  4018. x + 2, y + font_ascent + 1, string, 1);
  4019. } else {
  4020. XDrawString(xDisplay, xBoardWindow, countGC,
  4021. x + 2, y + font_ascent + 1, string, 1);
  4022. }
  4023. }
  4024. } else {
  4025. if (piece == EmptySquare || appData.blindfold) {
  4026. BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
  4027. } else {
  4028. drawfunc = ChooseDrawFunc();
  4029. if (do_flash && appData.flashCount > 0) {
  4030. for (i=0; i<appData.flashCount; ++i) {
  4031. drawfunc(piece, square_color, x, y, xBoardWindow);
  4032. XSync(xDisplay, False);
  4033. do_flash_delay(flash_delay);
  4034. BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
  4035. XSync(xDisplay, False);
  4036. do_flash_delay(flash_delay);
  4037. }
  4038. }
  4039. drawfunc(piece, square_color, x, y, xBoardWindow);
  4040. }
  4041. }
  4042. string[1] = NULLCHAR;
  4043. if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
  4044. && column >= BOARD_LEFT && column < BOARD_RGHT) {
  4045. string[0] = 'a' + column - BOARD_LEFT;
  4046. XTextExtents(coordFontStruct, string, 1, &direction,
  4047. &font_ascent, &font_descent, &overall);
  4048. if (appData.monoMode) {
  4049. XDrawImageString(xDisplay, xBoardWindow, coordGC,
  4050. x + squareSize - overall.width - 2,
  4051. y + squareSize - font_descent - 1, string, 1);
  4052. } else {
  4053. XDrawString(xDisplay, xBoardWindow, coordGC,
  4054. x + squareSize - overall.width - 2,
  4055. y + squareSize - font_descent - 1, string, 1);
  4056. }
  4057. }
  4058. if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
  4059. string[0] = ONE + row;
  4060. XTextExtents(coordFontStruct, string, 1, &direction,
  4061. &font_ascent, &font_descent, &overall);
  4062. if (appData.monoMode) {
  4063. XDrawImageString(xDisplay, xBoardWindow, coordGC,
  4064. x + 2, y + font_ascent + 1, string, 1);
  4065. } else {
  4066. XDrawString(xDisplay, xBoardWindow, coordGC,
  4067. x + 2, y + font_ascent + 1, string, 1);
  4068. }
  4069. }
  4070. if(!partnerUp && marker[row][column]) {
  4071. XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
  4072. x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
  4073. }
  4074. }
  4075. /* Why is this needed on some versions of X? */
  4076. void EventProc(widget, unused, event)
  4077. Widget widget;
  4078. caddr_t unused;
  4079. XEvent *event;
  4080. {
  4081. if (!XtIsRealized(widget))
  4082. return;
  4083. switch (event->type) {
  4084. case Expose:
  4085. if (event->xexpose.count > 0) return; /* no clipping is done */
  4086. XDrawPosition(widget, True, NULL);
  4087. if(twoBoards) { // [HGM] dual: draw other board in other orientation
  4088. flipView = !flipView; partnerUp = !partnerUp;
  4089. XDrawPosition(widget, True, NULL);
  4090. flipView = !flipView; partnerUp = !partnerUp;
  4091. }
  4092. break;
  4093. case MotionNotify:
  4094. if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
  4095. default:
  4096. return;
  4097. }
  4098. }
  4099. /* end why */
  4100. void DrawPosition(fullRedraw, board)
  4101. /*Boolean*/int fullRedraw;
  4102. Board board;
  4103. {
  4104. XDrawPosition(boardWidget, fullRedraw, board);
  4105. }
  4106. /* Returns 1 if there are "too many" differences between b1 and b2
  4107. (i.e. more than 1 move was made) */
  4108. static int too_many_diffs(b1, b2)
  4109. Board b1, b2;
  4110. {
  4111. int i, j;
  4112. int c = 0;
  4113. for (i=0; i<BOARD_HEIGHT; ++i) {
  4114. for (j=0; j<BOARD_WIDTH; ++j) {
  4115. if (b1[i][j] != b2[i][j]) {
  4116. if (++c > 4) /* Castling causes 4 diffs */
  4117. return 1;
  4118. }
  4119. }
  4120. }
  4121. return 0;
  4122. }
  4123. /* Matrix describing castling maneuvers */
  4124. /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
  4125. static int castling_matrix[4][5] = {
  4126. { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
  4127. { 0, 7, 4, 5, 6 }, /* 0-0, white */
  4128. { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
  4129. { 7, 7, 4, 5, 6 } /* 0-0, black */
  4130. };
  4131. /* Checks whether castling occurred. If it did, *rrow and *rcol
  4132. are set to the destination (row,col) of the rook that moved.
  4133. Returns 1 if castling occurred, 0 if not.
  4134. Note: Only handles a max of 1 castling move, so be sure
  4135. to call too_many_diffs() first.
  4136. */
  4137. static int check_castle_draw(newb, oldb, rrow, rcol)
  4138. Board newb, oldb;
  4139. int *rrow, *rcol;
  4140. {
  4141. int i, *r, j;
  4142. int match;
  4143. /* For each type of castling... */
  4144. for (i=0; i<4; ++i) {
  4145. r = castling_matrix[i];
  4146. /* Check the 4 squares involved in the castling move */
  4147. match = 0;
  4148. for (j=1; j<=4; ++j) {
  4149. if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
  4150. match = 1;
  4151. break;
  4152. }
  4153. }
  4154. if (!match) {
  4155. /* All 4 changed, so it must be a castling move */
  4156. *rrow = r[0];
  4157. *rcol = r[3];
  4158. return 1;
  4159. }
  4160. }
  4161. return 0;
  4162. }
  4163. // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
  4164. void DrawSeekAxis( int x, int y, int xTo, int yTo )
  4165. {
  4166. XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
  4167. }
  4168. void DrawSeekBackground( int left, int top, int right, int bottom )
  4169. {
  4170. XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
  4171. }
  4172. void DrawSeekText(char *buf, int x, int y)
  4173. {
  4174. XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
  4175. }
  4176. void DrawSeekDot(int x, int y, int colorNr)
  4177. {
  4178. int square = colorNr & 0x80;
  4179. GC color;
  4180. colorNr &= 0x7F;
  4181. color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
  4182. if(square)
  4183. XFillRectangle(xDisplay, xBoardWindow, color,
  4184. x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
  4185. else
  4186. XFillArc(xDisplay, xBoardWindow, color,
  4187. x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
  4188. }
  4189. static int damage[2][BOARD_RANKS][BOARD_FILES];
  4190. /*
  4191. * event handler for redrawing the board
  4192. */
  4193. void XDrawPosition(w, repaint, board)
  4194. Widget w;
  4195. /*Boolean*/int repaint;
  4196. Board board;
  4197. {
  4198. int i, j, do_flash;
  4199. static int lastFlipView = 0;
  4200. static int lastBoardValid[2] = {0, 0};
  4201. static Board lastBoard[2];
  4202. Arg args[16];
  4203. int rrow, rcol;
  4204. int nr = twoBoards*partnerUp;
  4205. if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
  4206. if (board == NULL) {
  4207. if (!lastBoardValid[nr]) return;
  4208. board = lastBoard[nr];
  4209. }
  4210. if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
  4211. XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
  4212. XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
  4213. args, 1);
  4214. }
  4215. /*
  4216. * It would be simpler to clear the window with XClearWindow()
  4217. * but this causes a very distracting flicker.
  4218. */
  4219. if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
  4220. if ( lineGap && IsDrawArrowEnabled())
  4221. XDrawSegments(xDisplay, xBoardWindow, lineGC,
  4222. gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
  4223. /* If too much changes (begin observing new game, etc.), don't
  4224. do flashing */
  4225. do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
  4226. /* Special check for castling so we don't flash both the king
  4227. and the rook (just flash the king). */
  4228. if (do_flash) {
  4229. if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
  4230. /* Draw rook with NO flashing. King will be drawn flashing later */
  4231. DrawSquare(rrow, rcol, board[rrow][rcol], 0);
  4232. lastBoard[nr][rrow][rcol] = board[rrow][rcol];
  4233. }
  4234. }
  4235. /* First pass -- Draw (newly) empty squares and repair damage.
  4236. This prevents you from having a piece show up twice while it
  4237. is flashing on its new square */
  4238. for (i = 0; i < BOARD_HEIGHT; i++)
  4239. for (j = 0; j < BOARD_WIDTH; j++)
  4240. if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
  4241. || damage[nr][i][j]) {
  4242. DrawSquare(i, j, board[i][j], 0);
  4243. damage[nr][i][j] = False;
  4244. }
  4245. /* Second pass -- Draw piece(s) in new position and flash them */
  4246. for (i = 0; i < BOARD_HEIGHT; i++)
  4247. for (j = 0; j < BOARD_WIDTH; j++)
  4248. if (board[i][j] != lastBoard[nr][i][j]) {
  4249. DrawSquare(i, j, board[i][j], do_flash);
  4250. }
  4251. } else {
  4252. if (lineGap > 0)
  4253. XDrawSegments(xDisplay, xBoardWindow, lineGC,
  4254. twoBoards & partnerUp ? secondSegments : // [HGM] dual
  4255. gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
  4256. for (i = 0; i < BOARD_HEIGHT; i++)
  4257. for (j = 0; j < BOARD_WIDTH; j++) {
  4258. DrawSquare(i, j, board[i][j], 0);
  4259. damage[nr][i][j] = False;
  4260. }
  4261. }
  4262. CopyBoard(lastBoard[nr], board);
  4263. lastBoardValid[nr] = 1;
  4264. if(nr == 0) { // [HGM] dual: no highlights on second board yet
  4265. lastFlipView = flipView;
  4266. /* Draw highlights */
  4267. if (pm1X >= 0 && pm1Y >= 0) {
  4268. drawHighlight(pm1X, pm1Y, prelineGC);
  4269. }
  4270. if (pm2X >= 0 && pm2Y >= 0) {
  4271. drawHighlight(pm2X, pm2Y, prelineGC);
  4272. }
  4273. if (hi1X >= 0 && hi1Y >= 0) {
  4274. drawHighlight(hi1X, hi1Y, highlineGC);
  4275. }
  4276. if (hi2X >= 0 && hi2Y >= 0) {
  4277. drawHighlight(hi2X, hi2Y, highlineGC);
  4278. }
  4279. DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
  4280. }
  4281. /* If piece being dragged around board, must redraw that too */
  4282. DrawDragPiece();
  4283. XSync(xDisplay, False);
  4284. }
  4285. /*
  4286. * event handler for redrawing the board
  4287. */
  4288. void DrawPositionProc(w, event, prms, nprms)
  4289. Widget w;
  4290. XEvent *event;
  4291. String *prms;
  4292. Cardinal *nprms;
  4293. {
  4294. XDrawPosition(w, True, NULL);
  4295. }
  4296. /*
  4297. * event handler for parsing user moves
  4298. */
  4299. // [HGM] This routine will need quite some reworking. Although the backend still supports the old
  4300. // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
  4301. // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
  4302. // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
  4303. // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
  4304. // and at the end FinishMove() to perform the move after optional promotion popups.
  4305. // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
  4306. void HandleUserMove(w, event, prms, nprms)
  4307. Widget w;
  4308. XEvent *event;
  4309. String *prms;
  4310. Cardinal *nprms;
  4311. {
  4312. if (w != boardWidget || errorExitStatus != -1) return;
  4313. if(nprms) shiftKey = !strcmp(prms[0], "1");
  4314. if (promotionUp) {
  4315. if (event->type == ButtonPress) {
  4316. XtPopdown(promotionShell);
  4317. XtDestroyWidget(promotionShell);
  4318. promotionUp = False;
  4319. ClearHighlights();
  4320. fromX = fromY = -1;
  4321. } else {
  4322. return;
  4323. }
  4324. }
  4325. // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
  4326. if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
  4327. if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
  4328. }
  4329. void AnimateUserMove (Widget w, XEvent * event,
  4330. String * params, Cardinal * nParams)
  4331. {
  4332. DragPieceMove(event->xmotion.x, event->xmotion.y);
  4333. }
  4334. void HandlePV (Widget w, XEvent * event,
  4335. String * params, Cardinal * nParams)
  4336. { // [HGM] pv: walk PV
  4337. MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
  4338. }
  4339. Widget CommentCreate(name, text, mutable, callback, lines)
  4340. char *name, *text;
  4341. int /*Boolean*/ mutable;
  4342. XtCallbackProc callback;
  4343. int lines;
  4344. {
  4345. Arg args[16];
  4346. Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
  4347. Dimension bw_width;
  4348. int j;
  4349. j = 0;
  4350. XtSetArg(args[j], XtNwidth, &bw_width); j++;
  4351. XtGetValues(boardWidget, args, j);
  4352. j = 0;
  4353. XtSetArg(args[j], XtNresizable, True); j++;
  4354. #if TOPLEVEL
  4355. shell =
  4356. XtCreatePopupShell(name, topLevelShellWidgetClass,
  4357. shellWidget, args, j);
  4358. #else
  4359. shell =
  4360. XtCreatePopupShell(name, transientShellWidgetClass,
  4361. shellWidget, args, j);
  4362. #endif
  4363. layout =
  4364. XtCreateManagedWidget(layoutName, formWidgetClass, shell,
  4365. layoutArgs, XtNumber(layoutArgs));
  4366. form =
  4367. XtCreateManagedWidget("form", formWidgetClass, layout,
  4368. formArgs, XtNumber(formArgs));
  4369. j = 0;
  4370. if (mutable) {
  4371. XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
  4372. XtSetArg(args[j], XtNuseStringInPlace, False); j++;
  4373. }
  4374. XtSetArg(args[j], XtNstring, text); j++;
  4375. XtSetArg(args[j], XtNtop, XtChainTop); j++;
  4376. XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
  4377. XtSetArg(args[j], XtNleft, XtChainLeft); j++;
  4378. XtSetArg(args[j], XtNright, XtChainRight); j++;
  4379. XtSetArg(args[j], XtNresizable, True); j++;
  4380. XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
  4381. /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
  4382. XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
  4383. XtSetArg(args[j], XtNautoFill, True); j++;
  4384. XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
  4385. edit =
  4386. XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
  4387. XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
  4388. if (mutable) {
  4389. j = 0;
  4390. XtSetArg(args[j], XtNfromVert, edit); j++;
  4391. XtSetArg(args[j], XtNtop, XtChainBottom); j++;
  4392. XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
  4393. XtSetArg(args[j], XtNleft, XtChainLeft); j++;
  4394. XtSetArg(args[j], XtNright, XtChainLeft); j++;
  4395. b_ok =
  4396. XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
  4397. XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
  4398. j = 0;
  4399. XtSetArg(args[j], XtNfromVert, edit); j++;
  4400. XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
  4401. XtSetArg(args[j], XtNtop, XtChainBottom); j++;
  4402. XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
  4403. XtSetArg(args[j], XtNleft, XtChainLeft); j++;
  4404. XtSetArg(args[j], XtNright, XtChainLeft); j++;
  4405. b_cancel =
  4406. XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
  4407. XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
  4408. j = 0;
  4409. XtSetArg(args[j], XtNfromVert, edit); j++;
  4410. XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
  4411. XtSetArg(args[j], XtNtop, XtChainBottom); j++;
  4412. XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
  4413. XtSetArg(args[j], XtNleft, XtChainLeft); j++;
  4414. XtSetArg(args[j], XtNright, XtChainLeft); j++;
  4415. b_clear =
  4416. XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
  4417. XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
  4418. } else {
  4419. j = 0;
  4420. XtSetArg(args[j], XtNfromVert, edit); j++;
  4421. XtSetArg(args[j], XtNtop, XtChainBottom); j++;
  4422. XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
  4423. XtSetArg(args[j], XtNleft, XtChainLeft); j++;
  4424. XtSetArg(args[j], XtNright, XtChainLeft); j++;
  4425. b_close =
  4426. XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
  4427. XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
  4428. j = 0;
  4429. XtSetArg(args[j], XtNfromVert, edit); j++;
  4430. XtSetArg(args[j], XtNfromHoriz, b_close); j++;
  4431. XtSetArg(args[j], XtNtop, XtChainBottom); j++;
  4432. XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
  4433. XtSetArg(args[j], XtNleft, XtChainLeft); j++;
  4434. XtSetArg(args[j], XtNright, XtChainLeft); j++;
  4435. b_edit =
  4436. XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
  4437. XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
  4438. }
  4439. XtRealizeWidget(shell);
  4440. if (commentX == -1) {
  4441. int xx, yy;
  4442. Window junk;
  4443. Dimension pw_height;
  4444. Dimension ew_height;
  4445. j = 0;
  4446. XtSetArg(args[j], XtNheight, &ew_height); j++;
  4447. XtGetValues(edit, args, j);
  4448. j = 0;
  4449. XtSetArg(args[j], XtNheight, &pw_height); j++;
  4450. XtGetValues(shell, args, j);
  4451. commentH = pw_height + (lines - 1) * ew_height;
  4452. commentW = bw_width - 16;
  4453. XSync(xDisplay, False);
  4454. #ifdef NOTDEF
  4455. /* This code seems to tickle an X bug if it is executed too soon
  4456. after xboard starts up. The coordinates get transformed as if
  4457. the main window was positioned at (0, 0).
  4458. */
  4459. XtTranslateCoords(shellWidget,
  4460. (bw_width - commentW) / 2, 0 - commentH / 2,
  4461. &commentX, &commentY);
  4462. #else /*!NOTDEF*/
  4463. XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
  4464. RootWindowOfScreen(XtScreen(shellWidget)),
  4465. (bw_width - commentW) / 2, 0 - commentH / 2,
  4466. &xx, &yy, &junk);
  4467. commentX = xx;
  4468. commentY = yy;
  4469. #endif /*!NOTDEF*/
  4470. if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
  4471. }
  4472. if(wpComment.width > 0) {
  4473. commentX = wpComment.x;
  4474. commentY = wpComment.y;
  4475. commentW = wpComment.width;
  4476. commentH = wpComment.height;
  4477. }
  4478. j = 0;
  4479. XtSetArg(args[j], XtNheight, commentH); j++;
  4480. XtSetArg(args[j], XtNwidth, commentW); j++;
  4481. XtSetArg(args[j], XtNx, commentX); j++;
  4482. XtSetArg(args[j], XtNy, commentY); j++;
  4483. XtSetValues(shell, args, j);
  4484. XtSetKeyboardFocus(shell, edit);
  4485. return shell;
  4486. }
  4487. static int savedIndex; /* gross that this is global */
  4488. void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
  4489. {
  4490. String val;
  4491. XawTextPosition index, dummy;
  4492. Arg arg;
  4493. XawTextGetSelectionPos(w, &index, &dummy);
  4494. XtSetArg(arg, XtNstring, &val);
  4495. XtGetValues(w, &arg, 1);
  4496. ReplaceComment(savedIndex, val);
  4497. if(savedIndex != currentMove) ToNrEvent(savedIndex);
  4498. LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
  4499. }
  4500. void EditCommentPopUp(index, title, text)
  4501. int index;
  4502. char *title, *text;
  4503. {
  4504. Widget edit;
  4505. Arg args[16];
  4506. int j;
  4507. savedIndex = index;
  4508. if (text == NULL) text = "";
  4509. if (editShell == NULL) {
  4510. editShell =
  4511. CommentCreate(title, text, True, EditCommentCallback, 4);
  4512. XtRealizeWidget(editShell);
  4513. CatchDeleteWindow(editShell, "EditCommentPopDown");
  4514. } else {
  4515. edit = XtNameToWidget(editShell, "*form.text");
  4516. j = 0;
  4517. XtSetArg(args[j], XtNstring, text); j++;
  4518. XtSetValues(edit, args, j);
  4519. j = 0;
  4520. XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
  4521. XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
  4522. XtSetValues(editShell, args, j);
  4523. }
  4524. XtPopup(editShell, XtGrabNone);
  4525. editUp = True;
  4526. j = 0;
  4527. XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
  4528. XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
  4529. args, j);
  4530. XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
  4531. args, j);
  4532. }
  4533. void EditCommentCallback(w, client_data, call_data)
  4534. Widget w;
  4535. XtPointer client_data, call_data;
  4536. {
  4537. String name, val;
  4538. Arg args[16];
  4539. int j;
  4540. Widget edit;
  4541. j = 0;
  4542. XtSetArg(args[j], XtNlabel, &name); j++;
  4543. XtGetValues(w, args, j);
  4544. if (strcmp(name, _("ok")) == 0) {
  4545. edit = XtNameToWidget(editShell, "*form.text");
  4546. j = 0;
  4547. XtSetArg(args[j], XtNstring, &val); j++;
  4548. XtGetValues(edit, args, j);
  4549. ReplaceComment(savedIndex, val);
  4550. EditCommentPopDown();
  4551. } else if (strcmp(name, _("cancel")) == 0) {
  4552. EditCommentPopDown();
  4553. } else if (strcmp(name, _("clear")) == 0) {
  4554. edit = XtNameToWidget(editShell, "*form.text");
  4555. XtCallActionProc(edit, "select-all", NULL, NULL, 0);
  4556. XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
  4557. }
  4558. }
  4559. void EditCommentPopDown()
  4560. {
  4561. Arg args[16];
  4562. int j;
  4563. if (!editUp) return;
  4564. j = 0;
  4565. XtSetArg(args[j], XtNx, &commentX); j++;
  4566. XtSetArg(args[j], XtNy, &commentY); j++;
  4567. XtSetArg(args[j], XtNheight, &commentH); j++;
  4568. XtSetArg(args[j], XtNwidth, &commentW); j++;
  4569. XtGetValues(editShell, args, j);
  4570. XtPopdown(editShell);
  4571. editUp = False;
  4572. j = 0;
  4573. XtSetArg(args[j], XtNleftBitmap, None); j++;
  4574. XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"),
  4575. args, j);
  4576. XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"),
  4577. args, j);
  4578. }
  4579. void ICSInputBoxPopUp()
  4580. {
  4581. InputBoxPopup();
  4582. }
  4583. extern Option boxOptions[];
  4584. void ICSInputSendText()
  4585. {
  4586. Widget edit;
  4587. int j;
  4588. Arg args[16];
  4589. String val;
  4590. edit = boxOptions[0].handle;
  4591. j = 0;
  4592. XtSetArg(args[j], XtNstring, &val); j++;
  4593. XtGetValues(edit, args, j);
  4594. SaveInHistory(val);
  4595. SendMultiLineToICS(val);
  4596. XtCallActionProc(edit, "select-all", NULL, NULL, 0);
  4597. XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
  4598. }
  4599. void ICSInputBoxPopDown()
  4600. {
  4601. PopDown(4);
  4602. }
  4603. void CommentPopUp(title, text)
  4604. char *title, *text;
  4605. {
  4606. Arg args[16];
  4607. int j;
  4608. Widget edit;
  4609. savedIndex = currentMove; // [HGM] vari
  4610. if (commentShell == NULL) {
  4611. commentShell =
  4612. CommentCreate(title, text, False, CommentCallback, 4);
  4613. XtRealizeWidget(commentShell);
  4614. CatchDeleteWindow(commentShell, "CommentPopDown");
  4615. } else {
  4616. edit = XtNameToWidget(commentShell, "*form.text");
  4617. j = 0;
  4618. XtSetArg(args[j], XtNstring, text); j++;
  4619. XtSetValues(edit, args, j);
  4620. j = 0;
  4621. XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
  4622. XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
  4623. XtSetValues(commentShell, args, j);
  4624. }
  4625. XtPopup(commentShell, XtGrabNone);
  4626. XSync(xDisplay, False);
  4627. commentUp = True;
  4628. }
  4629. void CommentCallback(w, client_data, call_data)
  4630. Widget w;
  4631. XtPointer client_data, call_data;
  4632. {
  4633. String name;
  4634. Arg args[16];
  4635. int j;
  4636. j = 0;
  4637. XtSetArg(args[j], XtNlabel, &name); j++;
  4638. XtGetValues(w, args, j);
  4639. if (strcmp(name, _("close")) == 0) {
  4640. CommentPopDown();
  4641. } else if (strcmp(name, _("edit")) == 0) {
  4642. CommentPopDown();
  4643. EditCommentEvent();
  4644. }
  4645. }
  4646. void CommentPopDown()
  4647. {
  4648. Arg args[16];
  4649. int j;
  4650. if (!commentUp) return;
  4651. j = 0;
  4652. XtSetArg(args[j], XtNx, &commentX); j++;
  4653. XtSetArg(args[j], XtNy, &commentY); j++;
  4654. XtSetArg(args[j], XtNwidth, &commentW); j++;
  4655. XtSetArg(args[j], XtNheight, &commentH); j++;
  4656. XtGetValues(commentShell, args, j);
  4657. XtPopdown(commentShell);
  4658. XSync(xDisplay, False);
  4659. commentUp = False;
  4660. }
  4661. void FileNamePopUp(label, def, filter, proc, openMode)
  4662. char *label;
  4663. char *def;
  4664. char *filter;
  4665. FileProc proc;
  4666. char *openMode;
  4667. {
  4668. fileProc = proc; /* I can't see a way not */
  4669. fileOpenMode = openMode; /* to use globals here */
  4670. { // [HGM] use file-selector dialog stolen from Ghostview
  4671. char *name;
  4672. int index; // this is not supported yet
  4673. FILE *f;
  4674. if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
  4675. (def[0] ? def : NULL), filter, openMode, NULL, &name))
  4676. (void) (*fileProc)(f, index=0, name);
  4677. }
  4678. }
  4679. void FileNamePopDown()
  4680. {
  4681. if (!filenameUp) return;
  4682. XtPopdown(fileNameShell);
  4683. XtDestroyWidget(fileNameShell);
  4684. filenameUp = False;
  4685. ModeHighlight();
  4686. }
  4687. void FileNameCallback(w, client_data, call_data)
  4688. Widget w;
  4689. XtPointer client_data, call_data;
  4690. {
  4691. String name;
  4692. Arg args[16];
  4693. XtSetArg(args[0], XtNlabel, &name);
  4694. XtGetValues(w, args, 1);
  4695. if (strcmp(name, _("cancel")) == 0) {
  4696. FileNamePopDown();
  4697. return;
  4698. }
  4699. FileNameAction(w, NULL, NULL, NULL);
  4700. }
  4701. void FileNameAction(w, event, prms, nprms)
  4702. Widget w;
  4703. XEvent *event;
  4704. String *prms;
  4705. Cardinal *nprms;
  4706. {
  4707. char buf[MSG_SIZ];
  4708. String name;
  4709. FILE *f;
  4710. char *p, *fullname;
  4711. int index;
  4712. name = XawDialogGetValueString(w = XtParent(w));
  4713. if ((name != NULL) && (*name != NULLCHAR)) {
  4714. safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
  4715. XtPopdown(w = XtParent(XtParent(w)));
  4716. XtDestroyWidget(w);
  4717. filenameUp = False;
  4718. p = strrchr(buf, ' ');
  4719. if (p == NULL) {
  4720. index = 0;
  4721. } else {
  4722. *p++ = NULLCHAR;
  4723. index = atoi(p);
  4724. }
  4725. fullname = ExpandPathName(buf);
  4726. if (!fullname) {
  4727. ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
  4728. }
  4729. else {
  4730. f = fopen(fullname, fileOpenMode);
  4731. if (f == NULL) {
  4732. DisplayError(_("Failed to open file"), errno);
  4733. } else {
  4734. (void) (*fileProc)(f, index, buf);
  4735. }
  4736. }
  4737. ModeHighlight();
  4738. return;
  4739. }
  4740. XtPopdown(w = XtParent(XtParent(w)));
  4741. XtDestroyWidget(w);
  4742. filenameUp = False;
  4743. ModeHighlight();
  4744. }
  4745. void PromotionPopUp()
  4746. {
  4747. Arg args[16];
  4748. Widget dialog, layout;
  4749. Position x, y;
  4750. Dimension bw_width, pw_width;
  4751. int j;
  4752. j = 0;
  4753. XtSetArg(args[j], XtNwidth, &bw_width); j++;
  4754. XtGetValues(boardWidget, args, j);
  4755. j = 0;
  4756. XtSetArg(args[j], XtNresizable, True); j++;
  4757. XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
  4758. promotionShell =
  4759. XtCreatePopupShell("Promotion", transientShellWidgetClass,
  4760. shellWidget, args, j);
  4761. layout =
  4762. XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
  4763. layoutArgs, XtNumber(layoutArgs));
  4764. j = 0;
  4765. XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
  4766. XtSetArg(args[j], XtNborderWidth, 0); j++;
  4767. dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
  4768. layout, args, j);
  4769. if(gameInfo.variant != VariantShogi) {
  4770. if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
  4771. XawDialogAddButton(dialog, _("Warlord"), PromotionCallback,
  4772. (XtPointer) dialog);
  4773. XawDialogAddButton(dialog, _("General"), PromotionCallback,
  4774. (XtPointer) dialog);
  4775. XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback,
  4776. (XtPointer) dialog);
  4777. XawDialogAddButton(dialog, _("Captain"), PromotionCallback,
  4778. (XtPointer) dialog);
  4779. } else {
  4780. XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
  4781. (XtPointer) dialog);
  4782. XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
  4783. (XtPointer) dialog);
  4784. XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
  4785. (XtPointer) dialog);
  4786. XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
  4787. (XtPointer) dialog);
  4788. }
  4789. if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
  4790. gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
  4791. gameInfo.variant == VariantGiveaway) {
  4792. XawDialogAddButton(dialog, _("King"), PromotionCallback,
  4793. (XtPointer) dialog);
  4794. }
  4795. if(gameInfo.variant == VariantCapablanca ||
  4796. gameInfo.variant == VariantGothic ||
  4797. gameInfo.variant == VariantCapaRandom) {
  4798. XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
  4799. (XtPointer) dialog);
  4800. XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
  4801. (XtPointer) dialog);
  4802. }
  4803. } else // [HGM] shogi
  4804. {
  4805. XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
  4806. (XtPointer) dialog);
  4807. XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
  4808. (XtPointer) dialog);
  4809. }
  4810. XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
  4811. (XtPointer) dialog);
  4812. XtRealizeWidget(promotionShell);
  4813. CatchDeleteWindow(promotionShell, "PromotionPopDown");
  4814. j = 0;
  4815. XtSetArg(args[j], XtNwidth, &pw_width); j++;
  4816. XtGetValues(promotionShell, args, j);
  4817. XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
  4818. lineGap + squareSize/3 +
  4819. ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
  4820. 0 : 6*(squareSize + lineGap)), &x, &y);
  4821. j = 0;
  4822. XtSetArg(args[j], XtNx, x); j++;
  4823. XtSetArg(args[j], XtNy, y); j++;
  4824. XtSetValues(promotionShell, args, j);
  4825. XtPopup(promotionShell, XtGrabNone);
  4826. promotionUp = True;
  4827. }
  4828. void PromotionPopDown()
  4829. {
  4830. if (!promotionUp) return;
  4831. XtPopdown(promotionShell);
  4832. XtDestroyWidget(promotionShell);
  4833. promotionUp = False;
  4834. }
  4835. void PromotionCallback(w, client_data, call_data)
  4836. Widget w;
  4837. XtPointer client_data, call_data;
  4838. {
  4839. String name;
  4840. Arg args[16];
  4841. int promoChar;
  4842. XtSetArg(args[0], XtNlabel, &name);
  4843. XtGetValues(w, args, 1);
  4844. PromotionPopDown();
  4845. if (fromX == -1) return;
  4846. if (strcmp(name, _("cancel")) == 0) {
  4847. fromX = fromY = -1;
  4848. ClearHighlights();
  4849. return;
  4850. } else if (strcmp(name, _("Knight")) == 0) {
  4851. promoChar = 'n';
  4852. } else if (strcmp(name, _("Promote")) == 0) {
  4853. promoChar = '+';
  4854. } else if (strcmp(name, _("Defer")) == 0) {
  4855. promoChar = '=';
  4856. } else {
  4857. promoChar = ToLower(name[0]);
  4858. }
  4859. UserMoveEvent(fromX, fromY, toX, toY, promoChar);
  4860. if (!appData.highlightLastMove || gotPremove) ClearHighlights();
  4861. if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
  4862. fromX = fromY = -1;
  4863. }
  4864. void ErrorCallback(w, client_data, call_data)
  4865. Widget w;
  4866. XtPointer client_data, call_data;
  4867. {
  4868. errorUp = False;
  4869. XtPopdown(w = XtParent(XtParent(XtParent(w))));
  4870. XtDestroyWidget(w);
  4871. if (errorExitStatus != -1) ExitEvent(errorExitStatus);
  4872. }
  4873. void ErrorPopDown()
  4874. {
  4875. if (!errorUp) return;
  4876. errorUp = False;
  4877. XtPopdown(errorShell);
  4878. XtDestroyWidget(errorShell);
  4879. if (errorExitStatus != -1) ExitEvent(errorExitStatus);
  4880. }
  4881. void ErrorPopUp(title, label, modal)
  4882. char *title, *label;
  4883. int modal;
  4884. {
  4885. Arg args[16];
  4886. Widget dialog, layout;
  4887. Position x, y;
  4888. int xx, yy;
  4889. Window junk;
  4890. Dimension bw_width, pw_width;
  4891. Dimension pw_height;
  4892. int i;
  4893. i = 0;
  4894. XtSetArg(args[i], XtNresizable, True); i++;
  4895. XtSetArg(args[i], XtNtitle, title); i++;
  4896. errorShell =
  4897. XtCreatePopupShell("errorpopup", transientShellWidgetClass,
  4898. shellWidget, args, i);
  4899. layout =
  4900. XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
  4901. layoutArgs, XtNumber(layoutArgs));
  4902. i = 0;
  4903. XtSetArg(args[i], XtNlabel, label); i++;
  4904. XtSetArg(args[i], XtNborderWidth, 0); i++;
  4905. dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
  4906. layout, args, i);
  4907. XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
  4908. XtRealizeWidget(errorShell);
  4909. CatchDeleteWindow(errorShell, "ErrorPopDown");
  4910. i = 0;
  4911. XtSetArg(args[i], XtNwidth, &bw_width); i++;
  4912. XtGetValues(boardWidget, args, i);
  4913. i = 0;
  4914. XtSetArg(args[i], XtNwidth, &pw_width); i++;
  4915. XtSetArg(args[i], XtNheight, &pw_height); i++;
  4916. XtGetValues(errorShell, args, i);
  4917. #ifdef NOTDEF
  4918. /* This code seems to tickle an X bug if it is executed too soon
  4919. after xboard starts up. The coordinates get transformed as if
  4920. the main window was positioned at (0, 0).
  4921. */
  4922. XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
  4923. 0 - pw_height + squareSize / 3, &x, &y);
  4924. #else
  4925. XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
  4926. RootWindowOfScreen(XtScreen(boardWidget)),
  4927. (bw_width - pw_width) / 2,
  4928. 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
  4929. x = xx;
  4930. y = yy;
  4931. #endif
  4932. if (y < 0) y = 0; /*avoid positioning top offscreen*/
  4933. i = 0;
  4934. XtSetArg(args[i], XtNx, x); i++;
  4935. XtSetArg(args[i], XtNy, y); i++;
  4936. XtSetValues(errorShell, args, i);
  4937. errorUp = True;
  4938. XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
  4939. }
  4940. /* Disable all user input other than deleting the window */
  4941. static int frozen = 0;
  4942. void FreezeUI()
  4943. {
  4944. if (frozen) return;
  4945. /* Grab by a widget that doesn't accept input */
  4946. XtAddGrab(messageWidget, TRUE, FALSE);
  4947. frozen = 1;
  4948. }
  4949. /* Undo a FreezeUI */
  4950. void ThawUI()
  4951. {
  4952. if (!frozen) return;
  4953. XtRemoveGrab(messageWidget);
  4954. frozen = 0;
  4955. }
  4956. char *ModeToWidgetName(mode)
  4957. GameMode mode;
  4958. {
  4959. switch (mode) {
  4960. case BeginningOfGame:
  4961. if (appData.icsActive)
  4962. return "menuMode.ICS Client";
  4963. else if (appData.noChessProgram ||
  4964. *appData.cmailGameName != NULLCHAR)
  4965. return "menuMode.Edit Game";
  4966. else
  4967. return "menuMode.Machine Black";
  4968. case MachinePlaysBlack:
  4969. return "menuMode.Machine Black";
  4970. case MachinePlaysWhite:
  4971. return "menuMode.Machine White";
  4972. case AnalyzeMode:
  4973. return "menuMode.Analysis Mode";
  4974. case AnalyzeFile:
  4975. return "menuMode.Analyze File";
  4976. case TwoMachinesPlay:
  4977. return "menuMode.Two Machines";
  4978. case EditGame:
  4979. return "menuMode.Edit Game";
  4980. case PlayFromGameFile:
  4981. return "menuFile.Load Game";
  4982. case EditPosition:
  4983. return "menuMode.Edit Position";
  4984. case Training:
  4985. return "menuMode.Training";
  4986. case IcsPlayingWhite:
  4987. case IcsPlayingBlack:
  4988. case IcsObserving:
  4989. case IcsIdle:
  4990. case IcsExamining:
  4991. return "menuMode.ICS Client";
  4992. default:
  4993. case EndOfGame:
  4994. return NULL;
  4995. }
  4996. }
  4997. void ModeHighlight()
  4998. {
  4999. Arg args[16];
  5000. static int oldPausing = FALSE;
  5001. static GameMode oldmode = (GameMode) -1;
  5002. char *wname;
  5003. if (!boardWidget || !XtIsRealized(boardWidget)) return;
  5004. if (pausing != oldPausing) {
  5005. oldPausing = pausing;
  5006. if (pausing) {
  5007. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  5008. } else {
  5009. XtSetArg(args[0], XtNleftBitmap, None);
  5010. }
  5011. XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
  5012. args, 1);
  5013. if (appData.showButtonBar) {
  5014. /* Always toggle, don't set. Previous code messes up when
  5015. invoked while the button is pressed, as releasing it
  5016. toggles the state again. */
  5017. {
  5018. Pixel oldbg, oldfg;
  5019. XtSetArg(args[0], XtNbackground, &oldbg);
  5020. XtSetArg(args[1], XtNforeground, &oldfg);
  5021. XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
  5022. args, 2);
  5023. XtSetArg(args[0], XtNbackground, oldfg);
  5024. XtSetArg(args[1], XtNforeground, oldbg);
  5025. }
  5026. XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
  5027. }
  5028. }
  5029. wname = ModeToWidgetName(oldmode);
  5030. if (wname != NULL) {
  5031. XtSetArg(args[0], XtNleftBitmap, None);
  5032. XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
  5033. }
  5034. wname = ModeToWidgetName(gameMode);
  5035. if (wname != NULL) {
  5036. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  5037. XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
  5038. }
  5039. oldmode = gameMode;
  5040. /* Maybe all the enables should be handled here, not just this one */
  5041. XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
  5042. gameMode == Training || gameMode == PlayFromGameFile);
  5043. }
  5044. /*
  5045. * Button/menu procedures
  5046. */
  5047. void ResetProc(w, event, prms, nprms)
  5048. Widget w;
  5049. XEvent *event;
  5050. String *prms;
  5051. Cardinal *nprms;
  5052. {
  5053. ResetGameEvent();
  5054. }
  5055. int LoadGamePopUp(f, gameNumber, title)
  5056. FILE *f;
  5057. int gameNumber;
  5058. char *title;
  5059. {
  5060. cmailMsgLoaded = FALSE;
  5061. if (gameNumber == 0) {
  5062. int error = GameListBuild(f);
  5063. if (error) {
  5064. DisplayError(_("Cannot build game list"), error);
  5065. } else if (!ListEmpty(&gameList) &&
  5066. ((ListGame *) gameList.tailPred)->number > 1) {
  5067. GameListPopUp(f, title);
  5068. return TRUE;
  5069. }
  5070. GameListDestroy();
  5071. gameNumber = 1;
  5072. }
  5073. return LoadGame(f, gameNumber, title, FALSE);
  5074. }
  5075. void LoadGameProc(w, event, prms, nprms)
  5076. Widget w;
  5077. XEvent *event;
  5078. String *prms;
  5079. Cardinal *nprms;
  5080. {
  5081. if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
  5082. Reset(FALSE, TRUE);
  5083. }
  5084. FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
  5085. }
  5086. void LoadNextGameProc(w, event, prms, nprms)
  5087. Widget w;
  5088. XEvent *event;
  5089. String *prms;
  5090. Cardinal *nprms;
  5091. {
  5092. ReloadGame(1);
  5093. }
  5094. void LoadPrevGameProc(w, event, prms, nprms)
  5095. Widget w;
  5096. XEvent *event;
  5097. String *prms;
  5098. Cardinal *nprms;
  5099. {
  5100. ReloadGame(-1);
  5101. }
  5102. void ReloadGameProc(w, event, prms, nprms)
  5103. Widget w;
  5104. XEvent *event;
  5105. String *prms;
  5106. Cardinal *nprms;
  5107. {
  5108. ReloadGame(0);
  5109. }
  5110. void LoadNextPositionProc(w, event, prms, nprms)
  5111. Widget w;
  5112. XEvent *event;
  5113. String *prms;
  5114. Cardinal *nprms;
  5115. {
  5116. ReloadPosition(1);
  5117. }
  5118. void LoadPrevPositionProc(w, event, prms, nprms)
  5119. Widget w;
  5120. XEvent *event;
  5121. String *prms;
  5122. Cardinal *nprms;
  5123. {
  5124. ReloadPosition(-1);
  5125. }
  5126. void ReloadPositionProc(w, event, prms, nprms)
  5127. Widget w;
  5128. XEvent *event;
  5129. String *prms;
  5130. Cardinal *nprms;
  5131. {
  5132. ReloadPosition(0);
  5133. }
  5134. void LoadPositionProc(w, event, prms, nprms)
  5135. Widget w;
  5136. XEvent *event;
  5137. String *prms;
  5138. Cardinal *nprms;
  5139. {
  5140. if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
  5141. Reset(FALSE, TRUE);
  5142. }
  5143. FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
  5144. }
  5145. void SaveGameProc(w, event, prms, nprms)
  5146. Widget w;
  5147. XEvent *event;
  5148. String *prms;
  5149. Cardinal *nprms;
  5150. {
  5151. FileNamePopUp(_("Save game file name?"),
  5152. DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
  5153. appData.oldSaveStyle ? ".game" : ".pgn",
  5154. SaveGame, "a");
  5155. }
  5156. void SavePositionProc(w, event, prms, nprms)
  5157. Widget w;
  5158. XEvent *event;
  5159. String *prms;
  5160. Cardinal *nprms;
  5161. {
  5162. FileNamePopUp(_("Save position file name?"),
  5163. DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
  5164. appData.oldSaveStyle ? ".pos" : ".fen",
  5165. SavePosition, "a");
  5166. }
  5167. void ReloadCmailMsgProc(w, event, prms, nprms)
  5168. Widget w;
  5169. XEvent *event;
  5170. String *prms;
  5171. Cardinal *nprms;
  5172. {
  5173. ReloadCmailMsgEvent(FALSE);
  5174. }
  5175. void MailMoveProc(w, event, prms, nprms)
  5176. Widget w;
  5177. XEvent *event;
  5178. String *prms;
  5179. Cardinal *nprms;
  5180. {
  5181. MailMoveEvent();
  5182. }
  5183. /* this variable is shared between CopyPositionProc and SendPositionSelection */
  5184. char *selected_fen_position=NULL;
  5185. Boolean
  5186. SendPositionSelection(Widget w, Atom *selection, Atom *target,
  5187. Atom *type_return, XtPointer *value_return,
  5188. unsigned long *length_return, int *format_return)
  5189. {
  5190. char *selection_tmp;
  5191. if (!selected_fen_position) return False; /* should never happen */
  5192. if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
  5193. /* note: since no XtSelectionDoneProc was registered, Xt will
  5194. * automatically call XtFree on the value returned. So have to
  5195. * make a copy of it allocated with XtMalloc */
  5196. selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
  5197. safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
  5198. *value_return=selection_tmp;
  5199. *length_return=strlen(selection_tmp);
  5200. *type_return=*target;
  5201. *format_return = 8; /* bits per byte */
  5202. return True;
  5203. } else if (*target == XA_TARGETS(xDisplay)) {
  5204. Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
  5205. targets_tmp[0] = XA_UTF8_STRING(xDisplay);
  5206. targets_tmp[1] = XA_STRING;
  5207. *value_return = targets_tmp;
  5208. *type_return = XA_ATOM;
  5209. *length_return = 2;
  5210. *format_return = 8 * sizeof(Atom);
  5211. if (*format_return > 32) {
  5212. *length_return *= *format_return / 32;
  5213. *format_return = 32;
  5214. }
  5215. return True;
  5216. } else {
  5217. return False;
  5218. }
  5219. }
  5220. /* note: when called from menu all parameters are NULL, so no clue what the
  5221. * Widget which was clicked on was, or what the click event was
  5222. */
  5223. void CopyPositionProc(w, event, prms, nprms)
  5224. Widget w;
  5225. XEvent *event;
  5226. String *prms;
  5227. Cardinal *nprms;
  5228. {
  5229. /*
  5230. * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
  5231. * have a notion of a position that is selected but not copied.
  5232. * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
  5233. */
  5234. if(gameMode == EditPosition) EditPositionDone(TRUE);
  5235. if (selected_fen_position) free(selected_fen_position);
  5236. selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
  5237. if (!selected_fen_position) return;
  5238. XtOwnSelection(menuBarWidget, XA_PRIMARY,
  5239. CurrentTime,
  5240. SendPositionSelection,
  5241. NULL/* lose_ownership_proc */ ,
  5242. NULL/* transfer_done_proc */);
  5243. XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
  5244. CurrentTime,
  5245. SendPositionSelection,
  5246. NULL/* lose_ownership_proc */ ,
  5247. NULL/* transfer_done_proc */);
  5248. }
  5249. /* function called when the data to Paste is ready */
  5250. static void
  5251. PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
  5252. Atom *type, XtPointer value, unsigned long *len, int *format)
  5253. {
  5254. char *fenstr=value;
  5255. if (value==NULL || *len==0) return; /* nothing had been selected to copy */
  5256. fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
  5257. EditPositionPasteFEN(fenstr);
  5258. XtFree(value);
  5259. }
  5260. /* called when Paste Position button is pressed,
  5261. * all parameters will be NULL */
  5262. void PastePositionProc(w, event, prms, nprms)
  5263. Widget w;
  5264. XEvent *event;
  5265. String *prms;
  5266. Cardinal *nprms;
  5267. {
  5268. XtGetSelectionValue(menuBarWidget,
  5269. appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
  5270. /* (XtSelectionCallbackProc) */ PastePositionCB,
  5271. NULL, /* client_data passed to PastePositionCB */
  5272. /* better to use the time field from the event that triggered the
  5273. * call to this function, but that isn't trivial to get
  5274. */
  5275. CurrentTime
  5276. );
  5277. return;
  5278. }
  5279. static Boolean
  5280. SendGameSelection(Widget w, Atom *selection, Atom *target,
  5281. Atom *type_return, XtPointer *value_return,
  5282. unsigned long *length_return, int *format_return)
  5283. {
  5284. char *selection_tmp;
  5285. if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
  5286. FILE* f = fopen(gameCopyFilename, "r");
  5287. long len;
  5288. size_t count;
  5289. if (f == NULL) return False;
  5290. fseek(f, 0, 2);
  5291. len = ftell(f);
  5292. rewind(f);
  5293. selection_tmp = XtMalloc(len + 1);
  5294. count = fread(selection_tmp, 1, len, f);
  5295. fclose(f);
  5296. if (len != count) {
  5297. XtFree(selection_tmp);
  5298. return False;
  5299. }
  5300. selection_tmp[len] = NULLCHAR;
  5301. *value_return = selection_tmp;
  5302. *length_return = len;
  5303. *type_return = *target;
  5304. *format_return = 8; /* bits per byte */
  5305. return True;
  5306. } else if (*target == XA_TARGETS(xDisplay)) {
  5307. Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
  5308. targets_tmp[0] = XA_UTF8_STRING(xDisplay);
  5309. targets_tmp[1] = XA_STRING;
  5310. *value_return = targets_tmp;
  5311. *type_return = XA_ATOM;
  5312. *length_return = 2;
  5313. *format_return = 8 * sizeof(Atom);
  5314. if (*format_return > 32) {
  5315. *length_return *= *format_return / 32;
  5316. *format_return = 32;
  5317. }
  5318. return True;
  5319. } else {
  5320. return False;
  5321. }
  5322. }
  5323. /* note: when called from menu all parameters are NULL, so no clue what the
  5324. * Widget which was clicked on was, or what the click event was
  5325. */
  5326. void CopyGameProc(w, event, prms, nprms)
  5327. Widget w;
  5328. XEvent *event;
  5329. String *prms;
  5330. Cardinal *nprms;
  5331. {
  5332. int ret;
  5333. ret = SaveGameToFile(gameCopyFilename, FALSE);
  5334. if (!ret) return;
  5335. /*
  5336. * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
  5337. * have a notion of a game that is selected but not copied.
  5338. * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
  5339. */
  5340. XtOwnSelection(menuBarWidget, XA_PRIMARY,
  5341. CurrentTime,
  5342. SendGameSelection,
  5343. NULL/* lose_ownership_proc */ ,
  5344. NULL/* transfer_done_proc */);
  5345. XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
  5346. CurrentTime,
  5347. SendGameSelection,
  5348. NULL/* lose_ownership_proc */ ,
  5349. NULL/* transfer_done_proc */);
  5350. }
  5351. /* function called when the data to Paste is ready */
  5352. static void
  5353. PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
  5354. Atom *type, XtPointer value, unsigned long *len, int *format)
  5355. {
  5356. FILE* f;
  5357. if (value == NULL || *len == 0) {
  5358. return; /* nothing had been selected to copy */
  5359. }
  5360. f = fopen(gamePasteFilename, "w");
  5361. if (f == NULL) {
  5362. DisplayError(_("Can't open temp file"), errno);
  5363. return;
  5364. }
  5365. fwrite(value, 1, *len, f);
  5366. fclose(f);
  5367. XtFree(value);
  5368. LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
  5369. }
  5370. /* called when Paste Game button is pressed,
  5371. * all parameters will be NULL */
  5372. void PasteGameProc(w, event, prms, nprms)
  5373. Widget w;
  5374. XEvent *event;
  5375. String *prms;
  5376. Cardinal *nprms;
  5377. {
  5378. XtGetSelectionValue(menuBarWidget,
  5379. appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
  5380. /* (XtSelectionCallbackProc) */ PasteGameCB,
  5381. NULL, /* client_data passed to PasteGameCB */
  5382. /* better to use the time field from the event that triggered the
  5383. * call to this function, but that isn't trivial to get
  5384. */
  5385. CurrentTime
  5386. );
  5387. return;
  5388. }
  5389. void AutoSaveGame()
  5390. {
  5391. SaveGameProc(NULL, NULL, NULL, NULL);
  5392. }
  5393. void QuitProc(w, event, prms, nprms)
  5394. Widget w;
  5395. XEvent *event;
  5396. String *prms;
  5397. Cardinal *nprms;
  5398. {
  5399. ExitEvent(0);
  5400. }
  5401. void PauseProc(w, event, prms, nprms)
  5402. Widget w;
  5403. XEvent *event;
  5404. String *prms;
  5405. Cardinal *nprms;
  5406. {
  5407. PauseEvent();
  5408. }
  5409. void MachineBlackProc(w, event, prms, nprms)
  5410. Widget w;
  5411. XEvent *event;
  5412. String *prms;
  5413. Cardinal *nprms;
  5414. {
  5415. MachineBlackEvent();
  5416. }
  5417. void MachineWhiteProc(w, event, prms, nprms)
  5418. Widget w;
  5419. XEvent *event;
  5420. String *prms;
  5421. Cardinal *nprms;
  5422. {
  5423. MachineWhiteEvent();
  5424. }
  5425. void AnalyzeModeProc(w, event, prms, nprms)
  5426. Widget w;
  5427. XEvent *event;
  5428. String *prms;
  5429. Cardinal *nprms;
  5430. {
  5431. char buf[MSG_SIZ];
  5432. if (!first.analysisSupport) {
  5433. snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
  5434. DisplayError(buf, 0);
  5435. return;
  5436. }
  5437. /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
  5438. if (appData.icsActive) {
  5439. if (gameMode != IcsObserving) {
  5440. snprintf(buf, MSG_SIZ, _("You are not observing a game"));
  5441. DisplayError(buf, 0);
  5442. /* secure check */
  5443. if (appData.icsEngineAnalyze) {
  5444. if (appData.debugMode)
  5445. fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
  5446. ExitAnalyzeMode();
  5447. ModeHighlight();
  5448. }
  5449. return;
  5450. }
  5451. /* if enable, use want disable icsEngineAnalyze */
  5452. if (appData.icsEngineAnalyze) {
  5453. ExitAnalyzeMode();
  5454. ModeHighlight();
  5455. return;
  5456. }
  5457. appData.icsEngineAnalyze = TRUE;
  5458. if (appData.debugMode)
  5459. fprintf(debugFP, _("ICS engine analyze starting... \n"));
  5460. }
  5461. #ifndef OPTIONSDIALOG
  5462. if (!appData.showThinking)
  5463. ShowThinkingProc(w,event,prms,nprms);
  5464. #endif
  5465. AnalyzeModeEvent();
  5466. }
  5467. void AnalyzeFileProc(w, event, prms, nprms)
  5468. Widget w;
  5469. XEvent *event;
  5470. String *prms;
  5471. Cardinal *nprms;
  5472. {
  5473. if (!first.analysisSupport) {
  5474. char buf[MSG_SIZ];
  5475. snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
  5476. DisplayError(buf, 0);
  5477. return;
  5478. }
  5479. Reset(FALSE, TRUE);
  5480. #ifndef OPTIONSDIALOG
  5481. if (!appData.showThinking)
  5482. ShowThinkingProc(w,event,prms,nprms);
  5483. #endif
  5484. AnalyzeFileEvent();
  5485. FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
  5486. AnalysisPeriodicEvent(1);
  5487. }
  5488. void TwoMachinesProc(w, event, prms, nprms)
  5489. Widget w;
  5490. XEvent *event;
  5491. String *prms;
  5492. Cardinal *nprms;
  5493. {
  5494. TwoMachinesEvent();
  5495. }
  5496. void MatchProc(w, event, prms, nprms)
  5497. Widget w;
  5498. XEvent *event;
  5499. String *prms;
  5500. Cardinal *nprms;
  5501. {
  5502. if(gameMode != BeginningOfGame) { DisplayError(_("You can only start a match from the initial position."), 0); return; }
  5503. appData.matchGames = appData.defaultMatchGames;
  5504. MatchEvent(2);
  5505. }
  5506. void IcsClientProc(w, event, prms, nprms)
  5507. Widget w;
  5508. XEvent *event;
  5509. String *prms;
  5510. Cardinal *nprms;
  5511. {
  5512. IcsClientEvent();
  5513. }
  5514. void EditGameProc(w, event, prms, nprms)
  5515. Widget w;
  5516. XEvent *event;
  5517. String *prms;
  5518. Cardinal *nprms;
  5519. {
  5520. EditGameEvent();
  5521. }
  5522. void EditPositionProc(w, event, prms, nprms)
  5523. Widget w;
  5524. XEvent *event;
  5525. String *prms;
  5526. Cardinal *nprms;
  5527. {
  5528. EditPositionEvent();
  5529. }
  5530. void TrainingProc(w, event, prms, nprms)
  5531. Widget w;
  5532. XEvent *event;
  5533. String *prms;
  5534. Cardinal *nprms;
  5535. {
  5536. TrainingEvent();
  5537. }
  5538. void EditCommentProc(w, event, prms, nprms)
  5539. Widget w;
  5540. XEvent *event;
  5541. String *prms;
  5542. Cardinal *nprms;
  5543. {
  5544. if (editUp) {
  5545. EditCommentPopDown();
  5546. } else {
  5547. EditCommentEvent();
  5548. }
  5549. }
  5550. void IcsInputBoxProc(w, event, prms, nprms)
  5551. Widget w;
  5552. XEvent *event;
  5553. String *prms;
  5554. Cardinal *nprms;
  5555. {
  5556. if (!PopDown(4)) ICSInputBoxPopUp();
  5557. }
  5558. void AcceptProc(w, event, prms, nprms)
  5559. Widget w;
  5560. XEvent *event;
  5561. String *prms;
  5562. Cardinal *nprms;
  5563. {
  5564. AcceptEvent();
  5565. }
  5566. void DeclineProc(w, event, prms, nprms)
  5567. Widget w;
  5568. XEvent *event;
  5569. String *prms;
  5570. Cardinal *nprms;
  5571. {
  5572. DeclineEvent();
  5573. }
  5574. void RematchProc(w, event, prms, nprms)
  5575. Widget w;
  5576. XEvent *event;
  5577. String *prms;
  5578. Cardinal *nprms;
  5579. {
  5580. RematchEvent();
  5581. }
  5582. void CallFlagProc(w, event, prms, nprms)
  5583. Widget w;
  5584. XEvent *event;
  5585. String *prms;
  5586. Cardinal *nprms;
  5587. {
  5588. CallFlagEvent();
  5589. }
  5590. void DrawProc(w, event, prms, nprms)
  5591. Widget w;
  5592. XEvent *event;
  5593. String *prms;
  5594. Cardinal *nprms;
  5595. {
  5596. DrawEvent();
  5597. }
  5598. void AbortProc(w, event, prms, nprms)
  5599. Widget w;
  5600. XEvent *event;
  5601. String *prms;
  5602. Cardinal *nprms;
  5603. {
  5604. AbortEvent();
  5605. }
  5606. void AdjournProc(w, event, prms, nprms)
  5607. Widget w;
  5608. XEvent *event;
  5609. String *prms;
  5610. Cardinal *nprms;
  5611. {
  5612. AdjournEvent();
  5613. }
  5614. void ResignProc(w, event, prms, nprms)
  5615. Widget w;
  5616. XEvent *event;
  5617. String *prms;
  5618. Cardinal *nprms;
  5619. {
  5620. ResignEvent();
  5621. }
  5622. void AdjuWhiteProc(w, event, prms, nprms)
  5623. Widget w;
  5624. XEvent *event;
  5625. String *prms;
  5626. Cardinal *nprms;
  5627. {
  5628. UserAdjudicationEvent(+1);
  5629. }
  5630. void AdjuBlackProc(w, event, prms, nprms)
  5631. Widget w;
  5632. XEvent *event;
  5633. String *prms;
  5634. Cardinal *nprms;
  5635. {
  5636. UserAdjudicationEvent(-1);
  5637. }
  5638. void AdjuDrawProc(w, event, prms, nprms)
  5639. Widget w;
  5640. XEvent *event;
  5641. String *prms;
  5642. Cardinal *nprms;
  5643. {
  5644. UserAdjudicationEvent(0);
  5645. }
  5646. void EnterKeyProc(w, event, prms, nprms)
  5647. Widget w;
  5648. XEvent *event;
  5649. String *prms;
  5650. Cardinal *nprms;
  5651. {
  5652. if (shellUp[4] == True)
  5653. ICSInputSendText();
  5654. }
  5655. void UpKeyProc(w, event, prms, nprms)
  5656. Widget w;
  5657. XEvent *event;
  5658. String *prms;
  5659. Cardinal *nprms;
  5660. { // [HGM] input: let up-arrow recall previous line from history
  5661. Widget edit;
  5662. int j;
  5663. Arg args[16];
  5664. String val;
  5665. XawTextBlock t;
  5666. if (!shellUp[4]) return;
  5667. edit = boxOptions[0].handle;
  5668. j = 0;
  5669. XtSetArg(args[j], XtNstring, &val); j++;
  5670. XtGetValues(edit, args, j);
  5671. val = PrevInHistory(val);
  5672. XtCallActionProc(edit, "select-all", NULL, NULL, 0);
  5673. XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
  5674. if(val) {
  5675. t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
  5676. XawTextReplace(edit, 0, 0, &t);
  5677. XawTextSetInsertionPoint(edit, 9999);
  5678. }
  5679. }
  5680. void DownKeyProc(w, event, prms, nprms)
  5681. Widget w;
  5682. XEvent *event;
  5683. String *prms;
  5684. Cardinal *nprms;
  5685. { // [HGM] input: let down-arrow recall next line from history
  5686. Widget edit;
  5687. String val;
  5688. XawTextBlock t;
  5689. if (!shellUp[4]) return;
  5690. edit = boxOptions[0].handle;
  5691. val = NextInHistory();
  5692. XtCallActionProc(edit, "select-all", NULL, NULL, 0);
  5693. XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
  5694. if(val) {
  5695. t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
  5696. XawTextReplace(edit, 0, 0, &t);
  5697. XawTextSetInsertionPoint(edit, 9999);
  5698. }
  5699. }
  5700. void StopObservingProc(w, event, prms, nprms)
  5701. Widget w;
  5702. XEvent *event;
  5703. String *prms;
  5704. Cardinal *nprms;
  5705. {
  5706. StopObservingEvent();
  5707. }
  5708. void StopExaminingProc(w, event, prms, nprms)
  5709. Widget w;
  5710. XEvent *event;
  5711. String *prms;
  5712. Cardinal *nprms;
  5713. {
  5714. StopExaminingEvent();
  5715. }
  5716. void UploadProc(w, event, prms, nprms)
  5717. Widget w;
  5718. XEvent *event;
  5719. String *prms;
  5720. Cardinal *nprms;
  5721. {
  5722. UploadGameEvent();
  5723. }
  5724. void ForwardProc(w, event, prms, nprms)
  5725. Widget w;
  5726. XEvent *event;
  5727. String *prms;
  5728. Cardinal *nprms;
  5729. {
  5730. ForwardEvent();
  5731. }
  5732. void BackwardProc(w, event, prms, nprms)
  5733. Widget w;
  5734. XEvent *event;
  5735. String *prms;
  5736. Cardinal *nprms;
  5737. {
  5738. BackwardEvent();
  5739. }
  5740. void ToStartProc(w, event, prms, nprms)
  5741. Widget w;
  5742. XEvent *event;
  5743. String *prms;
  5744. Cardinal *nprms;
  5745. {
  5746. ToStartEvent();
  5747. }
  5748. void ToEndProc(w, event, prms, nprms)
  5749. Widget w;
  5750. XEvent *event;
  5751. String *prms;
  5752. Cardinal *nprms;
  5753. {
  5754. ToEndEvent();
  5755. }
  5756. void RevertProc(w, event, prms, nprms)
  5757. Widget w;
  5758. XEvent *event;
  5759. String *prms;
  5760. Cardinal *nprms;
  5761. {
  5762. RevertEvent(False);
  5763. }
  5764. void AnnotateProc(w, event, prms, nprms)
  5765. Widget w;
  5766. XEvent *event;
  5767. String *prms;
  5768. Cardinal *nprms;
  5769. {
  5770. RevertEvent(True);
  5771. }
  5772. void TruncateGameProc(w, event, prms, nprms)
  5773. Widget w;
  5774. XEvent *event;
  5775. String *prms;
  5776. Cardinal *nprms;
  5777. {
  5778. TruncateGameEvent();
  5779. }
  5780. void RetractMoveProc(w, event, prms, nprms)
  5781. Widget w;
  5782. XEvent *event;
  5783. String *prms;
  5784. Cardinal *nprms;
  5785. {
  5786. RetractMoveEvent();
  5787. }
  5788. void MoveNowProc(w, event, prms, nprms)
  5789. Widget w;
  5790. XEvent *event;
  5791. String *prms;
  5792. Cardinal *nprms;
  5793. {
  5794. MoveNowEvent();
  5795. }
  5796. void FlipViewProc(w, event, prms, nprms)
  5797. Widget w;
  5798. XEvent *event;
  5799. String *prms;
  5800. Cardinal *nprms;
  5801. {
  5802. flipView = !flipView;
  5803. DrawPosition(True, NULL);
  5804. }
  5805. void PonderNextMoveProc(w, event, prms, nprms)
  5806. Widget w;
  5807. XEvent *event;
  5808. String *prms;
  5809. Cardinal *nprms;
  5810. {
  5811. Arg args[16];
  5812. PonderNextMoveEvent(!appData.ponderNextMove);
  5813. #ifndef OPTIONSDIALOG
  5814. if (appData.ponderNextMove) {
  5815. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  5816. } else {
  5817. XtSetArg(args[0], XtNleftBitmap, None);
  5818. }
  5819. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
  5820. args, 1);
  5821. #endif
  5822. }
  5823. #ifndef OPTIONSDIALOG
  5824. void AlwaysQueenProc(w, event, prms, nprms)
  5825. Widget w;
  5826. XEvent *event;
  5827. String *prms;
  5828. Cardinal *nprms;
  5829. {
  5830. Arg args[16];
  5831. appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
  5832. if (appData.alwaysPromoteToQueen) {
  5833. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  5834. } else {
  5835. XtSetArg(args[0], XtNleftBitmap, None);
  5836. }
  5837. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
  5838. args, 1);
  5839. }
  5840. void AnimateDraggingProc(w, event, prms, nprms)
  5841. Widget w;
  5842. XEvent *event;
  5843. String *prms;
  5844. Cardinal *nprms;
  5845. {
  5846. Arg args[16];
  5847. appData.animateDragging = !appData.animateDragging;
  5848. if (appData.animateDragging) {
  5849. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  5850. CreateAnimVars();
  5851. } else {
  5852. XtSetArg(args[0], XtNleftBitmap, None);
  5853. }
  5854. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
  5855. args, 1);
  5856. }
  5857. void AnimateMovingProc(w, event, prms, nprms)
  5858. Widget w;
  5859. XEvent *event;
  5860. String *prms;
  5861. Cardinal *nprms;
  5862. {
  5863. Arg args[16];
  5864. appData.animate = !appData.animate;
  5865. if (appData.animate) {
  5866. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  5867. CreateAnimVars();
  5868. } else {
  5869. XtSetArg(args[0], XtNleftBitmap, None);
  5870. }
  5871. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
  5872. args, 1);
  5873. }
  5874. void AutoflagProc(w, event, prms, nprms)
  5875. Widget w;
  5876. XEvent *event;
  5877. String *prms;
  5878. Cardinal *nprms;
  5879. {
  5880. Arg args[16];
  5881. appData.autoCallFlag = !appData.autoCallFlag;
  5882. if (appData.autoCallFlag) {
  5883. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  5884. } else {
  5885. XtSetArg(args[0], XtNleftBitmap, None);
  5886. }
  5887. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
  5888. args, 1);
  5889. }
  5890. void AutoflipProc(w, event, prms, nprms)
  5891. Widget w;
  5892. XEvent *event;
  5893. String *prms;
  5894. Cardinal *nprms;
  5895. {
  5896. Arg args[16];
  5897. appData.autoFlipView = !appData.autoFlipView;
  5898. if (appData.autoFlipView) {
  5899. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  5900. } else {
  5901. XtSetArg(args[0], XtNleftBitmap, None);
  5902. }
  5903. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
  5904. args, 1);
  5905. }
  5906. void BlindfoldProc(w, event, prms, nprms)
  5907. Widget w;
  5908. XEvent *event;
  5909. String *prms;
  5910. Cardinal *nprms;
  5911. {
  5912. Arg args[16];
  5913. appData.blindfold = !appData.blindfold;
  5914. if (appData.blindfold) {
  5915. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  5916. } else {
  5917. XtSetArg(args[0], XtNleftBitmap, None);
  5918. }
  5919. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
  5920. args, 1);
  5921. DrawPosition(True, NULL);
  5922. }
  5923. void TestLegalityProc(w, event, prms, nprms)
  5924. Widget w;
  5925. XEvent *event;
  5926. String *prms;
  5927. Cardinal *nprms;
  5928. {
  5929. Arg args[16];
  5930. appData.testLegality = !appData.testLegality;
  5931. if (appData.testLegality) {
  5932. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  5933. } else {
  5934. XtSetArg(args[0], XtNleftBitmap, None);
  5935. }
  5936. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
  5937. args, 1);
  5938. }
  5939. void FlashMovesProc(w, event, prms, nprms)
  5940. Widget w;
  5941. XEvent *event;
  5942. String *prms;
  5943. Cardinal *nprms;
  5944. {
  5945. Arg args[16];
  5946. if (appData.flashCount == 0) {
  5947. appData.flashCount = 3;
  5948. } else {
  5949. appData.flashCount = -appData.flashCount;
  5950. }
  5951. if (appData.flashCount > 0) {
  5952. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  5953. } else {
  5954. XtSetArg(args[0], XtNleftBitmap, None);
  5955. }
  5956. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
  5957. args, 1);
  5958. }
  5959. #if HIGHDRAG
  5960. void HighlightDraggingProc(w, event, prms, nprms)
  5961. Widget w;
  5962. XEvent *event;
  5963. String *prms;
  5964. Cardinal *nprms;
  5965. {
  5966. Arg args[16];
  5967. appData.highlightDragging = !appData.highlightDragging;
  5968. if (appData.highlightDragging) {
  5969. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  5970. } else {
  5971. XtSetArg(args[0], XtNleftBitmap, None);
  5972. }
  5973. XtSetValues(XtNameToWidget(menuBarWidget,
  5974. "menuOptions.Highlight Dragging"), args, 1);
  5975. }
  5976. #endif
  5977. void HighlightLastMoveProc(w, event, prms, nprms)
  5978. Widget w;
  5979. XEvent *event;
  5980. String *prms;
  5981. Cardinal *nprms;
  5982. {
  5983. Arg args[16];
  5984. appData.highlightLastMove = !appData.highlightLastMove;
  5985. if (appData.highlightLastMove) {
  5986. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  5987. } else {
  5988. XtSetArg(args[0], XtNleftBitmap, None);
  5989. }
  5990. XtSetValues(XtNameToWidget(menuBarWidget,
  5991. "menuOptions.Highlight Last Move"), args, 1);
  5992. }
  5993. void HighlightArrowProc(w, event, prms, nprms)
  5994. Widget w;
  5995. XEvent *event;
  5996. String *prms;
  5997. Cardinal *nprms;
  5998. {
  5999. Arg args[16];
  6000. appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
  6001. if (appData.highlightMoveWithArrow) {
  6002. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  6003. } else {
  6004. XtSetArg(args[0], XtNleftBitmap, None);
  6005. }
  6006. XtSetValues(XtNameToWidget(menuBarWidget,
  6007. "menuOptions.Arrow"), args, 1);
  6008. }
  6009. #if 0
  6010. void IcsAlarmProc(w, event, prms, nprms)
  6011. Widget w;
  6012. XEvent *event;
  6013. String *prms;
  6014. Cardinal *nprms;
  6015. {
  6016. Arg args[16];
  6017. appData.icsAlarm = !appData.icsAlarm;
  6018. if (appData.icsAlarm) {
  6019. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  6020. } else {
  6021. XtSetArg(args[0], XtNleftBitmap, None);
  6022. }
  6023. XtSetValues(XtNameToWidget(menuBarWidget,
  6024. "menuOptions.ICS Alarm"), args, 1);
  6025. }
  6026. #endif
  6027. void MoveSoundProc(w, event, prms, nprms)
  6028. Widget w;
  6029. XEvent *event;
  6030. String *prms;
  6031. Cardinal *nprms;
  6032. {
  6033. Arg args[16];
  6034. appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
  6035. if (appData.ringBellAfterMoves) {
  6036. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  6037. } else {
  6038. XtSetArg(args[0], XtNleftBitmap, None);
  6039. }
  6040. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
  6041. args, 1);
  6042. }
  6043. void OneClickProc(w, event, prms, nprms)
  6044. Widget w;
  6045. XEvent *event;
  6046. String *prms;
  6047. Cardinal *nprms;
  6048. {
  6049. Arg args[16];
  6050. appData.oneClick = !appData.oneClick;
  6051. if (appData.oneClick) {
  6052. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  6053. } else {
  6054. XtSetArg(args[0], XtNleftBitmap, None);
  6055. }
  6056. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
  6057. args, 1);
  6058. }
  6059. void PeriodicUpdatesProc(w, event, prms, nprms)
  6060. Widget w;
  6061. XEvent *event;
  6062. String *prms;
  6063. Cardinal *nprms;
  6064. {
  6065. Arg args[16];
  6066. PeriodicUpdatesEvent(!appData.periodicUpdates);
  6067. if (appData.periodicUpdates) {
  6068. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  6069. } else {
  6070. XtSetArg(args[0], XtNleftBitmap, None);
  6071. }
  6072. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
  6073. args, 1);
  6074. }
  6075. void PopupExitMessageProc(w, event, prms, nprms)
  6076. Widget w;
  6077. XEvent *event;
  6078. String *prms;
  6079. Cardinal *nprms;
  6080. {
  6081. Arg args[16];
  6082. appData.popupExitMessage = !appData.popupExitMessage;
  6083. if (appData.popupExitMessage) {
  6084. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  6085. } else {
  6086. XtSetArg(args[0], XtNleftBitmap, None);
  6087. }
  6088. XtSetValues(XtNameToWidget(menuBarWidget,
  6089. "menuOptions.Popup Exit Message"), args, 1);
  6090. }
  6091. void PopupMoveErrorsProc(w, event, prms, nprms)
  6092. Widget w;
  6093. XEvent *event;
  6094. String *prms;
  6095. Cardinal *nprms;
  6096. {
  6097. Arg args[16];
  6098. appData.popupMoveErrors = !appData.popupMoveErrors;
  6099. if (appData.popupMoveErrors) {
  6100. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  6101. } else {
  6102. XtSetArg(args[0], XtNleftBitmap, None);
  6103. }
  6104. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
  6105. args, 1);
  6106. }
  6107. #if 0
  6108. void PremoveProc(w, event, prms, nprms)
  6109. Widget w;
  6110. XEvent *event;
  6111. String *prms;
  6112. Cardinal *nprms;
  6113. {
  6114. Arg args[16];
  6115. appData.premove = !appData.premove;
  6116. if (appData.premove) {
  6117. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  6118. } else {
  6119. XtSetArg(args[0], XtNleftBitmap, None);
  6120. }
  6121. XtSetValues(XtNameToWidget(menuBarWidget,
  6122. "menuOptions.Premove"), args, 1);
  6123. }
  6124. #endif
  6125. void ShowCoordsProc(w, event, prms, nprms)
  6126. Widget w;
  6127. XEvent *event;
  6128. String *prms;
  6129. Cardinal *nprms;
  6130. {
  6131. Arg args[16];
  6132. appData.showCoords = !appData.showCoords;
  6133. if (appData.showCoords) {
  6134. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  6135. } else {
  6136. XtSetArg(args[0], XtNleftBitmap, None);
  6137. }
  6138. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
  6139. args, 1);
  6140. DrawPosition(True, NULL);
  6141. }
  6142. void ShowThinkingProc(w, event, prms, nprms)
  6143. Widget w;
  6144. XEvent *event;
  6145. String *prms;
  6146. Cardinal *nprms;
  6147. {
  6148. appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
  6149. ShowThinkingEvent();
  6150. }
  6151. void HideThinkingProc(w, event, prms, nprms)
  6152. Widget w;
  6153. XEvent *event;
  6154. String *prms;
  6155. Cardinal *nprms;
  6156. {
  6157. Arg args[16];
  6158. appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
  6159. ShowThinkingEvent();
  6160. if (appData.hideThinkingFromHuman) {
  6161. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  6162. } else {
  6163. XtSetArg(args[0], XtNleftBitmap, None);
  6164. }
  6165. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
  6166. args, 1);
  6167. }
  6168. #endif
  6169. void SaveOnExitProc(w, event, prms, nprms)
  6170. Widget w;
  6171. XEvent *event;
  6172. String *prms;
  6173. Cardinal *nprms;
  6174. {
  6175. Arg args[16];
  6176. saveSettingsOnExit = !saveSettingsOnExit;
  6177. if (saveSettingsOnExit) {
  6178. XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
  6179. } else {
  6180. XtSetArg(args[0], XtNleftBitmap, None);
  6181. }
  6182. XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
  6183. args, 1);
  6184. }
  6185. void SaveSettingsProc(w, event, prms, nprms)
  6186. Widget w;
  6187. XEvent *event;
  6188. String *prms;
  6189. Cardinal *nprms;
  6190. {
  6191. SaveSettings(settingsFileName);
  6192. }
  6193. void InfoProc(w, event, prms, nprms)
  6194. Widget w;
  6195. XEvent *event;
  6196. String *prms;
  6197. Cardinal *nprms;
  6198. {
  6199. char buf[MSG_SIZ];
  6200. snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
  6201. INFODIR, INFOFILE);
  6202. system(buf);
  6203. }
  6204. void ManProc(w, event, prms, nprms)
  6205. Widget w;
  6206. XEvent *event;
  6207. String *prms;
  6208. Cardinal *nprms;
  6209. {
  6210. char buf[MSG_SIZ];
  6211. String name;
  6212. if (nprms && *nprms > 0)
  6213. name = prms[0];
  6214. else
  6215. name = "xboard";
  6216. snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
  6217. system(buf);
  6218. }
  6219. void HintProc(w, event, prms, nprms)
  6220. Widget w;
  6221. XEvent *event;
  6222. String *prms;
  6223. Cardinal *nprms;
  6224. {
  6225. HintEvent();
  6226. }
  6227. void BookProc(w, event, prms, nprms)
  6228. Widget w;
  6229. XEvent *event;
  6230. String *prms;
  6231. Cardinal *nprms;
  6232. {
  6233. BookEvent();
  6234. }
  6235. void AboutProc(w, event, prms, nprms)
  6236. Widget w;
  6237. XEvent *event;
  6238. String *prms;
  6239. Cardinal *nprms;
  6240. {
  6241. char buf[MSG_SIZ];
  6242. #if ZIPPY
  6243. char *zippy = " (with Zippy code)";
  6244. #else
  6245. char *zippy = "";
  6246. #endif
  6247. snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
  6248. programVersion, zippy,
  6249. "Copyright 1991 Digital Equipment Corporation",
  6250. "Enhancements Copyright 1992-2009 Free Software Foundation",
  6251. "Enhancements Copyright 2005 Alessandro Scotti",
  6252. PACKAGE, " is free software and carries NO WARRANTY;",
  6253. "see the file COPYING for more information.");
  6254. ErrorPopUp(_("About XBoard"), buf, FALSE);
  6255. }
  6256. void DebugProc(w, event, prms, nprms)
  6257. Widget w;
  6258. XEvent *event;
  6259. String *prms;
  6260. Cardinal *nprms;
  6261. {
  6262. appData.debugMode = !appData.debugMode;
  6263. }
  6264. void AboutGameProc(w, event, prms, nprms)
  6265. Widget w;
  6266. XEvent *event;
  6267. String *prms;
  6268. Cardinal *nprms;
  6269. {
  6270. AboutGameEvent();
  6271. }
  6272. void NothingProc(w, event, prms, nprms)
  6273. Widget w;
  6274. XEvent *event;
  6275. String *prms;
  6276. Cardinal *nprms;
  6277. {
  6278. return;
  6279. }
  6280. void Iconify(w, event, prms, nprms)
  6281. Widget w;
  6282. XEvent *event;
  6283. String *prms;
  6284. Cardinal *nprms;
  6285. {
  6286. Arg args[16];
  6287. fromX = fromY = -1;
  6288. XtSetArg(args[0], XtNiconic, True);
  6289. XtSetValues(shellWidget, args, 1);
  6290. }
  6291. void DisplayMessage(message, extMessage)
  6292. char *message, *extMessage;
  6293. {
  6294. /* display a message in the message widget */
  6295. char buf[MSG_SIZ];
  6296. Arg arg;
  6297. if (extMessage)
  6298. {
  6299. if (*message)
  6300. {
  6301. snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
  6302. message = buf;
  6303. }
  6304. else
  6305. {
  6306. message = extMessage;
  6307. };
  6308. };
  6309. /* need to test if messageWidget already exists, since this function
  6310. can also be called during the startup, if for example a Xresource
  6311. is not set up correctly */
  6312. if(messageWidget)
  6313. {
  6314. XtSetArg(arg, XtNlabel, message);
  6315. XtSetValues(messageWidget, &arg, 1);
  6316. };
  6317. return;
  6318. }
  6319. void DisplayTitle(text)
  6320. char *text;
  6321. {
  6322. Arg args[16];
  6323. int i;
  6324. char title[MSG_SIZ];
  6325. char icon[MSG_SIZ];
  6326. if (text == NULL) text = "";
  6327. if (appData.titleInWindow) {
  6328. i = 0;
  6329. XtSetArg(args[i], XtNlabel, text); i++;
  6330. XtSetValues(titleWidget, args, i);
  6331. }
  6332. if (*text != NULLCHAR) {
  6333. safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
  6334. safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
  6335. } else if (appData.icsActive) {
  6336. snprintf(icon, sizeof(icon), "%s", appData.icsHost);
  6337. snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
  6338. } else if (appData.cmailGameName[0] != NULLCHAR) {
  6339. snprintf(icon, sizeof(icon), "%s", "CMail");
  6340. snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
  6341. #ifdef GOTHIC
  6342. // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
  6343. } else if (gameInfo.variant == VariantGothic) {
  6344. safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
  6345. safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
  6346. #endif
  6347. #ifdef FALCON
  6348. } else if (gameInfo.variant == VariantFalcon) {
  6349. safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
  6350. safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
  6351. #endif
  6352. } else if (appData.noChessProgram) {
  6353. safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
  6354. safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
  6355. } else {
  6356. safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
  6357. snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
  6358. }
  6359. i = 0;
  6360. XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
  6361. XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
  6362. XtSetValues(shellWidget, args, i);
  6363. }
  6364. void
  6365. DisplayError(message, error)
  6366. String message;
  6367. int error;
  6368. {
  6369. char buf[MSG_SIZ];
  6370. if (error == 0) {
  6371. if (appData.debugMode || appData.matchMode) {
  6372. fprintf(stderr, "%s: %s\n", programName, message);
  6373. }
  6374. } else {
  6375. if (appData.debugMode || appData.matchMode) {
  6376. fprintf(stderr, "%s: %s: %s\n",
  6377. programName, message, strerror(error));
  6378. }
  6379. snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
  6380. message = buf;
  6381. }
  6382. ErrorPopUp(_("Error"), message, FALSE);
  6383. }
  6384. void DisplayMoveError(message)
  6385. String message;
  6386. {
  6387. fromX = fromY = -1;
  6388. ClearHighlights();
  6389. DrawPosition(FALSE, NULL);
  6390. if (appData.debugMode || appData.matchMode) {
  6391. fprintf(stderr, "%s: %s\n", programName, message);
  6392. }
  6393. if (appData.popupMoveErrors) {
  6394. ErrorPopUp(_("Error"), message, FALSE);
  6395. } else {
  6396. DisplayMessage(message, "");
  6397. }
  6398. }
  6399. void DisplayFatalError(message, error, status)
  6400. String message;
  6401. int error, status;
  6402. {
  6403. char buf[MSG_SIZ];
  6404. errorExitStatus = status;
  6405. if (error == 0) {
  6406. fprintf(stderr, "%s: %s\n", programName, message);
  6407. } else {
  6408. fprintf(stderr, "%s: %s: %s\n",
  6409. programName, message, strerror(error));
  6410. snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
  6411. message = buf;
  6412. }
  6413. if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
  6414. ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
  6415. } else {
  6416. ExitEvent(status);
  6417. }
  6418. }
  6419. void DisplayInformation(message)
  6420. String message;
  6421. {
  6422. ErrorPopDown();
  6423. ErrorPopUp(_("Information"), message, TRUE);
  6424. }
  6425. void DisplayNote(message)
  6426. String message;
  6427. {
  6428. ErrorPopDown();
  6429. ErrorPopUp(_("Note"), message, FALSE);
  6430. }
  6431. static int
  6432. NullXErrorCheck(dpy, error_event)
  6433. Display *dpy;
  6434. XErrorEvent *error_event;
  6435. {
  6436. return 0;
  6437. }
  6438. void DisplayIcsInteractionTitle(message)
  6439. String message;
  6440. {
  6441. if (oldICSInteractionTitle == NULL) {
  6442. /* Magic to find the old window title, adapted from vim */
  6443. char *wina = getenv("WINDOWID");
  6444. if (wina != NULL) {
  6445. Window win = (Window) atoi(wina);
  6446. Window root, parent, *children;
  6447. unsigned int nchildren;
  6448. int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
  6449. for (;;) {
  6450. if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
  6451. if (!XQueryTree(xDisplay, win, &root, &parent,
  6452. &children, &nchildren)) break;
  6453. if (children) XFree((void *)children);
  6454. if (parent == root || parent == 0) break;
  6455. win = parent;
  6456. }
  6457. XSetErrorHandler(oldHandler);
  6458. }
  6459. if (oldICSInteractionTitle == NULL) {
  6460. oldICSInteractionTitle = "xterm";
  6461. }
  6462. }
  6463. printf("\033]0;%s\007", message);
  6464. fflush(stdout);
  6465. }
  6466. char pendingReplyPrefix[MSG_SIZ];
  6467. ProcRef pendingReplyPR;
  6468. void AskQuestionProc(w, event, prms, nprms)
  6469. Widget w;
  6470. XEvent *event;
  6471. String *prms;
  6472. Cardinal *nprms;
  6473. {
  6474. if (*nprms != 4) {
  6475. fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
  6476. *nprms);
  6477. return;
  6478. }
  6479. AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
  6480. }
  6481. void AskQuestionPopDown()
  6482. {
  6483. if (!askQuestionUp) return;
  6484. XtPopdown(askQuestionShell);
  6485. XtDestroyWidget(askQuestionShell);
  6486. askQuestionUp = False;
  6487. }
  6488. void AskQuestionReplyAction(w, event, prms, nprms)
  6489. Widget w;
  6490. XEvent *event;
  6491. String *prms;
  6492. Cardinal *nprms;
  6493. {
  6494. char buf[MSG_SIZ];
  6495. int err;
  6496. String reply;
  6497. reply = XawDialogGetValueString(w = XtParent(w));
  6498. safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
  6499. if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
  6500. strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
  6501. strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
  6502. OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
  6503. AskQuestionPopDown();
  6504. if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
  6505. }
  6506. void AskQuestionCallback(w, client_data, call_data)
  6507. Widget w;
  6508. XtPointer client_data, call_data;
  6509. {
  6510. String name;
  6511. Arg args[16];
  6512. XtSetArg(args[0], XtNlabel, &name);
  6513. XtGetValues(w, args, 1);
  6514. if (strcmp(name, _("cancel")) == 0) {
  6515. AskQuestionPopDown();
  6516. } else {
  6517. AskQuestionReplyAction(w, NULL, NULL, NULL);
  6518. }
  6519. }
  6520. void AskQuestion(title, question, replyPrefix, pr)
  6521. char *title, *question, *replyPrefix;
  6522. ProcRef pr;
  6523. {
  6524. Arg args[16];
  6525. Widget popup, layout, dialog, edit;
  6526. Window root, child;
  6527. int x, y, i;
  6528. int win_x, win_y;
  6529. unsigned int mask;
  6530. safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
  6531. pendingReplyPR = pr;
  6532. i = 0;
  6533. XtSetArg(args[i], XtNresizable, True); i++;
  6534. XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
  6535. askQuestionShell = popup =
  6536. XtCreatePopupShell(title, transientShellWidgetClass,
  6537. shellWidget, args, i);
  6538. layout =
  6539. XtCreateManagedWidget(layoutName, formWidgetClass, popup,
  6540. layoutArgs, XtNumber(layoutArgs));
  6541. i = 0;
  6542. XtSetArg(args[i], XtNlabel, question); i++;
  6543. XtSetArg(args[i], XtNvalue, ""); i++;
  6544. XtSetArg(args[i], XtNborderWidth, 0); i++;
  6545. dialog = XtCreateManagedWidget("question", dialogWidgetClass,
  6546. layout, args, i);
  6547. XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
  6548. (XtPointer) dialog);
  6549. XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
  6550. (XtPointer) dialog);
  6551. XtRealizeWidget(popup);
  6552. CatchDeleteWindow(popup, "AskQuestionPopDown");
  6553. XQueryPointer(xDisplay, xBoardWindow, &root, &child,
  6554. &x, &y, &win_x, &win_y, &mask);
  6555. XtSetArg(args[0], XtNx, x - 10);
  6556. XtSetArg(args[1], XtNy, y - 30);
  6557. XtSetValues(popup, args, 2);
  6558. XtPopup(popup, XtGrabExclusive);
  6559. askQuestionUp = True;
  6560. edit = XtNameToWidget(dialog, "*value");
  6561. XtSetKeyboardFocus(popup, edit);
  6562. }
  6563. void
  6564. PlaySound(name)
  6565. char *name;
  6566. {
  6567. if (*name == NULLCHAR) {
  6568. return;
  6569. } else if (strcmp(name, "$") == 0) {
  6570. putc(BELLCHAR, stderr);
  6571. } else {
  6572. char buf[2048];
  6573. char *prefix = "", *sep = "";
  6574. if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
  6575. snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
  6576. system(buf);
  6577. }
  6578. }
  6579. void
  6580. RingBell()
  6581. {
  6582. PlaySound(appData.soundMove);
  6583. }
  6584. void
  6585. PlayIcsWinSound()
  6586. {
  6587. PlaySound(appData.soundIcsWin);
  6588. }
  6589. void
  6590. PlayIcsLossSound()
  6591. {
  6592. PlaySound(appData.soundIcsLoss);
  6593. }
  6594. void
  6595. PlayIcsDrawSound()
  6596. {
  6597. PlaySound(appData.soundIcsDraw);
  6598. }
  6599. void
  6600. PlayIcsUnfinishedSound()
  6601. {
  6602. PlaySound(appData.soundIcsUnfinished);
  6603. }
  6604. void
  6605. PlayAlarmSound()
  6606. {
  6607. PlaySound(appData.soundIcsAlarm);
  6608. }
  6609. void
  6610. EchoOn()
  6611. {
  6612. system("stty echo");
  6613. }
  6614. void
  6615. EchoOff()
  6616. {
  6617. system("stty -echo");
  6618. }
  6619. void
  6620. Colorize(cc, continuation)
  6621. ColorClass cc;
  6622. int continuation;
  6623. {
  6624. char buf[MSG_SIZ];
  6625. int count, outCount, error;
  6626. if (textColors[(int)cc].bg > 0) {
  6627. if (textColors[(int)cc].fg > 0) {
  6628. snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
  6629. textColors[(int)cc].fg, textColors[(int)cc].bg);
  6630. } else {
  6631. snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
  6632. textColors[(int)cc].bg);
  6633. }
  6634. } else {
  6635. if (textColors[(int)cc].fg > 0) {
  6636. snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
  6637. textColors[(int)cc].fg);
  6638. } else {
  6639. snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
  6640. }
  6641. }
  6642. count = strlen(buf);
  6643. outCount = OutputToProcess(NoProc, buf, count, &error);
  6644. if (outCount < count) {
  6645. DisplayFatalError(_("Error writing to display"), error, 1);
  6646. }
  6647. if (continuation) return;
  6648. switch (cc) {
  6649. case ColorShout:
  6650. PlaySound(appData.soundShout);
  6651. break;
  6652. case ColorSShout:
  6653. PlaySound(appData.soundSShout);
  6654. break;
  6655. case ColorChannel1:
  6656. PlaySound(appData.soundChannel1);
  6657. break;
  6658. case ColorChannel:
  6659. PlaySound(appData.soundChannel);
  6660. break;
  6661. case ColorKibitz:
  6662. PlaySound(appData.soundKibitz);
  6663. break;
  6664. case ColorTell:
  6665. PlaySound(appData.soundTell);
  6666. break;
  6667. case ColorChallenge:
  6668. PlaySound(appData.soundChallenge);
  6669. break;
  6670. case ColorRequest:
  6671. PlaySound(appData.soundRequest);
  6672. break;
  6673. case ColorSeek:
  6674. PlaySound(appData.soundSeek);
  6675. break;
  6676. case ColorNormal:
  6677. case ColorNone:
  6678. default:
  6679. break;
  6680. }
  6681. }
  6682. char *UserName()
  6683. {
  6684. return getpwuid(getuid())->pw_name;
  6685. }
  6686. static char *
  6687. ExpandPathName(path)
  6688. char *path;
  6689. {
  6690. static char static_buf[4*MSG_SIZ];
  6691. char *d, *s, buf[4*MSG_SIZ];
  6692. struct passwd *pwd;
  6693. s = path;
  6694. d = static_buf;
  6695. while (*s && isspace(*s))
  6696. ++s;
  6697. if (!*s) {
  6698. *d = 0;
  6699. return static_buf;
  6700. }
  6701. if (*s == '~') {
  6702. if (*(s+1) == '/') {
  6703. safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
  6704. strcat(d, s+1);
  6705. }
  6706. else {
  6707. safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
  6708. { char *p; if(p = strchr(buf, '/')) *p = 0; }
  6709. pwd = getpwnam(buf);
  6710. if (!pwd)
  6711. {
  6712. fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
  6713. buf, path);
  6714. return NULL;
  6715. }
  6716. safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
  6717. strcat(d, strchr(s+1, '/'));
  6718. }
  6719. }
  6720. else
  6721. safeStrCpy(d, s, 4*MSG_SIZ );
  6722. return static_buf;
  6723. }
  6724. char *HostName()
  6725. {
  6726. static char host_name[MSG_SIZ];
  6727. #if HAVE_GETHOSTNAME
  6728. gethostname(host_name, MSG_SIZ);
  6729. return host_name;
  6730. #else /* not HAVE_GETHOSTNAME */
  6731. # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
  6732. sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
  6733. return host_name;
  6734. # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
  6735. return "localhost";
  6736. # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
  6737. #endif /* not HAVE_GETHOSTNAME */
  6738. }
  6739. XtIntervalId delayedEventTimerXID = 0;
  6740. DelayedEventCallback delayedEventCallback = 0;
  6741. void
  6742. FireDelayedEvent()
  6743. {
  6744. delayedEventTimerXID = 0;
  6745. delayedEventCallback();
  6746. }
  6747. void
  6748. ScheduleDelayedEvent(cb, millisec)
  6749. DelayedEventCallback cb; long millisec;
  6750. {
  6751. if(delayedEventTimerXID && delayedEventCallback == cb)
  6752. // [HGM] alive: replace, rather than add or flush identical event
  6753. XtRemoveTimeOut(delayedEventTimerXID);
  6754. delayedEventCallback = cb;
  6755. delayedEventTimerXID =
  6756. XtAppAddTimeOut(appContext, millisec,
  6757. (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
  6758. }
  6759. DelayedEventCallback
  6760. GetDelayedEvent()
  6761. {
  6762. if (delayedEventTimerXID) {
  6763. return delayedEventCallback;
  6764. } else {
  6765. return NULL;
  6766. }
  6767. }
  6768. void
  6769. CancelDelayedEvent()
  6770. {
  6771. if (delayedEventTimerXID) {
  6772. XtRemoveTimeOut(delayedEventTimerXID);
  6773. delayedEventTimerXID = 0;
  6774. }
  6775. }
  6776. XtIntervalId loadGameTimerXID = 0;
  6777. int LoadGameTimerRunning()
  6778. {
  6779. return loadGameTimerXID != 0;
  6780. }
  6781. int StopLoadGameTimer()
  6782. {
  6783. if (loadGameTimerXID != 0) {
  6784. XtRemoveTimeOut(loadGameTimerXID);
  6785. loadGameTimerXID = 0;
  6786. return TRUE;
  6787. } else {
  6788. return FALSE;
  6789. }
  6790. }
  6791. void
  6792. LoadGameTimerCallback(arg, id)
  6793. XtPointer arg;
  6794. XtIntervalId *id;
  6795. {
  6796. loadGameTimerXID = 0;
  6797. AutoPlayGameLoop();
  6798. }
  6799. void
  6800. StartLoadGameTimer(millisec)
  6801. long millisec;
  6802. {
  6803. loadGameTimerXID =
  6804. XtAppAddTimeOut(appContext, millisec,
  6805. (XtTimerCallbackProc) LoadGameTimerCallback,
  6806. (XtPointer) 0);
  6807. }
  6808. XtIntervalId analysisClockXID = 0;
  6809. void
  6810. AnalysisClockCallback(arg, id)
  6811. XtPointer arg;
  6812. XtIntervalId *id;
  6813. {
  6814. if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
  6815. || appData.icsEngineAnalyze) { // [DM]
  6816. AnalysisPeriodicEvent(0);
  6817. StartAnalysisClock();
  6818. }
  6819. }
  6820. void
  6821. StartAnalysisClock()
  6822. {
  6823. analysisClockXID =
  6824. XtAppAddTimeOut(appContext, 2000,
  6825. (XtTimerCallbackProc) AnalysisClockCallback,
  6826. (XtPointer) 0);
  6827. }
  6828. XtIntervalId clockTimerXID = 0;
  6829. int ClockTimerRunning()
  6830. {
  6831. return clockTimerXID != 0;
  6832. }
  6833. int StopClockTimer()
  6834. {
  6835. if (clockTimerXID != 0) {
  6836. XtRemoveTimeOut(clockTimerXID);
  6837. clockTimerXID = 0;
  6838. return TRUE;
  6839. } else {
  6840. return FALSE;
  6841. }
  6842. }
  6843. void
  6844. ClockTimerCallback(arg, id)
  6845. XtPointer arg;
  6846. XtIntervalId *id;
  6847. {
  6848. clockTimerXID = 0;
  6849. DecrementClocks();
  6850. }
  6851. void
  6852. StartClockTimer(millisec)
  6853. long millisec;
  6854. {
  6855. clockTimerXID =
  6856. XtAppAddTimeOut(appContext, millisec,
  6857. (XtTimerCallbackProc) ClockTimerCallback,
  6858. (XtPointer) 0);
  6859. }
  6860. void
  6861. DisplayTimerLabel(w, color, timer, highlight)
  6862. Widget w;
  6863. char *color;
  6864. long timer;
  6865. int highlight;
  6866. {
  6867. char buf[MSG_SIZ];
  6868. Arg args[16];
  6869. /* check for low time warning */
  6870. Pixel foregroundOrWarningColor = timerForegroundPixel;
  6871. if (timer > 0 &&
  6872. appData.lowTimeWarning &&
  6873. (timer / 1000) < appData.icsAlarmTime)
  6874. foregroundOrWarningColor = lowTimeWarningColor;
  6875. if (appData.clockMode) {
  6876. snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
  6877. XtSetArg(args[0], XtNlabel, buf);
  6878. } else {
  6879. snprintf(buf, MSG_SIZ, "%s ", color);
  6880. XtSetArg(args[0], XtNlabel, buf);
  6881. }
  6882. if (highlight) {
  6883. XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
  6884. XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
  6885. } else {
  6886. XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
  6887. XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
  6888. }
  6889. XtSetValues(w, args, 3);
  6890. }
  6891. void
  6892. DisplayWhiteClock(timeRemaining, highlight)
  6893. long timeRemaining;
  6894. int highlight;
  6895. {
  6896. Arg args[16];
  6897. if(appData.noGUI) return;
  6898. DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
  6899. if (highlight && iconPixmap == bIconPixmap) {
  6900. iconPixmap = wIconPixmap;
  6901. XtSetArg(args[0], XtNiconPixmap, iconPixmap);
  6902. XtSetValues(shellWidget, args, 1);
  6903. }
  6904. }
  6905. void
  6906. DisplayBlackClock(timeRemaining, highlight)
  6907. long timeRemaining;
  6908. int highlight;
  6909. {
  6910. Arg args[16];
  6911. if(appData.noGUI) return;
  6912. DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
  6913. if (highlight && iconPixmap == wIconPixmap) {
  6914. iconPixmap = bIconPixmap;
  6915. XtSetArg(args[0], XtNiconPixmap, iconPixmap);
  6916. XtSetValues(shellWidget, args, 1);
  6917. }
  6918. }
  6919. #define CPNone 0
  6920. #define CPReal 1
  6921. #define CPComm 2
  6922. #define CPSock 3
  6923. #define CPLoop 4
  6924. typedef int CPKind;
  6925. typedef struct {
  6926. CPKind kind;
  6927. int pid;
  6928. int fdTo, fdFrom;
  6929. } ChildProc;
  6930. int StartChildProcess(cmdLine, dir, pr)
  6931. char *cmdLine;
  6932. char *dir;
  6933. ProcRef *pr;
  6934. {
  6935. char *argv[64], *p;
  6936. int i, pid;
  6937. int to_prog[2], from_prog[2];
  6938. ChildProc *cp;
  6939. char buf[MSG_SIZ];
  6940. if (appData.debugMode) {
  6941. fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
  6942. }
  6943. /* We do NOT feed the cmdLine to the shell; we just
  6944. parse it into blank-separated arguments in the
  6945. most simple-minded way possible.
  6946. */
  6947. i = 0;
  6948. safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
  6949. p = buf;
  6950. for (;;) {
  6951. while(*p == ' ') p++;
  6952. argv[i++] = p;
  6953. if(*p == '"' || *p == '\'')
  6954. p = strchr(++argv[i-1], *p);
  6955. else p = strchr(p, ' ');
  6956. if (p == NULL) break;
  6957. *p++ = NULLCHAR;
  6958. }
  6959. argv[i] = NULL;
  6960. SetUpChildIO(to_prog, from_prog);
  6961. if ((pid = fork()) == 0) {
  6962. /* Child process */
  6963. // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
  6964. close(to_prog[1]); // first close the unused pipe ends
  6965. close(from_prog[0]);
  6966. dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
  6967. dup2(from_prog[1], 1);
  6968. if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
  6969. close(from_prog[1]); // and closing again loses one of the pipes!
  6970. if(fileno(stderr) >= 2) // better safe than sorry...
  6971. dup2(1, fileno(stderr)); /* force stderr to the pipe */
  6972. if (dir[0] != NULLCHAR && chdir(dir) != 0) {
  6973. perror(dir);
  6974. exit(1);
  6975. }
  6976. nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
  6977. execvp(argv[0], argv);
  6978. /* If we get here, exec failed */
  6979. perror(argv[0]);
  6980. exit(1);
  6981. }
  6982. /* Parent process */
  6983. close(to_prog[0]);
  6984. close(from_prog[1]);
  6985. cp = (ChildProc *) calloc(1, sizeof(ChildProc));
  6986. cp->kind = CPReal;
  6987. cp->pid = pid;
  6988. cp->fdFrom = from_prog[0];
  6989. cp->fdTo = to_prog[1];
  6990. *pr = (ProcRef) cp;
  6991. return 0;
  6992. }
  6993. // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
  6994. static RETSIGTYPE AlarmCallBack(int n)
  6995. {
  6996. return;
  6997. }
  6998. void
  6999. DestroyChildProcess(pr, signalType)
  7000. ProcRef pr;
  7001. int signalType;
  7002. {
  7003. ChildProc *cp = (ChildProc *) pr;
  7004. if (cp->kind != CPReal) return;
  7005. cp->kind = CPNone;
  7006. if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
  7007. signal(SIGALRM, AlarmCallBack);
  7008. alarm(3);
  7009. if(wait((int *) 0) == -1) { // process does not terminate on its own accord
  7010. kill(cp->pid, SIGKILL); // kill it forcefully
  7011. wait((int *) 0); // and wait again
  7012. }
  7013. } else {
  7014. if (signalType) {
  7015. kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
  7016. }
  7017. /* Process is exiting either because of the kill or because of
  7018. a quit command sent by the backend; either way, wait for it to die.
  7019. */
  7020. wait((int *) 0);
  7021. }
  7022. close(cp->fdFrom);
  7023. close(cp->fdTo);
  7024. }
  7025. void
  7026. InterruptChildProcess(pr)
  7027. ProcRef pr;
  7028. {
  7029. ChildProc *cp = (ChildProc *) pr;
  7030. if (cp->kind != CPReal) return;
  7031. (void) kill(cp->pid, SIGINT); /* stop it thinking */
  7032. }
  7033. int OpenTelnet(host, port, pr)
  7034. char *host;
  7035. char *port;
  7036. ProcRef *pr;
  7037. {
  7038. char cmdLine[MSG_SIZ];
  7039. if (port[0] == NULLCHAR) {
  7040. snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
  7041. } else {
  7042. snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
  7043. }
  7044. return StartChildProcess(cmdLine, "", pr);
  7045. }
  7046. int OpenTCP(host, port, pr)
  7047. char *host;
  7048. char *port;
  7049. ProcRef *pr;
  7050. {
  7051. #if OMIT_SOCKETS
  7052. DisplayFatalError(_("Socket support is not configured in"), 0, 2);
  7053. #else /* !OMIT_SOCKETS */
  7054. int s;
  7055. struct sockaddr_in sa;
  7056. struct hostent *hp;
  7057. unsigned short uport;
  7058. ChildProc *cp;
  7059. if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
  7060. return errno;
  7061. }
  7062. memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
  7063. sa.sin_family = AF_INET;
  7064. sa.sin_addr.s_addr = INADDR_ANY;
  7065. uport = (unsigned short) 0;
  7066. sa.sin_port = htons(uport);
  7067. if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
  7068. return errno;
  7069. }
  7070. memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
  7071. if (!(hp = gethostbyname(host))) {
  7072. int b0, b1, b2, b3;
  7073. if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
  7074. hp = (struct hostent *) calloc(1, sizeof(struct hostent));
  7075. hp->h_addrtype = AF_INET;
  7076. hp->h_length = 4;
  7077. hp->h_addr_list = (char **) calloc(2, sizeof(char *));
  7078. hp->h_addr_list[0] = (char *) malloc(4);
  7079. hp->h_addr_list[0][0] = b0;
  7080. hp->h_addr_list[0][1] = b1;
  7081. hp->h_addr_list[0][2] = b2;
  7082. hp->h_addr_list[0][3] = b3;
  7083. } else {
  7084. return ENOENT;
  7085. }
  7086. }
  7087. sa.sin_family = hp->h_addrtype;
  7088. uport = (unsigned short) atoi(port);
  7089. sa.sin_port = htons(uport);
  7090. memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
  7091. if (connect(s, (struct sockaddr *) &sa,
  7092. sizeof(struct sockaddr_in)) < 0) {
  7093. return errno;
  7094. }
  7095. cp = (ChildProc *) calloc(1, sizeof(ChildProc));
  7096. cp->kind = CPSock;
  7097. cp->pid = 0;
  7098. cp->fdFrom = s;
  7099. cp->fdTo = s;
  7100. *pr = (ProcRef) cp;
  7101. #endif /* !OMIT_SOCKETS */
  7102. return 0;
  7103. }
  7104. int OpenCommPort(name, pr)
  7105. char *name;
  7106. ProcRef *pr;
  7107. {
  7108. int fd;
  7109. ChildProc *cp;
  7110. fd = open(name, 2, 0);
  7111. if (fd < 0) return errno;
  7112. cp = (ChildProc *) calloc(1, sizeof(ChildProc));
  7113. cp->kind = CPComm;
  7114. cp->pid = 0;
  7115. cp->fdFrom = fd;
  7116. cp->fdTo = fd;
  7117. *pr = (ProcRef) cp;
  7118. return 0;
  7119. }
  7120. int OpenLoopback(pr)
  7121. ProcRef *pr;
  7122. {
  7123. ChildProc *cp;
  7124. int to[2], from[2];
  7125. SetUpChildIO(to, from);
  7126. cp = (ChildProc *) calloc(1, sizeof(ChildProc));
  7127. cp->kind = CPLoop;
  7128. cp->pid = 0;
  7129. cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
  7130. cp->fdTo = to[1];
  7131. *pr = (ProcRef) cp;
  7132. return 0;
  7133. }
  7134. int OpenRcmd(host, user, cmd, pr)
  7135. char *host, *user, *cmd;
  7136. ProcRef *pr;
  7137. {
  7138. DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
  7139. return -1;
  7140. }
  7141. #define INPUT_SOURCE_BUF_SIZE 8192
  7142. typedef struct {
  7143. CPKind kind;
  7144. int fd;
  7145. int lineByLine;
  7146. char *unused;
  7147. InputCallback func;
  7148. XtInputId xid;
  7149. char buf[INPUT_SOURCE_BUF_SIZE];
  7150. VOIDSTAR closure;
  7151. } InputSource;
  7152. void
  7153. DoInputCallback(closure, source, xid)
  7154. caddr_t closure;
  7155. int *source;
  7156. XtInputId *xid;
  7157. {
  7158. InputSource *is = (InputSource *) closure;
  7159. int count;
  7160. int error;
  7161. char *p, *q;
  7162. if (is->lineByLine) {
  7163. count = read(is->fd, is->unused,
  7164. INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
  7165. if (count <= 0) {
  7166. (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
  7167. return;
  7168. }
  7169. is->unused += count;
  7170. p = is->buf;
  7171. while (p < is->unused) {
  7172. q = memchr(p, '\n', is->unused - p);
  7173. if (q == NULL) break;
  7174. q++;
  7175. (is->func)(is, is->closure, p, q - p, 0);
  7176. p = q;
  7177. }
  7178. q = is->buf;
  7179. while (p < is->unused) {
  7180. *q++ = *p++;
  7181. }
  7182. is->unused = q;
  7183. } else {
  7184. count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
  7185. if (count == -1)
  7186. error = errno;
  7187. else
  7188. error = 0;
  7189. (is->func)(is, is->closure, is->buf, count, error);
  7190. }
  7191. }
  7192. InputSourceRef AddInputSource(pr, lineByLine, func, closure)
  7193. ProcRef pr;
  7194. int lineByLine;
  7195. InputCallback func;
  7196. VOIDSTAR closure;
  7197. {
  7198. InputSource *is;
  7199. ChildProc *cp = (ChildProc *) pr;
  7200. is = (InputSource *) calloc(1, sizeof(InputSource));
  7201. is->lineByLine = lineByLine;
  7202. is->func = func;
  7203. if (pr == NoProc) {
  7204. is->kind = CPReal;
  7205. is->fd = fileno(stdin);
  7206. } else {
  7207. is->kind = cp->kind;
  7208. is->fd = cp->fdFrom;
  7209. }
  7210. if (lineByLine) {
  7211. is->unused = is->buf;
  7212. }
  7213. is->xid = XtAppAddInput(appContext, is->fd,
  7214. (XtPointer) (XtInputReadMask),
  7215. (XtInputCallbackProc) DoInputCallback,
  7216. (XtPointer) is);
  7217. is->closure = closure;
  7218. return (InputSourceRef) is;
  7219. }
  7220. void
  7221. RemoveInputSource(isr)
  7222. InputSourceRef isr;
  7223. {
  7224. InputSource *is = (InputSource *) isr;
  7225. if (is->xid == 0) return;
  7226. XtRemoveInput(is->xid);
  7227. is->xid = 0;
  7228. }
  7229. int OutputToProcess(pr, message, count, outError)
  7230. ProcRef pr;
  7231. char *message;
  7232. int count;
  7233. int *outError;
  7234. {
  7235. static int line = 0;
  7236. ChildProc *cp = (ChildProc *) pr;
  7237. int outCount;
  7238. if (pr == NoProc)
  7239. {
  7240. if (appData.noJoin || !appData.useInternalWrap)
  7241. outCount = fwrite(message, 1, count, stdout);
  7242. else
  7243. {
  7244. int width = get_term_width();
  7245. int len = wrap(NULL, message, count, width, &line);
  7246. char *msg = malloc(len);
  7247. int dbgchk;
  7248. if (!msg)
  7249. outCount = fwrite(message, 1, count, stdout);
  7250. else
  7251. {
  7252. dbgchk = wrap(msg, message, count, width, &line);
  7253. if (dbgchk != len && appData.debugMode)
  7254. fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
  7255. outCount = fwrite(msg, 1, dbgchk, stdout);
  7256. free(msg);
  7257. }
  7258. }
  7259. }
  7260. else
  7261. outCount = write(cp->fdTo, message, count);
  7262. if (outCount == -1)
  7263. *outError = errno;
  7264. else
  7265. *outError = 0;
  7266. return outCount;
  7267. }
  7268. /* Output message to process, with "ms" milliseconds of delay
  7269. between each character. This is needed when sending the logon
  7270. script to ICC, which for some reason doesn't like the
  7271. instantaneous send. */
  7272. int OutputToProcessDelayed(pr, message, count, outError, msdelay)
  7273. ProcRef pr;
  7274. char *message;
  7275. int count;
  7276. int *outError;
  7277. long msdelay;
  7278. {
  7279. ChildProc *cp = (ChildProc *) pr;
  7280. int outCount = 0;
  7281. int r;
  7282. while (count--) {
  7283. r = write(cp->fdTo, message++, 1);
  7284. if (r == -1) {
  7285. *outError = errno;
  7286. return outCount;
  7287. }
  7288. ++outCount;
  7289. if (msdelay >= 0)
  7290. TimeDelay(msdelay);
  7291. }
  7292. return outCount;
  7293. }
  7294. /**** Animation code by Hugh Fisher, DCS, ANU.
  7295. Known problem: if a window overlapping the board is
  7296. moved away while a piece is being animated underneath,
  7297. the newly exposed area won't be updated properly.
  7298. I can live with this.
  7299. Known problem: if you look carefully at the animation
  7300. of pieces in mono mode, they are being drawn as solid
  7301. shapes without interior detail while moving. Fixing
  7302. this would be a major complication for minimal return.
  7303. ****/
  7304. /* Masks for XPM pieces. Black and white pieces can have
  7305. different shapes, but in the interest of retaining my
  7306. sanity pieces must have the same outline on both light
  7307. and dark squares, and all pieces must use the same
  7308. background square colors/images. */
  7309. static int xpmDone = 0;
  7310. static void
  7311. CreateAnimMasks (pieceDepth)
  7312. int pieceDepth;
  7313. {
  7314. ChessSquare piece;
  7315. Pixmap buf;
  7316. GC bufGC, maskGC;
  7317. int kind, n;
  7318. unsigned long plane;
  7319. XGCValues values;
  7320. /* Need a bitmap just to get a GC with right depth */
  7321. buf = XCreatePixmap(xDisplay, xBoardWindow,
  7322. 8, 8, 1);
  7323. values.foreground = 1;
  7324. values.background = 0;
  7325. /* Don't use XtGetGC, not read only */
  7326. maskGC = XCreateGC(xDisplay, buf,
  7327. GCForeground | GCBackground, &values);
  7328. XFreePixmap(xDisplay, buf);
  7329. buf = XCreatePixmap(xDisplay, xBoardWindow,
  7330. squareSize, squareSize, pieceDepth);
  7331. values.foreground = XBlackPixel(xDisplay, xScreen);
  7332. values.background = XWhitePixel(xDisplay, xScreen);
  7333. bufGC = XCreateGC(xDisplay, buf,
  7334. GCForeground | GCBackground, &values);
  7335. for (piece = WhitePawn; piece <= BlackKing; piece++) {
  7336. /* Begin with empty mask */
  7337. if(!xpmDone) // [HGM] pieces: keep using existing
  7338. xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
  7339. squareSize, squareSize, 1);
  7340. XSetFunction(xDisplay, maskGC, GXclear);
  7341. XFillRectangle(xDisplay, xpmMask[piece], maskGC,
  7342. 0, 0, squareSize, squareSize);
  7343. /* Take a copy of the piece */
  7344. if (White(piece))
  7345. kind = 0;
  7346. else
  7347. kind = 2;
  7348. XSetFunction(xDisplay, bufGC, GXcopy);
  7349. XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
  7350. buf, bufGC,
  7351. 0, 0, squareSize, squareSize, 0, 0);
  7352. /* XOR the background (light) over the piece */
  7353. XSetFunction(xDisplay, bufGC, GXxor);
  7354. if (useImageSqs)
  7355. XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
  7356. 0, 0, squareSize, squareSize, 0, 0);
  7357. else {
  7358. XSetForeground(xDisplay, bufGC, lightSquareColor);
  7359. XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
  7360. }
  7361. /* We now have an inverted piece image with the background
  7362. erased. Construct mask by just selecting all the non-zero
  7363. pixels - no need to reconstruct the original image. */
  7364. XSetFunction(xDisplay, maskGC, GXor);
  7365. plane = 1;
  7366. /* Might be quicker to download an XImage and create bitmap
  7367. data from it rather than this N copies per piece, but it
  7368. only takes a fraction of a second and there is a much
  7369. longer delay for loading the pieces. */
  7370. for (n = 0; n < pieceDepth; n ++) {
  7371. XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
  7372. 0, 0, squareSize, squareSize,
  7373. 0, 0, plane);
  7374. plane = plane << 1;
  7375. }
  7376. }
  7377. /* Clean up */
  7378. XFreePixmap(xDisplay, buf);
  7379. XFreeGC(xDisplay, bufGC);
  7380. XFreeGC(xDisplay, maskGC);
  7381. }
  7382. static void
  7383. InitAnimState (anim, info)
  7384. AnimState * anim;
  7385. XWindowAttributes * info;
  7386. {
  7387. XtGCMask mask;
  7388. XGCValues values;
  7389. /* Each buffer is square size, same depth as window */
  7390. anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
  7391. squareSize, squareSize, info->depth);
  7392. anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
  7393. squareSize, squareSize, info->depth);
  7394. /* Create a plain GC for blitting */
  7395. mask = GCForeground | GCBackground | GCFunction |
  7396. GCPlaneMask | GCGraphicsExposures;
  7397. values.foreground = XBlackPixel(xDisplay, xScreen);
  7398. values.background = XWhitePixel(xDisplay, xScreen);
  7399. values.function = GXcopy;
  7400. values.plane_mask = AllPlanes;
  7401. values.graphics_exposures = False;
  7402. anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
  7403. /* Piece will be copied from an existing context at
  7404. the start of each new animation/drag. */
  7405. anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
  7406. /* Outline will be a read-only copy of an existing */
  7407. anim->outlineGC = None;
  7408. }
  7409. static void
  7410. CreateAnimVars ()
  7411. {
  7412. XWindowAttributes info;
  7413. if (xpmDone && gameInfo.variant == oldVariant) return;
  7414. if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
  7415. XGetWindowAttributes(xDisplay, xBoardWindow, &info);
  7416. InitAnimState(&game, &info);
  7417. InitAnimState(&player, &info);
  7418. /* For XPM pieces, we need bitmaps to use as masks. */
  7419. if (useImages)
  7420. CreateAnimMasks(info.depth), xpmDone = 1;
  7421. }
  7422. #ifndef HAVE_USLEEP
  7423. static Boolean frameWaiting;
  7424. static RETSIGTYPE FrameAlarm (sig)
  7425. int sig;
  7426. {
  7427. frameWaiting = False;
  7428. /* In case System-V style signals. Needed?? */
  7429. signal(SIGALRM, FrameAlarm);
  7430. }
  7431. static void
  7432. FrameDelay (time)
  7433. int time;
  7434. {
  7435. struct itimerval delay;
  7436. XSync(xDisplay, False);
  7437. if (time > 0) {
  7438. frameWaiting = True;
  7439. signal(SIGALRM, FrameAlarm);
  7440. delay.it_interval.tv_sec =
  7441. delay.it_value.tv_sec = time / 1000;
  7442. delay.it_interval.tv_usec =
  7443. delay.it_value.tv_usec = (time % 1000) * 1000;
  7444. setitimer(ITIMER_REAL, &delay, NULL);
  7445. while (frameWaiting) pause();
  7446. delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
  7447. delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
  7448. setitimer(ITIMER_REAL, &delay, NULL);
  7449. }
  7450. }
  7451. #else
  7452. static void
  7453. FrameDelay (time)
  7454. int time;
  7455. {
  7456. XSync(xDisplay, False);
  7457. if (time > 0)
  7458. usleep(time * 1000);
  7459. }
  7460. #endif
  7461. /* Convert board position to corner of screen rect and color */
  7462. static void
  7463. ScreenSquare(column, row, pt, color)
  7464. int column; int row; XPoint * pt; int * color;
  7465. {
  7466. if (flipView) {
  7467. pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
  7468. pt->y = lineGap + row * (squareSize + lineGap);
  7469. } else {
  7470. pt->x = lineGap + column * (squareSize + lineGap);
  7471. pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
  7472. }
  7473. *color = SquareColor(row, column);
  7474. }
  7475. /* Convert window coords to square */
  7476. static void
  7477. BoardSquare(x, y, column, row)
  7478. int x; int y; int * column; int * row;
  7479. {
  7480. *column = EventToSquare(x, BOARD_WIDTH);
  7481. if (flipView && *column >= 0)
  7482. *column = BOARD_WIDTH - 1 - *column;
  7483. *row = EventToSquare(y, BOARD_HEIGHT);
  7484. if (!flipView && *row >= 0)
  7485. *row = BOARD_HEIGHT - 1 - *row;
  7486. }
  7487. /* Utilities */
  7488. #undef Max /* just in case */
  7489. #undef Min
  7490. #define Max(a, b) ((a) > (b) ? (a) : (b))
  7491. #define Min(a, b) ((a) < (b) ? (a) : (b))
  7492. static void
  7493. SetRect(rect, x, y, width, height)
  7494. XRectangle * rect; int x; int y; int width; int height;
  7495. {
  7496. rect->x = x;
  7497. rect->y = y;
  7498. rect->width = width;
  7499. rect->height = height;
  7500. }
  7501. /* Test if two frames overlap. If they do, return
  7502. intersection rect within old and location of
  7503. that rect within new. */
  7504. static Boolean
  7505. Intersect(old, new, size, area, pt)
  7506. XPoint * old; XPoint * new;
  7507. int size; XRectangle * area; XPoint * pt;
  7508. {
  7509. if (old->x > new->x + size || new->x > old->x + size ||
  7510. old->y > new->y + size || new->y > old->y + size) {
  7511. return False;
  7512. } else {
  7513. SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
  7514. size - abs(old->x - new->x), size - abs(old->y - new->y));
  7515. pt->x = Max(old->x - new->x, 0);
  7516. pt->y = Max(old->y - new->y, 0);
  7517. return True;
  7518. }
  7519. }
  7520. /* For two overlapping frames, return the rect(s)
  7521. in the old that do not intersect with the new. */
  7522. static void
  7523. CalcUpdateRects(old, new, size, update, nUpdates)
  7524. XPoint * old; XPoint * new; int size;
  7525. XRectangle update[]; int * nUpdates;
  7526. {
  7527. int count;
  7528. /* If old = new (shouldn't happen) then nothing to draw */
  7529. if (old->x == new->x && old->y == new->y) {
  7530. *nUpdates = 0;
  7531. return;
  7532. }
  7533. /* Work out what bits overlap. Since we know the rects
  7534. are the same size we don't need a full intersect calc. */
  7535. count = 0;
  7536. /* Top or bottom edge? */
  7537. if (new->y > old->y) {
  7538. SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
  7539. count ++;
  7540. } else if (old->y > new->y) {
  7541. SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
  7542. size, old->y - new->y);
  7543. count ++;
  7544. }
  7545. /* Left or right edge - don't overlap any update calculated above. */
  7546. if (new->x > old->x) {
  7547. SetRect(&(update[count]), old->x, Max(new->y, old->y),
  7548. new->x - old->x, size - abs(new->y - old->y));
  7549. count ++;
  7550. } else if (old->x > new->x) {
  7551. SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
  7552. old->x - new->x, size - abs(new->y - old->y));
  7553. count ++;
  7554. }
  7555. /* Done */
  7556. *nUpdates = count;
  7557. }
  7558. /* Generate a series of frame coords from start->mid->finish.
  7559. The movement rate doubles until the half way point is
  7560. reached, then halves back down to the final destination,
  7561. which gives a nice slow in/out effect. The algorithmn
  7562. may seem to generate too many intermediates for short
  7563. moves, but remember that the purpose is to attract the
  7564. viewers attention to the piece about to be moved and
  7565. then to where it ends up. Too few frames would be less
  7566. noticeable. */
  7567. static void
  7568. Tween(start, mid, finish, factor, frames, nFrames)
  7569. XPoint * start; XPoint * mid;
  7570. XPoint * finish; int factor;
  7571. XPoint frames[]; int * nFrames;
  7572. {
  7573. int fraction, n, count;
  7574. count = 0;
  7575. /* Slow in, stepping 1/16th, then 1/8th, ... */
  7576. fraction = 1;
  7577. for (n = 0; n < factor; n++)
  7578. fraction *= 2;
  7579. for (n = 0; n < factor; n++) {
  7580. frames[count].x = start->x + (mid->x - start->x) / fraction;
  7581. frames[count].y = start->y + (mid->y - start->y) / fraction;
  7582. count ++;
  7583. fraction = fraction / 2;
  7584. }
  7585. /* Midpoint */
  7586. frames[count] = *mid;
  7587. count ++;
  7588. /* Slow out, stepping 1/2, then 1/4, ... */
  7589. fraction = 2;
  7590. for (n = 0; n < factor; n++) {
  7591. frames[count].x = finish->x - (finish->x - mid->x) / fraction;
  7592. frames[count].y = finish->y - (finish->y - mid->y) / fraction;
  7593. count ++;
  7594. fraction = fraction * 2;
  7595. }
  7596. *nFrames = count;
  7597. }
  7598. /* Draw a piece on the screen without disturbing what's there */
  7599. static void
  7600. SelectGCMask(piece, clip, outline, mask)
  7601. ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
  7602. {
  7603. GC source;
  7604. /* Bitmap for piece being moved. */
  7605. if (appData.monoMode) {
  7606. *mask = *pieceToSolid(piece);
  7607. } else if (useImages) {
  7608. #if HAVE_LIBXPM
  7609. *mask = xpmMask[piece];
  7610. #else
  7611. *mask = ximMaskPm[piece];
  7612. #endif
  7613. } else {
  7614. *mask = *pieceToSolid(piece);
  7615. }
  7616. /* GC for piece being moved. Square color doesn't matter, but
  7617. since it gets modified we make a copy of the original. */
  7618. if (White(piece)) {
  7619. if (appData.monoMode)
  7620. source = bwPieceGC;
  7621. else
  7622. source = wlPieceGC;
  7623. } else {
  7624. if (appData.monoMode)
  7625. source = wbPieceGC;
  7626. else
  7627. source = blPieceGC;
  7628. }
  7629. XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
  7630. /* Outline only used in mono mode and is not modified */
  7631. if (White(piece))
  7632. *outline = bwPieceGC;
  7633. else
  7634. *outline = wbPieceGC;
  7635. }
  7636. static void
  7637. OverlayPiece(piece, clip, outline, dest)
  7638. ChessSquare piece; GC clip; GC outline; Drawable dest;
  7639. {
  7640. int kind;
  7641. if (!useImages) {
  7642. /* Draw solid rectangle which will be clipped to shape of piece */
  7643. XFillRectangle(xDisplay, dest, clip,
  7644. 0, 0, squareSize, squareSize);
  7645. if (appData.monoMode)
  7646. /* Also draw outline in contrasting color for black
  7647. on black / white on white cases */
  7648. XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
  7649. 0, 0, squareSize, squareSize, 0, 0, 1);
  7650. } else {
  7651. /* Copy the piece */
  7652. if (White(piece))
  7653. kind = 0;
  7654. else
  7655. kind = 2;
  7656. if(appData.upsideDown && flipView) kind ^= 2;
  7657. XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
  7658. dest, clip,
  7659. 0, 0, squareSize, squareSize,
  7660. 0, 0);
  7661. }
  7662. }
  7663. /* Animate the movement of a single piece */
  7664. static void
  7665. BeginAnimation(anim, piece, startColor, start)
  7666. AnimState *anim;
  7667. ChessSquare piece;
  7668. int startColor;
  7669. XPoint * start;
  7670. {
  7671. Pixmap mask;
  7672. if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
  7673. /* The old buffer is initialised with the start square (empty) */
  7674. BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
  7675. anim->prevFrame = *start;
  7676. /* The piece will be drawn using its own bitmap as a matte */
  7677. SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
  7678. XSetClipMask(xDisplay, anim->pieceGC, mask);
  7679. }
  7680. static void
  7681. AnimationFrame(anim, frame, piece)
  7682. AnimState *anim;
  7683. XPoint *frame;
  7684. ChessSquare piece;
  7685. {
  7686. XRectangle updates[4];
  7687. XRectangle overlap;
  7688. XPoint pt;
  7689. int count, i;
  7690. /* Save what we are about to draw into the new buffer */
  7691. XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
  7692. frame->x, frame->y, squareSize, squareSize,
  7693. 0, 0);
  7694. /* Erase bits of the previous frame */
  7695. if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
  7696. /* Where the new frame overlapped the previous,
  7697. the contents in newBuf are wrong. */
  7698. XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
  7699. overlap.x, overlap.y,
  7700. overlap.width, overlap.height,
  7701. pt.x, pt.y);
  7702. /* Repaint the areas in the old that don't overlap new */
  7703. CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
  7704. for (i = 0; i < count; i++)
  7705. XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
  7706. updates[i].x - anim->prevFrame.x,
  7707. updates[i].y - anim->prevFrame.y,
  7708. updates[i].width, updates[i].height,
  7709. updates[i].x, updates[i].y);
  7710. } else {
  7711. /* Easy when no overlap */
  7712. XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
  7713. 0, 0, squareSize, squareSize,
  7714. anim->prevFrame.x, anim->prevFrame.y);
  7715. }
  7716. /* Save this frame for next time round */
  7717. XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
  7718. 0, 0, squareSize, squareSize,
  7719. 0, 0);
  7720. anim->prevFrame = *frame;
  7721. /* Draw piece over original screen contents, not current,
  7722. and copy entire rect. Wipes out overlapping piece images. */
  7723. OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
  7724. XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
  7725. 0, 0, squareSize, squareSize,
  7726. frame->x, frame->y);
  7727. }
  7728. static void
  7729. EndAnimation (anim, finish)
  7730. AnimState *anim;
  7731. XPoint *finish;
  7732. {
  7733. XRectangle updates[4];
  7734. XRectangle overlap;
  7735. XPoint pt;
  7736. int count, i;
  7737. /* The main code will redraw the final square, so we
  7738. only need to erase the bits that don't overlap. */
  7739. if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
  7740. CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
  7741. for (i = 0; i < count; i++)
  7742. XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
  7743. updates[i].x - anim->prevFrame.x,
  7744. updates[i].y - anim->prevFrame.y,
  7745. updates[i].width, updates[i].height,
  7746. updates[i].x, updates[i].y);
  7747. } else {
  7748. XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
  7749. 0, 0, squareSize, squareSize,
  7750. anim->prevFrame.x, anim->prevFrame.y);
  7751. }
  7752. }
  7753. static void
  7754. FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
  7755. AnimState *anim;
  7756. ChessSquare piece; int startColor;
  7757. XPoint * start; XPoint * finish;
  7758. XPoint frames[]; int nFrames;
  7759. {
  7760. int n;
  7761. BeginAnimation(anim, piece, startColor, start);
  7762. for (n = 0; n < nFrames; n++) {
  7763. AnimationFrame(anim, &(frames[n]), piece);
  7764. FrameDelay(appData.animSpeed);
  7765. }
  7766. EndAnimation(anim, finish);
  7767. }
  7768. void
  7769. AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
  7770. {
  7771. int i, x, y;
  7772. ChessSquare piece = board[fromY][toY];
  7773. board[fromY][toY] = EmptySquare;
  7774. DrawPosition(FALSE, board);
  7775. if (flipView) {
  7776. x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
  7777. y = lineGap + toY * (squareSize + lineGap);
  7778. } else {
  7779. x = lineGap + toX * (squareSize + lineGap);
  7780. y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
  7781. }
  7782. for(i=1; i<4*kFactor; i++) {
  7783. int r = squareSize * 9 * i/(20*kFactor - 5);
  7784. XFillArc(xDisplay, xBoardWindow, highlineGC,
  7785. x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
  7786. FrameDelay(appData.animSpeed);
  7787. }
  7788. board[fromY][toY] = piece;
  7789. }
  7790. /* Main control logic for deciding what to animate and how */
  7791. void
  7792. AnimateMove(board, fromX, fromY, toX, toY)
  7793. Board board;
  7794. int fromX;
  7795. int fromY;
  7796. int toX;
  7797. int toY;
  7798. {
  7799. ChessSquare piece;
  7800. int hop;
  7801. XPoint start, finish, mid;
  7802. XPoint frames[kFactor * 2 + 1];
  7803. int nFrames, startColor, endColor;
  7804. /* Are we animating? */
  7805. if (!appData.animate || appData.blindfold)
  7806. return;
  7807. if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
  7808. board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
  7809. return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
  7810. if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
  7811. piece = board[fromY][fromX];
  7812. if (piece >= EmptySquare) return;
  7813. #if DONT_HOP
  7814. hop = FALSE;
  7815. #else
  7816. hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
  7817. #endif
  7818. if (appData.debugMode) {
  7819. fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
  7820. _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
  7821. piece, fromX, fromY, toX, toY); }
  7822. ScreenSquare(fromX, fromY, &start, &startColor);
  7823. ScreenSquare(toX, toY, &finish, &endColor);
  7824. if (hop) {
  7825. /* Knight: make straight movement then diagonal */
  7826. if (abs(toY - fromY) < abs(toX - fromX)) {
  7827. mid.x = start.x + (finish.x - start.x) / 2;
  7828. mid.y = start.y;
  7829. } else {
  7830. mid.x = start.x;
  7831. mid.y = start.y + (finish.y - start.y) / 2;
  7832. }
  7833. } else {
  7834. mid.x = start.x + (finish.x - start.x) / 2;
  7835. mid.y = start.y + (finish.y - start.y) / 2;
  7836. }
  7837. /* Don't use as many frames for very short moves */
  7838. if (abs(toY - fromY) + abs(toX - fromX) <= 2)
  7839. Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
  7840. else
  7841. Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
  7842. FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
  7843. if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
  7844. int i,j;
  7845. for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
  7846. if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
  7847. }
  7848. /* Be sure end square is redrawn */
  7849. damage[0][toY][toX] = True;
  7850. }
  7851. void
  7852. DragPieceBegin(x, y)
  7853. int x; int y;
  7854. {
  7855. int boardX, boardY, color;
  7856. XPoint corner;
  7857. /* Are we animating? */
  7858. if (!appData.animateDragging || appData.blindfold)
  7859. return;
  7860. /* Figure out which square we start in and the
  7861. mouse position relative to top left corner. */
  7862. BoardSquare(x, y, &boardX, &boardY);
  7863. player.startBoardX = boardX;
  7864. player.startBoardY = boardY;
  7865. ScreenSquare(boardX, boardY, &corner, &color);
  7866. player.startSquare = corner;
  7867. player.startColor = color;
  7868. /* As soon as we start dragging, the piece will jump slightly to
  7869. be centered over the mouse pointer. */
  7870. player.mouseDelta.x = squareSize/2;
  7871. player.mouseDelta.y = squareSize/2;
  7872. /* Initialise animation */
  7873. player.dragPiece = PieceForSquare(boardX, boardY);
  7874. /* Sanity check */
  7875. if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
  7876. player.dragActive = True;
  7877. BeginAnimation(&player, player.dragPiece, color, &corner);
  7878. /* Mark this square as needing to be redrawn. Note that
  7879. we don't remove the piece though, since logically (ie
  7880. as seen by opponent) the move hasn't been made yet. */
  7881. if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
  7882. boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
  7883. XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
  7884. corner.x, corner.y, squareSize, squareSize,
  7885. 0, 0); // [HGM] zh: unstack in stead of grab
  7886. if(gatingPiece != EmptySquare) {
  7887. /* Kludge alert: When gating we want the introduced
  7888. piece to appear on the from square. To generate an
  7889. image of it, we draw it on the board, copy the image,
  7890. and draw the original piece again. */
  7891. ChessSquare piece = boards[currentMove][boardY][boardX];
  7892. DrawSquare(boardY, boardX, gatingPiece, 0);
  7893. XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
  7894. corner.x, corner.y, squareSize, squareSize, 0, 0);
  7895. DrawSquare(boardY, boardX, piece, 0);
  7896. }
  7897. damage[0][boardY][boardX] = True;
  7898. } else {
  7899. player.dragActive = False;
  7900. }
  7901. }
  7902. static void
  7903. DragPieceMove(x, y)
  7904. int x; int y;
  7905. {
  7906. XPoint corner;
  7907. /* Are we animating? */
  7908. if (!appData.animateDragging || appData.blindfold)
  7909. return;
  7910. /* Sanity check */
  7911. if (! player.dragActive)
  7912. return;
  7913. /* Move piece, maintaining same relative position
  7914. of mouse within square */
  7915. corner.x = x - player.mouseDelta.x;
  7916. corner.y = y - player.mouseDelta.y;
  7917. AnimationFrame(&player, &corner, player.dragPiece);
  7918. #if HIGHDRAG*0
  7919. if (appData.highlightDragging) {
  7920. int boardX, boardY;
  7921. BoardSquare(x, y, &boardX, &boardY);
  7922. SetHighlights(fromX, fromY, boardX, boardY);
  7923. }
  7924. #endif
  7925. }
  7926. void
  7927. DragPieceEnd(x, y)
  7928. int x; int y;
  7929. {
  7930. int boardX, boardY, color;
  7931. XPoint corner;
  7932. /* Are we animating? */
  7933. if (!appData.animateDragging || appData.blindfold)
  7934. return;
  7935. /* Sanity check */
  7936. if (! player.dragActive)
  7937. return;
  7938. /* Last frame in sequence is square piece is
  7939. placed on, which may not match mouse exactly. */
  7940. BoardSquare(x, y, &boardX, &boardY);
  7941. ScreenSquare(boardX, boardY, &corner, &color);
  7942. EndAnimation(&player, &corner);
  7943. /* Be sure end square is redrawn */
  7944. damage[0][boardY][boardX] = True;
  7945. /* This prevents weird things happening with fast successive
  7946. clicks which on my Sun at least can cause motion events
  7947. without corresponding press/release. */
  7948. player.dragActive = False;
  7949. }
  7950. /* Handle expose event while piece being dragged */
  7951. static void
  7952. DrawDragPiece ()
  7953. {
  7954. if (!player.dragActive || appData.blindfold)
  7955. return;
  7956. /* What we're doing: logically, the move hasn't been made yet,
  7957. so the piece is still in it's original square. But visually
  7958. it's being dragged around the board. So we erase the square
  7959. that the piece is on and draw it at the last known drag point. */
  7960. BlankSquare(player.startSquare.x, player.startSquare.y,
  7961. player.startColor, EmptySquare, xBoardWindow, 1);
  7962. AnimationFrame(&player, &player.prevFrame, player.dragPiece);
  7963. damage[0][player.startBoardY][player.startBoardX] = TRUE;
  7964. }
  7965. #include <sys/ioctl.h>
  7966. int get_term_width()
  7967. {
  7968. int fd, default_width;
  7969. fd = STDIN_FILENO;
  7970. default_width = 79; // this is FICS default anyway...
  7971. #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
  7972. struct ttysize win;
  7973. if (!ioctl(fd, TIOCGSIZE, &win))
  7974. default_width = win.ts_cols;
  7975. #elif defined(TIOCGWINSZ)
  7976. struct winsize win;
  7977. if (!ioctl(fd, TIOCGWINSZ, &win))
  7978. default_width = win.ws_col;
  7979. #endif
  7980. return default_width;
  7981. }
  7982. void
  7983. update_ics_width()
  7984. {
  7985. static int old_width = 0;
  7986. int new_width = get_term_width();
  7987. if (old_width != new_width)
  7988. ics_printf("set width %d\n", new_width);
  7989. old_width = new_width;
  7990. }
  7991. void NotifyFrontendLogin()
  7992. {
  7993. update_ics_width();
  7994. }
  7995. /* [AS] Arrow highlighting support */
  7996. static double A_WIDTH = 5; /* Width of arrow body */
  7997. #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
  7998. #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
  7999. static double Sqr( double x )
  8000. {
  8001. return x*x;
  8002. }
  8003. static int Round( double x )
  8004. {
  8005. return (int) (x + 0.5);
  8006. }
  8007. void SquareToPos(int rank, int file, int *x, int *y)
  8008. {
  8009. if (flipView) {
  8010. *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
  8011. *y = lineGap + rank * (squareSize + lineGap);
  8012. } else {
  8013. *x = lineGap + file * (squareSize + lineGap);
  8014. *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
  8015. }
  8016. }
  8017. /* Draw an arrow between two points using current settings */
  8018. void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
  8019. {
  8020. XPoint arrow[7];
  8021. double dx, dy, j, k, x, y;
  8022. if( d_x == s_x ) {
  8023. int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
  8024. arrow[0].x = s_x + A_WIDTH + 0.5;
  8025. arrow[0].y = s_y;
  8026. arrow[1].x = s_x + A_WIDTH + 0.5;
  8027. arrow[1].y = d_y - h;
  8028. arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
  8029. arrow[2].y = d_y - h;
  8030. arrow[3].x = d_x;
  8031. arrow[3].y = d_y;
  8032. arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
  8033. arrow[5].y = d_y - h;
  8034. arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
  8035. arrow[4].y = d_y - h;
  8036. arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
  8037. arrow[6].y = s_y;
  8038. }
  8039. else if( d_y == s_y ) {
  8040. int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
  8041. arrow[0].x = s_x;
  8042. arrow[0].y = s_y + A_WIDTH + 0.5;
  8043. arrow[1].x = d_x - w;
  8044. arrow[1].y = s_y + A_WIDTH + 0.5;
  8045. arrow[2].x = d_x - w;
  8046. arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
  8047. arrow[3].x = d_x;
  8048. arrow[3].y = d_y;
  8049. arrow[5].x = d_x - w;
  8050. arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
  8051. arrow[4].x = d_x - w;
  8052. arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
  8053. arrow[6].x = s_x;
  8054. arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
  8055. }
  8056. else {
  8057. /* [AS] Needed a lot of paper for this! :-) */
  8058. dy = (double) (d_y - s_y) / (double) (d_x - s_x);
  8059. dx = (double) (s_x - d_x) / (double) (s_y - d_y);
  8060. j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
  8061. k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
  8062. x = s_x;
  8063. y = s_y;
  8064. arrow[0].x = Round(x - j);
  8065. arrow[0].y = Round(y + j*dx);
  8066. arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
  8067. arrow[1].y = Round(arrow[0].y - 2*j*dx);
  8068. if( d_x > s_x ) {
  8069. x = (double) d_x - k;
  8070. y = (double) d_y - k*dy;
  8071. }
  8072. else {
  8073. x = (double) d_x + k;
  8074. y = (double) d_y + k*dy;
  8075. }
  8076. x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
  8077. arrow[6].x = Round(x - j);
  8078. arrow[6].y = Round(y + j*dx);
  8079. arrow[2].x = Round(arrow[6].x + 2*j);
  8080. arrow[2].y = Round(arrow[6].y - 2*j*dx);
  8081. arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
  8082. arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
  8083. arrow[4].x = d_x;
  8084. arrow[4].y = d_y;
  8085. arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
  8086. arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
  8087. }
  8088. XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
  8089. // Polygon( hdc, arrow, 7 );
  8090. }
  8091. /* [AS] Draw an arrow between two squares */
  8092. void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
  8093. {
  8094. int s_x, s_y, d_x, d_y, hor, vert, i;
  8095. if( s_col == d_col && s_row == d_row ) {
  8096. return;
  8097. }
  8098. /* Get source and destination points */
  8099. SquareToPos( s_row, s_col, &s_x, &s_y);
  8100. SquareToPos( d_row, d_col, &d_x, &d_y);
  8101. if( d_y > s_y ) {
  8102. d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
  8103. }
  8104. else if( d_y < s_y ) {
  8105. d_y += squareSize / 2 + squareSize / 4;
  8106. }
  8107. else {
  8108. d_y += squareSize / 2;
  8109. }
  8110. if( d_x > s_x ) {
  8111. d_x += squareSize / 2 - squareSize / 4;
  8112. }
  8113. else if( d_x < s_x ) {
  8114. d_x += squareSize / 2 + squareSize / 4;
  8115. }
  8116. else {
  8117. d_x += squareSize / 2;
  8118. }
  8119. s_x += squareSize / 2;
  8120. s_y += squareSize / 2;
  8121. /* Adjust width */
  8122. A_WIDTH = squareSize / 14.; //[HGM] make float
  8123. DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
  8124. hor = 64*s_col + 32; vert = 64*s_row + 32;
  8125. for(i=0; i<= 64; i++) {
  8126. damage[0][vert+6>>6][hor+6>>6] = True;
  8127. damage[0][vert-6>>6][hor+6>>6] = True;
  8128. damage[0][vert+6>>6][hor-6>>6] = True;
  8129. damage[0][vert-6>>6][hor-6>>6] = True;
  8130. hor += d_col - s_col; vert += d_row - s_row;
  8131. }
  8132. }
  8133. Boolean IsDrawArrowEnabled()
  8134. {
  8135. return appData.highlightMoveWithArrow && squareSize >= 32;
  8136. }
  8137. void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
  8138. {
  8139. if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
  8140. DrawArrowBetweenSquares(fromX, fromY, toX, toY);
  8141. }