xclipboard.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. /*
  2. Copyright 1989, 1998 The Open Group
  3. Permission to use, copy, modify, distribute, and sell this software and its
  4. documentation for any purpose is hereby granted without fee, provided that
  5. the above copyright notice appear in all copies and that both that
  6. copyright notice and this permission notice appear in supporting
  7. documentation.
  8. The above copyright notice and this permission notice shall be included in
  9. all copies or substantial portions of the Software.
  10. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  11. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  12. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  13. OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  14. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  15. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  16. Except as contained in this notice, the name of The Open Group shall not be
  17. used in advertising or otherwise to promote the sale, use or other dealings
  18. in this Software without prior written authorization from The Open Group.
  19. * *
  20. * Author: Ralph Swick, DEC/Project Athena
  21. * Updated for R4: Chris D. Peterson, MIT X Consortium.
  22. * Reauthored by: Keith Packard, MIT X Consortium.
  23. * UTF-8 and CTEXT support: Stanislav Maslovski <stanislav.maslovski@gmail.com>
  24. */
  25. #ifdef HAVE_CONFIG_H
  26. #include "config.h"
  27. #endif
  28. #include <stdio.h>
  29. #include <X11/Intrinsic.h>
  30. #include <X11/StringDefs.h>
  31. #include <X11/Xatom.h>
  32. #include <X11/Xmu/Atoms.h>
  33. #include <X11/Xmu/StdSel.h>
  34. #include <X11/Shell.h>
  35. #include <X11/Xaw/Form.h>
  36. #include <X11/Xaw/Label.h>
  37. #include <X11/Xaw/Command.h>
  38. #include <X11/Xaw/AsciiText.h>
  39. #include <X11/Xaw/Dialog.h>
  40. #include <X11/Xaw/Cardinals.h>
  41. #include <X11/IntrinsicP.h>
  42. #include <X11/Xaw/TextP.h>
  43. #include <X11/Xfuncs.h>
  44. #ifdef XKB
  45. #include <X11/extensions/XKBbells.h>
  46. #endif
  47. #include <stdlib.h>
  48. #define Command commandWidgetClass
  49. #define Label labelWidgetClass
  50. #define Text asciiTextWidgetClass
  51. #define INFINITY 10000000 /* pretty big, huh? */
  52. typedef struct _Clip {
  53. struct _Clip *next, *prev;
  54. char *clip;
  55. char *filename;
  56. size_t avail;
  57. } ClipRec, *ClipPtr;
  58. static Atom wm_delete_window;
  59. static Atom wm_protocols;
  60. static void EraseTextWidget ( void );
  61. static void NewCurrentClipContents ( char *data, int len );
  62. static String fallback_resources[] = {
  63. "*international: true",
  64. NULL
  65. };
  66. static long
  67. TextLength(Widget w)
  68. {
  69. return XawTextSourceScan (XawTextGetSource (w),
  70. (XawTextPosition) 0,
  71. XawstAll, XawsdRight, 1, TRUE);
  72. }
  73. static void
  74. SaveClip(Widget w, ClipPtr clip)
  75. {
  76. Arg args[1];
  77. char *data;
  78. size_t len;
  79. Widget source;
  80. source = XawTextGetSource (w);
  81. XtSetArg (args[0], XtNstring, &data);
  82. XtGetValues (source, args, 1);
  83. len = strlen (data);
  84. if (len >= clip->avail)
  85. {
  86. if (clip->clip)
  87. free (clip->clip);
  88. clip->clip = malloc (len + 1);
  89. if (!clip->clip)
  90. clip->avail = 0;
  91. else
  92. clip->avail = len + 1;
  93. }
  94. if (clip->avail)
  95. {
  96. strcpy (clip->clip, data);
  97. }
  98. }
  99. static void
  100. RestoreClip(Widget w, ClipPtr clip)
  101. {
  102. Arg args[1];
  103. Widget source;
  104. source = XawTextGetSource (w);
  105. XtSetArg (args[0], XtNstring, clip->clip);
  106. XtSetValues (source, args, 1);
  107. }
  108. /*ARGSUSED*/
  109. static ClipPtr
  110. NewClip(Widget w, ClipPtr old)
  111. {
  112. ClipPtr newClip;
  113. newClip = (ClipPtr) malloc (sizeof (ClipRec));
  114. if (!newClip)
  115. return newClip;
  116. newClip->clip = NULL;
  117. newClip->avail = 0;
  118. newClip->prev = old;
  119. newClip->next = NULL;
  120. newClip->filename = NULL;
  121. if (old)
  122. {
  123. newClip->next = old->next;
  124. old->next = newClip;
  125. }
  126. return newClip;
  127. }
  128. /*ARGSUSED*/
  129. static void
  130. DeleteClip(Widget w, ClipPtr clip)
  131. {
  132. if (clip->prev)
  133. clip->prev->next = clip->next;
  134. if (clip->next)
  135. clip->next->prev = clip->prev;
  136. if (clip->clip)
  137. free (clip->clip);
  138. free ((char *) clip);
  139. }
  140. static ClipPtr currentClip;
  141. static Widget top;
  142. static Widget text, nextButton, prevButton, indexLabel;
  143. static Widget fileDialog, fileDialogShell;
  144. static Widget failDialog, failDialogShell;
  145. static int
  146. IndexCurrentClip (void)
  147. {
  148. int i = 0;
  149. ClipPtr clip;
  150. for (clip = currentClip; clip; clip = clip->prev)
  151. i++;
  152. return i;
  153. }
  154. static void
  155. set_button_state (void)
  156. {
  157. Boolean prevvalid, nextvalid;
  158. Arg arg;
  159. char labelString[10];
  160. prevvalid = currentClip->prev != NULL;
  161. nextvalid = currentClip->next != NULL;
  162. XtSetArg (arg, XtNsensitive, prevvalid);
  163. XtSetValues (prevButton, &arg, ONE);
  164. XtSetArg (arg, XtNsensitive, nextvalid);
  165. XtSetValues (nextButton, &arg, ONE);
  166. snprintf (labelString, sizeof(labelString), "%d", IndexCurrentClip ());
  167. XtSetArg (arg, XtNlabel, labelString);
  168. XtSetValues (indexLabel, &arg, ONE);
  169. }
  170. /* ARGSUSED */
  171. static void
  172. NextCurrentClip(Widget w, XEvent *ev, String *parms, Cardinal *np)
  173. {
  174. if (currentClip->next)
  175. {
  176. SaveClip (text, currentClip);
  177. currentClip = currentClip->next;
  178. RestoreClip (text, currentClip);
  179. set_button_state ();
  180. }
  181. }
  182. /* ARGSUSED */
  183. static void
  184. PrevCurrentClip(Widget w, XEvent *ev, String *parms, Cardinal *np)
  185. {
  186. if (currentClip->prev)
  187. {
  188. SaveClip (text, currentClip);
  189. currentClip = currentClip->prev;
  190. RestoreClip (text, currentClip);
  191. set_button_state ();
  192. }
  193. }
  194. /* ARGSUSED */
  195. static void
  196. DeleteCurrentClip(Widget w, XEvent *ev, String *parms, Cardinal *np)
  197. {
  198. ClipPtr newCurrent;
  199. if (currentClip->prev)
  200. newCurrent = currentClip->prev;
  201. else
  202. newCurrent = currentClip->next;
  203. if (newCurrent)
  204. {
  205. DeleteClip (text, currentClip);
  206. currentClip = newCurrent;
  207. RestoreClip (text, currentClip);
  208. }
  209. else
  210. EraseTextWidget ();
  211. set_button_state ();
  212. }
  213. /* ARGSUSED */
  214. static void _X_NORETURN
  215. Quit(Widget w, XEvent *ev, String *parms, Cardinal *np)
  216. {
  217. XtCloseDisplay (XtDisplay (text));
  218. exit (0);
  219. }
  220. static void
  221. CenterWidgetAtPoint(Widget w, int x, int y)
  222. {
  223. Arg args[2];
  224. Dimension width, height;
  225. XtSetArg(args[0], XtNwidth, &width);
  226. XtSetArg(args[1], XtNheight, &height);
  227. XtGetValues (w, args, 2);
  228. x = x - (int) width / 2;
  229. y = y - (int) height / 2;
  230. if (x < 0)
  231. x = 0;
  232. else {
  233. int scr_width = WidthOfScreen (XtScreen(w));
  234. if (x + (int)width > scr_width)
  235. x = scr_width - width;
  236. }
  237. if (y < 0)
  238. y = 0;
  239. else {
  240. int scr_height = HeightOfScreen (XtScreen(w));
  241. if (y + (int)height > scr_height)
  242. y = scr_height - height;
  243. }
  244. XtSetArg(args[0], XtNx, x);
  245. XtSetArg(args[1], XtNy, y);
  246. XtSetValues (w, args, 2);
  247. }
  248. static void
  249. CenterWidgetOnEvent(Widget w, XEvent *e)
  250. {
  251. CenterWidgetAtPoint (w, e->xbutton.x_root, e->xbutton.y_root);
  252. }
  253. static void
  254. CenterWidgetOnWidget(Widget w, Widget wT)
  255. {
  256. Position rootX, rootY;
  257. Dimension width, height;
  258. Arg args[2];
  259. XtSetArg (args[0], XtNwidth, &width);
  260. XtSetArg (args[1], XtNheight, &height);
  261. XtGetValues (wT, args, 2);
  262. XtTranslateCoords (wT, (Position) width/2, (Position) height/2, &rootX, &rootY);
  263. CenterWidgetAtPoint (w, (int) rootX, (int) rootY);
  264. }
  265. /*ARGSUSED*/
  266. static void
  267. SaveToFile(Widget w, XEvent *e, String *argv, Cardinal *argc)
  268. {
  269. Arg args[1];
  270. char *filename;
  271. filename = "clipboard";
  272. if (currentClip->filename)
  273. filename = currentClip->filename;
  274. XtSetArg(args[0], XtNvalue, filename);
  275. XtSetValues (fileDialog, args, 1);
  276. CenterWidgetOnEvent (fileDialogShell, e);
  277. XtPopup (fileDialogShell, XtGrabNone);
  278. }
  279. /*ARGSUSED*/
  280. static void
  281. AcceptSaveFile(Widget w, XEvent *e, String *argv, Cardinal *argc)
  282. {
  283. char *filename;
  284. Bool success;
  285. Arg args[1];
  286. filename = XawDialogGetValueString (fileDialog);
  287. success = XawAsciiSaveAsFile (XawTextGetSource (text), filename);
  288. XtPopdown (fileDialogShell);
  289. if (!success)
  290. {
  291. char *failMessage;
  292. XtAsprintf (&failMessage, "Can't open file \"%s\"", filename);
  293. XtSetArg (args[0], XtNlabel, failMessage);
  294. XtSetValues (failDialog, args, 1);
  295. CenterWidgetOnEvent (failDialogShell, e);
  296. XtPopup (failDialogShell, XtGrabNone);
  297. XtFree (failMessage);
  298. }
  299. else
  300. {
  301. if (currentClip->filename)
  302. free (currentClip->filename);
  303. currentClip->filename = strdup (filename);
  304. }
  305. }
  306. /* ARGSUSED */
  307. static void
  308. CancelSaveFile(Widget w, XEvent *ev, String *parms, Cardinal *np)
  309. {
  310. XtPopdown (fileDialogShell);
  311. }
  312. /* ARGSUSED */
  313. static void
  314. FailContinue(Widget w, XEvent *ev, String *parms, Cardinal *np)
  315. {
  316. XtPopdown (failDialogShell);
  317. }
  318. /*ARGSUSED*/
  319. static void
  320. WMProtocols(Widget w, XEvent *ev, String *params, Cardinal *n)
  321. {
  322. if (ev->type == ClientMessage &&
  323. ev->xclient.message_type == wm_protocols &&
  324. ev->xclient.data.l[0] == (long) wm_delete_window) {
  325. while (w && !XtIsShell(w))
  326. w = XtParent(w);
  327. if (w == top)
  328. Quit(w, ev, params, n);
  329. else if (w == fileDialogShell)
  330. CancelSaveFile(w, ev, params, n);
  331. else if (w == failDialogShell)
  332. FailContinue(w, ev, params, n);
  333. }
  334. }
  335. /* ARGUSED */
  336. static void
  337. NewCurrentClip(Widget w, XEvent *ev, String *parms, Cardinal *np)
  338. {
  339. NewCurrentClipContents ("", 0);
  340. }
  341. static void
  342. NewCurrentClipContents(char *data, int len)
  343. {
  344. XawTextBlock textBlock;
  345. SaveClip (text, currentClip);
  346. /* append new clips at the end */
  347. while (currentClip && currentClip->next)
  348. currentClip = currentClip->next;
  349. /* any trailing clips with no text get overwritten */
  350. if (strlen (currentClip->clip) != 0)
  351. currentClip = NewClip (text, currentClip);
  352. textBlock.ptr = data;
  353. textBlock.firstPos = 0;
  354. textBlock.length = len;
  355. textBlock.format = FMT8BIT;
  356. if (XawTextReplace(text, 0, TextLength (text), &textBlock)) {
  357. #ifdef XKB
  358. XkbStdBell(XtDisplay(text), XtWindow(text), 0, XkbBI_Info);
  359. #else
  360. XBell( XtDisplay(text), 0);
  361. #endif
  362. }
  363. set_button_state ();
  364. }
  365. static void
  366. EraseTextWidget(void)
  367. {
  368. XawTextBlock block;
  369. block.ptr = "";
  370. block.length = 0;
  371. block.firstPos = 0;
  372. block.format = FMT8BIT;
  373. XawTextReplace(text, 0, INFINITY, &block);
  374. /* If this fails, too bad. */
  375. }
  376. static XtActionsRec xclipboard_actions[] = {
  377. { "NewClip", NewCurrentClip },
  378. { "NextClip", NextCurrentClip },
  379. { "PrevClip", PrevCurrentClip },
  380. { "DeleteClip", DeleteCurrentClip },
  381. { "Save", SaveToFile },
  382. { "AcceptSave", AcceptSaveFile },
  383. { "CancelSave", CancelSaveFile },
  384. { "FailContinue", FailContinue },
  385. { "Quit", Quit },
  386. { "WMProtocols", WMProtocols }
  387. };
  388. static XrmOptionDescRec table[] = {
  389. {"-w", "wrap", XrmoptionNoArg, "on"},
  390. /* {"-nw", "wrap", XrmoptionNoArg, "False"} */
  391. };
  392. static Boolean ConvertSelection ( Widget w, Atom *selection, Atom *target,
  393. Atom *type, XtPointer *value,
  394. unsigned long *length, int *format );
  395. static void LoseSelection ( Widget w, Atom *selection );
  396. static Atom ManagerAtom, ClipboardAtom;
  397. /*ARGSUSED*/
  398. static void
  399. InsertClipboard(Widget w, XtPointer client_data, Atom *selection,
  400. Atom *type, XtPointer value, unsigned long *length,
  401. int *format)
  402. {
  403. Display *d = XtDisplay(w);
  404. Atom target = (Atom)client_data;
  405. Boolean convert_failed = (*type == XT_CONVERT_FAIL);
  406. if (!convert_failed)
  407. {
  408. char **list;
  409. int i, ret, count;
  410. XTextProperty prop;
  411. prop.value = value;
  412. prop.nitems = *length;
  413. prop.format = *format;
  414. prop.encoding = *type;
  415. ret = XmbTextPropertyToTextList(d, &prop, &list, &count);
  416. if (ret >= Success)
  417. {
  418. /* manuals say something about multiple strings in a disjoint
  419. text selection (?), it should be harmless to get them all */
  420. for (i = 0; i < count; i++)
  421. NewCurrentClipContents(list[i], strlen(list[i]));
  422. XFreeStringList(list);
  423. } else
  424. convert_failed = True;
  425. XFree(value);
  426. }
  427. if (convert_failed) {
  428. /* if UTF8_STRING failed try COMPOUND_TEXT */
  429. if (target == XA_UTF8_STRING(d))
  430. {
  431. XtGetSelectionValue(w, *selection, XA_COMPOUND_TEXT(d),
  432. InsertClipboard,
  433. (XtPointer)(XA_COMPOUND_TEXT(d)),
  434. CurrentTime);
  435. return;
  436. }
  437. /* if COMPOUND_TEXT failed try STRING */
  438. else if (target == XA_COMPOUND_TEXT(d))
  439. {
  440. XtGetSelectionValue(w, *selection, XA_STRING,
  441. InsertClipboard,
  442. NULL,
  443. CurrentTime);
  444. return;
  445. }
  446. /* all conversions failed */
  447. else
  448. {
  449. Arg arg;
  450. XtSetArg (arg, XtNlabel, "CLIPBOARD selection conversion failed");
  451. XtSetValues (failDialog, &arg, 1);
  452. CenterWidgetOnWidget (failDialogShell, text);
  453. XtPopup (failDialogShell, XtGrabNone);
  454. #ifdef XKB
  455. XkbStdBell (d, XtWindow(w), 0, XkbBI_MinorError);
  456. #else
  457. XBell (d, 0);
  458. #endif
  459. }
  460. }
  461. XtOwnSelection(top, ClipboardAtom, CurrentTime,
  462. ConvertSelection, LoseSelection, NULL);
  463. }
  464. static Boolean
  465. ConvertSelection(Widget w, Atom *selection, Atom *target,
  466. Atom *type, XtPointer *value, unsigned long *length,
  467. int *format)
  468. {
  469. Display* d = XtDisplay(w);
  470. XSelectionRequestEvent* req =
  471. XtGetSelectionRequest(w, *selection, (XtRequestId)NULL);
  472. if (*target == XA_TARGETS(d)) {
  473. Atom* targetP;
  474. Atom* std_targets;
  475. unsigned long std_length;
  476. XmuConvertStandardSelection(w, req->time, selection, target, type,
  477. (XPointer*)&std_targets, &std_length,
  478. format);
  479. *value = XtMalloc(sizeof(Atom)*(std_length + 7));
  480. targetP = *(Atom**)value;
  481. *targetP++ = XA_STRING;
  482. *targetP++ = XA_TEXT(d);
  483. *targetP++ = XA_UTF8_STRING(d);
  484. *targetP++ = XA_COMPOUND_TEXT(d);
  485. *targetP++ = XA_LENGTH(d);
  486. *targetP++ = XA_LIST_LENGTH(d);
  487. *targetP++ = XA_CHARACTER_POSITION(d);
  488. *length = std_length + (targetP - (*(Atom **) value));
  489. memmove( (char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
  490. XtFree((char*)std_targets);
  491. *type = XA_ATOM;
  492. *format = 32;
  493. return True;
  494. }
  495. if (*target == XA_LIST_LENGTH(d) ||
  496. *target == XA_LENGTH(d))
  497. {
  498. long * temp;
  499. temp = (long *) XtMalloc(sizeof(long));
  500. if (*target == XA_LIST_LENGTH(d))
  501. *temp = 1L;
  502. else /* *target == XA_LENGTH(d) */
  503. *temp = (long) TextLength (text);
  504. *value = (XPointer) temp;
  505. *type = XA_INTEGER;
  506. *length = 1L;
  507. *format = 32;
  508. return True;
  509. }
  510. if (*target == XA_CHARACTER_POSITION(d))
  511. {
  512. long * temp;
  513. temp = (long *) XtMalloc(2 * sizeof(long));
  514. temp[0] = (long) 0;
  515. temp[1] = TextLength (text);
  516. *value = (XPointer) temp;
  517. *type = XA_SPAN(d);
  518. *length = 2L;
  519. *format = 32;
  520. return True;
  521. }
  522. if (*target == XA_STRING ||
  523. *target == XA_TEXT(d) ||
  524. *target == XA_UTF8_STRING(d) ||
  525. *target == XA_COMPOUND_TEXT(d))
  526. {
  527. Arg args[1];
  528. Widget source;
  529. XTextProperty prop;
  530. int ret, style = XStdICCTextStyle; /* a safe default for TEXT */
  531. char *data;
  532. source = XawTextGetSource (text);
  533. XtSetArg (args[0], XtNstring, &data);
  534. XtGetValues (source, args, 1);
  535. if (*target == XA_UTF8_STRING(d))
  536. style = XUTF8StringStyle;
  537. else if (*target == XA_COMPOUND_TEXT(d))
  538. style = XCompoundTextStyle;
  539. else if (*target == XA_STRING)
  540. style = XStringStyle;
  541. ret = XmbTextListToTextProperty (d, &data, 1, style, &prop);
  542. if (ret >= Success) {
  543. *length = prop.nitems;
  544. *value = prop.value;
  545. *type = prop.encoding;
  546. *format = prop.format;
  547. return True;
  548. } else
  549. return False;
  550. }
  551. if (XmuConvertStandardSelection(w, req->time, selection, target, type,
  552. (XPointer *) value, length, format))
  553. return True;
  554. return False;
  555. }
  556. static void
  557. LoseSelection(Widget w, Atom *selection)
  558. {
  559. Display *d = XtDisplay(w);
  560. XtGetSelectionValue(w, *selection, XA_UTF8_STRING(d), InsertClipboard,
  561. (XtPointer)(XA_UTF8_STRING(d)), CurrentTime);
  562. }
  563. /*ARGSUSED*/
  564. static Boolean
  565. RefuseSelection(Widget w, Atom *selection, Atom *target,
  566. Atom *type, XtPointer *value, unsigned long *length,
  567. int *format)
  568. {
  569. return False;
  570. }
  571. /*ARGSUSED*/
  572. static void
  573. LoseManager(Widget w, Atom *selection)
  574. {
  575. XtError("another clipboard has taken over control\n");
  576. }
  577. typedef struct {
  578. Boolean wrap;
  579. } ResourceData, *ResourceDataPtr;
  580. static ResourceData userOptions;
  581. #define Offset(field) XtOffsetOf(ResourceData, field)
  582. static XtResource resources[] = {
  583. {"wrap", "Wrap", XtRBoolean, sizeof(Boolean),
  584. Offset(wrap), XtRImmediate, (XtPointer)False}
  585. };
  586. #undef Offset
  587. int
  588. main(int argc, char *argv[])
  589. {
  590. Arg args[4];
  591. Cardinal n;
  592. XtAppContext xtcontext;
  593. Widget parent;
  594. XtSetLanguageProc(NULL, NULL, NULL);
  595. top = XtAppInitialize( &xtcontext, "XClipboard", table, XtNumber(table),
  596. &argc, argv, fallback_resources, NULL, 0);
  597. XtGetApplicationResources(top, (XtPointer)&userOptions, resources,
  598. XtNumber(resources), NULL, 0);
  599. XtAppAddActions (xtcontext,
  600. xclipboard_actions, XtNumber (xclipboard_actions));
  601. /* CLIPBOARD_MANAGER is a non-standard mechanism */
  602. ManagerAtom = XInternAtom(XtDisplay(top), "CLIPBOARD_MANAGER", False);
  603. ClipboardAtom = XA_CLIPBOARD(XtDisplay(top));
  604. if (XGetSelectionOwner(XtDisplay(top), ManagerAtom))
  605. XtError("another clipboard is already running\n");
  606. parent = XtCreateManagedWidget("form", formWidgetClass, top, NULL, ZERO);
  607. (void) XtCreateManagedWidget("quit", Command, parent, NULL, ZERO);
  608. (void) XtCreateManagedWidget("delete", Command, parent, NULL, ZERO);
  609. (void) XtCreateManagedWidget("new", Command, parent, NULL, ZERO);
  610. (void) XtCreateManagedWidget("save", Command, parent, NULL, ZERO);
  611. nextButton = XtCreateManagedWidget("next", Command, parent, NULL, ZERO);
  612. prevButton = XtCreateManagedWidget("prev", Command, parent, NULL, ZERO);
  613. indexLabel = XtCreateManagedWidget("index", Label, parent, NULL, ZERO);
  614. n=0;
  615. XtSetArg(args[n], XtNtype, XawAsciiString); n++;
  616. XtSetArg(args[n], XtNeditType, XawtextEdit); n++;
  617. if (userOptions.wrap) {
  618. XtSetArg(args[n], XtNwrap, XawtextWrapWord); n++;
  619. XtSetArg(args[n], XtNscrollHorizontal, False); n++;
  620. }
  621. text = XtCreateManagedWidget( "text", Text, parent, args, n);
  622. currentClip = NewClip (text, (ClipPtr) 0);
  623. set_button_state ();
  624. fileDialogShell = XtCreatePopupShell("fileDialogShell",
  625. transientShellWidgetClass,
  626. top, NULL, ZERO);
  627. fileDialog = XtCreateManagedWidget ("fileDialog", dialogWidgetClass,
  628. fileDialogShell, NULL, ZERO);
  629. XawDialogAddButton(fileDialog, "accept", NULL, NULL);
  630. XawDialogAddButton(fileDialog, "cancel", NULL, NULL);
  631. failDialogShell = XtCreatePopupShell("failDialogShell",
  632. transientShellWidgetClass,
  633. top, NULL, ZERO);
  634. failDialog = XtCreateManagedWidget ("failDialog", dialogWidgetClass,
  635. failDialogShell, NULL, ZERO);
  636. XawDialogAddButton (failDialog, "continue", NULL, NULL);
  637. XtRealizeWidget(top);
  638. XtRealizeWidget(fileDialogShell);
  639. XtRealizeWidget(failDialogShell);
  640. XtOwnSelection(top, ManagerAtom, CurrentTime,
  641. RefuseSelection, LoseManager, NULL);
  642. if (XGetSelectionOwner (XtDisplay(top), ClipboardAtom)) {
  643. LoseSelection (top, &ClipboardAtom);
  644. } else {
  645. XtOwnSelection(top, ClipboardAtom, CurrentTime,
  646. ConvertSelection, LoseSelection, NULL);
  647. }
  648. wm_delete_window = XInternAtom(XtDisplay(top), "WM_DELETE_WINDOW", False);
  649. wm_protocols = XInternAtom(XtDisplay(top), "WM_PROTOCOLS", False);
  650. (void) XSetWMProtocols(XtDisplay(top), XtWindow(top), &wm_delete_window,1);
  651. (void) XSetWMProtocols(XtDisplay(top), XtWindow(fileDialogShell),
  652. &wm_delete_window,1);
  653. (void) XSetWMProtocols(XtDisplay(top), XtWindow(failDialogShell),
  654. &wm_delete_window,1);
  655. XtAppMainLoop(xtcontext);
  656. exit(0);
  657. }