#include <vncviewer.h>
static void GetInitialSelectionTimeCallback(Widget w, XtPointer clientData,
Atom* selection, Atom* type,
XtPointer value,
unsigned long* length,
int* format);
static void GetSelectionCallback(Widget w, XtPointer clientData,
Atom* selection, Atom* type, XtPointer value,
unsigned long* length, int* format);
static void GetSelectionTimeCallback(Widget w, XtPointer clientData,
Atom* selection, Atom* type,
XtPointer value, unsigned long* length,
int* format);
static void SendCutBuffer();
static void CutBufferChange(Widget w, XtPointer ptr, XEvent *ev,
Boolean *cont);
static Boolean ConvertSelection(Widget w, Atom* selection, Atom* target,
Atom* type, XtPointer* value,
unsigned long* length, int* format);
static void LoseSelection(Widget w, Atom *selection);
static Bool iAmSelectionOwner = False;
static Time prevSelectionTime = 0L;
static Time cutBufferTime = 0L;
#define TIME_LATER(a, b) ((a) != 0 && ((b) == 0 || (INT32)((a) - (b)) > 0))
void
InitialiseSelection()
{
#if XtSpecificationRelease >= 6
XtRegisterDrawable(dpy, DefaultRootWindow(dpy), toplevel);
#else
_XtRegisterWindow(DefaultRootWindow(dpy), toplevel);
#endif
XSelectInput(dpy, DefaultRootWindow(dpy), PropertyChangeMask);
XtAddRawEventHandler(toplevel, PropertyChangeMask, False, CutBufferChange,
NULL);
XtGetSelectionValue(toplevel, XA_PRIMARY,
XInternAtom(dpy, "TIMESTAMP", False),
GetInitialSelectionTimeCallback, NULL, CurrentTime);
}
static void
GetInitialSelectionTimeCallback(Widget w, XtPointer clientData,
Atom* selection, Atom* type, XtPointer value,
unsigned long* length, int* format)
{
if (value && *format == 32 && *length == 1)
prevSelectionTime = *(CARD32 *)value;
else
prevSelectionTime = 0L;
if (value)
XtFree(value);
}
void
SelectionToVNC(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
Bool always = False;
if (*num_params != 0) {
if (strcmp(params[0],"always") == 0) {
always = True;
} else if (strcmp(params[0],"new") == 0) {
always = False;
} else {
fprintf(stderr,"Invalid params: SelectionToVNC(always|new)\n");
return;
}
}
if (always) {
XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, GetSelectionCallback, NULL,
TimeFromEvent(event));
} else {
XtGetSelectionValue(w, XA_PRIMARY, XInternAtom(dpy, "TIMESTAMP", False),
GetSelectionTimeCallback, NULL, TimeFromEvent(event));
}
}
static void
GetSelectionCallback(Widget w, XtPointer clientData, Atom* selection,
Atom* type, XtPointer value, unsigned long* length,
int* format)
{
int len = *length;
char *str = (char *)value;
if (str)
SendClientCutText(str, len);
else
SendCutBuffer();
}
static void
GetSelectionTimeCallback(Widget w, XtPointer clientData, Atom* selection,
Atom* type, XtPointer value, unsigned long* length,
int* format)
{
if (value && *format == 32 && *length == 1) {
Time t = *(CARD32 *)value;
if (TIME_LATER(t, prevSelectionTime)) {
prevSelectionTime = t;
XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, GetSelectionCallback, NULL,
CurrentTime);
}
} else {
if (TIME_LATER(cutBufferTime, prevSelectionTime)) {
prevSelectionTime = cutBufferTime;
SendCutBuffer();
}
}
if (value)
XtFree(value);
}
static void
SendCutBuffer()
{
char *str;
int len;
str = XFetchBytes(dpy, &len);
if (!str) return;
SendClientCutText(str, len);
XFree(str);
}
static void
CutBufferChange(Widget w, XtPointer ptr, XEvent *ev, Boolean *cont)
{
if (ev->type != PropertyNotify || ev->xproperty.atom != XA_CUT_BUFFER0)
return;
cutBufferTime = ev->xproperty.time;
}
void
SelectionFromVNC(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
Bool always = False;
Time t = TimeFromEvent(event);
if (*num_params != 0) {
if (strcmp(params[0],"always") == 0) {
always = True;
} else if (strcmp(params[0],"new") == 0) {
always = False;
} else {
fprintf(stderr,"Invalid params: SelectionFromVNC(always|new)\n");
return;
}
}
if (t == CurrentTime) {
fprintf(stderr,"Error in translations: SelectionFromVNC() must act on "
"event with time field\n");
return;
}
if (!serverCutText || (!always && !newServerCutText))
return;
newServerCutText = False;
XStoreBytes(dpy, serverCutText, strlen(serverCutText));
if (XtOwnSelection(desktop, XA_PRIMARY, t, ConvertSelection, LoseSelection,
NULL)) {
iAmSelectionOwner = True;
}
}
static Boolean
ConvertSelection(Widget w, Atom* selection, Atom* target, Atom* type,
XtPointer* value, unsigned long* length, int* format)
{
if (*target == XA_STRING && serverCutText != NULL) {
*type = XA_STRING;
*length = strlen(serverCutText);
*value = (XtPointer)XtMalloc(*length);
memcpy((char*)*value, serverCutText, *length);
*format = 8;
return True;
}
if (XmuConvertStandardSelection(w, CurrentTime, selection, target, type,
(XPointer*)value, length, format)) {
if (*target == XInternAtom(dpy, "TARGETS", False)) {
Atom* targetP;
Atom* std_targets = (Atom*)*value;
unsigned long std_length = *length;
*length = std_length + 1;
*value = (XtPointer)XtMalloc(sizeof(Atom)*(*length));
targetP = *(Atom**)value;
*targetP++ = XA_STRING;
memmove((char*)targetP, (char*)std_targets, sizeof(Atom)*std_length);
XtFree((char*)std_targets);
*type = XA_ATOM;
*format = 32;
return True;
}
return True;
}
return False;
}
static void
LoseSelection(Widget w, Atom *selection)
{
iAmSelectionOwner = False;
}