¿Es posible conocer la fuente (aplicación) del portapapeles?

10

Me di cuenta de que a veces el contenido del portapapeles no está disponible si la aplicación de origen (de donde se copió el contenido) está cerrada.

Esto me lleva a preguntarme si es posible saber cuál es la aplicación de origen (por ejemplo, tal vez por PID).

¿Por qué? Si la aplicación de origen es una terminal, me gustaría encontrar el directorio de trabajo de la terminal, en caso de que el contenido copiado sea una ruta relativa, para construir una ruta completa a un archivo.

FYI, actualmente estoy usando xclip para determinar el contenido del portapapeles, por ejemplo

xclip -selection primary -t STRING -o 2> /dev/null
Jeff Ward
fuente
2
XGetSelectionOwner(3)le proporciona la identificación de la ventana del propietario de la selección. Desde el cual puede subir el árbol de la ventana para tratar de encontrar una ventana con una propiedad _NET_WM_PID con xprop(suponiendo que esa ventana proviene de un cliente local que establece esa propiedad). xwininfo -root -tree | less +/0x<that-id>puede ser suficiente para identificar la aplicación.
Stéphane Chazelas
2
Lo que dijo @ StéphaneChazelas. Pero tenga en cuenta que es poco probable que obtenga un PID confiable del otro cliente de X11. Recordando que los clientes X se conectan a los servidores X a través de conexiones de red genéricas (socket UNIX o socket TCP), un PID podría no tener sentido ya que la aplicación podría no ser local. Puede estar conectado a través de TCP (ya no es común en estos días) o una conexión X11 reenviada por SSH (más común).
Celada
Gracias por las notas. Supongo que tendré que escribir un código C para acceder a XGetSelectionOwner. Probablemente pueda hacer eso: volveré a publicar cuando llegue a una solución.
Jeff Ward

Respuestas:

5

Escribí una herramienta que devuelve el nombre de la aplicación simple (por ejemplo, 'Terminal', 'gedit' o 'SmartGit', que son los que probé). La mayor parte del código es robado descaradamente de @Harvey aquí .

// 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
fuente
Un gran comienzo, gracias! Hmm, funciona con terminal, Firefox y Chrome, pero arroja "No se puede obtener la propiedad WM_NAME" para otros como emacs y robomongo, etc. Me pregunto si esa es la parte de "caminar por el árbol" a la que se refería Stéphane.
Jeff Ward
Yo probé la adición de un "padre intentarlo hasta que la propiedad se encuentra WM_NAME" - y que el trabajo realizado emacs, aunque no robomongo. Interesante. Esta respuesta también tiene información relevante para encontrar el PID: unix.stackexchange.com/questions/5478/… Curiosamente, este PID (¿es cardinal?) Es el mismo para todas las ventanas de "Terminal". Esto no es un buen augurio para mi caso de uso específico, ya que cada terminal puede estar en un directorio de trabajo actual separado.
Jeff Ward
Si. No tuve suerte con la propiedad "_NET_WM_PID" para obtener el PID, pero esperaba que pudieras usar el nombre como punto de partida.
jschlichtholz
1
@JeffWard algunos programas de terminal modernos como gnome-terminaliniciar solo una vez la instancia de la aplicación por sesión en lugar de una instancia por ventana de terminal como venerable xterm. ¿Quizás por eso estás viendo el mismo PID en todos ellos? Porque gnome-terminalsolía deshabilitar esa característica errónea con --disable-factory(nombre extraño para una opción) pero aparentemente eso ya no sería posible . De todos modos, parece que necesita la contraseña de uno de los procesos que se ejecutan dentro del terminal, no de sí mismo.
Celada
@Celada, es cierto, y tiene sentido: el sistema de ventanas X conoce las ventanas, no necesariamente lo que cada programa elige hacer con ellas. También parece que Chrome tiene una ventana separada (¿o proceso?) Dedicada al portapapeles. Aparentemente hay muchos esquemas, y mi idea puede no funcionar.
Jeff Ward,