كيفية الحصول على نافذة X11 من معرف العملية؟

StackOverflow https://stackoverflow.com/questions/151407

  •  02-07-2019
  •  | 
  •  

سؤال

في نظام التشغيل Linux، يستخدم تطبيق C++ الخاص بي fork() و execv() لتشغيل مثيلات متعددة من OpenOffice وذلك لعرض بعض عروض شرائح PowerPoint.يعمل هذا الجزء.

بعد ذلك، أريد أن أكون قادرًا على نقل نوافذ OpenOffice إلى مواقع محددة على الشاشة.يمكنني القيام بذلك باستخدام الدالة XMoveResizeWindow() ولكنني بحاجة إلى العثور على النافذة لكل مثيل.

لدي معرف العملية لكل مثيل، كيف يمكنني العثور على نافذة X11 من ذلك؟


تحديث - بفضل اقتراح آندي، لقد نجحت في ذلك.أقوم بنشر الكود هنا لمشاركته مع مجتمع Stack Overflow.

لسوء الحظ، لا يبدو أن Open Office يقوم بتعيين خاصية _NET_WM_PID، لذا فإن هذا لا يحل مشكلتي في النهاية ولكنه يجيب على السؤال.

// Attempt to identify a window by name or attribute.
// by Adam Pierce <adam@doctort.org>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <iostream>
#include <list>

using namespace std;

class WindowsMatchingPid
{
public:
    WindowsMatchingPid(Display *display, Window wRoot, unsigned long pid)
        : _display(display)
        , _pid(pid)
    {
    // Get the PID property atom.
        _atomPID = XInternAtom(display, "_NET_WM_PID", True);
        if(_atomPID == None)
        {
            cout << "No such atom" << endl;
            return;
        }

        search(wRoot);
    }

    const list<Window> &result() const { return _result; }

private:
    unsigned long  _pid;
    Atom           _atomPID;
    Display       *_display;
    list<Window>   _result;

    void search(Window w)
    {
    // Get the PID for the current Window.
        Atom           type;
        int            format;
        unsigned long  nItems;
        unsigned long  bytesAfter;
        unsigned char *propPID = 0;
        if(Success == XGetWindowProperty(_display, w, _atomPID, 0, 1, False, XA_CARDINAL,
                                         &type, &format, &nItems, &bytesAfter, &propPID))
        {
            if(propPID != 0)
            {
            // If the PID matches, add this window to the result set.
                if(_pid == *((unsigned long *)propPID))
                    _result.push_back(w);

                XFree(propPID);
            }
        }

    // Recurse into child windows.
        Window    wRoot;
        Window    wParent;
        Window   *wChild;
        unsigned  nChildren;
        if(0 != XQueryTree(_display, w, &wRoot, &wParent, &wChild, &nChildren))
        {
            for(unsigned i = 0; i < nChildren; i++)
                search(wChild[i]);
        }
    }
};

int main(int argc, char **argv)
{
    if(argc < 2)
        return 1;

    int pid = atoi(argv[1]);
    cout << "Searching for windows associated with PID " << pid << endl;

// Start with the root window.
    Display *display = XOpenDisplay(0);

    WindowsMatchingPid match(display, XDefaultRootWindow(display), pid);

// Print the result.
    const list<Window> &result = match.result();
    for(list<Window>::const_iterator it = result.begin(); it != result.end(); it++)
        cout << "Window #" << (unsigned long)(*it) << endl;

    return 0;
}
هل كانت مفيدة؟

المحلول

الطريقة الوحيدة التي أعرفها للقيام بذلك هي اجتياز شجرة النوافذ حتى تجد ما تبحث عنه.العبور ليس بالأمر الصعب (فقط شاهد ما يفعله xwininfo -root -tree من خلال النظر إلى xwininfo.c إذا كنت بحاجة إلى مثال).

ولكن كيف يمكنك تحديد النافذة التي تبحث عنها؟ بعض تقوم التطبيقات بتعيين خاصية نافذة تسمى _NET_WM_PID.

وأعتقد أن أوبن أوفيس يكون أحد التطبيقات التي تحدد هذه الخاصية (كما هو الحال مع معظم تطبيقات جنوم)، فأنت محظوظ.

نصائح أخرى

تحقق مما إذا كان /proc/PID/environ يحتوي على متغير يسمى WINDOWID

متأخرا بعض الشيء إلى الحفلة.لكن:في عام 2004، نشر Harald Welte مقتطفًا من التعليمات البرمجية يغلف استدعاء XCreateWindow() عبر LD_PRELOAD ويخزن معرف العملية في _NET_WM_PID.يؤدي هذا إلى التأكد من أن كل نافذة تم إنشاؤها تحتوي على إدخال PID.

http://www.mail-archive.com/devel@xfree86.org/msg05806.html

حاول التثبيت xdotool, ، ثم:

#!/bin/bash
# --any and --name present only as a work-around, see: https://github.com/jordansissel/xdotool/issues/14
ids=$(xdotool search --any --pid "$1" --name "dummy")

أحصل على الكثير من معرفات.أستخدم هذا لتعيين نافذة طرفية على أنها عاجلة عند الانتهاء من أمر طويل باستخدام البرنامج seturgent.أنا فقط أتصفح جميع المعرفات التي أحصل عليها منها xdotool و اهرب seturgent عليهم.

لا توجد طريقة جيدة.الخيارات الحقيقية الوحيدة التي أراها هي:

  1. يمكنك البحث في مساحة عنوان العملية للعثور على معلومات الاتصال ومعرف النافذة.
  2. يمكنك محاولة استخدام netstat أو lsof أو ipcs لتعيين الاتصالات بـ Xserver، وبعد ذلك (بطريقة ما!ستحتاج إلى الجذر على الأقل) انظر إلى معلومات الاتصال الخاصة به للعثور عليها.
  3. عند إنشاء مثيل، يمكنك الانتظار حتى يتم تعيين نافذة أخرى، وافترض أنها النافذة الصحيحة، ثم "استمر".

هل أنت متأكد من أن لديك معرف العملية لكل مثيل؟تجربتي مع OOo هي أن محاولة تشغيل مثيل ثانٍ لـ OOo تتحدث فقط مع المثيل الأول لـ OOo، وتخبره بفتح الملف الإضافي.

أعتقد أنك ستحتاج إلى استخدام إمكانات إرسال الرسائل الخاصة بـ X لتطلب منه بشكل جيد نافذته.أتمنى أن تقوم OOo بتوثيق أغلفةها في مكان ما.

إذا كنت تستخدم بايثون، وجدت طريقة هنا, ، الفكرة من BurntSushi

إذا قمت بتشغيل التطبيق، فيجب أن تعرف سلسلة cmd الخاصة به، والتي يمكنك من خلالها تقليل المكالمات إليها xprop, ، يمكنك دائمًا تكرار جميع xids والتحقق مما إذا كان pid هو نفس pid الذي تريده

import subprocess
import re

import struct
import xcffib as xcb
import xcffib.xproto

def get_property_value(property_reply):
    assert isinstance(property_reply, xcb.xproto.GetPropertyReply)

    if property_reply.format == 8:
        if 0 in property_reply.value:
            ret = []
            s = ''
            for o in property_reply.value:
                if o == 0:
                    ret.append(s)
                    s = ''
                else:
                    s += chr(o)
        else:
            ret = str(property_reply.value.buf())

        return ret
    elif property_reply.format in (16, 32):
        return list(struct.unpack('I' * property_reply.value_len,
                                  property_reply.value.buf()))

    return None

def getProperty(connection, ident, propertyName):

    propertyType = eval(' xcb.xproto.Atom.%s' % propertyName)

    try:
        return connection.core.GetProperty(False, ident, propertyType,
                                        xcb.xproto.GetPropertyType.Any,
                                        0, 2 ** 32 - 1)
    except:
        return None


c = xcb.connect()
root = c.get_setup().roots[0].root

_NET_CLIENT_LIST = c.core.InternAtom(True, len('_NET_CLIENT_LIST'),
                                     '_NET_CLIENT_LIST').reply().atom


raw_clientlist = c.core.GetProperty(False, root, _NET_CLIENT_LIST,
                                    xcb.xproto.GetPropertyType.Any,
                                    0, 2 ** 32 - 1).reply()

clientlist = get_property_value(raw_clientlist)

cookies = {}

for ident in clientlist:
    wm_command = getProperty(c, ident, 'WM_COMMAND')
    cookies[ident] = (wm_command)

xids=[]

for ident in cookies:
    cmd = get_property_value(cookies[ident].reply())
    if cmd and spref in cmd:
        xids.append(ident)

for xid in xids:
    pid = subprocess.check_output('xprop -id %s _NET_WM_PID' % xid, shell=True)
    pid = re.search('(?<=\s=\s)\d+', pid).group()

    if int(pid) == self.pid:
        print 'found pid:', pid
        break

print 'your xid:', xid

لقد حصلت على الحرية في إعادة تنفيذ كود OP باستخدام بعض ميزات C++ الحديثة.إنه يحتفظ بنفس الوظائف ولكني أعتقد أنه يقرأ بشكل أفضل قليلاً.كما أنه لا يتسرب حتى في حالة رمي إدخال المتجه.

// Attempt to identify a window by name or attribute.
// originally written by Adam Pierce <adam@doctort.org>
// revised by Dario Pellegrini <pellegrini.dario@gmail.com>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <iostream>
#include <vector>


std::vector<Window> pid2windows(pid_t pid, Display* display, Window w) {
  struct implementation {
    struct FreeWrapRAII {
      void * data;
      FreeWrapRAII(void * data): data(data) {}
      ~FreeWrapRAII(){ XFree(data); }
    };

    std::vector<Window> result;
    pid_t pid;
    Display* display;
    Atom atomPID;

    implementation(pid_t pid, Display* display): pid(pid), display(display) {
      // Get the PID property atom
      atomPID = XInternAtom(display, "_NET_WM_PID", True);
      if(atomPID == None) {
        throw std::runtime_error("pid2windows: no such atom");
      }
    }

    std::vector<Window> getChildren(Window w) {
      Window    wRoot;
      Window    wParent;
      Window   *wChild;
      unsigned  nChildren;
      std::vector<Window> children;
      if(0 != XQueryTree(display, w, &wRoot, &wParent, &wChild, &nChildren)) {
        FreeWrapRAII tmp( wChild );
        children.insert(children.end(), wChild, wChild+nChildren);
      }
      return children;
    }

    void emplaceIfMatches(Window w) {
      // Get the PID for the given Window
      Atom           type;
      int            format;
      unsigned long  nItems;
      unsigned long  bytesAfter;
      unsigned char *propPID = 0;
      if(Success == XGetWindowProperty(display, w, atomPID, 0, 1, False, XA_CARDINAL,
                                       &type, &format, &nItems, &bytesAfter, &propPID)) {
        if(propPID != 0) {
          FreeWrapRAII tmp( propPID );
          if(pid == *reinterpret_cast<pid_t*>(propPID)) {
            result.emplace_back(w);
          }
        }
      }
    }

    void recurse( Window w) {
      emplaceIfMatches(w);
      for (auto & child: getChildren(w)) {
        recurse(child);
      }
    }

    std::vector<Window> operator()( Window w ) {
      result.clear();
      recurse(w);
      return result;
    }
  };
  //back to pid2windows function
  return implementation{pid, display}(w);
}

std::vector<Window> pid2windows(const size_t pid, Display* display) {
  return pid2windows(pid, display, XDefaultRootWindow(display));
}


int main(int argc, char **argv) {
  if(argc < 2)
    return 1;

  int pid = atoi(argv[1]);
  std::cout << "Searching for windows associated with PID " << pid << std::endl;

  // Start with the root window.
  Display *display = XOpenDisplay(0);
  auto res = pid2windows(pid, display);

  // Print the result.
  for( auto & w: res) {
    std::cout << "Window #" << static_cast<unsigned long>(w) << std::endl;
  }

  XCloseDisplay(display);
  return 0;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top