Чи можна знати джерело (додаток) буфера обміну?


10

Я помітив, що іноді вміст буфера обміну стає недоступним, якщо вихідна програма (куди було скопійовано вміст) закрита.

Це змушує мене замислитися, чи можна дізнатися, що таке програма-джерело (наприклад, можливо, PID).

Чому? Якщо вихідним додатком є ​​термінал, я хотів би знайти робочий каталог терміналу, якщо скопійований вміст є відносним шляхом, щоб побудувати повний шлях до файлу.

FYI, я зараз використовую xclip для визначення вмісту буфера обміну, наприклад

xclip -selection primary -t STRING -o 2> /dev/null

2
XGetSelectionOwner(3)отримує ідентифікатор вікна власника вибору. З якого ви можете підійти до дерева вікон, щоб спробувати знайти вікно з властивістю _NET_WM_PID, наприклад, з xprop(якщо припустити, що вікно походить від локального клієнта, який встановлює цю властивість). xwininfo -root -tree | less +/0x<that-id>може бути достатньо для ідентифікації програми.
Стефан Шазелас

2
Що сказав @ StéphaneChazelas Але майте на увазі, що навряд чи ви отримаєте надійний PID іншого клієнта з X11. Пам’ятаючи, що клієнти X підключаються до X-серверів за допомогою загальних мережевих підключень (UNIX-сокет або TCP-сокет), PID може бути безглуздим, оскільки програма може бути не локальною. Він може бути підключений через TCP (більше не поширений в ці дні) або передане SSH-з'єднання X11 (більш поширене).
Селада

Дякую за замітки - я припускаю, що мені потрібно буде написати якийсь код C для доступу до XGetSelectionOwner? Я, мабуть, можу це зробити - я відправлю назад, коли прийду до рішення.
Джефф Уорд

Відповіді:


5

Я написав інструмент, який повертає звичайну назву програми (наприклад, "Terminal", "gedit" або "SmartGit", які я тестував). Більшість кодів безсоромно викрадено у @Harvey тут .

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

Чудовий початок, дякую! Хм, він працює з терміналом, firefox та chrome, але кидає "Неможливо отримати власність WM_NAME" для інших, таких як emacs та robomongo тощо. Мені цікаво, чи це частина "прогулянки по дереву", на яку посилався Стефан.
Джефф Уорд

Я спробував додати "спробувати батьків, поки не буде знайдено властивість WM_NAME" - і це призвело до того, що emacs працює, хоча і не робомонго. Цікаво. У цій відповіді є також відповідна інформація для пошуку PID: unix.stackexchange.com/questions/5478/… Цікаво, що цей PID (будучи кардинальним?) Однаковий для всіх вікон "Терміналу". Це не означає нічого для мого конкретного випадку використання, оскільки кожен термінал може бути в окремому поточному робочому каталозі.
Джефф Уорд

Так. Мені не пощастило з властивістю "_NET_WM_PID" отримати PID, але я сподівався, що ви можете використовувати це ім'я як вихідну точку.
jschlichtholz

1
@JeffWard деякі сучасні програми терміналів, такі як gnome-terminalзапуск лише одного разу екземпляр програми за сеанс, а не один екземпляр у вікні терміналу, як поважний xterm. Можливо, саме тому ви бачите однаковий PID в усіх них? Для НЕ gnome-terminalви використовували , щоб мати можливість відключити цю помилкову особливість з --disable-factory(непарних назвою опції) , але , по- видимому , що , можливо , більше не буде можливим . У будь-якому випадку, це здається, що вам потрібен pwd одного з процесів, що працюють всередині терміналу, а не сам по собі.
Селада

@Celada - правильно, і це має сенс - система X вікон знає про вікна, не обов'язково те, що кожна програма обирає робити з ними. Також виявляється, що у Chrome є окреме вікно (чи процес?), Присвячене буфера обміну. Мабуть, є багато схем, і моя ідея може не зникати.
Джефф Уорд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.