Ist es möglich, die Quelle (Anwendung) der Zwischenablage zu kennen?

10

Ich habe festgestellt, dass der Inhalt der Zwischenablage manchmal nicht mehr verfügbar ist, wenn die Quellanwendung (aus der der Inhalt kopiert wurde) geschlossen wird.

Dies führt mich zu der Frage, ob es möglich ist, die Quellanwendung zu kennen (z. B. durch PID).

Warum? Wenn die Quellanwendung ein Terminal ist, möchte ich das Arbeitsverzeichnis des Terminals finden, falls der kopierte Inhalt ein relativer Pfad ist, um einen vollständigen Pfad zu einer Datei zu erstellen.

Zu Ihrer Information, ich verwende derzeit xclip, um den Inhalt der Zwischenablage zu bestimmen, z

xclip -selection primary -t STRING -o 2> /dev/null
Jeff Ward
quelle
2
XGetSelectionOwner(3)Ruft die Fenster-ID des Eigentümers der Auswahl ab. Von hier aus können Sie im Fensterbaum versuchen, ein Fenster mit einer _NET_WM_PID-Eigenschaft zu finden, beispielsweise mit xprop(vorausgesetzt, das Fenster stammt von einem lokalen Client, der diese Eigenschaft festlegt). xwininfo -root -tree | less +/0x<that-id>kann ausreichen, um die Anwendung zu identifizieren.
Stéphane Chazelas
2
Was @ StéphaneChazelas gesagt hat. Beachten Sie jedoch, dass es unwahrscheinlich ist, dass Sie aus X11 eine zuverlässige PID des anderen Clients erhalten. Denken Sie daran, dass X-Clients über generische Netzwerkverbindungen (UNIX-Socket oder TCP-Socket) eine Verbindung zu X-Servern herstellen. Eine PID ist möglicherweise bedeutungslos, da die Anwendung möglicherweise nicht lokal ist. Möglicherweise wird eine Verbindung über TCP (heutzutage nicht mehr üblich) oder eine über SSH weitergeleitete X11-Verbindung (häufiger) hergestellt.
Celada
Vielen Dank für die Hinweise. Ich gehe davon aus, dass ich C-Code schreiben muss, um dann auf XGetSelectionOwner zugreifen zu können. Ich kann das wahrscheinlich tun - ich werde zurückschreiben, wenn ich zu einer Lösung komme.
Jeff Ward

Antworten:

5

Ich habe ein Tool geschrieben, das den einfachen Anwendungsnamen zurückgibt (z. B. 'Terminal', 'gedit' oder 'SmartGit', die ich getestet habe). Die meisten Code ist schamlos aus @Harvey gestohlen hier .

// 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
quelle
Ein toller Start, danke! Hmm, es funktioniert mit Terminal, Firefox und Chrome, wirft aber "Kann WM_NAME-Eigenschaft nicht erhalten" für andere wie Emacs und Robomongo usw. Ich frage mich, ob das der Teil "Walk the Tree" ist, auf den sich Stéphane bezog.
Jeff Ward
Ich habe versucht, ein "try parent, bis die Eigenschaft WM_NAME gefunden wird" hinzuzufügen - und das hat dazu geführt, dass Emacs funktionieren, aber nicht Robomongo. Interessant. Diese Antwort enthält auch einige relevante Informationen zum Auffinden der PID: unix.stackexchange.com/questions/5478/… Interessanterweise ist diese PID (Kardinal?) Für alle "Terminal" -Fenster gleich. Dies ist kein gutes Zeichen für meinen speziellen Anwendungsfall, da sich jedes Terminal möglicherweise in einem separaten aktuellen Arbeitsverzeichnis befindet.
Jeff Ward
Ja. Ich hatte kein Glück mit der Eigenschaft "_NET_WM_PID", die PID zu erhalten, aber ich hoffte, Sie könnten den Namen als Ausgangspunkt verwenden.
Jschlichtholz
1
@JeffWard einige moderne Terminalprogramme wie gnome-terminalstarten nur einmal Instanz der Anwendung pro Sitzung anstelle einer Instanz pro Terminalfenster wie ehrwürdig xterm. Vielleicht sehen Sie deshalb in allen die gleiche PID? Für gnome-terminalSie , dass misfeature mit der Lage sein , verwendet zu deaktivieren --disable-factory(ungeradeem Namen für eine Option) , aber offensichtlich , dass nicht mehr möglich sein könnte . Wie auch immer, es hört sich so an, als ob Sie das pwd eines der Prozesse benötigen, die im Terminal ausgeführt werden, nicht von sich selbst.
Celada
@ Celada - richtig, und es macht Sinn - das X-Fenstersystem kennt Windows, nicht unbedingt, was jedes Programm damit macht. Es scheint auch, dass Chrome ein separates Fenster (oder einen Prozess?) Für die Zwischenablage hat. Anscheinend gibt es viele Schemata, und meine Idee kann nicht umgesetzt werden.
Jeff Ward