3

I am trying to completely disable middle-click for pasting from a buffer, using Radivarig's solution.

Place this in ~/.xbindkeysrc

"echo -n | xsel -n -i; pkill xbindkeys; xdotool click 2; xbindkeys"
b:2 + Release

This solution, however, depends on xsel (or, equivalently, xclip) completing its job quickly.

Recently I've noticed a delay of several seconds for xsel and xclip when attempting to clear the primary buffer.

Is there a less "polite" way than whatever xsel or xclip are doing to force X to empty a specific buffer?

The Linux distribution in question is Manjaro ... this could be a Manjaro or Arch-specific bug, but end-user-oriented information about how to interact with the X11 server without xsel or xclip or another similar tool seems to be somewhat lacking.

~  > xclip -selection primary -verbose -in </dev/null
Connected to X server.
Using selection: XA_PRIMARY
Using UTF8_STRING.
Waiting for selection requests, Control-C to quit
  Waiting for selection request number 1
  Waiting for selection request number 2
Time: 13s

~  > xclip -selection primary -verbose -in </dev/null
...
Time: 11s

~  > xclip -selection primary -verbose -in </dev/null
...
Time: 23s

I attached gdb to one of the hung xclips and it appears to be stuck waiting for a response from the X server.

(gdb) where
#0  0x00007f905e1f1b78 in poll () from /usr/lib/libc.so.6
#1  0x00007f905dc68630 in ?? () from /usr/lib/libxcb.so.1
#2  0x00007f905dc6a2db in xcb_wait_for_event () from /usr/lib/libxcb.so.1
#3  0x00007f905e306009 in _XReadEvents () from /usr/lib/libX11.so.6
#4  0x00007f905e2f4ee1 in XNextEvent () from /usr/lib/libX11.so.6
#5  0x0000563eb8eaea70 in ?? ()
#6  0x00007f905e125223 in __libc_start_main () from /usr/lib/libc.so.6
#7  0x0000563eb8eaf53e in ?? ()

I attempted to write a stripped down program using the X API directly, based on part of the xsel source code, in particular: https://github.com/kfish/xsel/blob/master/xsel.c#L1003-L1018 .

In order to clear the buffer, xsel appears to be relying on this property of XSetSelectionOwner:

If the new owner (whether a client or None ) is not the same as the current owner of the selection and the current owner is not None , the current owner is sent a SelectionClear event. If the client that is the owner of a selection is later terminated (that is, its connection is closed) or if the owner window it has specified in the request is later destroyed, the owner of the selection automatically reverts to None , but the last-change time is not affected. The selection atom is uninterpreted by the X server. XGetSelectionOwner() returns the owner window, which is reported in SelectionRequest and SelectionClear events. Selections are global to the X server.

Here's my attempt to strip down xsel to just the functionality I need.

I'm assuming that the owner of the XA_PRIMARY buffer usually isn't None. I am setting it to None inside the body of my C program and then hoping it worked.

// clear.c
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <assert.h>

// always debug
#undef NDEBUG

static Display * display = NULL;

static char * display_name = NULL;

static void clear_selection(void)
{
  printf("%d\n", 300);
  display = XOpenDisplay(display_name);
  assert(display != NULL);
  printf("%d\n", 200);
  XSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);
  printf("%d\n, 500);
  XSync(display, False);
  return;
}

int main(void)
{
  printf("%d\n", 100);
  clear_selection();
  printf("%d\n", 200);
  return 0;
}

This program runs and prints

100
300
400
500
200

as expected.

However, it failed to clear the primary buffer.

xclip -selection -primary out shows the same thing before and after.

1 Answer 1

2
  XSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);

This will not work. As the first line in the DESCRIPTION of XSetSelectionOwner(3) says:

The XSetSelectionOwner function changes the owner and last-change time for the specified selection and has no effect if the specified time is earlier than the current last-change time of the specified selection or is later than the current X server time.

You'll have to pass it a real timestamp, which you could obtain from an XEvent received from the server. This is what I did in my own implementation of xsel:

Time getctime(void){
        XSelectInput(dpy, w, PropertyChangeMask);
        XStoreName(dpy, w, "xsel");
        for(;;){
                XEvent e;
                XNextEvent(dpy, &e);
                if(e.type == PropertyNotify && e.xproperty.window == w)
                        return e.xproperty.time;
        }
}

I set a property on a window, wait for the PropertyNotify event and then get the timestamp from the XPropertyEvent structure. The window can be an InputOnly one. This is also described in the xlib programming manual, or some X11 manpage.

Unfortunately, that will also mean that your little program won't be quick enough either, as it has to wait for that event ;-)

I don't think that the answers to the linked question are satisfactory. You better explore using some LD_PRELOAD hack, or modifying the programs that are causing you trouble.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .