template.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $TOG: template.c /main/6 1999/09/20 15:48:19 mgreess $ */
  24. /*
  25. * (c) Copyright 1993, 1994 Hewlett-Packard Company
  26. * (c) Copyright 1993, 1994 International Business Machines Corp.
  27. * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
  28. * (c) Copyright 1993, 1994 Novell, Inc.
  29. */
  30. /*
  31. * template.c
  32. *
  33. * Example code for typical Dt application
  34. *
  35. * Simple spray-can drawing tool
  36. */
  37. #include <X11/IntrinsicP.h>
  38. #include <X11/CoreP.h>
  39. #include <Dt/MsgCatP.h>
  40. #include <Xm/XmAll.h>
  41. #include <Dt/Dnd.h>
  42. #include <Dt/Dts.h>
  43. #include <Dt/HelpDialog.h>
  44. #include <Tt/tttk.h>
  45. /* default brush - used when the brush bitmap file is not found at run-time. */
  46. #include "default_brush.bm"
  47. /* Portability for catopen */
  48. #if !defined(NL_CAT_LOCALE)
  49. #define NL_CAT_LOCALE 0
  50. #endif
  51. #define ApplicationClass "Template"
  52. #define MessageCatalog "template.cat"
  53. #define HelpVolume "template"
  54. #define HelpTopic "_hometopic"
  55. #define IconPixmap "template_icon.pm"
  56. #define IconMask "template_icon_m.bm"
  57. #define Suffix ".template"
  58. #define SuffixLength 9
  59. #define UnnamedFile "unnamed.template"
  60. #define SearchPattern "*.template"
  61. #define DataType "TemplateData"
  62. #define ToolTalkPType "DT_Example_Template"
  63. #define FileSignature "@template@\n"
  64. #define MallocInc 10
  65. typedef struct _WindowData {
  66. int npoints;
  67. int nalloc;
  68. XPoint *points;
  69. Widget shell;
  70. Widget openDialog;
  71. Widget saveDialog;
  72. char *name; /* NULL if no file */
  73. struct _WindowData *next;
  74. } WindowData;
  75. static XtAppContext appContext;
  76. static nl_catd msgCatalog;
  77. static Widget appShell;
  78. static WindowData *windowList = NULL;
  79. static XContext wdContext;
  80. static Atom WM_DELETE_WINDOW;
  81. static Atom WM_SAVE_YOURSELF;
  82. static char *appnameString;
  83. static char *separatorString;
  84. static char *untitledString;
  85. static char *argv0;
  86. static char *programName;
  87. /* ToolTalk stuff */
  88. static int ttfd;
  89. static char *procid;
  90. static Tt_pattern *ttpat;
  91. static Tt_status ttrc;
  92. static Tt_message HandleTtMedia(Tt_message, void *, Tttk_op, Tt_status,
  93. unsigned char *, int, char *, char *);
  94. #define DrawingTranslations "#replace\
  95. <Btn1Down>: DrawingAreaInput()\n\
  96. <Btn1Motion>: DrawingAreaInput()"
  97. static void ClearCb(Widget, XtPointer, XtPointer);
  98. static void HelpCb(Widget, XtPointer, XtPointer);
  99. static void NewCb(Widget, XtPointer, XtPointer);
  100. static void OpenCb(Widget, XtPointer, XtPointer);
  101. static void OpenOkCb(Widget, XtPointer, XtPointer);
  102. static void SaveCb(Widget, XtPointer, XtPointer);
  103. static void SaveOkCb(Widget, XtPointer, XtPointer);
  104. static void PrintCb(Widget, XtPointer, XtPointer);
  105. static void ExitCb(Widget, XtPointer, XtPointer);
  106. static void ExposeCb(Widget, XtPointer, XtPointer);
  107. static void InputCb(Widget, XtPointer, XtPointer);
  108. static void DropTransferCb(Widget, XtPointer, XtPointer);
  109. static void SaveSessionCb(Widget, XtPointer, XtPointer);
  110. typedef enum {
  111. LOAD_EMPTY, LOAD_FILE, LOAD_BUFFER
  112. } LoadType;
  113. static void Fatal(char*);
  114. static void ReallyExit(int);
  115. static void SetTitle(Widget,char*);
  116. static Boolean NewWindow(LoadType,char*,int);
  117. static WindowData *NewData(void);
  118. static void AssocData(WindowData*,Widget);
  119. static WindowData *FindData(Widget);
  120. static void DestroyData(WindowData*);
  121. static Boolean LoadFile(WindowData*,char*);
  122. static Boolean LoadBuffer(WindowData*,void*,int);
  123. static void FreeData(WindowData*);
  124. static void PrintData(WindowData*);
  125. static void AddPoint(WindowData*, int, int);
  126. static void DrawPoint(Widget, int, int);
  127. static char* AppendString(char*,char*);
  128. static XtCallbackRec DropTransferCbList[] = {
  129. { DropTransferCb, NULL},
  130. { NULL, NULL}
  131. };
  132. static XrmOptionDescRec optionTable[] = {
  133. {"-print", ".printMode", XrmoptionIsArg, NULL},
  134. {"-server", ".serverMode", XrmoptionIsArg, NULL},
  135. };
  136. typedef struct {
  137. String printMode;
  138. String serverMode;
  139. } appResourceRec;
  140. static XtResource appResources[] = {
  141. { "printMode", "PrintMode", XtRString, sizeof(String),
  142. XtOffsetOf(appResourceRec, printMode), XtRString, NULL },
  143. { "serverMode", "ServerMode", XtRString, sizeof(String),
  144. XtOffsetOf(appResourceRec, serverMode), XtRString, NULL },
  145. };
  146. main(int argc, char **argv)
  147. {
  148. int i;
  149. appResourceRec argvals;
  150. char *errfmt, *errmsg, *statmsg;
  151. argv0 = argv[0];
  152. programName = strrchr(argv[0], '/');
  153. if (programName == NULL)
  154. programName = argv[0];
  155. else
  156. ++programName;
  157. XtSetLanguageProc(NULL, NULL, NULL);
  158. appShell = XtAppInitialize(&appContext, ApplicationClass,
  159. optionTable, XtNumber(optionTable),
  160. &argc, argv, NULL, NULL, 0);
  161. msgCatalog = CATOPEN(MessageCatalog, NL_CAT_LOCALE);
  162. XtGetApplicationResources(appShell, &argvals,
  163. appResources, XtNumber(appResources),
  164. NULL, 0);
  165. wdContext = XUniqueContext();
  166. WM_DELETE_WINDOW = XmInternAtom(XtDisplay(appShell), "WM_DELETE_WINDOW",
  167. False);
  168. WM_SAVE_YOURSELF = XmInternAtom(XtDisplay(appShell), "WM_SAVE_YOURSELF",
  169. False);
  170. appnameString = CATGETS(msgCatalog, 1, 1, "Template");
  171. separatorString = CATGETS(msgCatalog, 1, 5, " - ");
  172. untitledString = CATGETS(msgCatalog, 1, 6, "(untitled)");
  173. if (argvals.printMode != NULL) {
  174. /* Load up each file and print it, then exit */
  175. WindowData *wd = NewData();
  176. for (i = 1; i < argc; ++i) {
  177. if (LoadFile(wd, argv[i]))
  178. PrintData(wd);
  179. else
  180. fprintf(stderr,
  181. CATGETS(msgCatalog, 1, 10, "template: can't open %s\n"),
  182. argv[i]);
  183. }
  184. DestroyData(wd);
  185. exit(0);
  186. }
  187. /* Initialize Data Typing and ToolTalk */
  188. DtDtsLoadDataTypes();
  189. procid = ttdt_open(&ttfd, appnameString, "CDE", "1.0", True);
  190. if ((ttrc = tt_ptr_error(procid)) != TT_OK) {
  191. errfmt = CATGETS(msgCatalog, 1, 7, "ttdt_open failed:\n%s");
  192. statmsg = tt_status_message(ttrc);
  193. errmsg = XtMalloc(strlen(errfmt) + strlen(statmsg) + 2);
  194. sprintf(errmsg, errfmt, statmsg);
  195. Fatal(errmsg);
  196. XtFree(errmsg);
  197. }
  198. ttrc = ttmedia_ptype_declare(ToolTalkPType, 0, HandleTtMedia,
  199. NULL, True);
  200. if (tt_is_err(ttrc)) {
  201. errfmt = CATGETS(msgCatalog, 1, 8, "ttmedia_ptype_declare failed:\n%s");
  202. statmsg = tt_status_message(status);
  203. errmsg = XtMalloc(strlen(errfmt) + strlen(statmsg) + 2);
  204. sprintf(errmsg, errfmt, statmsg);
  205. Fatal(errmsg);
  206. XtFree(errmsg);
  207. }
  208. ttpat = ttdt_session_join(NULL, NULL, NULL, NULL, True);
  209. if ((ttrc = tt_ptr_error(ttpat)) != TT_OK) {
  210. errfmt = CATGETS(msgCatalog, 1, 9, "ttdt_session_join failed:\n%s");
  211. statmsg = tt_status_message(status);
  212. errmsg = XtMalloc(strlen(errfmt) + strlen(statmsg) + 2);
  213. sprintf(errmsg, errfmt, statmsg);
  214. Fatal(errmsg);
  215. XtFree(errmsg);
  216. }
  217. XtAppAddInput(appContext, ttfd, (XtPointer)XtInputReadMask,
  218. tttk_Xt_input_handler, NULL);
  219. if (argvals.serverMode != NULL) {
  220. /*
  221. * We're in server mode. Thus do nothing until requested to do so
  222. * through ToolTalk.
  223. */
  224. } else if (argc < 2) {
  225. /* No files given, so put up an untitled window. */
  226. (void) NewWindow(LOAD_EMPTY, NULL, 0);
  227. } else {
  228. /* Load each file into its own window. */
  229. for (i = 1; i < argc; ++i)
  230. (void) NewWindow(LOAD_FILE, argv[i], 0);
  231. }
  232. /*
  233. * Start the GUI. Note that we explicitly do not realize the appShell
  234. * widget, since it is the unmapped parent of all of the top-level shells
  235. * we pop up.
  236. */
  237. XtAppMainLoop(appContext);
  238. ReallyExit(0);
  239. }
  240. /*
  241. * Close ToolTalk and exit.
  242. */
  243. static void ReallyExit(int rc)
  244. {
  245. tt_close();
  246. exit(rc);
  247. }
  248. /*
  249. * Issue an error message and exit.
  250. */
  251. static void Fatal(char *msg)
  252. {
  253. fprintf(stderr, "%s: %s\n", programName, msg);
  254. exit(1);
  255. }
  256. /*
  257. * Create a new top-level window. If loadtype is LOAD_EMPTY, name_or_buf and
  258. * len are ignored. If loadtype is LOAD_FILE, name_or_buf should point to the
  259. * name of the file to load, and len is ignored. If loadtype is LOAD_BUFFER,
  260. * name_or_buf is a pointer to the data buffer and len is its length.
  261. */
  262. static Boolean
  263. NewWindow(LoadType loadtype, char *name_or_buf, int len)
  264. {
  265. Widget toplevel, mainWindow, menuBar, frame1, frame2,
  266. drawingArea, pd, cb, pb;
  267. char *title;
  268. XmString labelString;
  269. XtTranslations drawingTranslations;
  270. Pixmap iconPixmap;
  271. Pixmap iconMask;
  272. Pixel fg, bg;
  273. Arg args[20];
  274. int n;
  275. WindowData *wd;
  276. wd = NewData();
  277. n = 0;
  278. toplevel = XtCreatePopupShell("foo", topLevelShellWidgetClass,
  279. appShell, args, n);
  280. /* Create main window */
  281. n = 0;
  282. mainWindow = XmCreateMainWindow(toplevel, "mainWindow", args, n);
  283. XtManageChild(mainWindow);
  284. /* Set window manager title and icon */
  285. XtVaGetValues(mainWindow, XmNforeground, &fg, XmNbackground, &bg, NULL);
  286. iconPixmap = XmGetPixmap(XtScreen(toplevel), IconPixmap, fg, bg);
  287. iconMask = XmGetPixmapByDepth(XtScreen(toplevel), IconMask, 1, 0, 1);
  288. XtVaSetValues(toplevel,
  289. XmNiconName, appnameString,
  290. XmNiconPixmap, iconPixmap,
  291. XmNiconMask, iconMask,
  292. NULL);
  293. /* Create the GUI */
  294. menuBar = XmCreateMenuBar(mainWindow, "menuBar", NULL, 0);
  295. XtManageChild(menuBar);
  296. /* File menu */
  297. pd = XmCreatePulldownMenu(menuBar, "fileMenu", NULL, 0);
  298. labelString = XmStringCreateLocalized(CATGETS(msgCatalog, 2, 1, "File"));
  299. n = 0;
  300. XtSetArg(args[n], XmNlabelString, labelString); n++;
  301. XtSetArg(args[n], XmNmnemonic, 'F'); n++;
  302. XtSetArg(args[n], XmNsubMenuId, pd); n++;
  303. cb = XmCreateCascadeButton(menuBar, "fileCascade", args, n);
  304. XtManageChild(cb);
  305. XmStringFree(labelString);
  306. labelString = XmStringCreateLocalized(CATGETS(msgCatalog, 2, 9, "New..."));
  307. n = 0;
  308. XtSetArg(args[n], XmNlabelString, labelString); n++;
  309. XtSetArg(args[n], XmNmnemonic, 'N'); n++;
  310. pb = XmCreatePushButton(pd, "newButton", args, n);
  311. XtManageChild(pb);
  312. XtAddCallback(pb, XmNactivateCallback, NewCb, NULL);
  313. XmStringFree(labelString);
  314. labelString = XmStringCreateLocalized(CATGETS(msgCatalog, 2, 2, "Open..."));
  315. n = 0;
  316. XtSetArg(args[n], XmNlabelString, labelString); n++;
  317. XtSetArg(args[n], XmNmnemonic, 'O'); n++;
  318. pb = XmCreatePushButton(pd, "openButton", args, n);
  319. XtManageChild(pb);
  320. XtAddCallback(pb, XmNactivateCallback, OpenCb, (XtPointer)wd);
  321. XmStringFree(labelString);
  322. labelString = XmStringCreateLocalized(CATGETS(msgCatalog, 2, 3,
  323. "Save As..."));
  324. n = 0;
  325. XtSetArg(args[n], XmNlabelString, labelString); n++;
  326. XtSetArg(args[n], XmNmnemonic, 'S'); n++;
  327. pb = XmCreatePushButton(pd, "saveButton", args, n);
  328. XtManageChild(pb);
  329. XtAddCallback(pb, XmNactivateCallback, SaveCb, (XtPointer)wd);
  330. XmStringFree(labelString);
  331. labelString = XmStringCreateLocalized(CATGETS(msgCatalog, 2, 4, "Print"));
  332. n = 0;
  333. XtSetArg(args[n], XmNlabelString, labelString); n++;
  334. XtSetArg(args[n], XmNmnemonic, 'P'); n++;
  335. pb = XmCreatePushButton(pd, "printButton", args, n);
  336. XtManageChild(pb);
  337. XtAddCallback(pb, XmNactivateCallback, PrintCb, (XtPointer)wd);
  338. XmStringFree(labelString);
  339. labelString = XmStringCreateLocalized(CATGETS(msgCatalog, 2, 5, "Clear"));
  340. n = 0;
  341. XtSetArg(args[n], XmNlabelString, labelString); n++;
  342. XtSetArg(args[n], XmNmnemonic, 'C'); n++;
  343. pb = XmCreatePushButton(pd, "clearButton", args, n);
  344. XtManageChild(pb);
  345. XtAddCallback(pb, XmNactivateCallback, ClearCb, (XtPointer)wd);
  346. XmStringFree(labelString);
  347. labelString = XmStringCreateLocalized(CATGETS(msgCatalog, 2, 6, "Exit"));
  348. n = 0;
  349. XtSetArg(args[n], XmNlabelString, labelString); n++;
  350. XtSetArg(args[n], XmNmnemonic, 'E'); n++;
  351. pb = XmCreatePushButton(pd, "exitButton", args, n);
  352. XtManageChild(pb);
  353. XtAddCallback(pb, XmNactivateCallback, ExitCb, (XtPointer)wd);
  354. XmStringFree(labelString);
  355. /* Help menu */
  356. pd = XmCreatePulldownMenu(menuBar, "helpMenu", NULL, 0);
  357. labelString = XmStringCreateLocalized(CATGETS(msgCatalog, 2, 7, "Help"));
  358. n = 0;
  359. XtSetArg(args[n], XmNlabelString, labelString); n++;
  360. XtSetArg(args[n], XmNmnemonic, 'H'); n++;
  361. XtSetArg(args[n], XmNsubMenuId, pd); n++;
  362. cb = XmCreateCascadeButton(menuBar, "helpCascade", args, n);
  363. XtManageChild(cb);
  364. XmStringFree(labelString);
  365. XtVaSetValues(menuBar, XmNmenuHelpWidget, cb, NULL);
  366. labelString = XmStringCreateLocalized(CATGETS(msgCatalog,2,8, "Overview..."));
  367. n = 0;
  368. XtSetArg(args[n], XmNlabelString, labelString); n++;
  369. XtSetArg(args[n], XmNmnemonic, 'O'); n++;
  370. pb = XmCreatePushButton(pd, "helpButton", args, n);
  371. XtManageChild(pb);
  372. XtAddCallback(pb, XmNactivateCallback, HelpCb, NULL);
  373. XmStringFree(labelString);
  374. /* Drawing work area */
  375. n = 0;
  376. XtSetArg(args[n], XmNshadowThickness, 0); n++;
  377. XtSetArg(args[n], XmNmarginWidth, 20); n++;
  378. XtSetArg(args[n], XmNmarginHeight, 20); n++;
  379. frame1 = XmCreateFrame(mainWindow, "frame1", args, n);
  380. XtManageChild(frame1);
  381. n = 0;
  382. XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_OUT); n++;
  383. frame2 = XmCreateFrame(frame1, "frame2", args, n);
  384. XtManageChild(frame2);
  385. drawingTranslations = XtParseTranslationTable(DrawingTranslations);
  386. n = 0;
  387. XtSetArg(args[n], XmNunitType, Xm100TH_MILLIMETERS); n++;
  388. XtSetArg(args[n], XmNwidth, 12000); n++;
  389. XtSetArg(args[n], XmNheight, 12000); n++;
  390. XtSetArg(args[n], XmNtranslations, drawingTranslations); n++;
  391. drawingArea = XmCreateDrawingArea(frame2, "drawingArea", args, n);
  392. XtManageChild(drawingArea);
  393. XtAddCallback(drawingArea, XmNexposeCallback, ExposeCb, NULL);
  394. XtAddCallback(drawingArea, XmNinputCallback, InputCb, NULL);
  395. DtDndDropRegister(drawingArea,
  396. DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
  397. XmDROP_COPY, DropTransferCbList, NULL, 0);
  398. XmAddWMProtocolCallback(toplevel, WM_DELETE_WINDOW, ExitCb, (XtPointer)wd);
  399. XmAddWMProtocolCallback(toplevel, WM_SAVE_YOURSELF, SaveSessionCb,
  400. (XtPointer)NULL);
  401. XtRealizeWidget(toplevel);
  402. XtPopup(toplevel, XtGrabNone);
  403. AssocData(wd, toplevel);
  404. switch (loadtype) {
  405. case LOAD_EMPTY:
  406. SetTitle(toplevel, NULL);
  407. return True;
  408. case LOAD_FILE:
  409. return LoadFile(wd, name_or_buf);
  410. case LOAD_BUFFER:
  411. return LoadBuffer(wd, name_or_buf, len);
  412. }
  413. /*NOTREACHED*/
  414. }
  415. /*
  416. * Display the help system. On the first call, create the help widget.
  417. */
  418. static void HelpCb(Widget w, XtPointer cd, XtPointer cb)
  419. {
  420. static Widget helpDialog = NULL;
  421. if (helpDialog == NULL) {
  422. char *title;
  423. Arg args[10];
  424. int n;
  425. n = 0;
  426. XtSetArg(args[n], DtNhelpVolume, HelpVolume); n++;
  427. XtSetArg(args[n], DtNhelpType, DtHELP_TYPE_TOPIC); n++;
  428. XtSetArg(args[n], DtNlocationId, HelpTopic); n++;
  429. helpDialog = DtCreateHelpDialog(appShell, "helpDialog", args, n);
  430. title = CATGETS(msgCatalog, 1, 4, "Template Help");
  431. XtVaSetValues(XtParent(helpDialog), XmNtitle, title, NULL);
  432. } else {
  433. XtVaSetValues(helpDialog,
  434. DtNhelpVolume, HelpVolume,
  435. DtNlocationId, HelpTopic,
  436. NULL);
  437. }
  438. XtManageChild(helpDialog);
  439. }
  440. /*
  441. * Clear the display and drawing data.
  442. */
  443. static void ClearCb(Widget w, XtPointer cd, XtPointer cb)
  444. {
  445. WindowData *wd = (WindowData *)cd;
  446. Widget drawingArea = XtNameToWidget(wd->shell, "*drawingArea");
  447. FreeData(wd);
  448. XClearWindow(XtDisplay(drawingArea), XtWindow(drawingArea));
  449. }
  450. /*
  451. * Create a new top-level window.
  452. */
  453. static void NewCb(Widget w, XtPointer cd, XtPointer cb)
  454. {
  455. (void) NewWindow(LOAD_EMPTY, NULL, 0);
  456. }
  457. /*
  458. * Display a File dialog. On the first call, create the dialog.
  459. */
  460. static void OpenCb(Widget w, XtPointer cd, XtPointer cb)
  461. {
  462. WindowData *wd = (WindowData *)cd;
  463. if (wd->openDialog == NULL) {
  464. XmString pattern;
  465. XmString dialogTitle;
  466. Arg args[20];
  467. int n;
  468. dialogTitle = XmStringCreateLocalized(CATGETS(msgCatalog, 1, 2,
  469. "Template Open"));
  470. pattern = XmStringCreateLocalized(SearchPattern);
  471. n = 0;
  472. XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL);n++;
  473. XtSetArg(args[n], XmNautoUnmanage, True); n++;
  474. XtSetArg(args[n], XmNpattern, pattern); n++;
  475. XtSetArg(args[n], XmNdialogTitle, dialogTitle); n++;
  476. wd->openDialog = XmCreateFileSelectionDialog(wd->shell, "openDialog",
  477. args, n);
  478. XtUnmanageChild(XtNameToWidget(wd->openDialog, "*Help"));
  479. XtAddCallback(wd->openDialog, XmNokCallback, OpenOkCb, cd);
  480. XmStringFree(pattern);
  481. XmStringFree(dialogTitle);
  482. }
  483. XtManageChild(wd->openDialog);
  484. }
  485. static void OpenOkCb(Widget w, XtPointer cd, XtPointer cb)
  486. {
  487. char *fileName;
  488. WindowData *wd = (WindowData *)cd;
  489. XmFileSelectionBoxCallbackStruct *fsbcs =
  490. (XmFileSelectionBoxCallbackStruct *) cb;
  491. Widget drawingArea = XtNameToWidget(wd->shell, "*drawingArea");
  492. fileName = XmStringUnparse(fsbcs->value, NULL, XmCHARSET_TEXT,
  493. XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
  494. (void) LoadFile(wd, fileName);
  495. XtFree(fileName);
  496. XClearArea(XtDisplay(drawingArea), XtWindow(drawingArea), 0, 0, 0, 0, True);
  497. }
  498. /*
  499. * Display a File dialog. On the first call, create the dialog.
  500. */
  501. static void SaveCb(Widget w, XtPointer cd, XtPointer cb)
  502. {
  503. WindowData *wd = (WindowData *)cd;
  504. if (wd->saveDialog == NULL) {
  505. XmString pattern;
  506. XmString dialogTitle;
  507. Arg args[20];
  508. int n;
  509. dialogTitle = XmStringCreateLocalized(CATGETS(msgCatalog, 1, 3,
  510. "Template Save As"));
  511. pattern = XmStringCreateLocalized(SearchPattern);
  512. n = 0;
  513. XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL);n++;
  514. XtSetArg(args[n], XmNautoUnmanage, True); n++;
  515. XtSetArg(args[n], XmNpattern, pattern); n++;
  516. XtSetArg(args[n], XmNdialogTitle, dialogTitle); n++;
  517. wd->saveDialog = XmCreateFileSelectionDialog(appShell, "saveAsDialog",
  518. args, n);
  519. XtUnmanageChild(XtNameToWidget(wd->saveDialog, "*Help"));
  520. XtAddCallback(wd->saveDialog, XmNokCallback, SaveOkCb, cd);
  521. XmStringFree(pattern);
  522. XmStringFree(dialogTitle);
  523. }
  524. XtManageChild(wd->saveDialog);
  525. }
  526. static void SaveOkCb(Widget w, XtPointer cd, XtPointer cb)
  527. {
  528. FILE *fp;
  529. int i;
  530. char * fileName;
  531. int fileLength;
  532. WindowData *wd = (WindowData *)cd;
  533. XmFileSelectionBoxCallbackStruct *fsbcs =
  534. (XmFileSelectionBoxCallbackStruct *) cb;
  535. XmStringGetLtoR(fsbcs->value, XmFONTLIST_DEFAULT_TAG, &fileName);
  536. fileLength = strlen(fileName);
  537. if (fileName[fileLength-1]== '/') {
  538. fileName = AppendString(fileName, UnnamedFile);
  539. fileLength = strlen(fileName);
  540. }
  541. if (fileLength > SuffixLength) {
  542. if (strcmp(fileName+fileLength-SuffixLength, Suffix) != 0) {
  543. fileName = AppendString(fileName,Suffix);
  544. }
  545. }
  546. else {
  547. fileName = AppendString(fileName, Suffix);
  548. }
  549. if ((fp = fopen(fileName, "w")) != NULL) {
  550. fputs(FileSignature, fp);
  551. for (i=0; i < wd->npoints; i++)
  552. fprintf(fp, "%d %d\n", wd->points[i].x, wd->points[i].y);
  553. fclose(fp);
  554. XtFree(wd->name);
  555. wd->name = XtNewString(fileName);
  556. SetTitle(wd->shell, fileName);
  557. }
  558. XtFree(fileName);
  559. }
  560. static char* AppendString(char *base, char *suffix)
  561. {
  562. char *file;
  563. file = XtMalloc(strlen(base)+strlen(suffix)+1);
  564. strcpy(file, base);
  565. strcat(file, suffix);
  566. XtFree(base);
  567. return(file);
  568. }
  569. /*
  570. * Respond to the TemplatePrint action by printing the data file
  571. * specified to the '-print' option.
  572. */
  573. static void PrintCb(Widget w, XtPointer cd, XtPointer cb)
  574. {
  575. WindowData *wd = (WindowData *)cd;
  576. PrintData(wd);
  577. }
  578. /*
  579. * Redraw the display when exposed.
  580. */
  581. static void ExposeCb(Widget w, XtPointer cd, XtPointer cb)
  582. {
  583. XmDrawingAreaCallbackStruct *dcb = (XmDrawingAreaCallbackStruct*)cb;
  584. WindowData *wd;
  585. int i;
  586. if (dcb->event != NULL && dcb->event->xexpose.count > 0) return;
  587. wd = FindData(w);
  588. for (i = 0; i < wd->npoints; i++)
  589. DrawPoint(w, wd->points[i].x, wd->points[i].y);
  590. }
  591. /*
  592. * Process mouse input.
  593. */
  594. static void InputCb(Widget w, XtPointer cd, XtPointer cb)
  595. {
  596. XmDrawingAreaCallbackStruct *dcb = (XmDrawingAreaCallbackStruct*)cb;
  597. WindowData *wd;
  598. if (dcb->event->xany.type != ButtonPress &&
  599. dcb->event->xany.type != MotionNotify)
  600. return;
  601. wd = FindData(w);
  602. AddPoint(wd, dcb->event->xbutton.x, dcb->event->xbutton.y);
  603. DrawPoint(w, dcb->event->xbutton.x, dcb->event->xbutton.y);
  604. }
  605. /*
  606. * Delete the current window. If there are no more windows, exit the
  607. * application.
  608. */
  609. static void ExitCb(Widget w, XtPointer cd, XtPointer cb)
  610. {
  611. WindowData *wd = (WindowData *)cd;
  612. DestroyData(wd);
  613. if (windowList == NULL)
  614. ReallyExit(0);
  615. }
  616. /*
  617. * Handle WM_SAVE_YOURSELF by updating the command line with all the files
  618. * currently being edited.
  619. */
  620. static void SaveSessionCb(Widget w, XtPointer cd, XtPointer cb)
  621. {
  622. char **command;
  623. int argcount = 1; /* starts at 1 for command name */
  624. WindowData *wd = windowList;
  625. int i;
  626. Widget first;
  627. /* count the number of windows bound to files */
  628. for (wd = windowList; wd != NULL; wd = wd->next) {
  629. if (wd->name != NULL)
  630. ++argcount;
  631. }
  632. command = (char **)XtMalloc(argcount*sizeof(char*));
  633. command[0] = argv0;
  634. i = 1;
  635. for (wd = windowList; wd != NULL; wd = wd->next) {
  636. if (wd->name != NULL)
  637. command[i++] = wd->name;
  638. }
  639. first = windowList->shell;
  640. XSetCommand(XtDisplay(first), XtWindow(first), command, i);
  641. if (w != first)
  642. XChangeProperty(XtDisplay(w), XtWindow(w), XA_WM_COMMAND, XA_STRING, 8,
  643. PropModeReplace, NULL, 0);
  644. XtFree((char *)command);
  645. }
  646. /*
  647. * Accept .template files dropped on the drawing window.
  648. */
  649. static void DropTransferCb(Widget drawingArea, XtPointer cd, XtPointer cb)
  650. {
  651. DtDndTransferCallbackStruct *dcb = (DtDndTransferCallbackStruct*)cb;
  652. WindowData *wd = FindData(drawingArea);
  653. char *fileName;
  654. char *dataType;
  655. void *bufPtr;
  656. int bufLen;
  657. dcb->status = DtDND_FAILURE;
  658. if (dcb->dropData->numItems > 1)
  659. return;
  660. switch (dcb->dropData->protocol) {
  661. case DtDND_FILENAME_TRANSFER:
  662. fileName = dcb->dropData->data.files[0];
  663. dataType = DtDtsFileToDataType(fileName);
  664. if (strcmp(dataType, DataType) != 0) {
  665. DtDtsFreeDataType(dataType);
  666. return;
  667. }
  668. if (LoadFile(wd, fileName))
  669. dcb->status = DtDND_SUCCESS;
  670. DtDtsFreeDataType(dataType);
  671. break;
  672. case DtDND_BUFFER_TRANSFER:
  673. bufPtr = dcb->dropData->data.buffers[0].bp;
  674. bufLen = dcb->dropData->data.buffers[0].size;
  675. dataType = DtDtsBufferToDataType(bufPtr, bufLen, NULL);
  676. if (strcmp(dataType, DataType) != 0) {
  677. DtDtsFreeDataType(dataType);
  678. return;
  679. }
  680. if (LoadBuffer(wd, bufPtr, bufLen))
  681. dcb->status = DtDND_SUCCESS;
  682. DtDtsFreeDataType(dataType);
  683. break;
  684. }
  685. XClearArea(XtDisplay(drawingArea), XtWindow(drawingArea),
  686. 0, 0, 0, 0, True);
  687. }
  688. /*
  689. * Set the widget's title to the program name followed by a separator followed
  690. * by the trailing pathname component of the filename. The widget must be a
  691. * shell. If name is NULL, uses "(untitled)" instead.
  692. */
  693. static void
  694. SetTitle(Widget w, char *name)
  695. {
  696. char buf[1000];
  697. char *p;
  698. if (name == NULL) {
  699. p = untitledString;
  700. } else {
  701. p = strrchr(name, '/');
  702. if (p == NULL)
  703. p = name;
  704. else
  705. p++;
  706. }
  707. sprintf(buf, "%s%s%s", appnameString, separatorString, p);
  708. XtVaSetValues(w, XtNtitle, buf, NULL);
  709. }
  710. /*
  711. * Create a new WindowData structure. The widget passed in should be the
  712. * shell associated with this data. It must be realized.
  713. */
  714. static WindowData *
  715. NewData(void)
  716. {
  717. WindowData *wd;
  718. wd = XtNew(WindowData);
  719. wd->npoints = 0;
  720. wd->nalloc = 0;
  721. wd->points = NULL;
  722. wd->shell = NULL;
  723. wd->openDialog = NULL;
  724. wd->saveDialog = NULL;
  725. wd->name = NULL;
  726. /* push it onto the front of the global list */
  727. wd->next = windowList;
  728. windowList = wd;
  729. return wd;
  730. }
  731. /*
  732. * Associate a top-level shell with a WindowData structure. The shell must be
  733. * realized.
  734. */
  735. static void
  736. AssocData(WindowData *wd, Widget w)
  737. {
  738. wd->shell = w;
  739. XSaveContext(XtDisplay(w), XtWindow(w), wdContext, (XPointer)wd);
  740. }
  741. /*
  742. * Given a widget, find the WindowData structure associated with it. First it
  743. * finds the shell ancestor of this widget, and then it extracts the window
  744. * data from using the X Context Manager.
  745. */
  746. static WindowData *
  747. FindData(Widget w)
  748. {
  749. WindowData *wd = NULL;
  750. while (! XtIsShell(w))
  751. w = XtParent(w);
  752. XFindContext(XtDisplay(w), XtWindow(w), wdContext, &wd);
  753. return wd;
  754. }
  755. /*
  756. * Destroy a WindowData structure.
  757. */
  758. static void
  759. DestroyData(WindowData *wd)
  760. {
  761. WindowData **p;
  762. FreeData(wd);
  763. if (wd->shell != NULL)
  764. XtDestroyWidget(wd->shell);
  765. if (wd->openDialog != NULL)
  766. XtDestroyWidget(wd->openDialog);
  767. if (wd->saveDialog != NULL)
  768. XtDestroyWidget(wd->saveDialog);
  769. /* remove from the global list */
  770. p = &windowList;
  771. while (*p != NULL) {
  772. if (*p == wd) {
  773. *p = wd->next;
  774. break;
  775. }
  776. p = &((*p)->next);
  777. }
  778. XtFree((char *)wd);
  779. }
  780. /*
  781. * Load a .template data file
  782. */
  783. static Boolean LoadFile(WindowData *wd, char *fileName)
  784. {
  785. FILE *fp;
  786. int np, i, x, y;
  787. char sig[100];
  788. if ((fp = fopen(fileName, "r")) == NULL)
  789. return False;
  790. if (fgets(sig, sizeof(sig), fp) == NULL) {
  791. fclose(fp);
  792. return False;
  793. }
  794. if (strcmp(sig, FileSignature) != 0) {
  795. fclose(fp);
  796. return False;
  797. }
  798. FreeData(wd);
  799. while (fscanf(fp, "%d %d", &x, &y) != EOF)
  800. AddPoint(wd, x, y);
  801. fclose(fp);
  802. if (wd->shell != NULL)
  803. SetTitle(wd->shell, fileName);
  804. wd->name = XtNewString(fileName);
  805. return True;
  806. }
  807. /*
  808. * Load a .template buffer
  809. */
  810. static Boolean LoadBuffer(WindowData *wd, void *buf, int len)
  811. {
  812. char *bufp = (char *)buf;
  813. char *endp = bufp + len;
  814. int r, x, y, l;
  815. char sig[100];
  816. (void) strncpy(sig, bufp, sizeof(FileSignature) - 1);
  817. sig[sizeof(FileSignature) - 1] = '\0';
  818. if (strcmp(sig, FileSignature) != 0)
  819. return False;
  820. bufp += sizeof(FileSignature) - 1;
  821. FreeData(wd);
  822. while (bufp < endp) {
  823. if (sscanf(bufp, "%d %d\n%n", &x, &y, &l) != 2)
  824. return False;
  825. AddPoint(wd, x, y);
  826. bufp += l;
  827. }
  828. if (wd->shell != NULL)
  829. SetTitle(wd->shell, NULL);
  830. return True;
  831. }
  832. static Tt_message
  833. HandleTtMedia(
  834. Tt_message msg,
  835. void *clientdata,
  836. Tttk_op op,
  837. Tt_status diagnosis,
  838. unsigned char *contents,
  839. int len,
  840. char *file,
  841. char *docname)
  842. {
  843. int mark = tt_mark();
  844. char *opstr = tt_message_op(msg);
  845. if (strcmp(opstr, "Edit") == 0) {
  846. if (file != NULL) {
  847. if (NewWindow(LOAD_FILE, file, 0))
  848. tt_message_reply(msg);
  849. else
  850. tttk_message_fail(msg, TT_ERR_OP, "open failed", False);
  851. } else if (contents != NULL && len > 0) {
  852. if (NewWindow(LOAD_BUFFER, (char *)contents, len))
  853. tt_message_reply(msg);
  854. else
  855. tttk_message_fail(msg, TT_ERR_OP, "load buffer failed", False);
  856. } else {
  857. tttk_message_fail(msg, TT_ERR_OP, "no file or buffer", False);
  858. }
  859. } else {
  860. tttk_message_fail(msg, TT_ERR_OP, "unsupported message", False);
  861. }
  862. tt_release(mark);
  863. tt_free((char *)contents);
  864. tt_free(file);
  865. tt_free(docname);
  866. tt_message_destroy(msg);
  867. return 0;
  868. }
  869. /*
  870. * Print the drawing data.
  871. *
  872. * This function is intentionally left blank.
  873. */
  874. static void PrintData(WindowData *wd)
  875. {
  876. FILE *PS;
  877. int i;
  878. PS = popen("/usr/bin/lp", "w");
  879. fputs("%!\n", PS);
  880. fputs("clippath pathbbox 0 exch translate pop pop pop\n", PS);
  881. fputs("1 -1 scale 72 72 translate\n", PS);
  882. fputs("newpath 0.5 setgray\n", PS);
  883. fputs("/S { 10 0 360 arc fill } def\n", PS);
  884. for (i = 0; i < wd->npoints; i++)
  885. fprintf(PS, "%d %d S\n", wd->points[i].x, wd->points[i].y);
  886. fputs("showpage\n", PS);
  887. (void) pclose(PS);
  888. }
  889. /*
  890. * Free drawing data structure
  891. */
  892. static void FreeData(WindowData *wd)
  893. {
  894. XtFree((char *)wd->points);
  895. XtFree(wd->name);
  896. wd->points = NULL;
  897. wd->name = NULL;
  898. wd->npoints = 0;
  899. wd->nalloc = 0;
  900. if (wd->shell != NULL)
  901. SetTitle(wd->shell, NULL);
  902. }
  903. /*
  904. * Add a point to the end of the drawing data structure.
  905. */
  906. static void AddPoint(WindowData *wd, int x, int y)
  907. {
  908. if (wd->npoints == wd->nalloc) {
  909. wd->nalloc += MallocInc;
  910. wd->points =
  911. (XPoint*)XtRealloc((char*)wd->points, wd->nalloc * sizeof(XPoint));
  912. }
  913. wd->points[wd->npoints].x = x;
  914. wd->points[wd->npoints].y = y;
  915. wd->npoints += 1;
  916. }
  917. /*
  918. * Draw an airbrush at (x,y)
  919. */
  920. static void DrawPoint(Widget w, int x, int y)
  921. {
  922. static Boolean initialized = False;
  923. static GC gc;
  924. static Pixmap pixmap;
  925. static unsigned int pixmapWidth, pixmapHeight;
  926. if (XtIsRealized(w) == False) return;
  927. if (initialized == False) {
  928. Pixel fg, bg;
  929. unsigned int tmpu;
  930. Window tmpw;
  931. int tmpi;
  932. XGCValues gcv;
  933. unsigned long gcm;
  934. XtVaGetValues(w, XmNforeground, &fg, XmNbackground, &bg, NULL);
  935. pixmap = XmGetPixmapByDepth(XtScreen(w), "template-brush.bm", 1, 0, 1);
  936. if (pixmap == XmUNSPECIFIED_PIXMAP) {
  937. XtAppWarning(appContext, "template:template-brush.bm not installed!");
  938. /* use hardcoded fallback bitmap */
  939. pixmap = XCreatePixmapFromBitmapData(XtDisplay(w), XtWindow(w),
  940. (char*)default_brush_bits,
  941. default_brush_width,
  942. default_brush_height,
  943. 1, 0, 1);
  944. }
  945. XGetGeometry(XtDisplay(w), pixmap, &tmpw, &tmpi, &tmpi,
  946. &pixmapWidth, &pixmapHeight, &tmpu, &tmpu);
  947. gcm = GCForeground | GCBackground | GCFillStyle | GCStipple;
  948. gcv.foreground = fg;
  949. gcv.background = bg;
  950. gcv.fill_style = FillStippled;
  951. gcv.stipple = pixmap;
  952. gc = XCreateGC(XtDisplay(w), XtWindow(w), gcm, &gcv);
  953. initialized = True;
  954. };
  955. XSetTSOrigin(XtDisplay(w), gc, x-pixmapWidth/2, y-pixmapWidth/2);
  956. XFillRectangle(XtDisplay(w), XtWindow(w), gc,
  957. x-pixmapWidth/2, y-pixmapWidth/2,
  958. pixmapWidth, pixmapHeight);
  959. }