Limpar buffer X específico diretamente, sem passar pelo xsel ou xclip

2

Estou tentando desabilitar completamente o clique do meio para colar de um buffer, usando a solução da Radivarig .

Place this in ~/.xbindkeysrc

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

Esta solução, no entanto, depende de xsel (ou, equivalentemente, xclip ) concluindo seu trabalho rapidamente.

Recentemente, notei um atraso de vários segundos para xsel e xclip ao tentar limpar o buffer principal.

Existe um modo menos "educado" do que o que o xsel ou xclip está fazendo para forçar o X a esvaziar um buffer específico?

A distribuição Linux em questão é Manjaro ... isso pode ser um bug específico do Manjaro ou Arch, mas informações orientadas ao usuário final sobre como interagir com o servidor X11 sem xsel ou xclip ou outro similar ferramenta parece ser um pouco falta.

~  > 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

Eu anexei gdb a um dos xclip s e ele parece estar parado esperando uma resposta do servidor X.

(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 ?? ()

Eu tentei escrever um programa simplificado usando a API X diretamente, com base em parte do código-fonte xsel , em particular: link .

Para limpar o buffer, o xsel parece estar confiando nessa propriedade de 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.

Esta é minha tentativa de remover o xsel da funcionalidade de que preciso.

Suponho que o proprietário do buffer XA_PRIMARY geralmente não seja None . Eu estou configurando para None dentro do corpo do meu programa C e depois esperando que funcionasse.

// 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;
}

Este programa é executado e imprime

100
300
400
500
200

como esperado.

No entanto, não conseguiu limpar o buffer principal.

xclip -selection -primary out mostra a mesma coisa antes e depois.

    
por Gregory Nisbet 16.10.2018 / 23:46

1 resposta

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

Isso não funcionará. Como a primeira linha no DESCRIPTION de XSetSelectionOwner(3) diz:

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.

Você terá que passar um timestamp real, que você pode obter de um XEvent recebido do servidor. Isto é o que eu fiz na minha própria implementação de 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;
        }
}

Eu defino uma propriedade em uma janela, aguardo o evento PropertyNotify e obtenho o timestamp da estrutura XPropertyEvent . A janela pode ser um InputOnly one. Isso também é descrito no manual de programação xlib ou em alguma página do X11.

Infelizmente, isso também significa que seu pequeno programa não será rápido o suficiente, já que tem que esperar pelo evento; -)

Eu não acho que as respostas para o link pergunta são satisfatórios. É melhor explorar usando algum LD_PRELOAD hack ou modificar os programas que estão causando problemas.

    
por 17.10.2018 / 00:32

Tags