diff options
author | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:53 +0000 |
---|---|---|
committer | Kaleb Keithley <kaleb@freedesktop.org> | 2003-11-14 15:54:53 +0000 |
commit | 729ceb19417c61603e659b2eb82d2e02fa388365 (patch) | |
tree | 7a40775a3d8ae140a7d4e0078b2284a3264d1cce |
R6.6 is the Xorg base-lineXORG-MAINXORG-STABLE
-rw-r--r-- | XClipboard.ad | 126 | ||||
-rw-r--r-- | xclipboard.c | 738 | ||||
-rw-r--r-- | xclipboard.man | 148 | ||||
-rw-r--r-- | xcutsel.c | 325 | ||||
-rw-r--r-- | xcutsel.man | 105 |
5 files changed, 1442 insertions, 0 deletions
diff --git a/XClipboard.ad b/XClipboard.ad new file mode 100644 index 0000000..7e3b1d2 --- /dev/null +++ b/XClipboard.ad @@ -0,0 +1,126 @@ +! $Xorg: XClipboard.ad,v 1.3 2000/08/17 19:54:12 cpqbld Exp $ +*Command*Font: -*-helvetica-bold-r-normal--*-120-*-*-*-*-iso8859-1 +*Label*Font: -*-helvetica-bold-r-normal--*-120-*-*-*-*-iso8859-1 +*Text*Font: -*-courier-medium-r-normal--*-120-*-*-*-*-iso8859-1 + +*quit.label: Quit +*quit.top: ChainTop +*quit.bottom: ChainTop +*quit.left: ChainLeft +*quit.right: ChainLeft +*quit.translations: #override \n\ + <Btn1Down>,<Btn1Up>:Quit() unset() + +*delete.label: Delete +*delete.fromHoriz: quit +*delete.top: ChainTop +*delete.bottom: ChainTop +*delete.left: ChainLeft +*delete.right: ChainLeft +*delete.translations: #override \n\ + <Btn1Down>,<Btn1Up>:DeleteClip() unset() + +*new.label: New +*new.fromHoriz: delete +*new.top: ChainTop +*new.bottom: ChainTop +*new.left: ChainLeft +*new.right: ChainLeft +*new.translations: #override \n\ + <Btn1Down>,<Btn1Up>:NewClip() unset() + +*save.label: Save +*save.fromHoriz: new +*save.top: ChainTop +*save.bottom: ChainTop +*save.left: ChainLeft +*save.right: ChainLeft +*save.translations: #override \n\ + <Btn1Down>,<Btn1Up>:Save() unset() + +*next.label: Next +*next.fromHoriz: save +*next.top: ChainTop +*next.bottom: ChainTop +*next.left: ChainLeft +*next.right: ChainLeft +*next.translations: #override \n\ + <Btn1Down>,<Btn1Up>:NextClip() unset() + +*prev.label: Prev +*prev.fromHoriz: next +*prev.top: ChainTop +*prev.bottom: ChainTop +*prev.left: ChainLeft +*prev.right: ChainLeft +*prev.translations: #override \n\ + <Btn1Down>,<Btn1Up>:PrevClip() unset() + +*index.fromHoriz: prev +*index.top: ChainTop +*index.bottom: ChainTop +*index.left: ChainLeft +*index.right: ChainLeft +*index.resizable: true + +*text.scrollVertical: WhenNeeded +*text.scrollHorizontal: WhenNeeded +*text.autoFill: on + +*text.fromVert: quit +*text.top: ChainTop +*text.bottom: ChainBottom +*text.left: ChainLeft +*text.right: ChainRight +*text.resizable: true +*text.width: 300 + +XClipboard.geometry: 300x200 +*ShapeStyle: oval +XClipboard.baseTranslations: #augment\n\ + <Message>WM_PROTOCOLS: WMProtocols()\n +*TransientShell.baseTranslations: #augment\n\ + <Message>WM_PROTOCOLS: WMProtocols()\n + +*fileDialog.label: Save to file: +*fileDialogShell.allowShellResize: true +*fileDialogShell.title: File Save + +*fileDialog*accept.label: Accept +*fileDialog*accept.translations: #override\ + <BtnUp>: AcceptSave() unset() +*fileDialog*value.translations: #override\ + <Key>Return: AcceptSave() \n\ + Ctrl<Key>S: no-op(ring-bell) \n\ + Ctrl<Key>R: no-op(ring-bell) \n\ + Ctrl<Key>M: no-op(ring-bell) \n\ + Ctrl<Key>J: no-op(ring-bell) \n\ + Meta<Key>I: no-op(ring-bell) +*fileDialog*value.baseTranslations: #override\ + <Key>Return: AcceptSave() \n\ + Ctrl<Key>S: no-op(ring-bell) \n\ + Ctrl<Key>R: no-op(ring-bell) \n\ + Ctrl<Key>M: no-op(ring-bell) \n\ + Ctrl<Key>J: no-op(ring-bell) \n\ + Meta<Key>I: no-op(ring-bell) + +*fileDialog*cancel.label: Cancel +*fileDialog*cancel.translations: #override\ + <BtnUp>:CancelSave() unset() + +*failDialog*Label.resizable: true +*failDialog.label: Can't write file +*failDialogShell.title: Error +*failDialogShell.allowShellResize: true + +*failDialog*continue.label: Continue +*failDialog*continue.translations: #override\ + <BtnUp>:FailContinue() unset() + +*failDialog*value.translations: #override\ + <Key>Return: FailContinue() \n\ + Ctrl<Key>S: no-op(ring-bell) \n\ + Ctrl<Key>R: no-op(ring-bell) \n\ + Ctrl<Key>M: no-op(ring-bell) \n\ + Ctrl<Key>J: no-op(ring-bell) \n\ + Meta<Key>I: no-op(ring-bell) diff --git a/xclipboard.c b/xclipboard.c new file mode 100644 index 0000000..f9e7418 --- /dev/null +++ b/xclipboard.c @@ -0,0 +1,738 @@ +/* + * $Xorg: xclipboard.c,v 1.4 2001/02/09 02:05:38 xorgcvs Exp $ + * + * +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * * + * Author: Ralph Swick, DEC/Project Athena + * Updated for R4: Chris D. Peterson, MIT X Consortium. + * Reauthored by: Keith Packard, MIT X Consortium. + */ + +#include <stdio.h> +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#include <X11/Xatom.h> + +#include <X11/Xmu/Atoms.h> +#include <X11/Xmu/StdSel.h> + +#include <X11/Shell.h> +#include <X11/Xaw/Form.h> +#include <X11/Xaw/Label.h> +#include <X11/Xaw/Command.h> +#include <X11/Xaw/AsciiText.h> +#include <X11/Xaw/Dialog.h> +#include <X11/Xaw/Cardinals.h> +#include <X11/Xfuncs.h> + +#ifdef XKB +#include <X11/extensions/XKBbells.h> +#endif + +#define Command commandWidgetClass +#define Label labelWidgetClass +#define Text asciiTextWidgetClass + +#define INFINITY 10000000 /* pretty big, huh? */ + +typedef struct _Clip { + struct _Clip *next, *prev; + char *clip; + char *filename; + int avail; +} ClipRec, *ClipPtr; + +extern char *malloc (); + +static Atom wm_delete_window; +static Atom wm_protocols; + +static long TextLength (w) + Widget w; +{ + return XawTextSourceScan (XawTextGetSource (w), + (XawTextPosition) 0, + XawstAll, XawsdRight, 1, TRUE); +} + +SaveClip (w, clip) + Widget w; + ClipPtr clip; +{ + Arg args[1]; + char *data; + int len; + Widget source; + + source = XawTextGetSource (w); + XtSetArg (args[0], XtNstring, &data); + XtGetValues (source, args, 1); + len = strlen (data); + if (len >= clip->avail) + { + if (clip->clip) + free (clip->clip); + clip->clip = malloc (len + 1); + if (!clip->clip) + clip->avail = 0; + else + clip->avail = len + 1; + } + if (clip->avail) + { + strcpy (clip->clip, data); + } +} + +RestoreClip (w, clip) + Widget w; + ClipPtr clip; +{ + Arg args[1]; + Widget source; + + source = XawTextGetSource (w); + XtSetArg (args[0], XtNstring, clip->clip); + XtSetValues (source, args, 1); +} + +/*ARGSUSED*/ +ClipPtr +NewClip (w, old) + Widget w; + ClipPtr old; +{ + ClipPtr newClip; + + newClip = (ClipPtr) malloc (sizeof (ClipRec)); + if (!newClip) + return newClip; + newClip->clip = 0; + newClip->avail = 0; + newClip->prev = old; + newClip->next = NULL; + newClip->filename = NULL; + if (old) + { + newClip->next = old->next; + old->next = newClip; + } + return newClip; +} + +/*ARGSUSED*/ +DeleteClip (w, clip) + Widget w; + ClipPtr clip; +{ + if (clip->prev) + clip->prev->next = clip->next; + if (clip->next) + clip->next->prev = clip->prev; + if (clip->clip) + free (clip->clip); + free ((char *) clip); +} + +static ClipPtr currentClip; +static Widget top; +static Widget text, nextButton, prevButton, indexLabel; +static Widget fileDialog, fileDialogShell; +static Widget failDialog, failDialogShell; + +static int +IndexCurrentClip () +{ + int i = 0; + ClipPtr clip; + + for (clip = currentClip; clip; clip = clip->prev) + i++; + return i; +} + +static void +set_button_state () +{ + Boolean prevvalid, nextvalid; + Arg arg; + char labelString[10]; + + prevvalid = currentClip->prev != NULL; + nextvalid = currentClip->next != NULL; + XtSetArg (arg, XtNsensitive, prevvalid); + XtSetValues (prevButton, &arg, ONE); + XtSetArg (arg, XtNsensitive, nextvalid); + XtSetValues (nextButton, &arg, ONE); + sprintf (labelString, "%d", IndexCurrentClip ()); + XtSetArg (arg, XtNlabel, labelString); + XtSetValues (indexLabel, &arg, ONE); +} + +/* ARGSUSED */ +static void +NextCurrentClip (w, ev, parms, np) + Widget w; + XEvent *ev; + String *parms; + Cardinal *np; +{ + if (currentClip->next) + { + SaveClip (text, currentClip); + currentClip = currentClip->next; + RestoreClip (text, currentClip); + set_button_state (); + } +} + +/* ARGSUSED */ +static void +PrevCurrentClip (w, ev, parms, np) + Widget w; + XEvent *ev; + String *parms; + Cardinal *np; +{ + if (currentClip->prev) + { + SaveClip (text, currentClip); + currentClip = currentClip->prev; + RestoreClip (text, currentClip); + set_button_state (); + } +} + +/* ARGSUSED */ +static void +DeleteCurrentClip (w, ev, parms, np) + Widget w; + XEvent *ev; + String *parms; + Cardinal *np; +{ + ClipPtr newCurrent; + + if (currentClip->prev) + newCurrent = currentClip->prev; + else + newCurrent = currentClip->next; + if (newCurrent) + { + DeleteClip (text, currentClip); + currentClip = newCurrent; + RestoreClip (text, currentClip); + } + else + EraseTextWidget (); + set_button_state (); +} + +/* ARGSUSED */ +static void +Quit (w, ev, parms, np) + Widget w; + XEvent *ev; + String *parms; + Cardinal *np; +{ + XtCloseDisplay (XtDisplay (text)); + exit (0); +} + +static void +CenterWidgetAtPoint (w, x, y) + Widget w; + int x, y; +{ + Arg args[2]; + Dimension width, height; + + XtSetArg(args[0], XtNwidth, &width); + XtSetArg(args[1], XtNheight, &height); + XtGetValues (w, args, 2); + x = x - (int) width / 2; + y = y - (int) height / 2; + if (x < 0) + x = 0; + else { + int scr_width = WidthOfScreen (XtScreen(w)); + if (x + (int)width > scr_width) + x = scr_width - width; + } + if (y < 0) + y = 0; + else { + int scr_height = HeightOfScreen (XtScreen(w)); + if (y + (int)height > scr_height) + y = scr_height - height; + } + XtSetArg(args[0], XtNx, x); + XtSetArg(args[1], XtNy, y); + XtSetValues (w, args, 2); +} + +static void +CenterWidgetOnEvent (w, e) + Widget w; + XEvent *e; +{ + CenterWidgetAtPoint (w, e->xbutton.x_root, e->xbutton.y_root); +} + +static void +CenterWidgetOnWidget (w, wT) + Widget w, wT; +{ + Position rootX, rootY; + Dimension width, height; + Arg args[2]; + + XtSetArg (args[0], XtNwidth, &width); + XtSetArg (args[1], XtNheight, &height); + XtGetValues (wT, args, 2); + XtTranslateCoords (wT, (Position) width/2, (Position) height/2, &rootX, &rootY); + CenterWidgetAtPoint (w, (int) rootX, (int) rootY); +} + +/*ARGSUSED*/ +static void +SaveToFile (w, e, argv, argc) + Widget w; + XEvent *e; + String *argv; + Cardinal *argc; +{ + Arg args[1]; + char *filename; + + filename = "clipboard"; + if (currentClip->filename) + filename = currentClip->filename; + XtSetArg(args[0], XtNvalue, filename); + XtSetValues (fileDialog, args, 1); + CenterWidgetOnEvent (fileDialogShell, e); + XtPopup (fileDialogShell, XtGrabNone); +} + +/*ARGSUSED*/ +static void +AcceptSaveFile (w, e, argv, argc) + Widget w; + XEvent *e; + String *argv; + Cardinal *argc; +{ + char *filename; + Boolean success; + Arg args[1]; + + filename = XawDialogGetValueString (fileDialog); + success = XawAsciiSaveAsFile (XawTextGetSource (text), filename); + XtPopdown (fileDialogShell); + if (!success) + { + char failMessage[1024]; + + sprintf (failMessage, "Can't open file \"%s\"", filename); + XtSetArg (args[0], XtNlabel, failMessage); + XtSetValues (failDialog, args, 1); + CenterWidgetOnEvent (failDialogShell, e); + XtPopup (failDialogShell, XtGrabNone); + } + else + { + if (currentClip->filename) + free (currentClip->filename); + currentClip->filename = malloc (strlen (filename) + 1); + if (currentClip->filename) + strcpy (currentClip->filename, filename); + } +} + +/* ARGSUSED */ +static void +CancelSaveFile (w, ev, parms, np) + Widget w; + XEvent *ev; + String *parms; + Cardinal *np; +{ + XtPopdown (fileDialogShell); +} + +/* ARGSUSED */ +static void +FailContinue (w, ev, parms, np) + Widget w; + XEvent *ev; + String *parms; + Cardinal *np; +{ + XtPopdown (failDialogShell); +} + +/*ARGSUSED*/ +static void WMProtocols(w, ev, params, n) + Widget w; + XEvent *ev; + String *params; + Cardinal *n; +{ + if (ev->type == ClientMessage && + ev->xclient.message_type == wm_protocols && + ev->xclient.data.l[0] == wm_delete_window) { + while (w && !XtIsShell(w)) + w = XtParent(w); + if (w == top) + Quit(w, ev, params, n); + else if (w == fileDialogShell) + CancelSaveFile(w, ev, params, n); + else if (w == failDialogShell) + FailContinue(w, ev, params, n); + } +} + +/* ARGUSED */ +static void +NewCurrentClip (w, ev, parms, np) + Widget w; + XEvent *ev; + String *parms; + Cardinal *np; +{ + NewCurrentClipContents ("", 0); +} + +NewCurrentClipContents (data, len) + char *data; + int len; +{ + XawTextBlock textBlock; + + SaveClip (text, currentClip); + + /* append new clips at the end */ + while (currentClip && currentClip->next) + currentClip = currentClip->next; + /* any trailing clips with no text get overwritten */ + if (strlen (currentClip->clip) != 0) + currentClip = NewClip (text, currentClip); + + textBlock.ptr = data; + textBlock.firstPos = 0; + textBlock.length = len; + textBlock.format = FMT8BIT; + if (XawTextReplace(text, 0, TextLength (text), &textBlock)) { +#ifdef XKB + XkbStdBell(XtDisplay(text), XtWindow(text), 0, XkbBI_Info); +#else + XBell( XtDisplay(text), 0); +#endif + } + set_button_state (); +} + +EraseTextWidget () +{ + XawTextBlock block; + + block.ptr = ""; + block.length = 0; + block.firstPos = 0; + block.format = FMT8BIT; + + XawTextReplace(text, 0, INFINITY, &block); + /* If this fails, too bad. */ +} + + +XtActionsRec xclipboard_actions[] = { + "NewClip", NewCurrentClip, + "NextClip", NextCurrentClip, + "PrevClip", PrevCurrentClip, + "DeleteClip", DeleteCurrentClip, + "Save", SaveToFile, + "AcceptSave", AcceptSaveFile, + "CancelSave", CancelSaveFile, + "FailContinue", FailContinue, + "Quit", Quit, + "WMProtocols", WMProtocols +}; + +static XrmOptionDescRec table[] = { + {"-w", "wrap", XrmoptionNoArg, "on"}, +/* {"-nw", "wrap", XrmoptionNoArg, "False"} */ +}; + +static void LoseSelection (); +static void InsertClipboard (); +static Boolean ConvertSelection(); +static Atom ManagerAtom, ClipboardAtom; + +/*ARGSUSED*/ +static void +InsertClipboard(w, client_data, selection, type, value, length, format) +Widget w; +XtPointer client_data; +Atom *selection, *type; +XtPointer value; +unsigned long *length; +int *format; +{ + if (*type != XT_CONVERT_FAIL) + NewCurrentClipContents ((char *) value, *length); + else + { + Arg arg; + XtSetArg (arg, XtNlabel, "CLIPBOARD selection conversion failed"); + XtSetValues (failDialog, &arg, 1); + CenterWidgetOnWidget (failDialogShell, text); + XtPopup (failDialogShell, XtGrabNone); +#ifdef XKB + XkbStdBell( XtDisplay(w), XtWindow(w), 0, XkbBI_MinorError ); +#else + XBell( XtDisplay(w), 0 ); +#endif + } + + XtOwnSelection(top, ClipboardAtom, CurrentTime, + ConvertSelection, LoseSelection, NULL); + XFree(value); +} + +static Boolean ConvertSelection(w, selection, target, + type, value, length, format) + Widget w; + Atom *selection, *target, *type; + XtPointer *value; + unsigned long *length; + int *format; +{ + Display* d = XtDisplay(w); + XSelectionRequestEvent* req = + XtGetSelectionRequest(w, *selection, (XtRequestId)NULL); + + if (*target == XA_TARGETS(d)) { + Atom* targetP; + Atom* std_targets; + unsigned long std_length; + XmuConvertStandardSelection(w, req->time, selection, target, type, + (XPointer*)&std_targets, &std_length, format); + *value = XtMalloc(sizeof(Atom)*(std_length + 5)); + targetP = *(Atom**)value; + *targetP++ = XA_STRING; + *targetP++ = XA_TEXT(d); + *targetP++ = XA_LENGTH(d); + *targetP++ = XA_LIST_LENGTH(d); + *targetP++ = XA_CHARACTER_POSITION(d); + *length = std_length + (targetP - (*(Atom **) value)); + memmove( (char*)targetP, (char*)std_targets, sizeof(Atom)*std_length); + XtFree((char*)std_targets); + *type = XA_ATOM; + *format = 32; + return True; + } + + if (*target == XA_LIST_LENGTH(d) || + *target == XA_LENGTH(d)) + { + long * temp; + + temp = (long *) XtMalloc(sizeof(long)); + if (*target == XA_LIST_LENGTH(d)) + *temp = 1L; + else /* *target == XA_LENGTH(d) */ + *temp = (long) TextLength (text); + + *value = (XPointer) temp; + *type = XA_INTEGER; + *length = 1L; + *format = 32; + return True; + } + + if (*target == XA_CHARACTER_POSITION(d)) + { + long * temp; + + temp = (long *) XtMalloc(2 * sizeof(long)); + temp[0] = (long) 0; + temp[1] = TextLength (text); + *value = (XPointer) temp; + *type = XA_SPAN(d); + *length = 2L; + *format = 32; + return True; + } + + if (*target == XA_STRING || + *target == XA_TEXT(d) || + *target == XA_COMPOUND_TEXT(d)) + { + extern char *_XawTextGetSTRING(); + if (*target == XA_COMPOUND_TEXT(d)) + *type = *target; + else + *type = XA_STRING; + *length = TextLength (text); + *value = _XawTextGetSTRING((TextWidget) text, 0, *length); + *format = 8; + return True; + } + + if (XmuConvertStandardSelection(w, req->time, selection, target, type, + (XPointer *)value, length, format)) + return True; + + return False; +} + +static void LoseSelection(w, selection) + Widget w; + Atom *selection; +{ + XtGetSelectionValue(w, *selection, XA_STRING, InsertClipboard, + NULL, CurrentTime); +} + +/*ARGSUSED*/ +static Boolean RefuseSelection(w, selection, target, + type, value, length, format) + Widget w; + Atom *selection, *target, *type; + XtPointer *value; + unsigned long *length; + int *format; +{ + return False; +} + +/*ARGSUSED*/ +static void LoseManager(w, selection) + Widget w; + Atom *selection; +{ + XtError("another clipboard has taken over control\n"); +} + +typedef struct { + Boolean wrap; +} ResourceData, *ResourceDataPtr; + +static ResourceData userOptions; + +#define Offset(field) XtOffsetOf(ResourceData, field) + +XtResource resources[] = { + {"wrap", "Wrap", XtRBoolean, sizeof(Boolean), + Offset(wrap), XtRImmediate, (XtPointer)False} +}; + +#undef Offset + +void +main(argc, argv) +int argc; +char **argv; +{ + Arg args[4]; + Cardinal n; + XtAppContext xtcontext; + Widget parent, quit, delete, new, save; + + XtSetLanguageProc(NULL, NULL, NULL); + + top = XtAppInitialize( &xtcontext, "XClipboard", table, XtNumber(table), + &argc, argv, NULL, NULL, 0); + + XtGetApplicationResources(top, (XtPointer)&userOptions, resources, + XtNumber(resources), NULL, 0); + + XtAppAddActions (xtcontext, + xclipboard_actions, XtNumber (xclipboard_actions)); + /* CLIPBOARD_MANAGER is a non-standard mechanism */ + ManagerAtom = XInternAtom(XtDisplay(top), "CLIPBOARD_MANAGER", False); + ClipboardAtom = XA_CLIPBOARD(XtDisplay(top)); + if (XGetSelectionOwner(XtDisplay(top), ManagerAtom)) + XtError("another clipboard is already running\n"); + + parent = XtCreateManagedWidget("form", formWidgetClass, top, NULL, ZERO); + quit = XtCreateManagedWidget("quit", Command, parent, NULL, ZERO); + delete = XtCreateManagedWidget("delete", Command, parent, NULL, ZERO); + new = XtCreateManagedWidget("new", Command, parent, NULL, ZERO); + save = XtCreateManagedWidget("save", Command, parent, NULL, ZERO); + nextButton = XtCreateManagedWidget("next", Command, parent, NULL, ZERO); + prevButton = XtCreateManagedWidget("prev", Command, parent, NULL, ZERO); + indexLabel = XtCreateManagedWidget("index", Label, parent, NULL, ZERO); + + n=0; + XtSetArg(args[n], XtNtype, XawAsciiString); n++; + XtSetArg(args[n], XtNeditType, XawtextEdit); n++; + if (userOptions.wrap) { + XtSetArg(args[n], XtNwrap, XawtextWrapWord); n++; + XtSetArg(args[n], XtNscrollHorizontal, False); n++; + } + + text = XtCreateManagedWidget( "text", Text, parent, args, n); + + currentClip = NewClip (text, (ClipPtr) 0); + + set_button_state (); + + fileDialogShell = XtCreatePopupShell("fileDialogShell", + transientShellWidgetClass, + top, NULL, ZERO); + fileDialog = XtCreateManagedWidget ("fileDialog", dialogWidgetClass, + fileDialogShell, NULL, ZERO); + XawDialogAddButton(fileDialog, "accept", NULL, NULL); + XawDialogAddButton(fileDialog, "cancel", NULL, NULL); + + failDialogShell = XtCreatePopupShell("failDialogShell", + transientShellWidgetClass, + top, NULL, ZERO); + failDialog = XtCreateManagedWidget ("failDialog", dialogWidgetClass, + failDialogShell, NULL, ZERO); + XawDialogAddButton (failDialog, "continue", NULL, NULL); + + XtRealizeWidget(top); + XtRealizeWidget(fileDialogShell); + XtRealizeWidget(failDialogShell); + XtOwnSelection(top, ManagerAtom, CurrentTime, + RefuseSelection, LoseManager, NULL); + if (XGetSelectionOwner (XtDisplay(top), ClipboardAtom)) { + LoseSelection (top, &ClipboardAtom); + } else { + XtOwnSelection(top, ClipboardAtom, CurrentTime, + ConvertSelection, LoseSelection, NULL); + } + wm_delete_window = XInternAtom(XtDisplay(top), "WM_DELETE_WINDOW", False); + wm_protocols = XInternAtom(XtDisplay(top), "WM_PROTOCOLS", False); + (void) XSetWMProtocols(XtDisplay(top), XtWindow(top), &wm_delete_window,1); + (void) XSetWMProtocols(XtDisplay(top), XtWindow(fileDialogShell), + &wm_delete_window,1); + (void) XSetWMProtocols(XtDisplay(top), XtWindow(failDialogShell), + &wm_delete_window,1); + XtAppMainLoop(xtcontext); +} diff --git a/xclipboard.man b/xclipboard.man new file mode 100644 index 0000000..23f13af --- /dev/null +++ b/xclipboard.man @@ -0,0 +1,148 @@ +.\" $Xorg: xclipboard.man,v 1.4 2001/02/09 02:05:39 xorgcvs Exp $ +.\" Copyright 1988, 1994, 1998 The Open Group +.\" +.\" Permission to use, copy, modify, distribute, and sell this software and its +.\" documentation for any purpose is hereby granted without fee, provided that +.\" the above copyright notice appear in all copies and that both that +.\" copyright notice and this permission notice appear in supporting +.\" documentation. +.\" +.\" The above copyright notice and this permission notice shall be included +.\" in all copies or substantial portions of the Software. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +.\" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +.\" IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +.\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +.\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +.\" OTHER DEALINGS IN THE SOFTWARE. +.\" +.\" Except as contained in this notice, the name of The Open Group shall +.\" not be used in advertising or otherwise to promote the sale, use or +.\" other dealings in this Software without prior written authorization +.\" from The Open Group. +.TH XCLIPBOARD 1 "Release 6.4" "X Version 11" +.SH NAME +xclipboard \- X clipboard client +.SH SYNOPSIS +\fBxclipboard\fP [ \fI\-toolkitoption\fP ... ] [ \fB\-w\fP ] +[ \fB\-nw\fP ] +.SH DESCRIPTION +The \fIxclipboard\fP program is used to collect and display text selections +that are sent to the CLIPBOARD by other clients. It is typically used to +save CLIPBOARD selections for later use. It stores each CLIPBOARD selection +as a separate string, each of which can be selected. Each time CLIPBOARD +is asserted by another application, \fIxclipboard\fP transfers the contents +of that selection to a new buffer and displays it in the text window. +Buffers are never automatically deleted, so you'll want to use the delete +button to get rid of useless items. +.PP +Since \fIxclipboard\fP uses a Text Widget to display the contents of the +clipboard, text sent to the CLIPBOARD may be re-selected for use in other +applications. \fIxclipboard\fP also responds to requests for the CLIPBOARD +selection from other clients by sending the entire contents of the currently +displayed buffer. +.PP +An \fIxclipboard\fP window has the following buttons across the top: +.TP 8 +.I quit +When this button is pressed, \fIxclipboard\fP exits. +.TP 8 +.I delete +When this button is pressed, the current buffer is deleted and the +next one displayed. +.TP 8 +.I new +Creates a new buffer with no contents. Useful in constructing a new +CLIPBOARD selection by hand. +.TP 8 +.I save +Displays a File Save dialog box. +Pressing the Accept button saves the currently +displayed buffer to the file specified in the text field. +.TP 8 +.I next +Displays the next buffer in the list. +.TP 8 +.I previous +Displays the previous buffer. +.SH OPTIONS +The \fIxclipboard\fP program accepts all of the standard X Toolkit command +line options as well as the following: +.TP 8 +.B \-w +This option indicates that lines of text that are too long to be displayed on +one line in the clipboard should wrap around to the following lines. +.TP 8 +.B \-nw +This option indicates that long lines of text should not wrap around. This +is the default behavior. +.SH WIDGETS +In order to specify resources, it is useful to know the hierarchy of +the widgets which compose \fIxclipboard\fR. In the notation below, +indentation indicates hierarchical structure. The widget class name +is given first, followed by the widget instance name. +.sp +.nf +.TA .5i 1.0i 1.5i +.ta .5i 1.0i 1.5i +XClipboard xclipboard + Form form + Command Quit + Command delete + Command new + Command Save + Command next + Command prev + Label index + Text text + TransientShell fileDialogShell + Dialog fileDialog + Label label + Command accept + Command cancel + Text value + TransientShell failDialogShell + Dialog failDialog + Label label + Command continue +.fi +.sp +.SH SENDING/RETRIEVING CLIPBOARD CONTENTS +Text is copied to the clipboard whenever a client asserts ownership of the +\fBCLIPBOARD\fP selection. Text is copied from the clipboard whenever a +client requests the contents of the \fBCLIPBOARD\fP selection. Examples of +event bindings that a user may wish to include in a resource configuration +file to use the clipboard are: +.sp +.nf +.TA .5i +.ta .5i 3.0i +*VT100.Translations: #override \\ + <Btn3Up>: select-end(CLIPBOARD) \\n\\ + <Btn2Up>: insert-selection(PRIMARY,CLIPBOARD) \\n\\ + <Btn2Down>: ignore () + +.fi +.sp +.SH "SEE ALSO" +X(1), xcutsel(1), xterm(1), individual client documentation for how to make a +selection and send it to the CLIPBOARD. +.SH ENVIRONMENT +.PP +.TP 8 +.B DISPLAY +to get the default host and display number. +.TP 8 +.B XENVIRONMENT +to get the name of a resource file that overrides the global resources +stored in the RESOURCE_MANAGER property. +.SH FILES +<XRoot>/lib/X11/app-defaults/XClipboard - specifies required resources +.SH AUTHOR +Ralph R. Swick, DEC/MIT Project Athena +.br +Chris D. Peterson, MIT X Consortium +.br +Keith Packard, MIT X Consortium diff --git a/xcutsel.c b/xcutsel.c new file mode 100644 index 0000000..e12ea29 --- /dev/null +++ b/xcutsel.c @@ -0,0 +1,325 @@ +/* + * $Xorg: xcutsel.c,v 1.4 2001/02/09 02:05:39 xorgcvs Exp $ + * + * +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * * + * Author: Ralph Swick, DEC/Project Athena + */ + +#include <stdio.h> +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#include <X11/Xatom.h> + +#include <X11/Xmu/Atoms.h> +#include <X11/Xmu/StdSel.h> + +#include <X11/Xaw/Command.h> +#include <X11/Xaw/Box.h> +#include <X11/Xaw/Cardinals.h> +#include <X11/Xfuncs.h> + +#ifdef XKB +#include <X11/extensions/XKBbells.h> +#endif + +static XrmOptionDescRec optionDesc[] = { + {"-selection", "selection", XrmoptionSepArg, NULL}, + {"-select", "selection", XrmoptionSepArg, NULL}, + {"-sel", "selection", XrmoptionSepArg, NULL}, + {"-s", "selection", XrmoptionSepArg, NULL}, + {"-cutbuffer", "cutBuffer", XrmoptionSepArg, NULL}, +}; + +typedef struct { + String selection_name; + int buffer; + Atom selection; + char* value; + int length; +} OptionsRec; + +OptionsRec options; + +#define Offset(field) XtOffsetOf(OptionsRec, field) + +static XtResource resources[] = { + {"selection", "Selection", XtRString, sizeof(String), + Offset(selection_name), XtRString, "PRIMARY"}, + {"cutBuffer", "CutBuffer", XtRInt, sizeof(int), + Offset(buffer), XtRImmediate, (XtPointer)0}, +}; + +#undef Offset + +typedef struct { + Widget button; + Boolean is_on; +} ButtonState; + +static ButtonState state; + +Syntax(call) + char *call; +{ + fprintf (stderr, "usage: %s [-selection name] [-cutbuffer number]\n", + call); + exit (1); +} + + +static void StoreBuffer(w, client_data, selection, type, value, length, format) + Widget w; + XtPointer client_data; + Atom *selection, *type; + XtPointer value; + unsigned long *length; + int *format; +{ + + if (*type == 0 || *type == XT_CONVERT_FAIL || *length == 0) { +#ifdef XKB + XkbStdBell( XtDisplay(w), XtWindow(w), 0, XkbBI_MinorError ); +#else + XBell( XtDisplay(w), 0 ); +#endif + return; + } + + XStoreBuffer( XtDisplay(w), (char*)value, (int)(*length), + options.buffer ); + + XtFree(value); +} + + +static Boolean ConvertSelection(w, selection, target, + type, value, length, format) + Widget w; + Atom *selection, *target, *type; + XtPointer *value; + unsigned long *length; + int *format; +{ + Display* d = XtDisplay(w); + XSelectionRequestEvent* req = + XtGetSelectionRequest(w, *selection, (XtRequestId)NULL); + + if (*target == XA_TARGETS(d)) { + Atom* targetP; + Atom* std_targets; + unsigned long std_length; + XmuConvertStandardSelection(w, req->time, selection, target, type, + (XPointer*)&std_targets, &std_length, format); + *value = XtMalloc(sizeof(Atom)*(std_length + 4)); + targetP = *(Atom**)value; + *length = std_length + 4; + *targetP++ = XA_STRING; + *targetP++ = XA_TEXT(d); + *targetP++ = XA_LENGTH(d); + *targetP++ = XA_LIST_LENGTH(d); +/* + *targetP++ = XA_CHARACTER_POSITION(d); +*/ + memmove( (char*)targetP, (char*)std_targets, sizeof(Atom)*std_length); + XtFree((char*)std_targets); + *type = XA_ATOM; + *format = 32; + return True; + } + if (*target == XA_STRING || *target == XA_TEXT(d)) { + *type = XA_STRING; + *value = XtMalloc((Cardinal) options.length); + memmove( (char *) *value, options.value, options.length); + *length = options.length; + *format = 8; + return True; + } + if (*target == XA_LIST_LENGTH(d)) { + long *temp = (long *) XtMalloc (sizeof(long)); + *temp = 1L; + *value = (XtPointer) temp; + *type = XA_INTEGER; + *length = 1; + *format = 32; + return True; + } + if (*target == XA_LENGTH(d)) { + long *temp = (long *) XtMalloc (sizeof(long)); + *temp = options.length; + *value = (XtPointer) temp; + *type = XA_INTEGER; + *length = 1; + *format = 32; + return True; + } +#ifdef notdef + if (*target == XA_CHARACTER_POSITION(d)) { + long *temp = (long *) XtMalloc (2 * sizeof(long)); + temp[0] = ctx->text.s.left + 1; + temp[1] = ctx->text.s.right; + *value = (XtPointer) temp; + *type = XA_SPAN(d); + *length = 2; + *format = 32; + return True; + } +#endif /* notdef */ + if (XmuConvertStandardSelection(w, req->time, selection, target, type, + (XPointer *)value, length, format)) + return True; + + /* else */ + return False; +} + + +static void SetButton(state, on) + ButtonState *state; + Boolean on; +{ + if (state->is_on != on) { + Arg args[2]; + Pixel fg, bg; + XtSetArg( args[0], XtNforeground, &fg ); + XtSetArg( args[1], XtNbackground, &bg ); + XtGetValues( state->button, args, TWO ); + args[0].value = (XtArgVal)bg; + args[1].value = (XtArgVal)fg; + XtSetValues( state->button, args, TWO ); + state->is_on = on; + } +} + + +static void LoseSelection(w, selection) + Widget w; + Atom *selection; +{ + if (options.value) { + XFree( options.value ); + options.value = NULL; + } + SetButton(&state, False); +} + + +/* ARGSUSED */ +static void Quit(w, closure, callData) + Widget w; + XtPointer closure; /* unused */ + XtPointer callData; /* unused */ +{ + XtCloseDisplay( XtDisplay(w) ); + exit(0); +} + + +/* ARGSUSED */ +static void GetSelection(w, closure, callData) + Widget w; + XtPointer closure; /* unused */ + XtPointer callData; /* unused */ +{ + XtGetSelectionValue(w, options.selection, XA_STRING, + StoreBuffer, NULL, + XtLastTimestampProcessed(XtDisplay(w))); +} + + +/* ARGSUSED */ +static void GetBuffer(w, closure, callData) + Widget w; + XtPointer closure; + XtPointer callData; /* unused */ +{ + if (options.value) XFree( options.value ); + options.value = + XFetchBuffer(XtDisplay(w), &options.length, options.buffer); + if (options.value != NULL) { + if (XtOwnSelection(w, options.selection, + XtLastTimestampProcessed(XtDisplay(w)), + ConvertSelection, LoseSelection, NULL)) + SetButton((ButtonState*)closure, True); + } +} + + +void main(argc, argv) + int argc; + char *argv[]; +{ + char label[100]; + Widget box, button; + XtAppContext appcon; + Widget shell; + XrmDatabase rdb; + + XtSetLanguageProc(NULL, NULL, NULL); + + shell = + XtAppInitialize( &appcon, "XCutsel", optionDesc, XtNumber(optionDesc), + &argc, argv, NULL, NULL, 0 ); + rdb = XtDatabase(XtDisplay(shell)); + + if (argc != 1) Syntax(argv[0]); + + XtGetApplicationResources( shell, (XtPointer)&options, + resources, XtNumber(resources), + NULL, ZERO ); + + options.value = NULL; + XmuInternStrings( XtDisplay(shell), &options.selection_name, ONE, + &options.selection ); + + box = XtCreateManagedWidget("box", boxWidgetClass, shell, NULL, ZERO); + + button = + XtCreateManagedWidget("quit", commandWidgetClass, box, NULL, ZERO); + XtAddCallback( button, XtNcallback, Quit, NULL ); + + /* %%% hack alert... */ + sprintf(label, "*label:copy %s to %d", + options.selection_name, + options.buffer); + XrmPutLineResource( &rdb, label ); + + button = + XtCreateManagedWidget("sel-cut", commandWidgetClass, box, NULL, ZERO); + XtAddCallback( button, XtNcallback, GetSelection, NULL ); + + sprintf(label, "*label:copy %d to %s", + options.buffer, + options.selection_name); + XrmPutLineResource( &rdb, label ); + + button = + XtCreateManagedWidget("cut-sel", commandWidgetClass, box, NULL, ZERO); + XtAddCallback( button, XtNcallback, GetBuffer, (XtPointer)&state ); + state.button = button; + state.is_on = False; + + XtRealizeWidget(shell); + XtAppMainLoop(appcon); +} diff --git a/xcutsel.man b/xcutsel.man new file mode 100644 index 0000000..992a4e4 --- /dev/null +++ b/xcutsel.man @@ -0,0 +1,105 @@ +.\" $Xorg: xcutsel.man,v 1.4 2001/02/09 02:05:39 xorgcvs Exp $ +.\" Copyright 1994, 1998 The Open Group +.\" +.\" Permission to use, copy, modify, distribute, and sell this software and its +.\" documentation for any purpose is hereby granted without fee, provided that +.\" the above copyright notice appear in all copies and that both that +.\" copyright notice and this permission notice appear in supporting +.\" documentation. +.\" +.\" The above copyright notice and this permission notice shall be included +.\" in all copies or substantial portions of the Software. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +.\" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +.\" IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +.\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +.\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +.\" OTHER DEALINGS IN THE SOFTWARE. +.\" +.\" Except as contained in this notice, the name of The Open Group shall +.\" not be used in advertising or otherwise to promote the sale, use or +.\" other dealings in this Software without prior written authorization +.\" from The Open Group. +.TH XCUTSEL 1 "Release 6.4" "X Version 11" +.SH NAME +xcutsel - interchange between cut buffer and selection +.SH SYNOPSIS +\fBxcutsel\fP [ \fI-toolkitoption\fP ...] [-selection \fIselection\fP] [-cutbuffer \fInumber\fP] +.SH DESCRIPTION +The \fIxcutsel\fP program is used to copy the current selection into a +cut buffer and to make a selection that contains the current contents of +the cut buffer. It acts as a bridge between applications that don't support +selections and those that do. +.PP +By default, \fIxcutsel\fP will use the selection named PRIMARY and the cut +buffer CUT_BUFFER0. Either or both of these can be overridden by command +line arguments or by resources. +.PP +An \fIxcutsel\fP window has the following buttons: +.TP 8 +.I " quit" +When this button is pressed, \fIxcutsel\fP exits. Any selections held by +\fIxcutsel\fP are automatically released. +.TP 8 +.I " copy PRIMARY to 0" +When this button is pressed, \fIxcutsel\fP copies the current selection into +the cut buffer. +.TP 8 +.I " copy 0 to PRIMARY" +When this button is pressed, \fIxcutsel\fP converts the current contents of +the cut buffer into the selection. +.PP +The button labels reflect the selection and cutbuffer selected by +command line options or through the resource database. +.PP +When the ``copy 0 to PRIMARY'' button is activated, the button will +remain inverted as long as \fIxcutsel\fP remains the owner of the +selection. This serves to remind you which client owns the current +selection. Note that the value of the selection remains constant; +if the cutbuffer is changed, you must again activate the copy button +to retrieve the new value when desired. +.SH OPTIONS +.I Xcutsel +accepts all of the standard X Toolkit command line options as well as the +following: +.TP 8 +.B \-selection \fIname\fP +This option specifies the name of the selection to use. The default is +PRIMARY. The only supported abbreviations for this option are ``-select'', +``-sel'' and ``-s'', as the standard toolkit option ``-selectionTimeout'' has a +similar name. +.TP 8 +.B \-cutbuffer \fInumber\fP +This option specifies the cut buffer to use. The default is cut buffer 0. +.SH X DEFAULTS +This program accepts all of the standard X Toolkit resource names and classes +as well as: +.TP 8 +.B "selection (\fPclass\fB Selection)" +This resource specifies the name of the selection to use. The default is +PRIMARY. +.TP 8 +.B "cutBuffer (\fPclass\fB CutBuffer)" +This resource specifies the number of the cut buffer to use. The default is 0. +.SH WIDGET NAMES +The following instance names may be used when user configuration of the +labels in them is desired: +.TP 8 +.B "sel-cut (\fPclass\fB Command)" +This is the ``copy SELECTION to BUFFER'' button. +.TP 8 +.B "cut-sel (\fPclass\fB Command)" +This is the ``copy BUFFER to SELECTION'' button. +.TP 8 +.B "quit (\fPclass\fB Command)" +This is the ``quit'' button. +.SH "SEE ALSO" +X(1), xclipboard(1), xterm(1), text widget documentation, individual client +documentation for how to make a selection. +.SH BUGS +There is no way to change the name of the selection or the number of the +cut buffer while the program is running. +.SH AUTHOR +Ralph R. Swick, DEC/MIT Project Athena |