1 #!/usr/bin/env python 2 3 """ 4 Simple desktop window enumeration for Python. 5 6 Copyright (C) 2007 Paul Boddie <paul@boddie.org.uk> 7 8 This library is free software; you can redistribute it and/or 9 modify it under the terms of the GNU Lesser General Public 10 License as published by the Free Software Foundation; either 11 version 2.1 of the License, or (at your option) any later version. 12 13 This library is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 Lesser General Public License for more details. 17 18 You should have received a copy of the GNU Lesser General Public 19 License along with this library; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 21 22 -------- 23 24 Finding Open Windows on the Desktop 25 ----------------------------------- 26 27 To obtain a list of windows, use the desktop.windows.list function as follows: 28 29 windows = desktop.windows.list() 30 31 Each window object can be inspected through a number of methods. For example: 32 33 name = window.name() 34 width, height = window.size() 35 x, y = window.position() 36 child_windows = window.children() 37 38 See the desktop.windows.Window class for more information. 39 """ 40 41 from desktop import _is_x11, _get_x11_vars, _readfrom, use_desktop 42 43 def _xwininfo(s): 44 d = {} 45 for line in s.split("\n"): 46 fields = line.split(":") 47 if len(fields) < 2: 48 continue 49 key, values = fields[0].strip(), fields[1:] 50 d[key] = values 51 return d 52 53 def _get_int_properties(d, properties): 54 results = [] 55 for property in properties: 56 results.append(int(d[property][0].strip())) 57 return results 58 59 # Window classes. 60 # NOTE: X11 is the only supported desktop so far. 61 62 class Window: 63 64 "A window on the desktop." 65 66 def __init__(self, identifier): 67 68 "Initialise the window with the given 'identifier'." 69 70 self.identifier = identifier 71 72 def __repr__(self): 73 return "Window(%r)" % self.identifier 74 75 def children(self): 76 77 "Return a list of windows which are children of this window." 78 79 s = _readfrom(_get_x11_vars() + "xwininfo -id %s -children" % self.identifier, shell=1) 80 handles = [] 81 adding = 0 82 for line in s.split("\n"): 83 if not adding and line.endswith("children:"): 84 adding = 1 85 elif adding and line: 86 handles.append(line.strip().split()[0]) 87 return [Window(handle) for handle in handles] 88 89 def name(self): 90 91 "Return the name of the window." 92 93 s = _readfrom(_get_x11_vars() + "xwininfo -id %s -stats" % self.identifier, shell=1) 94 for line in s.split("\n"): 95 if line.startswith("xwininfo:"): 96 97 # Format is 'xwininfo: Window id: <handle> "<name>" 98 99 fields = line.split(":") 100 handle_and_name = fields[2].strip() 101 fields2 = handle_and_name.split(" ") 102 103 # Get the "<name>" part, stripping off the quotes. 104 105 return " ".join(fields2[1:]).strip('"') 106 107 return None 108 109 def size(self): 110 111 "Return a tuple containing the width and height of this window." 112 113 s = _readfrom(_get_x11_vars() + "xwininfo -id %s -stats" % self.identifier, shell=1) 114 d = _xwininfo(s) 115 return _get_int_properties(d, ["Width", "Height"]) 116 117 def position(self): 118 119 "Return a tuple containing the upper left co-ordinates of this window." 120 121 s = _readfrom(_get_x11_vars() + "xwininfo -id %s -stats" % self.identifier, shell=1) 122 d = _xwininfo(s) 123 return _get_int_properties(d, ["Absolute upper-left X", "Absolute upper-left Y"]) 124 125 def list(desktop=None): 126 127 """ 128 Return a list of windows for the current desktop. If the optional 'desktop' 129 parameter is specified then attempt to use that particular desktop 130 environment's mechanisms to look for windows. 131 """ 132 133 # NOTE: The desktop parameter is currently ignored and X11 is tested for 134 # NOTE: directly. 135 136 if _is_x11(): 137 s = _readfrom(_get_x11_vars() + "xlsclients -a -l", shell=1) 138 prefix = "Window " 139 prefix_end = len(prefix) 140 handles = [] 141 142 for line in s.split("\n"): 143 if line.startswith(prefix): 144 handles.append(line[prefix_end:-1]) # NOTE: Assume ":" at end. 145 else: 146 raise OSError, "Desktop '%s' not supported" % use_desktop(desktop) 147 148 return [Window(handle) for handle in handles] 149 150 # vim: tabstop=4 expandtab shiftwidth=4