215 lines
5.3 KiB
C
215 lines
5.3 KiB
C
/* This file is part of the Project Athena Zephyr Notification System.
|
|
* It is one of the source files comprising zwgc, the Zephyr WindowGram
|
|
* client.
|
|
*
|
|
* Created by: Marc Horowitz <marc@athena.mit.edu>
|
|
*
|
|
* $Id$
|
|
*
|
|
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
|
|
* For copying and distribution information, see the file
|
|
* "mit-copyright.h".
|
|
*/
|
|
|
|
#include <sysdep.h>
|
|
|
|
#if (!defined(lint) && !defined(SABER))
|
|
static const char rcsid_xselect_c[] = "$Id$";
|
|
#endif
|
|
|
|
#include <zephyr/mit-copyright.h>
|
|
|
|
/* xselect.c - ICCCM compliant cut-and-paste */
|
|
/* also includes some other ICCCMisms, such as the WM_PROTOCOL handling */
|
|
|
|
#ifndef X_DISPLAY_MISSING
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xproto.h>
|
|
#include <X11/Xatom.h>
|
|
#include "new_string.h"
|
|
#include "xselect.h"
|
|
|
|
extern char *getSelectedText(void);
|
|
|
|
static Time ownership_start = CurrentTime;
|
|
static Time ownership_end = CurrentTime;
|
|
Atom XA_WM_PROTOCOLS,XA_WM_DELETE_WINDOW;
|
|
static Atom ZA_TARGETS,ZA_MULTIPLE,ZA_TIMESTAMP,ZA_ATOM_PAIR;
|
|
|
|
static struct _ZAtom {
|
|
Atom *patom;
|
|
char *name;
|
|
} ZAtom[] = {
|
|
{&XA_WM_PROTOCOLS,"WM_PROTOCOLS"},
|
|
{&XA_WM_DELETE_WINDOW,"WM_DELETE_WINDOW"},
|
|
{&ZA_TARGETS,"TARGETS"},
|
|
{&ZA_MULTIPLE,"MULTIPLE"},
|
|
{&ZA_TIMESTAMP,"TIMESTAMP"},
|
|
{&ZA_ATOM_PAIR,"ATOM_PAIR"}
|
|
};
|
|
#define NumZAtoms (sizeof(ZAtom)/sizeof(struct _ZAtom))
|
|
|
|
/* internal static functions */
|
|
|
|
static void
|
|
xselNotify(Display *dpy,
|
|
XSelectionRequestEvent *selreq,
|
|
Atom property)
|
|
{
|
|
XSelectionEvent ev;
|
|
|
|
ev.type=SelectionNotify;
|
|
ev.requestor=selreq->requestor;
|
|
ev.selection=selreq->selection;
|
|
ev.target=selreq->target;
|
|
ev.property=property;
|
|
ev.time=selreq->time;
|
|
|
|
XSendEvent(dpy,ev.requestor,False,0,(XEvent *) &ev);
|
|
}
|
|
|
|
/* pRequestAtoms and RequestAtoms should have the same size. */
|
|
static Atom *pRequestAtoms[] = {
|
|
&ZA_TARGETS,&ZA_MULTIPLE,&ZA_TIMESTAMP,NULL
|
|
};
|
|
static Atom RequestAtoms[] = {
|
|
None,None,None,XA_STRING
|
|
};
|
|
#define NumRequestAtoms (sizeof(RequestAtoms)/sizeof(Atom))
|
|
#define PROP(prop,targ) ((prop)!=None?(prop):(targ))
|
|
#define ChangeProp(type,format,data,size) \
|
|
XChangeProperty(dpy,w,PROP(property,target),(type),(format), \
|
|
PropModeReplace, (unsigned char *) (data),(size))
|
|
|
|
static void
|
|
xselSetProperties(Display *dpy,
|
|
Window w,
|
|
Atom property,
|
|
Atom target,
|
|
XSelectionRequestEvent *selreq)
|
|
{
|
|
if (target==ZA_TARGETS) {
|
|
|
|
ChangeProp(XA_ATOM,32,RequestAtoms,NumRequestAtoms);
|
|
XSync(dpy,0);
|
|
} else if (target==ZA_MULTIPLE) {
|
|
Atom atype;
|
|
int aformat;
|
|
unsigned char *alistp; /* Avoid strict aliasing violation, we hope */
|
|
Atom *alist;
|
|
unsigned long alistsize,i;
|
|
|
|
XGetWindowProperty(dpy,w,property,0L,0L,False,ZA_ATOM_PAIR,&atype,
|
|
&aformat,&i,&alistsize,&alistp);
|
|
|
|
if (alistsize)
|
|
XGetWindowProperty(dpy,w,property,0L,alistsize/sizeof(Atom),False,
|
|
ZA_ATOM_PAIR,&atype,&aformat,&alistsize,&i, &alistp);
|
|
|
|
alist = (Atom *)alistp;
|
|
alistsize/=(sizeof(Atom)/4);
|
|
for (i=0;i<alistsize;i+=2)
|
|
xselSetProperties(dpy,w,alist[i+1],alist[i],selreq);
|
|
|
|
XFree((char *) alist);
|
|
} else if (target==ZA_TIMESTAMP) {
|
|
ChangeProp(XA_INTEGER,32,&ownership_start,1);
|
|
XSync(dpy,0);
|
|
} else if (target==XA_STRING) {
|
|
char *selected;
|
|
|
|
selected = getSelectedText();
|
|
if (selected) {
|
|
ChangeProp(XA_STRING,8,selected,string_Length(selected));
|
|
} else {
|
|
/* This should only happen if the pasting client is out of
|
|
spec (or if this program is buggy), but it could happen */
|
|
#ifdef DEBUG
|
|
fprintf(stderr,
|
|
"SelectionRequest event received for unowned selection: requestor wid=0x%lx", (unsigned long)w);
|
|
#endif
|
|
ChangeProp(XA_STRING,8,"",0);
|
|
}
|
|
XSync(dpy,0);
|
|
}
|
|
|
|
xselNotify(dpy,selreq,property);
|
|
}
|
|
|
|
/* global functions */
|
|
|
|
void
|
|
xicccmInitAtoms(Display *dpy)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i=0;i<NumZAtoms;i++)
|
|
*(ZAtom[i].patom)=XInternAtom(dpy,ZAtom[i].name,False);
|
|
for (i=0;i<NumRequestAtoms;i++)
|
|
if (pRequestAtoms[i])
|
|
RequestAtoms[i] = *(pRequestAtoms[i]);
|
|
}
|
|
|
|
int
|
|
xselGetOwnership(Display *dpy,
|
|
Window w,
|
|
Time when)
|
|
{
|
|
int temp;
|
|
|
|
XSetSelectionOwner(dpy,XA_PRIMARY,w,when);
|
|
temp=(w == XGetSelectionOwner(dpy,XA_PRIMARY));
|
|
|
|
if (temp)
|
|
ownership_start = when;
|
|
|
|
return(temp);
|
|
}
|
|
|
|
/* Get the selection. Return !0 if success, 0 if fail */
|
|
int
|
|
xselProcessSelection(Display *dpy,
|
|
Window w,
|
|
XEvent *event)
|
|
{
|
|
XSelectionRequestEvent *selreq = &(event->xselectionrequest);
|
|
|
|
#ifdef DEBUG
|
|
if ((selreq->owner != w) || (selreq->selection != XA_PRIMARY))
|
|
fprintf(stderr,"SelectionRequest event has bogus field values\n");
|
|
#endif
|
|
|
|
if ((ownership_start == CurrentTime) ||
|
|
(((selreq->time != CurrentTime) &&
|
|
(selreq->time < ownership_start)) ||
|
|
((ownership_end != CurrentTime) &&
|
|
(ownership_end > ownership_start) &&
|
|
(selreq->time > ownership_end))))
|
|
xselNotify(dpy,selreq,None);
|
|
else
|
|
xselSetProperties(dpy,selreq->requestor,selreq->property,selreq->target,
|
|
selreq);
|
|
|
|
return(1);
|
|
}
|
|
|
|
void
|
|
xselOwnershipLost(Time when)
|
|
{
|
|
ownership_end = when;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
xselGiveUpOwnership(Display *dpy,
|
|
Window w)
|
|
{
|
|
XSetSelectionOwner(dpy,XA_PRIMARY,None,ownership_start);
|
|
|
|
ownership_end=ownership_start; /* Is this right? what should I use? */
|
|
}
|
|
|
|
#endif /* X_DISPLAY_MISSING */
|
|
|