เป็นไปได้หรือไม่ที่จะทราบถึงแหล่งที่มา (แอปพลิเคชั่น) ของคลิปบอร์ด


10

ฉันสังเกตเห็นว่าบางครั้งเนื้อหาคลิปบอร์ดไม่สามารถใช้งานได้หากแอปพลิเคชันต้นทาง (ที่คัดลอกเนื้อหามา) ถูกปิด

นี่ทำให้ฉันสงสัยว่าเป็นไปได้หรือไม่ที่จะรู้ว่าแอปพลิเคชันต้นฉบับคืออะไร (เช่นอาจเป็น PID)

ทำไม? หากแอปพลิเคชันต้นทางเป็นเทอร์มินัลฉันต้องการค้นหาไดเรกทอรีการทำงานของเทอร์มินัลในกรณีที่เนื้อหาที่คัดลอกเป็นพา ธ สัมพัทธ์เพื่อสร้างพา ธ แบบเต็มไปยังไฟล์

FYI ฉันกำลังใช้ xclip เพื่อกำหนดเนื้อหาของคลิปบอร์ดเช่น

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

2
XGetSelectionOwner(3)ทำให้คุณได้รับ ID หน้าต่างของเจ้าของสิ่งที่เลือก ซึ่งคุณสามารถเดินขึ้นไปที่แผนผังหน้าต่างเพื่อลองและค้นหาหน้าต่างที่มีคุณสมบัติ _NET_WM_PID ด้วยเช่นกันxprop(สมมติว่าหน้าต่างนั้นมาจากไคลเอนต์ท้องถิ่นที่ตั้งค่าคุณสมบัตินั้น) xwininfo -root -tree | less +/0x<that-id>อาจเพียงพอที่จะระบุแอปพลิเคชัน
Stéphane Chazelas

2
สิ่งที่ @ StéphaneChazelasพูด แต่พึงระวังว่าคุณไม่น่าจะได้รับ PID ที่เชื่อถือได้ของลูกค้ารายอื่นจาก X11 การจดจำว่าไคลเอนต์ X เชื่อมต่อกับเซิร์ฟเวอร์ X ผ่านการเชื่อมต่อเครือข่ายทั่วไป (ซ็อกเก็ต UNIX หรือซ็อกเก็ต TCP) PID อาจไม่มีความหมายเนื่องจากแอปพลิเคชันอาจไม่ได้อยู่ในเครื่อง มันอาจจะเชื่อมต่อผ่าน TCP (ไม่ธรรมดาอีกต่อไปในวันนี้) หรือการเชื่อมต่อ X11 ที่ส่งต่อ SSH (พบมากขึ้น)
Celada

ขอบคุณสำหรับบันทึก - ฉันคิดว่าฉันจะต้องเขียนรหัส C เพื่อเข้าถึง XGetSelectionOwner แล้ว? ฉันอาจจะทำอย่างนั้น - ฉันจะโพสต์กลับเมื่อฉันได้รับการแก้ไข
Jeff Ward

คำตอบ:


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

เป็นการเริ่มต้นที่ดีขอบคุณ! อืมมันใช้งานกับ terminal, firefox และ chrome แต่พ่น "ไม่สามารถรับทรัพย์สิน WM_NAME" สำหรับคนอื่น ๆ เช่น emacs และ robomongo เป็นต้นฉันสงสัยว่านั่นคือ "walk the tree" ส่วนที่Stéphaneอ้างถึงหรือไม่
เจฟฟ์วอร์ด

ฉันพยายามเพิ่ม "ลองพาเรนต์จนกว่าจะพบทรัพย์สิน WM_NAME" - และนั่นทำให้ emacs ใช้งานได้แม้ว่าจะไม่ใช่ robomongo น่าสนใจ คำตอบนี้ยังมีข้อมูลที่เกี่ยวข้องสำหรับการค้นหา PID: unix.stackexchange.com/questions/5478/ … PID นี้ที่น่าสนใจ (สำคัญมาก) นั้นเหมือนกันสำหรับหน้าต่าง "Terminal" ทั้งหมด สิ่งนี้ไม่เป็นลางดีสำหรับกรณีการใช้งานเฉพาะของฉันเนื่องจากแต่ละเทอร์มินัลอาจอยู่ในไดเรกทอรีการทำงานปัจจุบันแยกต่างหาก
เจฟฟ์วอร์ด

ใช่. ฉันไม่มีโชคกับคุณสมบัติ "_NET_WM_PID" เพื่อรับ PID แต่ฉันหวังว่าคุณสามารถใช้ชื่อเป็นจุดเริ่มต้นได้
jschlichtholz

1
@JeffWard โปรแกรมเทอร์มินัลสมัยใหม่บางโปรแกรมเช่นgnome-terminalเริ่มต้นเพียงครั้งเดียวของอินสแตนซ์แอปพลิเคชันต่อเซสชันแทนที่จะเป็นหนึ่งอินสแตนซ์ต่อหนึ่งหน้าต่างเทอร์มินัลอย่างน่าxtermเชื่อถือ บางทีนั่นอาจเป็นเหตุผลว่าทำไมคุณถึงเห็น PID เดียวกันในทั้งหมด สำหรับgnome-terminalคุณใช้เพื่อให้สามารถปิดการใช้งานที่มี misfeature --disable-factory(ชื่อแปลกสำหรับตัวเลือก) แต่เห็นได้ชัดว่าไม่อาจจะเป็นไปได้ อย่างไรก็ตามดูเหมือนว่าคุณต้องการ pwd ของหนึ่งในกระบวนการที่ทำงานภายในเทอร์มินัลไม่ใช่ของตัวเอง
Celada

@Celada - ถูกต้องและสมเหตุสมผล - ระบบ X window รู้เกี่ยวกับ windows ไม่จำเป็นว่าแต่ละโปรแกรมเลือกที่จะทำอะไรกับมัน นอกจากนี้ยังปรากฏว่า Chrome มีหน้าต่างแยกต่างหาก (หรือกระบวนการ) โดยเฉพาะสำหรับคลิปบอร์ด เห็นได้ชัดว่ามี schemata จำนวนมากและความคิดของฉันอาจไม่เลื่อนออกไป
Jeff Ward
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.