Ruft den Fenstertitel des X-Fenstersystems in Python ab

Neulich schrieb ich in Python den Prozess des Wartens auf eine Anwendung in der X-Umgebung, um eine Datei zu öffnen, aber ich fragte mich, warum es eine gute Idee wäre, wmctrl -l viele Male zu starten, um den Fenstertitel zu erhalten. Ich dachte, also habe ich versucht, so etwas mit dem "pyglet" -Modul zu schreiben, während ich die Quelle von "wmctrl" gelesen habe.

Es ist ein beschissener Code, aber er wird unter einer BSD-Lizenz mit zwei Klauseln bereitgestellt. Sie können ihn also gerne verwenden, wenn Sie ihn hilfreich finden.

wmctrl.py


#!/usr/bin/env python3
# vim:fileencoding=utf-8

# Copyright (c) 2014 Masami HIRATA <[email protected]>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#     1. Redistributions of source code must retain the above copyright notice,
#        this list of conditions and the following disclaimer.
#
#     2. Redistributions in binary form must reproduce the above copyright
#        notice, this list of conditions and the following disclaimer in the
#        documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

__all__ = ["WMCtrl"]

from ctypes import (POINTER,
                    byref,
                    cast,
                    c_buffer,
                    c_char_p,
                    c_int,
                    c_ubyte,
                    c_ulong,
                    memmove,
                    pointer,
                    sizeof)

from pyglet.window.xlib import xlib
from pyglet.compat import asbytes

X_TRUE = xlib.True_
X_FALSE = xlib.False_
X_SUCCESS = xlib.Success
MAX_PROPERTY_VALUE_LEN = 4096

# from X11/Xatom.h
XA_CARDINAL = 6
XA_STRING = 31
XA_WINDOW = 33


class WMCtrl:
    def __init__(self):
        self.display = xlib.XOpenDisplay(None)
        self.root = xlib.XDefaultRootWindow(self.display)
        self.xatom_net_wm_name = self.get_xatom("_NET_WM_NAME")

    def get_xatom(self, name, exists=False):
        only_if_exists = X_TRUE if exists else X_FALSE
        xatom = xlib.XInternAtom(self.display,
                                 asbytes(name),
                                 only_if_exists)
        return xatom

    def get_property(self, window, xatom_property_type, property_name):
        return_xatom_property_type = xlib.Atom()
        return_c_int_format = c_int()
        return_c_ulong_nitems = c_ulong()
        return_c_ulong_bytes_after = c_ulong()
        return_c_ubyte_p_property_orig = pointer(c_ubyte())

        if window is None:
            window = self.root

        xatom_property_name = self.get_xatom(property_name, exists=True)
        if xatom_property_name == 0:
            return None

        status = xlib.XGetWindowProperty(self.display,
                                         window,
                                         xatom_property_name,
                                         0,
                                         MAX_PROPERTY_VALUE_LEN // 4,
                                         X_FALSE,
                                         xatom_property_type,
                                         byref(return_xatom_property_type),
                                         byref(return_c_int_format),
                                         byref(return_c_ulong_nitems),
                                         byref(return_c_ulong_bytes_after),
                                         byref(return_c_ubyte_p_property_orig))

        if status != X_SUCCESS:
            print("Can't get {} property. ({})",
                  property_name,
                  status)

        if xatom_property_type != return_xatom_property_type.value:
            print("Invalid type of {} property. ({} != {})".format(
                  property_name,
                  xatom_property_type,
                  return_xatom_property_type.value))
            xlib.XFree(return_c_ubyte_p_property_orig)
            return None

        bytes_per_item = return_c_int_format.value // 8
        if bytes_per_item == 4:
            bytes_per_item = sizeof(c_ulong)

        property_size = (bytes_per_item * return_c_ulong_nitems.value)
        # +1 is for NUL termination
        return_c_char_p_property = c_buffer(property_size + 1)
        memmove(return_c_char_p_property,
                return_c_ubyte_p_property_orig,
                property_size)
        xlib.XFree(return_c_ubyte_p_property_orig)

        return return_c_char_p_property

    def get_window_list(self):
        c_window_p_client_list = self.get_property(self.root,
                                                   XA_WINDOW,
                                                   "_NET_CLIENT_LIST")

        if c_window_p_client_list is None:
            c_window_p_client_list = self.get_property(self.root,
                                                       XA_CARDINAL,
                                                       "_WIN_CLIENT_LIST")

        if c_window_p_client_list is None:
            print("Can't get _(NET|WIN)_CLIENT_LIST property.")
            return []

        nitems = (len(c_window_p_client_list) - 1) // sizeof(xlib.Window)
        c_window_p_client_list = cast(c_window_p_client_list,
                                      POINTER(xlib.Window * nitems))

        window_list = []
        for window in c_window_p_client_list.contents:
            window_list.append(window)
        return window_list

    def get_window_title(self, window):
        text_property = xlib.XTextProperty()

        status = xlib.XGetTextProperty(self.display,
                                       window,
                                       text_property,
                                       self.xatom_net_wm_name)
        if status == 0 or text_property.nitems < 1 or text_property.value == 0:
            status = xlib.XGetWMName(self.display, window, text_property)
        if status == 0 or text_property.nitems < 1 or text_property.value == 0:
            return None

        c_char_ppp_title = pointer(pointer(c_char_p()))
        c_int_p_count = pointer(c_int())
        xlib.XmbTextPropertyToTextList(self.display,
                                       text_property,
                                       c_char_ppp_title,
                                       c_int_p_count)

        if c_int_p_count.contents.value < 1:
            return None
        return c_char_ppp_title.contents.contents.value.decode('utf-8')

    def get_window_titles(self):
        titles = []
        for window in self.get_window_list():
            title = self.get_window_title(window)
            if title is None:
                continue
            titles.append(title)

        return titles


def main():
    titles = WMCtrl().get_window_titles()
    for title in titles:
        print(title)

if __name__ == '__main__':  # pragma: nocover
    main()

Recommended Posts

Ruft den Fenstertitel des X-Fenstersystems in Python ab
Holen Sie sich den Desktop-Pfad in Python
Holen Sie sich den Skriptpfad in Python
Was ist das X Window System?
Holen Sie sich den Desktop-Pfad in Python
Holen Sie sich den Hostnamen in Python
Ruft die EDINET-Codeliste in Python ab
Holen Sie sich den Titel und das Lieferdatum von Yahoo! News in Python
Begriffe, die eng mit dem X-Fenstersystem verwandt sind
[Python] Holen Sie sich die Dateien mit Python in den Ordner
Holen Sie sich das Wetter in Osaka über Web-API (Python)
Holen Sie sich den Aufrufer einer Funktion in Python
Abrufen und Konvertieren der aktuellen Zeit in der lokalen Systemzeitzone mit Python
Holen Sie sich Datum in Python
So erhalten Sie die Dateien im Ordner [Python]
Laden Sie Dateien herunter, während Sie den Fortschritt in Python 3.x anzeigen
So erhalten Sie den Variablennamen selbst in Python
So ermitteln Sie die Anzahl der Stellen in Python
[Python] Holen Sie sich die Zahlen im Diagramm mit OCR
Ermitteln Sie die Größe (Anzahl der Elemente) von Union Find in Python
Rufen Sie den im Pulldown-Menü Selenium Python VBA ausgewählten Wert ab
Rufen Sie die URL des HTTP-Umleitungsziels in Python ab
Holen Sie sich YouTube-Kommentare in Python
Holen Sie sich letzten Monat in Python
Finde Fehler in Python
Holen Sie sich die Terminalgröße in Python
[Python] Holen Sie sich den Vormonat
Holen Sie sich explizit EOF in Python
Holen Sie sich Evernote-Notizen in Python
Holen Sie sich japanische Synonyme mit Python
Holen Sie sich Ihre Herzfrequenz von der Fitbit-API in Python!
Holen Sie sich den MIME-Typ in Python und bestimmen Sie das Dateiformat
Holen Sie sich die Anzahl der spezifischen Elemente in der Python-Liste
Rufen Sie den Wert ab, während Sie den Standardwert aus dict in Python angeben
So erhalten Sie den letzten (letzten) Wert in einer Liste in Python
Holen Sie sich automatisch den Port, an dem Arduino in Python steckt
Holen Sie sich das aktuelle Datum und die aktuelle Uhrzeit in Python unter Berücksichtigung des Zeitunterschieds
Systemhandel ab Python3: Holen Sie sich den neuesten Programmcode
Ruft den Index jedes Elements der Verwirrungsmatrix in Python ab
Holen Sie sich LeapMotion-Daten in Python.
Wahrscheinlich in einer Nishiki-Schlange (Originaltitel: Vielleicht in Python)
Abrufen der arXiv-API in Python
Python im Browser: Brythons Empfehlung
Speichern Sie die Binärdatei in Python
Klicken Sie in Python auf die Sesami-API
Holen Sie sich das Wetter mit Python-Anfragen
Holen Sie sich das Wetter mit Python-Anfragen 2
Im Python-Befehl zeigt Python auf Python3.8
Implementieren Sie das Singleton-Muster in Python
So erhalten Sie die Python-Version
Holen Sie sich ein Kommunikationsmemo in Python
Klicken Sie auf die Web-API in Python
Ich habe die Warteschlange in Python geschrieben
Berechnen Sie den Vormonat in Python
Untersuchen Sie die Klasse eines Objekts mit Python
Verwenden Sie OpenCV mit Python 3 in Window
Greifen Sie mit Python auf die Twitter-API zu
Python Hinweis: Holen Sie sich den aktuellen Monat
Der erste Schritt von Python Matplotlib