Có thể biết nguồn (ứng dụng) của clipboard?


10

Tôi đã nhận thấy rằng đôi khi nội dung clipboard trở nên không khả dụng nếu ứng dụng nguồn (nơi nội dung được sao chép từ đó) bị đóng.

Điều này khiến tôi tự hỏi liệu có thể biết ứng dụng nguồn là gì không (ví dụ như có lẽ bởi PID).

Tại sao? Nếu ứng dụng nguồn là một thiết bị đầu cuối, tôi muốn tìm thư mục làm việc của thiết bị đầu cuối, trong trường hợp nội dung được sao chép là một đường dẫn tương đối, để xây dựng một đường dẫn đầy đủ đến một tệp.

FYI, tôi hiện đang sử dụng xclip để xác định nội dung clipboard, ví dụ:

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

2
XGetSelectionOwner(3)giúp bạn có id cửa sổ của chủ sở hữu của lựa chọn. Từ đó bạn có thể đi lên cây cửa sổ để thử và tìm một cửa sổ có thuộc tính _NET_WM_PID xprop(giả sử cửa sổ đó đến từ một máy khách cục bộ đặt thuộc tính đó). xwininfo -root -tree | less +/0x<that-id>có thể đủ để xác định ứng dụng.
Stéphane Chazelas

2
Những gì @ StéphaneChazelas nói. Nhưng hãy lưu ý rằng bạn khó có thể có được một bộ lọc đáng tin cậy của khách hàng khác trong X11. Hãy nhớ rằng các máy khách X kết nối với máy chủ X thông qua các kết nối mạng chung (ổ cắm UNIX hoặc ổ cắm TCP), một PID có thể là vô nghĩa vì ứng dụng có thể không cục bộ. Nó có thể được kết nối qua TCP (không còn phổ biến nữa trong những ngày này) hoặc kết nối X11 chuyển tiếp SSH (phổ biến hơn).
Celada

Cảm ơn các ghi chú - Tôi giả sử tôi sẽ cần viết một số mã C để truy cập XGetSelectionOwner? Tôi có thể làm điều đó - tôi sẽ đăng lại khi tôi nhận được giải pháp.
Jeff Ward

Câu trả lời:


5

Tôi đã viết một công cụ trả về tên ứng dụng đơn giản (ví dụ: 'Terminal', 'gedit' hoặc 'SmartGit' là những công cụ tôi đã thử nghiệm). Hầu hết các mã bị đánh cắp một cách đáng xấu hổ từ @Harvey ở đây .

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

Một khởi đầu tuyệt vời, cảm ơn! Hmm, nó hoạt động với thiết bị đầu cuối, firefox và chrome, nhưng ném "Không thể có tài sản WM_NAME" cho những người khác như emacs và robomongo, v.v. Tôi tự hỏi liệu đó có phải là phần "đi trên cây" mà Stéphane đang đề cập đến không.
Jeff Ward

Tôi đã thử thêm "thử cha mẹ cho đến khi tìm thấy tài sản WM_NAME" - và điều đó làm cho emacs hoạt động, mặc dù không phải là robomongo. Hấp dẫn. Câu trả lời này cũng có một số thông tin liên quan để tìm ra PID: unix.stackexchange.com/questions/5478/ Quảng cáo Điều thú vị này là PID (là hồng y?) Giống nhau cho tất cả các cửa sổ "Terminal". Điều này không tốt cho trường hợp sử dụng cụ thể của tôi, vì mỗi thiết bị đầu cuối có thể nằm trong một thư mục làm việc hiện tại riêng biệt.
Jeff Ward

Đúng. Tôi đã không gặp may mắn với thuộc tính "_NET_WM_PID" để có được PID nhưng tôi hy vọng bạn có thể sử dụng tên này làm điểm bắt đầu.
jschlichtholz

1
@Jeffard một số chương trình thiết bị đầu cuối hiện đại như gnome-terminalchỉ bắt đầu một lần phiên bản của ứng dụng mỗi phiên thay vì một phiên bản trên mỗi cửa sổ thiết bị đầu cuối như đáng kính xterm. Có lẽ đó là lý do tại sao bạn đang nhìn thấy cùng một PID trong tất cả chúng? Đối với gnome-terminalbạn đã từng có thể vô hiệu hóa sự không phù hợp đó với --disable-factory(tên lẻ cho một tùy chọn) nhưng dường như điều đó có thể không còn có thể . Dù sao, âm thanh như bạn cần pwd của một trong các quá trình chạy bên trong thiết bị đầu cuối, không phải của chính nó.
Celada

@Celada - đúng, và nó có ý nghĩa - hệ thống cửa sổ X biết về các cửa sổ, không nhất thiết là mỗi chương trình chọn làm gì với chúng. Dường như Chrome có một cửa sổ riêng (hoặc quy trình?) Dành riêng cho bảng tạm. Rõ ràng có rất nhiều schemata, và ý tưởng của tôi có thể không được triển khai.
Jeff Ward
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.