É possível conhecer a fonte (aplicativo) da área de transferência?

10

Percebi que, às vezes, o conteúdo da área de transferência fica indisponível se o aplicativo de origem (de onde o conteúdo foi copiado) estiver fechado.

Isso me leva a pensar se é possível saber qual é o aplicativo de origem (por exemplo, talvez por PID).

Por quê? Se o aplicativo de origem for um terminal, eu gostaria de encontrar o diretório de trabalho do terminal, caso o conteúdo copiado seja um caminho relativo, para construir um caminho completo para um arquivo.

Para sua informação, atualmente estou usando o xclip para determinar o conteúdo da área de transferência, por exemplo

xclip -selection primary -t STRING -o 2> /dev/null
Jeff Ward
fonte
2
XGetSelectionOwner(3)fornece o ID da janela do proprietário da seleção. A partir do qual você pode percorrer a árvore da janela para tentar encontrar uma janela com uma propriedade _NET_WM_PID, por exemplo, com xprop(assumindo que a janela vem de um cliente local que define essa propriedade). xwininfo -root -tree | less +/0x<that-id>pode ser suficiente para identificar o aplicativo.
Stéphane Chazelas
2
O que @ StéphaneChazelas disse. Mas lembre-se de que é improvável que você obtenha um PID confiável do outro cliente no X11. Lembrando que os clientes X se conectam aos servidores X por meio de conexões de rede genéricas (soquete UNIX ou soquete TCP), um PID pode não ter sentido, pois o aplicativo pode não ser local. Pode estar conectado por TCP (não é mais comum atualmente) ou por uma conexão X11 encaminhada por SSH (mais comum).
23915 Celada
Obrigado pelas anotações - presumo que precisarei escrever um código C para acessar o XGetSelectionOwner, então? Provavelmente, posso fazer isso - postarei de volta quando chegar a uma solução.
Jeff Ward

Respostas:

5

Eu escrevi uma ferramenta que retorna o nome simples do aplicativo (por exemplo, 'Terminal', 'gedit' ou 'SmartGit', que são os que eu testei). A maioria dos códigos é descaradamente roubada do @Harvey aqui .

// gcc clipboard-owner.c -lX11 -o clipboard-owner

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>

#define MAX_PROPERTY_VALUE_LEN 4096

typedef unsigned long ulong;

static char *get_property(Display *, Window, Atom , const char *, ulong *);

int main(void)
{
  // Open the Display
  Display *display = XOpenDisplay(NULL);

  // Get the selection window
  Window selection_owner = XGetSelectionOwner(display, XA_PRIMARY);

  if(!selection_owner) {
    exit(0);
  } else {
      char *window_name = get_property(display, selection_owner, XA_STRING, "WM_NAME", NULL);
      printf("%s\n", window_name);
  }

  XCloseDisplay(display);
}

static char *get_property (Display *disp, Window win,
        Atom xa_prop_type, const char *prop_name, ulong *size) {
    Atom xa_prop_name;
    Atom xa_ret_type;
    int ret_format;
    ulong ret_nitems;
    ulong ret_bytes_after;
    ulong tmp_size;
    unsigned char *ret_prop;
    char *ret;

    xa_prop_name = XInternAtom(disp, prop_name, False);

    if (XGetWindowProperty(disp, win, xa_prop_name, 0,
            MAX_PROPERTY_VALUE_LEN / 4, False,
            xa_prop_type, &xa_ret_type, &ret_format,     
            &ret_nitems, &ret_bytes_after, &ret_prop) != Success) {
        printf("Cannot get %s property.\n", prop_name);
        return NULL;
    }

    if (xa_ret_type != xa_prop_type) {
        printf("Invalid type of %s property.\n", prop_name);
        XFree(ret_prop);
        return NULL;
    }

    /* null terminate the result to make string handling easier */
    tmp_size = (ret_format / 8) * ret_nitems;
    /* Correct 64 Architecture implementation of 32 bit data */
    if(ret_format==32) tmp_size *= sizeof(long)/4;
    ret = (char *)malloc(tmp_size + 1);
    memcpy(ret, ret_prop, tmp_size);
    ret[tmp_size] = '\0';

    if (size) {
        *size = tmp_size;
    }

    XFree(ret_prop);
    return ret;
}
jschlichtholz
fonte
Um ótimo começo, obrigado! Hmm, ele funciona com terminal, firefox e chrome, mas lança "Não é possível obter a propriedade WM_NAME" para outros, como emacs e robomongo, etc. Gostaria de saber se essa é a parte "caminhar na árvore" a que Stéphane se referia.
Jeff Ward
Eu tentei adicionar um "pai tentar até WM_NAME propriedade encontra-se" - e que fez um trabalho emacs, embora não robomongo. Interessante. Esta resposta também possui algumas informações relevantes para encontrar o PID: unix.stackexchange.com/questions/5478/… Curiosamente, esse PID (sendo cardinal?) É o mesmo para todas as janelas "Terminal". Isso não é um bom presságio para o meu caso de uso específico, pois cada terminal pode estar em um diretório de trabalho atual separado.
Jeff Ward
Sim. Não tive sorte com a propriedade "_NET_WM_PID" para obter o PID, mas esperava que você pudesse usar o nome como ponto de partida.
Jschlichtholz
1
@ Jeffffard alguns programas modernos de terminal, como gnome-terminaliniciar apenas uma instância do aplicativo por sessão, em vez de uma instância por janela de terminal, como venerável xterm. Talvez seja por isso que você esteja vendo o mesmo PID em todos eles? Para gnome-terminalvocê costumava ser capaz de desativar que misfeature com --disable-factory(nome estranho para uma opção), mas aparentemente isso pode não ser mais possível . Enfim, parece que você precisa da senha de um dos processos em execução no terminal, não de si mesma.
Celada
@ Celada - certo, e faz sentido - o sistema de janelas X sabe sobre janelas, não necessariamente o que cada programa escolhe fazer com elas. Parece também que o Chrome possui uma janela (ou processo?) Separado dedicado à área de transferência. Aparentemente, existem muitos esquemas, e minha ideia pode não dar certo.
Jeff Ward