def get_window_class(window: Window) -> str: cls = None try: cls = window.get_wm_class() except Xlib.error.BadWindow: logger.warning("Unable to get window class, got a BadWindow exception.") # TODO: Is this needed? # nikanar: Indeed, it seems that it is. But it would be interesting to see how often this succeeds, and if it is low, maybe fail earlier. if not cls: print("") logger.warning("Code made an unclear branch") try: window = window.query_tree().parent except Xlib.error.XError as e: logger.warning("Unable to get window query_tree().parent, got a {} exception from Xlib".format(type(e).__name__)) return "unknown" if window: return get_window_class(window) else: return "unknown" cls = cls[1] return cls
def get_window_name(window: Window) -> str: """ After some annoying debugging I resorted to pretty much copying selfspy. Source: https://github.com/gurgeh/selfspy/blob/8a34597f81000b3a1be12f8cde092a40604e49cf/selfspy/sniff_x.py#L165 """ d = window.get_full_property(NET_WM_NAME, UTF8_STRING) if d is None or d.format != 8: # Fallback. r = window.get_wm_name() if type(r) == str: return r else: logger.warning( "I don't think this case will ever happen, but not sure so leaving this message here just in case." ) return r.decode('latin1') # WM_NAME with type=STRING. else: # Fixing utf8 issue on Ubuntu (https://github.com/gurgeh/selfspy/issues/133) # Thanks to https://github.com/gurgeh/selfspy/issues/133#issuecomment-142943681 try: return d.value.decode('utf8') except UnicodeError: logger.warning( "Failed to decode one or more characters which will be skipped, bytes are: {}" .format(d.value)) if isinstance(d.value, bytes): return d.value.decode('utf8', 'ignore') else: return d.value.encode('utf8').decode('utf8', 'ignore')
def get_window_name(window: Window) -> str: """ After some annoying debugging I resorted to pretty much copying selfspy. Source: https://github.com/gurgeh/selfspy/blob/8a34597f81000b3a1be12f8cde092a40604e49cf/selfspy/sniff_x.py#L165 """ try: d = window.get_full_property(NET_WM_NAME, UTF8_STRING) except Xlib.error.XError as e: logger.warning("Unable to get window property NET_WM_NAME, got a {} exception from Xlib".format(type(e).__name__)) # I strongly suspect window.get_wm_name() will also fail and we should return "unknown" right away. # But I don't know, so I pass the thing on, for now. d = None if d is None or d.format != 8: # Fallback. r = window.get_wm_name() if type(r) == str: return r else: logger.warning("I don't think this case will ever happen, but not sure so leaving this message here just in case.") return r.decode('latin1') # WM_NAME with type=STRING. else: # Fixing utf8 issue on Ubuntu (https://github.com/gurgeh/selfspy/issues/133) # Thanks to https://github.com/gurgeh/selfspy/issues/133#issuecomment-142943681 try: return d.value.decode('utf8') except UnicodeError: logger.warning("Failed to decode one or more characters which will be skipped, bytes are: {}".format(d.value)) if isinstance(d.value, bytes): return d.value.decode('utf8', 'ignore') else: return d.value.encode('utf8').decode('utf8', 'ignore')
def find_window(name: str, window: Window) -> Optional[Window]: """Recursively locate a window with name `name` in the tree, starting at `window`.""" if window.get_wm_name() == name: return window children = window.query_tree().children for child in children: val = find_window(name, child) if val: return val
def get_window_pid(window: Window) -> str: atom = display.get_atom("_NET_WM_PID") pid_property = window.get_full_property(atom, X.AnyPropertyType) if pid_property: pid = pid_property.value[-1] return pid else: # TODO: Needed? raise Exception("pid_property was None")
def get_window_class(window: Window) -> str: cls = None try: cls = window.get_wm_class() except Xlib.error.BadWindow: logger.warning( "Unable to get window class, got a BadWindow exception.") # TODO: Is this needed? if not cls: print("") logger.warning("Code made an unclear branch") window = window.query_tree().parent if window: return get_window_class(window) else: return "unknown" cls = cls[1] return cls
def _get_window_class_name(self, win_obj: Window) -> str: """SReturn window class name""" try: window_name = win_obj.get_full_property(self.WM_CLASS, 0) except UnicodeDecodeError: # Apparently a Debian distro package bug title = "<could not decode characters>" else: if window_name: win_class_name = window_name.value # type: Union[str, bytes] if isinstance(win_class_name, bytes): # Apparently COMPOUND_TEXT is so arcane that this is how # tools like xprop deal with receiving it these days win_class_name = win_class_name.replace(b'\x00',b' ').decode("utf-8").lower() return win_class_name else: title = "<undefined wm_class_name>" return "{} (XID: {})".format(title, win_obj.id)
def _get_window_name_inner(self, win_obj: Window) -> str: """Simplify dealing with _NET_WM_NAME (UTF-8) vs. WM_NAME (legacy)""" for atom in (self.NET_WM_NAME, self.WM_NAME): try: window_name = win_obj.get_full_property(atom, 0) except UnicodeDecodeError: # Apparently a Debian distro package bug title = "<could not decode characters>" else: if window_name: win_name = window_name.value # type: Union[str, bytes] if isinstance(win_name, bytes): # Apparently COMPOUND_TEXT is so arcane that this is how # tools like xprop deal with receiving it these days win_name = win_name.decode('latin1', 'replace') return win_name else: title = "<unnamed window>" return "{} (XID: {})".format(title, win_obj.id)
def get_window_user(window: Window) -> str: d = window.get_full_property(NET_WM_NAME, UTF8_STRING) r = get_window_pid(window) p = psutil.Process(r) u = p.username() return u
def from_xlib_window(cls, xlib_win): window = Window(xlib_win=xlib_win) return window