Czy można poznać źródło (aplikację) schowka?

10

Zauważyłem, że czasami zawartość schowka staje się niedostępna, jeśli aplikacja źródłowa (z której treść została skopiowana) jest zamknięta.

To prowadzi mnie do zastanowienia się, czy można dowiedzieć się, co to jest aplikacja źródłowa (np. Przez PID).

Dlaczego? Jeśli aplikacją źródłową jest terminal, chciałbym znaleźć katalog roboczy terminala, na wypadek gdyby skopiowana zawartość była ścieżką względną, aby utworzyć pełną ścieżkę do pliku.

Do Twojej wiadomości, obecnie używam xclip do określenia zawartości schowka, np

xclip -selection primary -t STRING -o 2> /dev/null
Jeff Ward
źródło
2
XGetSelectionOwner(3)pobiera identyfikator okna właściciela zaznaczenia. Z którego można przejść po drzewie okien, aby na przykład znaleźć okno z właściwością _NET_WM_PID xprop(przy założeniu, że okno pochodzi od lokalnego klienta, który ustawia tę właściwość). xwininfo -root -tree | less +/0x<that-id>może wystarczyć do zidentyfikowania aplikacji.
Stéphane Chazelas
2
Co powiedział @ StéphaneChazelas. Ale pamiętaj, że prawdopodobnie nie uzyskasz niezawodnego PID drugiego klienta z X11. Pamiętając, że klienci X łączą się z serwerami X za pośrednictwem ogólnych połączeń sieciowych (gniazdo UNIX lub gniazdo TCP), PID może nie mieć znaczenia, ponieważ aplikacja może nie być lokalna. Może być połączony przez TCP (obecnie nie jest to obecnie powszechne) lub połączenie X11 przekazane przez SSH (bardziej powszechne).
Celada
Dzięki za notatki - zakładam, że będę musiał napisać kod C, aby uzyskać dostęp do XGetSelectionOwner? Prawdopodobnie mogę to zrobić - wyślę wiadomość, gdy dojdę do rozwiązania.
Jeff Ward

Odpowiedzi:

5

Napisałem narzędzie, które zwraca prostą nazwę aplikacji (np. „Terminal”, „gedit” lub „SmartGit”, które testowałem). Większość kodu jest bezwstydnie skradziona z @Harvey tutaj .

// 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
źródło
Świetny początek, dzięki! Hmm, działa z terminalem, firefoxem i chromem, ale rzuca „Nie można uzyskać właściwości WM_NAME” dla innych, takich jak emacs i robomongo itp. Zastanawiam się, czy to była część „chodzić po drzewie”, o której mówił Stéphane.
Jeff Ward
Ja próbowałem dodając do „try rodzica aż nieruchomość WM_NAME znajduje się” - i że wykonane prace emacs, choć nie robomongo. Ciekawy. Ta odpowiedź zawiera również istotne informacje dotyczące znalezienia PID: unix.stackexchange.com/questions/5478/... Co ciekawe, ten PID (będąc kardynałem?) Jest taki sam dla wszystkich okien „Terminal”. Nie wróży to dobrze dla mojego konkretnego przypadku użycia, ponieważ każdy terminal może znajdować się w osobnym bieżącym katalogu roboczym.
Jeff Ward
Tak. Nie miałem szczęścia z właściwością „_NET_WM_PID”, aby uzyskać PID, ale miałem nadzieję, że użyjesz tej nazwy jako punktu wyjścia.
jschlichtholz
1
@JeffWard niektóre nowoczesne programy terminalowe, takie jak gnome-terminaluruchamianie tylko raz wystąpienie aplikacji na sesję zamiast jednego wystąpienia na okno terminala, jak czcigodny xterm. Może dlatego widzisz ten sam PID we wszystkich? Dla gnome-terminalużyłeś aby móc wyłączyć tę misfeature z --disable-factory(nieparzyste nazwy opcji), ale widocznie, że może nie być możliwe . W każdym razie wygląda na to, że potrzebujesz pwd jednego z procesów działających w terminalu, a nie samego.
Celada
@Celada - racja i ma to sens - system okien X wie o oknach, niekoniecznie o tym, co każdy program z nimi zrobi. Wygląda również na to, że Chrome ma osobne okno (lub proces?) Dedykowane do schowka. Najwyraźniej istnieje wiele schematów i mój pomysł może się nie udać.
Jeff Ward