Beispiel #1
0
String GetProperty(Window w, Atom property, Atom rtype)
{
	GuiLock __; 
	LLOG("GetProperty");
	String result;
	int format;
	unsigned long nitems, after = 1;
	long offset = 0;
	Atom type = None;
	unsigned char *data;
	long rsize = minmax((long)(XMaxRequestSize(Xdisplay) - 100), (long)256, (long)65536);
	while(after > 0) {
		if(XGetWindowProperty(Xdisplay, w, property, offset, rsize, XFalse,
	                          rtype, &type, &format, &nitems, &after, &data) != Success)
	    	break;
	    if(type == None)
	        break;
		if(data) {
			int len = format == 32 ? sizeof(unsigned long) * nitems : nitems * (format >> 3);
			result.Cat(data, len);
			XFree((char *)data);
			offset += nitems / (32 / format);
		}
		else
			break;
	}
Beispiel #2
0
int x11_init(GraceApp *gapp)
{
    X11Stuff *xstuff = gapp->gui->xstuff;
    XGCValues gc_val;
    long mrsize;
    int max_path_limit;
    
    xstuff->screennumber = DefaultScreen(xstuff->disp);
    xstuff->root = RootWindow(xstuff->disp, xstuff->screennumber);
 
    xstuff->gc = DefaultGC(xstuff->disp, xstuff->screennumber);
    
    xstuff->depth = DisplayPlanes(xstuff->disp, xstuff->screennumber);

    /* init colormap */
    xstuff->cmap = DefaultColormap(xstuff->disp, xstuff->screennumber);
    /* redefine colormap, if needed */
    if (gapp->gui->install_cmap == CMAP_INSTALL_ALWAYS) {
        xstuff->cmap = XCopyColormapAndFree(xstuff->disp, xstuff->cmap);
        gapp->gui->private_cmap = TRUE;
    }
    
    /* set GCs */
    if (gapp->gui->invert) {
        gc_val.function = GXinvert;
    } else {
        gc_val.function = GXxor;
    }
    gcxor = XCreateGC(xstuff->disp, xstuff->root, GCFunction, &gc_val);

    /* XExtendedMaxRequestSize() appeared in X11R6 */
#if XlibSpecificationRelease > 5
    mrsize = XExtendedMaxRequestSize(xstuff->disp);
#else
    mrsize = 0;
#endif
    if (mrsize <= 0) {
        mrsize = XMaxRequestSize(xstuff->disp);
    }
    max_path_limit = (mrsize - 3)/2;
    if (max_path_limit < get_max_path_limit(grace_get_canvas(gapp->grace))) {
        char buf[128];
        sprintf(buf,
            "Setting max drawing path length to %d (limited by the X server)",
            max_path_limit);
        errmsg(buf);
        set_max_path_limit(grace_get_canvas(gapp->grace), max_path_limit);
    }
    
    xstuff->dpi = rint(MM_PER_INCH*DisplayWidth(xstuff->disp, xstuff->screennumber)/
        DisplayWidthMM(xstuff->disp, xstuff->screennumber));

    return RETURN_SUCCESS;
}
Beispiel #3
0
static Atom send_selection(QClipboardData *d, Atom target, Window window, Atom property)
{
    Atom atomFormat = target;
    int dataFormat = 0;
    QByteArray data;

    QByteArray fmt = X11->xdndAtomToString(target);
    if (fmt.isEmpty()) { // Not a MIME type we have
        DEBUG("QClipboard: send_selection(): converting to type '%s' is not supported", fmt.data());
        return XNone;
    }
    DEBUG("QClipboard: send_selection(): converting to type '%s'", fmt.data());

    if (X11->xdndMimeDataForAtom(target, d->source(), &data, &atomFormat, &dataFormat)) {

        VDEBUG("QClipboard: send_selection():\n"
          "    property type %lx\n"
          "    property name '%s'\n"
          "    format %d\n"
          "    %d bytes\n",
          target, X11->xdndMimeAtomToString(atomFormat).toLatin1().data(), dataFormat, data.size());

         // don't allow INCR transfers when using MULTIPLE or to
        // Motif clients (since Motif doesn't support INCR)
        static Atom motif_clip_temporary = ATOM(CLIP_TEMPORARY);
        bool allow_incr = property != motif_clip_temporary;

        // X_ChangeProperty protocol request is 24 bytes
        const int increment = (XMaxRequestSize(X11->display) * 4) - 24;
        if (data.size() > increment && allow_incr) {
            long bytes = data.size();
            XChangeProperty(X11->display, window, property,
                            ATOM(INCR), 32, PropModeReplace, (uchar *) &bytes, 1);

            (void)new QClipboardINCRTransaction(window, property, atomFormat, dataFormat, data, increment);
            return property;
        }

        // make sure we can perform the XChangeProperty in a single request
        if (data.size() > increment)
            return XNone; // ### perhaps use several XChangeProperty calls w/ PropModeAppend?
        int dataSize = data.size() / (dataFormat / 8);
        // use a single request to transfer data
        XChangeProperty(X11->display, window, property, atomFormat,
                        dataFormat, PropModeReplace, (uchar *) data.data(),
                        dataSize);
    }
    return property;
}
Beispiel #4
0
void
p_lines(p_win *w)
{
  p_scr *s = w->s;
  Display *dpy = s->xdpy->dpy;
  GC gc = x_getgc(s, w, FillSolid);
  int nmx = XMaxRequestSize(dpy)-3;
  int n = x_pt_count;
  x_pt_count = 0;
  while (n>1) {
    if (n<nmx) nmx = n;
    XDrawLines(dpy, w->d, gc, x_pt_list, nmx, CoordModeOrigin);
    n -= nmx;
  }
  if (p_signalling) p_abort();
}
Beispiel #5
0
void
p_segments(p_win *w)
{
  p_scr *s = w->s;
  Display *dpy = s->xdpy->dpy;
  GC gc = x_getgc(s, w, FillSolid);
  int nmx = (XMaxRequestSize(dpy)-3)/2;
  int n = x_pt_count / 2;
  x_pt_count = 0;
  while (n>0) {
    if (n<nmx) nmx = n;
    /* note: assume here that XPoint[2] identical to XSegment */
    XDrawSegments(dpy, w->d, gc, (XSegment *)x_pt_list, nmx);
    n -= nmx;
  }
  if (p_signalling) p_abort();
}
Beispiel #6
0
static void handleSelectionRequest(XSelectionRequestEvent ev) {
    static long chunk_size;
    static Atom targets;
    int sel_len = 0;
    int x, y;
    unsigned char *dst = cutBuffer;

    XEvent res;

    sortSelectionCorners();
    //printf("cx1=%d\n", cx1);
    for (y = cy1; y <= cy2; y++) {
        for (x = cx1; x <= cx2; x++) {
            *dst++ = bws[y * selected_model->text_width + x];
            sel_len++;
        }
        *dst++ = 0x0a;
        sel_len++;
    }

    if (!targets) {
        targets = XInternAtom(display, "TARGETS", False);
    }
    if (!chunk_size) {
        chunk_size = XExtendedMaxRequestSize(display) / 4;
        if (!chunk_size) {
            chunk_size = XMaxRequestSize(display) / 4;
        }
    }
    sel_len = sel_len > chunk_size ? chunk_size : sel_len;

    XChangeProperty(display, ev.requestor, ev.property, XA_STRING, 8,
    PropModeReplace, cutBuffer, sel_len);

    res.xselection.property = ev.property;
    res.xselection.type = SelectionNotify;
    res.xselection.display = ev.display;
    res.xselection.requestor = ev.requestor;
    res.xselection.selection = ev.selection;
    res.xselection.target = ev.target;
    res.xselection.time = ev.time;

    XSendEvent(display, ev.requestor, 0, 0, &res);
    XFlush(display);
}
void
JXGC::DrawLines
	(
	const Drawable	drawable,
	const JSize		ptCount,
	XPoint			xpt[]
	)
	const
{
	const JSize kMaxPointCount = 1 + (XMaxRequestSize(*itsDisplay) - 3) / 2;

	JSize offset = 0;
	while (offset < ptCount-1)
		{
		const JSize count = JMin(ptCount - offset, kMaxPointCount);
		XDrawLines(*itsDisplay, drawable, itsXGC, &(xpt[offset]), count, CoordModeOrigin);
		offset += count - 1;
		}
}
Beispiel #8
0
// Create display, and other initialization
bool wxApp::OnInitGui()
{
#if wxUSE_LOG
    // Eventually this line will be removed, but for
    // now we don't want to try popping up a dialog
    // for error messages.
    delete wxLog::SetActiveTarget(new wxLogStderr);
#endif

    if (!wxAppBase::OnInitGui())
        return false;

    Display *dpy = wxGlobalDisplay();
    GetMainColormap(dpy);

    m_maxRequestSize = XMaxRequestSize(dpy);

#if !wxUSE_NANOX
    m_visualInfo = new wxXVisualInfo;
    wxFillXVisualInfo(m_visualInfo, dpy);
#endif

    return true;
}
Beispiel #9
0
/* put data into a selection, in response to a SelecionRequest event from
 * another window (and any subsequent events relating to an INCR transfer).
 *
 * Arguments are:
 *
 * A display
 * 
 * A window
 * 
 * The event to respond to
 * 
 * A pointer to an Atom. This gets set to the property nominated by the other
 * app in it's SelectionRequest. Things are likely to break if you change the
 * value of this yourself.
 * 
 * The target(UTF8_STRING or XA_STRING) to respond to
 *
 * A pointer to an array of chars to read selection data from.
 * 
 * The length of the array of chars.
 *
 * In the case of an INCR transfer, the position within the array of chars
 * that is being processed.
 *
 * The context that event is the be processed within.
 */
int
xcin(Display * dpy,
     Window * win,
     XEvent evt,
     Atom * pty, Atom target, unsigned char *txt, unsigned long len, unsigned long *pos,
     unsigned int *context)
{
    unsigned long chunk_len;	/* length of current chunk (for incr
				 * transfers only)
				 */
    XEvent res;			/* response to event */
    static Atom inc;
    static Atom targets;
    static long chunk_size;

    if (!targets) {
	targets = XInternAtom(dpy, "TARGETS", False);
    }

    if (!inc) {
	inc = XInternAtom(dpy, "INCR", False);
    }

    /* We consider selections larger than a quarter of the maximum
       request size to be "large". See ICCCM section 2.5 */
    if (!chunk_size) {
	chunk_size = XExtendedMaxRequestSize(dpy) / 4;
	if (!chunk_size) {
	    chunk_size = XMaxRequestSize(dpy) / 4;
	}
    }

    switch (*context) {
    case XCLIB_XCIN_NONE:
	if (evt.type != SelectionRequest)
	    return (0);

	/* set the window and property that is being used */
	*win = evt.xselectionrequest.requestor;
	*pty = evt.xselectionrequest.property;

	/* reset position to 0 */
	*pos = 0;

	/* put the data into an property */
	if (evt.xselectionrequest.target == targets) {
	    Atom types[2] = { targets, target };

	    /* send data all at once (not using INCR) */
	    XChangeProperty(dpy,
			    *win,
			    *pty,
			    XA_ATOM,
			    32, PropModeReplace, (unsigned char *) types,
			    (int) (sizeof(types) / sizeof(Atom))
		);
	}
	else if (len > chunk_size) {
	    /* send INCR response */
	    XChangeProperty(dpy, *win, *pty, inc, 32, PropModeReplace, 0, 0);

	    /* With the INCR mechanism, we need to know
	     * when the requestor window changes (deletes)
	     * its properties
	     */
	    XSelectInput(dpy, *win, PropertyChangeMask);

	    *context = XCLIB_XCIN_INCR;
	}
	else {
	    /* send data all at once (not using INCR) */
	    XChangeProperty(dpy,
			    *win,
			    *pty, target, 8, PropModeReplace, (unsigned char *) txt, (int) len);
	}

	/* Perhaps FIXME: According to ICCCM section 2.5, we should
	   confirm that XChangeProperty succeeded without any Alloc
	   errors before replying with SelectionNotify. However, doing
	   so would require an error handler which modifies a global
	   variable, plus doing XSync after each XChangeProperty. */

	/* set values for the response event */
	res.xselection.property = *pty;
	res.xselection.type = SelectionNotify;
	res.xselection.display = evt.xselectionrequest.display;
	res.xselection.requestor = *win;
	res.xselection.selection = evt.xselectionrequest.selection;
	res.xselection.target = evt.xselectionrequest.target;
	res.xselection.time = evt.xselectionrequest.time;

	/* send the response event */
	XSendEvent(dpy, evt.xselectionrequest.requestor, 0, 0, &res);
	XFlush(dpy);

	/* if len < chunk_size, then the data was sent all at
	 * once and the transfer is now complete, return 1
	 */
	if (len > chunk_size)
	    return (0);
	else
	    return (1);

	break;

    case XCLIB_XCIN_INCR:
	/* length of current chunk */

	/* ignore non-property events */
	if (evt.type != PropertyNotify)
	    return (0);

	/* ignore the event unless it's to report that the
	 * property has been deleted
	 */
	if (evt.xproperty.state != PropertyDelete)
	    return (0);

	/* set the chunk length to the maximum size */
	chunk_len = chunk_size;

	/* if a chunk length of maximum size would extend
	 * beyond the end ot txt, set the length to be the
	 * remaining length of txt
	 */
	if ((*pos + chunk_len) > len)
	    chunk_len = len - *pos;

	/* if the start of the chunk is beyond the end of txt,
	 * then we've already sent all the data, so set the
	 * length to be zero
	 */
	if (*pos > len)
	    chunk_len = 0;

	if (chunk_len) {
	    /* put the chunk into the property */
	    XChangeProperty(dpy,
			    *win, *pty, target, 8, PropModeReplace, &txt[*pos], (int) chunk_len);
	}
	else {
	    /* make an empty property to show we've
	     * finished the transfer
	     */
	    XChangeProperty(dpy, *win, *pty, target, 8, PropModeReplace, 0, 0);
	}
	XFlush(dpy);

	/* all data has been sent, break out of the loop */
	if (!chunk_len)
	    *context = XCLIB_XCIN_NONE;

	*pos += chunk_size;

	/* if chunk_len == 0, we just finished the transfer,
	 * return 1
	 */
	if (chunk_len > 0)
	    return (0);
	else
	    return (1);
	break;
    }
    return (0);
}
bool CUnixEventEmitter::processMessage (XEvent &event, CEventServer *server)
{
	if (!server)
		server=&_InternalServer;

	XWindowAttributes xwa;
	XGetWindowAttributes (_dpy, _win, &xwa);

	switch (event.type)
	{
	case ButtonPress:
	{
		//nlinfo("%d %d %d", event.xbutton.button, event.xbutton.x, event.xbutton.y);
		float fX = (float) event.xbutton.x / (float) xwa.width;
		float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height;
		TMouseButton button=getMouseButton(event.xbutton.state);
		switch(event.xbutton.button)
		{
		case Button1:
			server->postEvent(new CEventMouseDown(fX, fY, (TMouseButton)(leftButton|(button&~(leftButton|middleButton|rightButton))), this));
			break;
		case Button2:
			server->postEvent(new CEventMouseDown(fX, fY, (TMouseButton)(middleButton|(button&~(leftButton|middleButton|rightButton))), this));
			break;
		case Button3:
			server->postEvent(new CEventMouseDown(fX, fY, (TMouseButton)(rightButton|(button&~(leftButton|middleButton|rightButton))), this));
			break;
		case Button4:
			server->postEvent(new CEventMouseWheel(fX, fY, button, true, this));
			break;
		case Button5:
			server->postEvent(new CEventMouseWheel(fX, fY, button, false, this));
			break;
		}
		break;
	}
	case ButtonRelease:
	{
		//nlinfo("%d %d %d", event.xbutton.button, event.xbutton.x, event.xbutton.y);
		float fX = (float) event.xbutton.x / (float) xwa.width;
		float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height;
		switch(event.xbutton.button)
		{
		case Button1:
			server->postEvent(new CEventMouseUp(fX, fY, leftButton, this));
			break;
		case Button2:
			server->postEvent(new CEventMouseUp(fX, fY, middleButton, this));
			break;
		case Button3:
			server->postEvent(new CEventMouseUp(fX, fY, rightButton, this));
			break;
		}
		break;
	}
	case MotionNotify:
	{
		TMouseButton button=getMouseButton (event.xbutton.state);

		// if raw mode should be emulated
		if(_emulateRawMode)
		{
			// when we just wrapped back the pointer to 0.5 / 0.5, ignore event
			if(event.xbutton.x == xwa.width / 2 && event.xbutton.y == xwa.height / 2)
				break;

			// post a CGDMouseMove with the movement delta to the event server
			server->postEvent(
				new CGDMouseMove(this, NULL /* no mouse device */,
					event.xbutton.x - (xwa.width / 2),
					(xwa.height / 2) - event.xbutton.y));

			// move the pointer back to the center of the window
			XWarpPointer(_dpy, None, _win, None, None, None, None,
				(xwa.width / 2), (xwa.height / 2));
		}
		// if in normal mouse mode
		else
		{
			// get the relative mouse position
			float fX = (float) event.xbutton.x / (float) xwa.width;
			float fY = 1.0f - (float) event.xbutton.y / (float) xwa.height;

			// post a normal mouse move event to the event server
			server->postEvent (new CEventMouseMove (fX, fY, button, this));
		}
		break;
	}
	case KeyPress:
	{
		// save keycode because XFilterEvent could set it to 0
		uint keyCode = event.xkey.keycode;
		KeySym k;
		static char Text[256];
		int c = 0;

		// check if event is filtered
		bool filtered = XFilterEvent(&event, _win);

		// if key event is filtered, we shouldn't use XLookupString to retrieve KeySym
		if (!filtered)
		{
			Status status = XLookupNone;

#ifdef X_HAVE_UTF8_STRING
			if (_ic)
				c = Xutf8LookupString(_ic, &event.xkey, Text, sizeof(Text), &k, &status);
#endif

			if (status == XLookupNone)
				c = XLookupString(&event.xkey, Text, sizeof(Text), &k, NULL);
		}
		else
		{
			k = XKeycodeToKeysym(_dpy, keyCode, 0);
		}

		// send CEventKeyDown event only if keyCode is defined
		if (keyCode)
		{
			TKey key = getKeyFromKeySym(k);
			if(key == KeyNOKEY)
				key = getKeyFromKeycode(keyCode);

			// search for key in map
			std::map<TKey, bool>::const_iterator it = _PressedKeys.find(key);

			// if key is not found or value is false, that's the first time
			bool firstTime = (it == _PressedKeys.end()) || !it->second;

			server->postEvent (new CEventKeyDown (key, getKeyButton(event.xbutton.state), firstTime, this));
			_PressedKeys[key] = true;

			// don't send a control character when deleting
			if (key == KeyDELETE)
				c = 0;
		}

		Text[c] = '\0';
		if(c>0)
		{
#ifdef X_HAVE_UTF8_STRING
			ucstring ucstr;
			ucstr.fromUtf8(Text);

			CEventChar *charEvent = new CEventChar (ucstr[0], getKeyButton(event.xbutton.state), this);

			// raw if not processed by IME
			charEvent->setRaw(keyCode != 0);

			server->postEvent (charEvent);
#else
			for (int i = 0; i < c; i++)
			{
				CEventChar *charEvent = new CEventChar ((ucchar)(unsigned char)Text[i], getKeyButton(event.xbutton.state), this);

				// raw if not processed by IME
				charEvent->setRaw(keyCode != 0);

				server->postEvent (charEvent);
			}
#endif
		}
		break;
	}
	case KeyRelease:
	{
		if (!keyRepeat(_dpy, &event))
		{
			KeySym k;
			// only need to get correct KeySym
			int c = XLookupString(&event.xkey, NULL, 0, &k, NULL);

			TKey key = getKeyFromKeySym(k);
			if(key == KeyNOKEY)
				key = getKeyFromKeycode(event.xkey.keycode);

			server->postEvent (new CEventKeyUp (key, getKeyButton(event.xbutton.state), this));
			_PressedKeys[key] = false;
		}
		break;
	}
	case SelectionRequest:
	{
		XEvent respond;
		XSelectionRequestEvent req = event.xselectionrequest;

		respond.xselection.type= SelectionNotify;
		respond.xselection.display= req.display;
		respond.xselection.requestor= req.requestor;
		respond.xselection.selection=req.selection;
		respond.xselection.target= req.target;
		respond.xselection.time = req.time;
		respond.xselection.property = req.property;

		if (req.property == None)
		{
			respond.xselection.property = req.target;
		}
		if (req.target == XA_TARGETS)
		{
			Atom targets[] =
			{
				XA_TARGETS,
				XA_STRING,
				XA_UTF8_STRING
			};

			respond.xselection.property = req.property;

			XChangeProperty(req.display, req.requestor, req.property, XA_ATOM, 32, PropModeReplace, (unsigned char *)targets, 3 /* number of element */);
		}
		else if (req.target == XA_STRING)
		{
			respond.xselection.property = req.property;
			std::string str = _CopiedString.toString();
			XChangeProperty(req.display, req.requestor, req.property, XA_STRING, 8, PropModeReplace, (const unsigned char*)str.c_str(), str.length());
		}
		else if (req.target == XA_UTF8_STRING)
		{
			respond.xselection.property = req.property;
			std::string str = _CopiedString.toUtf8();
			XChangeProperty(req.display, req.requestor, respond.xselection.property, XA_UTF8_STRING, 8, PropModeReplace, (const unsigned char*)str.c_str(), str.length());
		}
		else
		{
			// Note: Calling XGetAtomName with arbitrary value crash the client, maybe req.target have been sanitized by X11 server
			respond.xselection.property = None;
		}

		XSendEvent (_dpy, req.requestor, 0, 0, &respond);

		break;
	}
	case SelectionClear:
		_SelectionOwned = false;
		_CopiedString = "";
		break;
	case SelectionNotify:
	{
		Atom target = event.xselection.target;

		Atom actualType = 0;
		int actualFormat = 0;
		unsigned long nitems = 0, bytesLeft = 0;

		// some applications are sending ATOM and other TARGETS
		if (target == XA_TARGETS || target == XA_ATOM)
		{
			Atom *supportedTargets = NULL;

			// list NeL selection properties
			if (XGetWindowProperty(_dpy, _win, XA_NEL_SEL, 0, XMaxRequestSize(_dpy), False, AnyPropertyType, &actualType, &actualFormat, &nitems, &bytesLeft, (unsigned char**)&supportedTargets) != Success)
				return false;

			if (bytesLeft > 0)
			{
				nlwarning("Paste: Supported TARGETS list too long.");
			}

			Atom bestTarget = 0;
			sint bestTargetElect = 0;

			// Elect best type
			for (uint i=0; i < nitems; i++)
			{
				// nlwarning(" - Type=%s (%u)", XGetAtomName(_dpy, supportedTargets[i]), (uint)supportedTargets[i]);
				if (supportedTargets[i] == XA_UTF8_STRING )
				{
					if (bestTargetElect < 2)
					{
						bestTarget = XA_UTF8_STRING;
						bestTargetElect = 2;
					}
				}
				else if (supportedTargets[i] == XA_STRING )
				{
					if (bestTargetElect < 1)
					{
						bestTarget = XA_STRING;
						bestTargetElect = 1;
					}
				}
			}

			XFree(supportedTargets);

			if (!bestTargetElect)
			{
				nlwarning("Paste buffer is not a text buffer.");
				return false;
			}

			// request string conversion
			XConvertSelection(_dpy, XA_CLIPBOARD, bestTarget, XA_NEL_SEL, _win, CurrentTime);
		}
		else if (target == XA_UTF8_STRING || target == XA_STRING)
		{
			uint8 *data = NULL;

			// get selection
			if (XGetWindowProperty(_dpy, _win, XA_NEL_SEL, 0, XMaxRequestSize(_dpy), False, AnyPropertyType, &actualType, &actualFormat, &nitems, &bytesLeft, (unsigned char**)&data) != Success)
				return false;

			ucstring text;
			std::string tmpData = (const char*)data;
			XFree(data);

			// convert buffer to ucstring
			if (target == XA_UTF8_STRING)
			{
				text = ucstring::makeFromUtf8(tmpData);
			}
			else if (target == XA_STRING)
			{
				text = tmpData;
			}
			else
			{
				nlwarning("Unknow format %u", (uint)target);
			}

			// sent string event to event server
			server->postEvent (new CEventString (text, this));
		}
		else
		{
			nlwarning("Unknow target %u", (uint)target);
		}

		break;
	}
	case FocusIn:
		// keyboard focus
//		server->postEvent (new CEventSetFocus (true, this));
		if (_ic) XSetICFocus(_ic);
		break;
	case FocusOut:
		// keyboard focus
//		server->postEvent (new CEventSetFocus (false, this));
		if (_ic) XUnsetICFocus(_ic);
		break;
	case KeymapNotify:
		break;
	case MappingNotify:
		// update keymap
		XRefreshKeyboardMapping((XMappingEvent *)&event);
		break;
	case DestroyNotify:
		// XIM server has crashed
		createIM();
		break;
	case ClientMessage:
		if ((event.xclient.format == 32) && ((Atom)event.xclient.data.l[0] == XA_WM_DELETE_WINDOW))
		{
			server->postEvent(new CEventDestroyWindow(this));
		}
		break;
	default:
		//	nlinfo("UnknownEvent");
		//	XtDispatchEvent(&event);
		return false;
	}

	return true;
}
bool
XWindowsClipboard::sendReply(Reply* reply)
{
	assert(reply != NULL);

	// bail out immediately if reply is done
	if (reply->m_done) {
		LOG((CLOG_DEBUG1 "clipboard: finished reply to 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property));
		return true;
	}

	// start in failed state if property is None
	bool failed = (reply->m_property == None);
	if (!failed) {
		LOG((CLOG_DEBUG1 "clipboard: setting property on 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property));

		// send using INCR if already sending incrementally or if reply
		// is too large, otherwise just send it.
		const UInt32 maxRequestSize = 3 * XMaxRequestSize(m_display);
		const bool useINCR = (reply->m_data.size() > maxRequestSize);

		// send INCR reply if incremental and we haven't replied yet
		if (useINCR && !reply->m_replied) {
			UInt32 size = reply->m_data.size();
			if (!XWindowsUtil::setWindowProperty(m_display,
								reply->m_requestor, reply->m_property,
								&size, 4, m_atomINCR, 32)) {
				failed = true;
			}
		}

		// send more INCR reply or entire non-incremental reply
		else {
			// how much more data should we send?
			UInt32 size = reply->m_data.size() - reply->m_ptr;
			if (size > maxRequestSize)
				size = maxRequestSize;

			// send it
			if (!XWindowsUtil::setWindowProperty(m_display,
								reply->m_requestor, reply->m_property,
								reply->m_data.data() + reply->m_ptr,
								size,
								reply->m_type, reply->m_format)) {
				failed = true;
			}
			else {
				reply->m_ptr += size;

				// we've finished the reply if we just sent the zero
				// size incremental chunk or if we're not incremental.
				reply->m_done = (size == 0 || !useINCR);
			}
		}
	}

	// if we've failed then delete the property and say we're done.
	// if we haven't replied yet then we can send a failure notify,
	// otherwise we've failed in the middle of an incremental
	// transfer;  i don't know how to cancel that so i'll just send
	// the final zero-length property.
	// FIXME -- how do you gracefully cancel an incremental transfer?
	if (failed) {
		LOG((CLOG_DEBUG1 "clipboard: sending failure to 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property));
		reply->m_done = true;
		if (reply->m_property != None) {
			XWindowsUtil::ErrorLock lock(m_display);
			XDeleteProperty(m_display, reply->m_requestor, reply->m_property);
		}

		if (!reply->m_replied) {
			sendNotify(reply->m_requestor, m_selection,
								reply->m_target, None,
								reply->m_time);

			// don't wait for any reply (because we're not expecting one)
			return true;
		}
		else {
			static const char dummy = 0;
			XWindowsUtil::setWindowProperty(m_display,
								reply->m_requestor, reply->m_property,
								&dummy,
								0,
								reply->m_type, reply->m_format);

			// wait for delete notify
			return false;
		}
	}

	// send notification if we haven't yet
	if (!reply->m_replied) {
		LOG((CLOG_DEBUG1 "clipboard: sending notify to 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property));
		reply->m_replied = true;

		// dump every property on the requestor window to the debug2
		// log.  we've seen what appears to be a bug in lesstif and
		// knowing the properties may help design a workaround, if
		// it becomes necessary.
		if (CLOG->getFilter() >= kDEBUG2) {
			XWindowsUtil::ErrorLock lock(m_display);
			int n;
			Atom* props = XListProperties(m_display, reply->m_requestor, &n);
			LOG((CLOG_DEBUG2 "properties of 0x%08x:", reply->m_requestor));
			for (int i = 0; i < n; ++i) {
				Atom target;
				String data;
				char* name = XGetAtomName(m_display, props[i]);
				if (!XWindowsUtil::getWindowProperty(m_display,
								reply->m_requestor,
								props[i], &data, &target, NULL, False)) {
					LOG((CLOG_DEBUG2 "  %s: <can't read property>", name));
				}
				else {
					// if there are any non-ascii characters in string
					// then print the binary data.
					static const char* hex = "0123456789abcdef";
					for (String::size_type j = 0; j < data.size(); ++j) {
						if (data[j] < 32 || data[j] > 126) {
							String tmp;
							tmp.reserve(data.size() * 3);
							for (j = 0; j < data.size(); ++j) {
								unsigned char v = (unsigned char)data[j];
								tmp += hex[v >> 16];
								tmp += hex[v & 15];
								tmp += ' ';
							}
							data = tmp;
							break;
						}
					}
					char* type = XGetAtomName(m_display, target);
					LOG((CLOG_DEBUG2 "  %s (%s): %s", name, type, data.c_str()));
					if (type != NULL) {
						XFree(type);
					}
				}
				if (name != NULL) {
					XFree(name);
				}
			}
Beispiel #12
0
static inline int maxSelectionIncr(Display *dpy)
{ return XMaxRequestSize(dpy) > 65536 ? 65536*4 : XMaxRequestSize(dpy)*4 - 100; }
Beispiel #13
0
static Bool
init_x11( char * error_buf )
{
	/*XXX*/ /* Namely, support for -display host:0.0 etc. */
	XrmQuark common_quarks_list[20];  /*XXX change number of elements if necessary */
	XrmQuarkList ql = common_quarks_list;
	XGCValues gcv;
	char *common_quarks =
		"String."
		"Blinkinvisibletime.blinkinvisibletime."
		"Blinkvisibletime.blinkvisibletime."
		"Clicktimeframe.clicktimeframe."
		"Doubleclicktimeframe.doubleclicktimeframe."
		"Wheeldown.wheeldown."
		"Wheelup.wheelup."
		"Submenudelay.submenudelay."
		"Scrollfirst.scrollfirst."
		"Scrollnext.scrollnext";

	char * atom_names[AI_count] = {
		"RESOLUTION_X",
		"RESOLUTION_Y",
		"PIXEL_SIZE",
		"SPACING",
		"RELATIVE_WEIGHT",
		"FOUNDRY",
		"AVERAGE_WIDTH",
		"CHARSET_REGISTRY",
		"CHARSET_ENCODING",
		"CREATE_EVENT",
		"WM_DELETE_WINDOW",
		"WM_PROTOCOLS",
		"WM_TAKE_FOCUS",
		"_NET_WM_STATE",
		"_NET_WM_STATE_SKIP_TASKBAR",
		"_NET_WM_STATE_MAXIMIZED_VERT",
		"_NET_WM_STATE_MAXIMIZED_HORZ",
		"_NET_WM_NAME",
		"_NET_WM_ICON_NAME",
		"UTF8_STRING",
		"TARGETS",
		"INCR",
		"PIXEL",
		"FOREGROUND",
		"BACKGROUND",
		"_MOTIF_WM_HINTS",
		"_NET_WM_STATE_MODAL",
		"_NET_SUPPORTED",
		"_NET_WM_STATE_MAXIMIZED_HORIZ",
		"text/plain;charset=UTF-8",
		"_NET_WM_STATE_STAYS_ON_TOP",
		"_NET_CURRENT_DESKTOP",
		"_NET_WORKAREA",
		"_NET_WM_STATE_ABOVE"
	};
	char hostname_buf[256], *hostname = hostname_buf;

	guts. click_time_frame = 200;
	guts. double_click_time_frame = 200;
	guts. visible_timeout = 500;
	guts. invisible_timeout = 500;
	guts. insert = true;
	guts. last_time = CurrentTime;

	guts. ri_head = guts. ri_tail = 0;
	DISP = XOpenDisplay( do_display);
	
	if (!DISP) {
		char * disp = getenv("DISPLAY");
		snprintf( error_buf, 256, "Error: Can't open display '%s'", 
					do_display ? do_display : (disp ? disp : ""));
		free( do_display);
		do_display = nil;
		return false;
	}
	free( do_display);
	do_display = nil;
	XSetErrorHandler( x_error_handler);
	guts.main_error_handler = x_error_handler;
	(void)x_io_error_handler;
	XCHECKPOINT;
	guts.connection = ConnectionNumber( DISP);

	{
		struct sockaddr name;
		unsigned int l = sizeof( name);
		guts. local_connection = getsockname( guts.connection, &name, &l) >= 0 && l == 0;
	}
	
#ifdef HAVE_X11_EXTENSIONS_SHAPE_H
	if ( XShapeQueryExtension( DISP, &guts.shape_event, &guts.shape_error)) {
		guts. shape_extension = true;
	} else {
		guts. shape_extension = false;
	}
#else
	guts. shape_extension = false;
#endif
#ifdef USE_MITSHM
	if ( !do_no_shmem && XShmQueryExtension( DISP)) {
		guts. shared_image_extension = true;
		guts. shared_image_completion_event = XShmGetEventBase( DISP) + ShmCompletion;
	} else {
		guts. shared_image_extension = false;
		guts. shared_image_completion_event = -1;
	}
#else
	guts. shared_image_extension = false;
	guts. shared_image_completion_event = -1;
#endif
	guts. randr_extension = false;
#ifdef HAVE_X11_EXTENSIONS_XRANDR_H
	{
		int dummy;
		if ( XRRQueryExtension( DISP, &dummy, &dummy))
			guts. randr_extension = true;
	}	 
#endif
#ifdef HAVE_X11_EXTENSIONS_XRENDER_H
	{
		int dummy;
		if ( XRenderQueryExtension( DISP, &dummy, &dummy))
			guts. render_extension = true;
	}	 
#endif
#ifdef HAVE_X11_EXTENSIONS_XCOMPOSITE_H
	{
		int dummy;
		if (XQueryExtension(DISP, COMPOSITE_NAME, &guts.composite_opcode, &dummy, &dummy))
			guts. composite_extension = true;
	}	 
#endif
	XrmInitialize();
	guts.db = get_database();
	XrmStringToQuarkList( common_quarks, common_quarks_list);
	guts.qString = *ql++;
	guts.qBlinkinvisibletime = *ql++;
	guts.qblinkinvisibletime = *ql++;
	guts.qBlinkvisibletime = *ql++;
	guts.qblinkvisibletime = *ql++;
	guts.qClicktimeframe = *ql++;
	guts.qclicktimeframe = *ql++;
	guts.qDoubleclicktimeframe = *ql++;
	guts.qdoubleclicktimeframe = *ql++;
	guts.qWheeldown = *ql++;
	guts.qwheeldown = *ql++;
	guts.qWheelup = *ql++;
	guts.qwheelup = *ql++;
	guts.qSubmenudelay = *ql++;
	guts.qsubmenudelay = *ql++;
	guts.qScrollfirst = *ql++;
	guts.qscrollfirst = *ql++;
	guts.qScrollnext = *ql++;
	guts.qscrollnext = *ql++;

	guts. mouse_buttons = XGetPointerMapping( DISP, guts. buttons_map, 256);
	XCHECKPOINT;

	guts. limits. request_length = XMaxRequestSize( DISP);
	guts. limits. XDrawLines = guts. limits. request_length - 3;
	guts. limits. XFillPolygon = guts. limits. request_length - 4;
	guts. limits. XDrawSegments = (guts. limits. request_length - 3) / 2;
	guts. limits. XDrawRectangles = (guts. limits. request_length - 3) / 2;
	guts. limits. XFillRectangles = (guts. limits. request_length - 3) / 2;
	guts. limits. XFillArcs =
		guts. limits. XDrawArcs = (guts. limits. request_length - 3) / 3;
	XCHECKPOINT;
	SCREEN = DefaultScreen( DISP);

	/* XXX - return code? */
	guts. root = RootWindow( DISP, SCREEN);
	guts. displaySize. x = DisplayWidth( DISP, SCREEN);
	guts. displaySize. y = DisplayHeight( DISP, SCREEN);
	XQueryBestCursor( DISP, guts. root,
							guts. displaySize. x,     /* :-) */
							guts. displaySize. y,
							&guts. cursor_width,
							&guts. cursor_height);
	XCHECKPOINT;
	
	TAILQ_INIT( &guts.paintq);
	TAILQ_INIT( &guts.peventq);
	TAILQ_INIT( &guts.bitmap_gc_pool);
	TAILQ_INIT( &guts.screen_gc_pool);
	TAILQ_INIT( &guts.argb_gc_pool);

	guts. currentFocusTime = CurrentTime;
	guts. windows = hash_create();
	guts. menu_windows = hash_create();
	guts. ximages = hash_create();
	gcv. graphics_exposures = false;
	guts. menugc = XCreateGC( DISP, guts. root, GCGraphicsExposures, &gcv);
	guts. resolution. x = 25.4 * guts. displaySize. x / DisplayWidthMM( DISP, SCREEN) + .5;
	guts. resolution. y = 25.4 * DisplayHeight( DISP, SCREEN) / DisplayHeightMM( DISP, SCREEN) + .5;
	guts. depth = DefaultDepth( DISP, SCREEN);
	guts. idepth = get_idepth();
	if ( guts.depth == 1) guts. qdepth = 1; else
	if ( guts.depth <= 4) guts. qdepth = 4; else
	if ( guts.depth <= 8) guts. qdepth = 8; else
		guts. qdepth = 24;
	guts. byte_order = ImageByteOrder( DISP);
	guts. bit_order = BitmapBitOrder( DISP);
	if ( BYTEORDER == LSB32 || BYTEORDER == LSB64)
		guts. machine_byte_order = LSBFirst;
	else if ( BYTEORDER == MSB32 || BYTEORDER == MSB64)
		guts. machine_byte_order = MSBFirst;
	else {
		sprintf( error_buf, "UAA_001: weird machine byte order: %08x", BYTEORDER);
		return false;
	}  

	XInternAtoms( DISP, atom_names, AI_count, 0, guts. atoms);

	guts. null_pointer = nilHandle;
	guts. pointer_invisible_count = 0;
	guts. files = plist_create( 16, 16);
	prima_rebuild_watchers();
	guts. wm_event_timeout = 100;
	guts. menu_timeout = 200;
	guts. scroll_first = 200;
	guts. scroll_next = 50;
	apc_timer_create( CURSOR_TIMER);
	apc_timer_set_timeout(CURSOR_TIMER, 2);
	apc_timer_create( MENU_TIMER);
	apc_timer_set_timeout( MENU_TIMER,  guts. menu_timeout);
	apc_timer_create( MENU_UNFOCUS_TIMER);
	apc_timer_set_timeout( MENU_UNFOCUS_TIMER, 50);
	if ( !prima_init_clipboard_subsystem( error_buf)) return false;
	if ( !prima_init_color_subsystem( error_buf)) return false;
	if ( !prima_init_font_subsystem( error_buf)) return false;
#ifdef WITH_GTK2
	if (!prima_gtk_init()) return false;
#endif
	bzero( &guts. cursor_gcv, sizeof( guts. cursor_gcv));
	guts. cursor_gcv. cap_style = CapButt;
	guts. cursor_gcv. function = GXcopy;

	gethostname( hostname, 256);
	hostname[255] = '\0';
	XStringListToTextProperty((char **)&hostname, 1, &guts. hostname);
	
	guts. net_wm_maximization = prima_wm_net_state_read_maximization( guts. root, NET_SUPPORTED);

	if ( do_sync) XSynchronize( DISP, true);
	return true;
}
Beispiel #14
0
static Bool 
initlisa(ModeInfo * mi, lisas * loop)
{
  lisacons   *lc = &Lisa[MI_SCREEN(mi)];
  lisafuncs **lf = loop->function;
  XPoint     *lp;
  int         phase, pctr, fctr, xctr, yctr, extra_points;
  double      xprod, yprod, xsum, ysum;
  
  xMaxLines = (XMaxRequestSize(MI_DISPLAY(mi))-3)/2;
  /*  printf("Got xMaxLines = %d\n", xMaxLines); */
  loop->nsteps = MI_CYCLES(mi);
  if (loop->nsteps == 0)
	loop->nsteps = 1;
  if (MI_NPIXELS(mi) > 2) {
	loop->color = STARTCOLOR;
	loop->cstep = (loop->nsteps > MI_NPIXELS(mi)) ? loop->nsteps / MI_NPIXELS(mi) : 1;
  } else {
	loop->color = MI_WHITE_PIXEL(mi);
	loop->cstep = 0;
  }
  extra_points = loop->cstep - (loop->nsteps % loop->cstep);
  lc->maxcycles = (MAXCYCLES * loop->nsteps) - 1;
  loop->cstep = ( loop->nsteps > MI_NPIXELS(mi) ) ? loop->nsteps / MI_NPIXELS(mi) : 1;
  /*  printf("Got cstep = %d\n", loop->cstep); */
  loop->melting = 0;
  loop->nfuncs = 1;
  loop->pistep = 2.0 * M_PI / (double) loop->nsteps;
  loop->center.x = lc->width / 2;
  loop->center.y = lc->height / 2;
  loop->radius = (int) MI_SIZE(mi);
  CHECK_RADIUS(loop, lc);
  loop->dx = NRAND(XVMAX);
  loop->dy = NRAND(YVMAX);
  loop->dx++;
  loop->dy++;
#if defined STARTFUNC
  lf[0] = &Function[STARTFUNC];
#else  /* STARTFUNC */
  lf[0] = &Function[NRAND(NUMSTDFUNCS)];
#endif  /* STARTFUNC */	
  
  if ((lp = loop->lastpoint = (XPoint *)
	   calloc(loop->nsteps+extra_points, sizeof (XPoint))) == NULL) {
	free_lisa(lc);
	return False;
  }
  phase = lc->loopcount % loop->nsteps;
  
#if defined DEBUG
  printf( "nsteps = %d\tcstep = %d\tmrs = %d\textra_points = %d\n", 
		  loop->nsteps, loop->cstep, xMaxLines, extra_points );
  PRINT_FUNC(lf[0]);
#endif  /* DEBUG */
  
  for (pctr = 0; pctr < loop->nsteps; pctr++) {
	loop->phi = (double) (pctr - phase) * loop->pistep;
	loop->theta = (double) (pctr + phase) * loop->pistep;
	fctr = loop->nfuncs;
	xsum = ysum = 0.0;
	while (fctr--) {
	  xprod = yprod = (double) loop->radius;
	  xctr = lf[fctr]->nx;
	  yctr = lf[fctr]->ny;
	  while (xctr--)
		xprod *= sin(lf[fctr]->xcoeff[xctr] * loop->theta);
	  while (yctr--)
		yprod *= sin(lf[fctr]->ycoeff[yctr] * loop->phi);
	  xsum += xprod;
	  ysum += yprod;
	}
	if (loop->nfuncs > 1) {
	  xsum /= 2.0;
	  ysum /= 2.0;
	}
	xsum += (double) loop->center.x;
	ysum += (double) loop->center.y;
	
	lp[pctr].x = (int) ceil(xsum);
	lp[pctr].y = (int) ceil(ysum);
  }
  /* this fills in the extra points, so we can use segment-drawing calls */
  for (pctr = loop->nsteps; pctr < loop->nsteps + extra_points; pctr++) {
	lp[pctr].x=lp[pctr - loop->nsteps].x;
	lp[pctr].y=lp[pctr - loop->nsteps].y;
  }
#if defined DRAWLINES
  loop->linewidth = LINEWIDTH;	/* #### make this a resource */
  
  if (loop->linewidth == 0)
	loop->linewidth = 1;
  if (loop->linewidth < 0)
	loop->linewidth = NRAND(-loop->linewidth) + 1;
  XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), loop->linewidth,
					 LINESTYLE, LINECAP, LINEJOIN);
#endif  /* DRAWLINES */
  
  if ( loop->cstep < xMaxLines ) { 
	/* we can send each color segment in a single request 
	 * because the max request length is long enough 
	 * and because we have padded out the array to have extra elements 
	 * to support calls which would otherwise fall off the end*/
	for (pctr = 0; pctr < loop->nsteps; pctr+=loop->cstep) {
	  /* Set the color */
	  SET_COLOR();
	  
#if defined DRAWLINES
	  XDrawLines(MI_DISPLAY(mi), MI_WINDOW(mi),
				 MI_GC(mi), &lp[pctr], loop->cstep, CoordModeOrigin );
#else  /* DRAWLINES */
	  XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
				  &lp[pctr], loop->cstep, CoordModeOrigin );
#endif  /* DRAWLINES */
	}
  } else { /* do it one by one as before */
	for (pctr = 0; pctr < loop->nsteps; pctr++ ) {
	  SET_COLOR();
	  
#if defined DRAWLINES
	  XDrawLine(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
				lp[pctr].x, lp[pctr].y,
				lp[pctr+1 % loop->nsteps].x, lp[pctr+1 % loop->nsteps].y);
#else  /* DRAWLINES */
	  XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
				 lp[pctr].x, lp[pctr].y);
#endif  /* DRAWLINES */
	}
  }
  
#if defined DRAWLINES
  XSetLineAttributes(MI_DISPLAY(mi), MI_GC(mi), 1,
					 LINESTYLE, LINECAP, LINEJOIN);
#endif  /* DRAWLINES */
  return True;
}
Beispiel #15
0
/* Put data into a selection, in response to a SelecionRequest event from
 * another window (and any subsequent events relating to an INCR transfer).
 *
 * Arguments are:
 *   A display
 *   A window
 *   The event to respond to
 *   A pointer to an Atom. This gets set to the property nominated by the other
 *     app in it's SelectionRequest. Things are likely to break if you change the
 *     value of this yourself.
 *   The target (UTF8_STRING or XA_STRING) to respond to
 *   A pointer to an array of chars to read selection data from.
 *   The length of the array of chars.
 *   In case of an INCR transfer, the position within the array of chars that's being processed.
 *   The context that event is the be processed within.
 */
static int xcin( Display*dpy, Window*win, XEvent evt, Atom*prop, 
                   Atom trg, uchar*txt, ulong len, ulong*pos, uint *ctx )
{
  ulong chunk_len;  /* length of current chunk (for incr transfers only) */
  XEvent resp;      /* response to event */
  static Atom inc;
  static Atom targets;
  static long chunk_size;
  if (!targets) { targets = XInternAtom(dpy, "TARGETS", False); }
  if (!inc) { inc = XInternAtom(dpy, "INCR", False); }
  /* Treat selections larger than 1/4 of the max request size as "large" per ICCCM sect. 2.5 */
  if (!chunk_size) {
    chunk_size = XExtendedMaxRequestSize(dpy) / 4;
    if (!chunk_size) { chunk_size = XMaxRequestSize(dpy) / 4; }
  }
  switch (*ctx) {
    case XCLIB_XCIN_NONE: {
      if (evt.type != SelectionRequest) { return (0); }
      *win = evt.xselectionrequest.requestor;
      *prop = evt.xselectionrequest.property;
      *pos = 0;
      if (evt.xselectionrequest.target == targets) {   /* put the data into an property */
        Atom types[2];
        int size=(int)(sizeof(types)/sizeof(Atom));
        types[0]=targets;
        types[1]=trg;
        /* send data all at once (not using INCR) */
        XChangeProperty(dpy,*win,*prop,XA_ATOM,32,PropModeReplace,(uchar*)types,size);
      } else if (len > chunk_size) {
        XChangeProperty(dpy,*win,*prop,inc,32,PropModeReplace,0,0); /* send INCR response */
        /* With INCR, we need to know when requestor window changes/deletes properties */
        XSelectInput(dpy, *win, PropertyChangeMask);
        *ctx = XCLIB_XCIN_INCR;
      } else {
        XChangeProperty(dpy,*win,*prop,trg,8,PropModeReplace,(uchar*)txt,(int)len); /* All, not INCR */
      }

      /* FIXME? According to ICCCM section 2.5, we should confirm that X ChangeProperty
         succeeded without any Alloc errors before replying with SelectionNotify. 
         However, doing so would require an error handler which modifies a global
         variable, plus doing XSync after each X ChangeProperty. */
      resp.xselection.property = *prop;
      resp.xselection.type = SelectionNotify;
      resp.xselection.display = evt.xselectionrequest.display;
      resp.xselection.requestor = *win;
      resp.xselection.selection = evt.xselectionrequest.selection;
      resp.xselection.target = evt.xselectionrequest.target;
      resp.xselection.time = evt.xselectionrequest.time;
      XSendEvent(dpy, evt.xselectionrequest.requestor, 0, 0, &resp); /* send response event */
      XFlush(dpy);
      return (len > chunk_size) ? 0 : 1; /* if data sent all at once, transfer is complete. */
      break;
    }
    case XCLIB_XCIN_INCR: { 
      if (evt.type != PropertyNotify) { return (0); } /* ignore non-property events */
      if (evt.xproperty.state != PropertyDelete) { return (0); }   /* only interest in deleted props */
      chunk_len = chunk_size; /* set length to max size */
      /* if a max-sized chunk length would extend past end, set length to remaining txt length */
      if ((*pos + chunk_len) > len) { chunk_len = len - *pos; }

      /* if start of chunk is beyond end of txt, then we've sent all data, so set length to zero */
      if (*pos > len) { chunk_len = 0; }
      if (chunk_len) {  /* put chunk into property */
        XChangeProperty(dpy,*win,*prop,trg,8,PropModeReplace,&txt[*pos],(int)chunk_len);
      } else {
        XChangeProperty(dpy,*win,*prop,trg,8,PropModeReplace,0,0); /* empty prop shows we're done */
      }
      XFlush(dpy);
      if (!chunk_len) { *ctx = XCLIB_XCIN_NONE; }   /* all data is sent, break out of the loop */
      *pos += chunk_size;
      return (chunk_len==0) ? 1 : 0; /* chunk_len == 0 means we finished the transfer. */
      break;
    }
  }
  return (0);
}