feat(SublimeText2.EditorPackages): cache packages

This commit is contained in:
Iristyle
2013-04-04 08:55:15 -04:00
parent d65666cdfc
commit c3efdad2c2
274 changed files with 26863 additions and 0 deletions

View File

@@ -0,0 +1,290 @@
#!/usr/bin/env python
"""
Simple desktop integration for Python. This module provides desktop environment
detection and resource opening support for a selection of common and
standardised desktop environments.
Copyright (C) 2005, 2006, 2007, 2008, 2009 Paul Boddie <paul@boddie.org.uk>
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
--------
Desktop Detection
-----------------
To detect a specific desktop environment, use the get_desktop function.
To detect whether the desktop environment is standardised (according to the
proposed DESKTOP_LAUNCH standard), use the is_standard function.
Opening URLs
------------
To open a URL in the current desktop environment, relying on the automatic
detection of that environment, use the desktop.open function as follows:
desktop.open("http://www.python.org")
To override the detected desktop, specify the desktop parameter to the open
function as follows:
desktop.open("http://www.python.org", "KDE") # Insists on KDE
desktop.open("http://www.python.org", "GNOME") # Insists on GNOME
desktop.open("http://www.python.org", "MATE") # Insists on MATE
Without overriding using the desktop parameter, the open function will attempt
to use the "standard" desktop opening mechanism which is controlled by the
DESKTOP_LAUNCH environment variable as described below.
The DESKTOP_LAUNCH Environment Variable
---------------------------------------
The DESKTOP_LAUNCH environment variable must be shell-quoted where appropriate,
as shown in some of the following examples:
DESKTOP_LAUNCH="kdialog --msgbox" Should present any opened URLs in
their entirety in a KDE message box.
(Command "kdialog" plus parameter.)
DESKTOP_LAUNCH="my\ opener" Should run the "my opener" program to
open URLs.
(Command "my opener", no parameters.)
DESKTOP_LAUNCH="my\ opener --url" Should run the "my opener" program to
open URLs.
(Command "my opener" plus parameter.)
Details of the DESKTOP_LAUNCH environment variable convention can be found here:
http://lists.freedesktop.org/archives/xdg/2004-August/004489.html
Other Modules
-------------
The desktop.dialog module provides support for opening dialogue boxes.
The desktop.windows module permits the inspection of desktop windows.
"""
__version__ = "0.4"
import os
import sys
# Provide suitable process creation functions.
try:
import subprocess
def _run(cmd, shell, wait):
opener = subprocess.Popen(cmd, shell=shell)
if wait: opener.wait()
return opener.pid
def _readfrom(cmd, shell):
opener = subprocess.Popen(cmd, shell=shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
opener.stdin.close()
return opener.stdout.read()
def _status(cmd, shell):
opener = subprocess.Popen(cmd, shell=shell)
opener.wait()
return opener.returncode == 0
except ImportError:
import popen2
def _run(cmd, shell, wait):
opener = popen2.Popen3(cmd)
if wait: opener.wait()
return opener.pid
def _readfrom(cmd, shell):
opener = popen2.Popen3(cmd)
opener.tochild.close()
opener.childerr.close()
return opener.fromchild.read()
def _status(cmd, shell):
opener = popen2.Popen3(cmd)
opener.wait()
return opener.poll() == 0
import commands
# Private functions.
def _get_x11_vars():
"Return suitable environment definitions for X11."
if not os.environ.get("DISPLAY", "").strip():
return "DISPLAY=:0.0 "
else:
return ""
def _is_xfce():
"Return whether XFCE is in use."
# XFCE detection involves testing the output of a program.
try:
return _readfrom(_get_x11_vars() + "xprop -root _DT_SAVE_MODE", shell=1).strip().endswith(' = "xfce4"')
except OSError:
return 0
def _is_x11():
"Return whether the X Window System is in use."
return os.environ.has_key("DISPLAY")
# Introspection functions.
def get_desktop():
"""
Detect the current desktop environment, returning the name of the
environment. If no environment could be detected, None is returned.
"""
if os.environ.has_key("KDE_FULL_SESSION") or \
os.environ.has_key("KDE_MULTIHEAD"):
return "KDE"
elif os.environ.has_key("GNOME_DESKTOP_SESSION_ID") or \
os.environ.has_key("GNOME_KEYRING_SOCKET"):
return "GNOME"
elif os.environ.has_key("MATE_DESKTOP_SESSION_ID") or \
os.environ.has_key("MATE_KEYRING_SOCKET"):
return "MATE"
elif sys.platform == "darwin":
return "Mac OS X"
elif hasattr(os, "startfile"):
return "Windows"
elif _is_xfce():
return "XFCE"
# KDE, GNOME, MATE and XFCE run on X11, so we have to test for X11 last.
if _is_x11():
return "X11"
else:
return None
def use_desktop(desktop):
"""
Decide which desktop should be used, based on the detected desktop and a
supplied 'desktop' argument (which may be None). Return an identifier
indicating the desktop type as being either "standard" or one of the results
from the 'get_desktop' function.
"""
# Attempt to detect a desktop environment.
detected = get_desktop()
# Start with desktops whose existence can be easily tested.
if (desktop is None or desktop == "standard") and is_standard():
return "standard"
elif (desktop is None or desktop == "Windows") and detected == "Windows":
return "Windows"
# Test for desktops where the overriding is not verified.
elif (desktop or detected) == "KDE":
return "KDE"
elif (desktop or detected) == "GNOME":
return "GNOME"
elif (desktop or detected) == "MATE":
return "MATE"
elif (desktop or detected) == "XFCE":
return "XFCE"
elif (desktop or detected) == "Mac OS X":
return "Mac OS X"
elif (desktop or detected) == "X11":
return "X11"
else:
return None
def is_standard():
"""
Return whether the current desktop supports standardised application
launching.
"""
return os.environ.has_key("DESKTOP_LAUNCH")
# Activity functions.
def open(url, desktop=None, wait=0):
"""
Open the 'url' in the current desktop's preferred file browser. If the
optional 'desktop' parameter is specified then attempt to use that
particular desktop environment's mechanisms to open the 'url' instead of
guessing or detecting which environment is being used.
Suggested values for 'desktop' are "standard", "KDE", "GNOME", "GNOME",
"XFCE", "Mac OS X", "Windows" where "standard" employs a DESKTOP_LAUNCH
environment variable to open the specified 'url'. DESKTOP_LAUNCH should
be a command, possibly followed by arguments, and must have any special
characters shell-escaped.
The process identifier of the "opener" (ie. viewer, editor, browser or
program) associated with the 'url' is returned by this function. If the
process identifier cannot be determined, None is returned.
An optional 'wait' parameter is also available for advanced usage and, if
'wait' is set to a true value, this function will wait for the launching
mechanism to complete before returning (as opposed to immediately returning
as is the default behaviour).
"""
# Decide on the desktop environment in use.
desktop_in_use = use_desktop(desktop)
if desktop_in_use == "standard":
arg = "".join([os.environ["DESKTOP_LAUNCH"], commands.mkarg(url)])
return _run(arg, 1, wait)
elif desktop_in_use == "Windows":
# NOTE: This returns None in current implementations.
return os.startfile(url)
elif desktop_in_use == "KDE":
cmd = ["xdg-open", url]
elif desktop_in_use == "GNOME":
cmd = ["xdg-open", url]
elif desktop_in_use == "MATE":
cmd = ["xdg-open", url]
elif desktop_in_use == "XFCE":
cmd = ["xdg-open", url]
elif desktop_in_use == "Mac OS X":
cmd = ["open", url]
elif desktop_in_use == "X11" and os.environ.has_key("BROWSER"):
cmd = [os.environ["BROWSER"], url]
# Finish with an error where no suitable desktop was identified.
else:
raise OSError, "Desktop '%s' not supported (neither DESKTOP_LAUNCH nor os.startfile could be used)" % desktop_in_use
return _run(cmd, 0, wait)
# vim: tabstop=4 expandtab shiftwidth=4

View File

@@ -0,0 +1,551 @@
#!/usr/bin/env python
"""
Simple desktop dialogue box support for Python.
Copyright (C) 2007, 2009 Paul Boddie <paul@boddie.org.uk>
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
--------
Opening Dialogue Boxes (Dialogs)
--------------------------------
To open a dialogue box (dialog) in the current desktop environment, relying on
the automatic detection of that environment, use the appropriate dialogue box
class:
question = desktop.dialog.Question("Are you sure?")
result = question.open()
To override the detected desktop, specify the desktop parameter to the open
function as follows:
question.open("KDE") # Insists on KDE
question.open("GNOME") # Insists on GNOME
question.open("MATE") # Insists on MATE
The dialogue box options are documented in each class's docstring.
Available dialogue box classes are listed in the desktop.dialog.available
attribute.
Supported desktop environments are listed in the desktop.dialog.supported
attribute.
"""
from desktop import use_desktop, _run, _readfrom, _status
class _wrapper:
def __init__(self, handler):
self.handler = handler
class _readvalue(_wrapper):
def __call__(self, cmd, shell):
return self.handler(cmd, shell).strip()
class _readinput(_wrapper):
def __call__(self, cmd, shell):
return self.handler(cmd, shell)[:-1]
class _readvalues_kdialog(_wrapper):
def __call__(self, cmd, shell):
result = self.handler(cmd, shell).strip().strip('"')
if result:
return result.split('" "')
else:
return []
class _readvalues_zenity(_wrapper):
def __call__(self, cmd, shell):
result = self.handler(cmd, shell).strip()
if result:
return result.split("|")
else:
return []
class _readvalues_Xdialog(_wrapper):
def __call__(self, cmd, shell):
result = self.handler(cmd, shell).strip()
if result:
return result.split("/")
else:
return []
# Dialogue parameter classes.
class String:
"A generic parameter."
def __init__(self, name):
self.name = name
def convert(self, value, program):
return [value or ""]
class Strings(String):
"Multiple string parameters."
def convert(self, value, program):
return value or []
class StringPairs(String):
"Multiple string parameters duplicated to make identifiers."
def convert(self, value, program):
l = []
for v in value:
l.append(v)
l.append(v)
return l
class StringKeyword:
"A keyword parameter."
def __init__(self, keyword, name):
self.keyword = keyword
self.name = name
def convert(self, value, program):
return [self.keyword + "=" + (value or "")]
class StringKeywords:
"Multiple keyword parameters."
def __init__(self, keyword, name):
self.keyword = keyword
self.name = name
def convert(self, value, program):
l = []
for v in value or []:
l.append(self.keyword + "=" + v)
return l
class Integer(String):
"An integer parameter."
defaults = {
"width" : 40,
"height" : 15,
"list_height" : 10
}
scale = 8
def __init__(self, name, pixels=0):
String.__init__(self, name)
if pixels:
self.factor = self.scale
else:
self.factor = 1
def convert(self, value, program):
if value is None:
value = self.defaults[self.name]
return [str(int(value) * self.factor)]
class IntegerKeyword(Integer):
"An integer keyword parameter."
def __init__(self, keyword, name, pixels=0):
Integer.__init__(self, name, pixels)
self.keyword = keyword
def convert(self, value, program):
if value is None:
value = self.defaults[self.name]
return [self.keyword + "=" + str(int(value) * self.factor)]
class Boolean(String):
"A boolean parameter."
values = {
"kdialog" : ["off", "on"],
"zenity" : ["FALSE", "TRUE"],
"Xdialog" : ["off", "on"]
}
def convert(self, value, program):
values = self.values[program]
if value:
return [values[1]]
else:
return [values[0]]
class MenuItemList(String):
"A menu item list parameter."
def convert(self, value, program):
l = []
for v in value:
l.append(v.value)
l.append(v.text)
return l
class ListItemList(String):
"A radiolist/checklist item list parameter."
def __init__(self, name, status_first=0):
String.__init__(self, name)
self.status_first = status_first
def convert(self, value, program):
l = []
for v in value:
boolean = Boolean(None)
status = boolean.convert(v.status, program)
if self.status_first:
l += status
l.append(v.value)
l.append(v.text)
if not self.status_first:
l += status
return l
# Dialogue argument values.
class MenuItem:
"A menu item which can also be used with radiolists and checklists."
def __init__(self, value, text, status=0):
self.value = value
self.text = text
self.status = status
# Dialogue classes.
class Dialogue:
commands = {
"KDE" : "kdialog",
"GNOME" : "zenity",
"MATE" : "zenity",
"XFCE" : "zenity", # NOTE: Based on observations with Xubuntu.
"X11" : "Xdialog"
}
def open(self, desktop=None):
"""
Open a dialogue box (dialog) using a program appropriate to the desktop
environment in use.
If the optional 'desktop' parameter is specified then attempt to use
that particular desktop environment's mechanisms to open the dialog
instead of guessing or detecting which environment is being used.
Suggested values for 'desktop' are "standard", "KDE", "GNOME",
"MATE", "Mac OS X", "Windows".
The result of the dialogue interaction may be a string indicating user
input (for Input, Password, Menu, Pulldown), a list of strings
indicating selections of one or more items (for RadioList, CheckList),
or a value indicating true or false (for Question, Warning, Message,
Error).
Where a string value may be expected but no choice is made, an empty
string may be returned. Similarly, where a list of values is expected
but no choice is made, an empty list may be returned.
"""
# Decide on the desktop environment in use.
desktop_in_use = use_desktop(desktop)
# Get the program.
try:
program = self.commands[desktop_in_use]
except KeyError:
raise OSError, "Desktop '%s' not supported (no known dialogue box command could be suggested)" % desktop_in_use
# The handler is one of the functions communicating with the subprocess.
# Some handlers return boolean values, others strings.
handler, options = self.info[program]
cmd = [program]
for option in options:
if isinstance(option, str):
cmd.append(option)
else:
value = getattr(self, option.name, None)
cmd += option.convert(value, program)
return handler(cmd, 0)
class Simple(Dialogue):
def __init__(self, text, width=None, height=None):
self.text = text
self.width = width
self.height = height
class Question(Simple):
"""
A dialogue asking a question and showing response buttons.
Options: text, width (in characters), height (in characters)
Response: a boolean value indicating an affirmative response (true) or a
negative response
"""
name = "question"
info = {
"kdialog" : (_status, ["--yesno", String("text")]),
"zenity" : (_status, ["--question", StringKeyword("--text", "text")]),
"Xdialog" : (_status, ["--stdout", "--yesno", String("text"), Integer("height"), Integer("width")]),
}
class Warning(Simple):
"""
A dialogue asking a question and showing response buttons.
Options: text, width (in characters), height (in characters)
Response: a boolean value indicating an affirmative response (true) or a
negative response
"""
name = "warning"
info = {
"kdialog" : (_status, ["--warningyesno", String("text")]),
"zenity" : (_status, ["--warning", StringKeyword("--text", "text")]),
"Xdialog" : (_status, ["--stdout", "--yesno", String("text"), Integer("height"), Integer("width")]),
}
class Message(Simple):
"""
A message dialogue.
Options: text, width (in characters), height (in characters)
Response: a boolean value indicating an affirmative response (true) or a
negative response
"""
name = "message"
info = {
"kdialog" : (_status, ["--msgbox", String("text")]),
"zenity" : (_status, ["--info", StringKeyword("--text", "text")]),
"Xdialog" : (_status, ["--stdout", "--msgbox", String("text"), Integer("height"), Integer("width")]),
}
class Error(Simple):
"""
An error dialogue.
Options: text, width (in characters), height (in characters)
Response: a boolean value indicating an affirmative response (true) or a
negative response
"""
name = "error"
info = {
"kdialog" : (_status, ["--error", String("text")]),
"zenity" : (_status, ["--error", StringKeyword("--text", "text")]),
"Xdialog" : (_status, ["--stdout", "--msgbox", String("text"), Integer("height"), Integer("width")]),
}
class Menu(Simple):
"""
A menu of options, one of which being selectable.
Options: text, width (in characters), height (in characters),
list_height (in items), items (MenuItem objects)
Response: a value corresponding to the chosen item
"""
name = "menu"
info = {
"kdialog" : (_readvalue(_readfrom), ["--menu", String("text"), MenuItemList("items")]),
"zenity" : (_readvalue(_readfrom), ["--list", StringKeyword("--text", "text"), StringKeywords("--column", "titles"),
MenuItemList("items")]
),
"Xdialog" : (_readvalue(_readfrom), ["--stdout", "--menubox",
String("text"), Integer("height"), Integer("width"), Integer("list_height"), MenuItemList("items")]
),
}
item = MenuItem
number_of_titles = 2
def __init__(self, text, titles, items=None, width=None, height=None, list_height=None):
"""
Initialise a menu with the given heading 'text', column 'titles', and
optional 'items' (which may be added later), 'width' (in characters),
'height' (in characters) and 'list_height' (in items).
"""
Simple.__init__(self, text, width, height)
self.titles = ([""] * self.number_of_titles + titles)[-self.number_of_titles:]
self.items = items or []
self.list_height = list_height
def add(self, *args, **kw):
"""
Add an item, passing the given arguments to the appropriate item class.
"""
self.items.append(self.item(*args, **kw))
class RadioList(Menu):
"""
A list of radio buttons, one of which being selectable.
Options: text, width (in characters), height (in characters),
list_height (in items), items (MenuItem objects), titles
Response: a list of values corresponding to chosen items (since some
programs, eg. zenity, appear to support multiple default
selections)
"""
name = "radiolist"
info = {
"kdialog" : (_readvalues_kdialog(_readfrom), ["--radiolist", String("text"), ListItemList("items")]),
"zenity" : (_readvalues_zenity(_readfrom),
["--list", "--radiolist", StringKeyword("--text", "text"), StringKeywords("--column", "titles"),
ListItemList("items", 1)]
),
"Xdialog" : (_readvalues_Xdialog(_readfrom), ["--stdout", "--radiolist",
String("text"), Integer("height"), Integer("width"), Integer("list_height"), ListItemList("items")]
),
}
number_of_titles = 3
class CheckList(Menu):
"""
A list of checkboxes, many being selectable.
Options: text, width (in characters), height (in characters),
list_height (in items), items (MenuItem objects), titles
Response: a list of values corresponding to chosen items
"""
name = "checklist"
info = {
"kdialog" : (_readvalues_kdialog(_readfrom), ["--checklist", String("text"), ListItemList("items")]),
"zenity" : (_readvalues_zenity(_readfrom),
["--list", "--checklist", StringKeyword("--text", "text"), StringKeywords("--column", "titles"),
ListItemList("items", 1)]
),
"Xdialog" : (_readvalues_Xdialog(_readfrom), ["--stdout", "--checklist",
String("text"), Integer("height"), Integer("width"), Integer("list_height"), ListItemList("items")]
),
}
number_of_titles = 3
class Pulldown(Menu):
"""
A pull-down menu of options, one of which being selectable.
Options: text, width (in characters), height (in characters),
items (list of values)
Response: a value corresponding to the chosen item
"""
name = "pulldown"
info = {
"kdialog" : (_readvalue(_readfrom), ["--combobox", String("text"), Strings("items")]),
"zenity" : (_readvalue(_readfrom),
["--list", "--radiolist", StringKeyword("--text", "text"), StringKeywords("--column", "titles"),
StringPairs("items")]
),
"Xdialog" : (_readvalue(_readfrom),
["--stdout", "--combobox", String("text"), Integer("height"), Integer("width"), Strings("items")]),
}
item = unicode
number_of_titles = 2
class Input(Simple):
"""
An input dialogue, consisting of an input field.
Options: text, input, width (in characters), height (in characters)
Response: the text entered into the dialogue by the user
"""
name = "input"
info = {
"kdialog" : (_readinput(_readfrom),
["--inputbox", String("text"), String("data")]),
"zenity" : (_readinput(_readfrom),
["--entry", StringKeyword("--text", "text"), StringKeyword("--entry-text", "data")]),
"Xdialog" : (_readinput(_readfrom),
["--stdout", "--inputbox", String("text"), Integer("height"), Integer("width"), String("data")]),
}
def __init__(self, text, data="", width=None, height=None):
Simple.__init__(self, text, width, height)
self.data = data
class Password(Input):
"""
A password dialogue, consisting of a password entry field.
Options: text, width (in characters), height (in characters)
Response: the text entered into the dialogue by the user
"""
name = "password"
info = {
"kdialog" : (_readinput(_readfrom),
["--password", String("text")]),
"zenity" : (_readinput(_readfrom),
["--entry", StringKeyword("--text", "text"), "--hide-text"]),
"Xdialog" : (_readinput(_readfrom),
["--stdout", "--password", "--inputbox", String("text"), Integer("height"), Integer("width")]),
}
class TextFile(Simple):
"""
A text file input box.
Options: filename, text, width (in characters), height (in characters)
Response: any text returned by the dialogue program (typically an empty
string)
"""
name = "textfile"
info = {
"kdialog" : (_readfrom, ["--textbox", String("filename"), Integer("width", pixels=1), Integer("height", pixels=1)]),
"zenity" : (_readfrom, ["--text-info", StringKeyword("--filename", "filename"), IntegerKeyword("--width", "width", pixels=1),
IntegerKeyword("--height", "height", pixels=1)]
),
"Xdialog" : (_readfrom, ["--stdout", "--textbox", String("filename"), Integer("height"), Integer("width")]),
}
def __init__(self, filename, text="", width=None, height=None):
Simple.__init__(self, text, width, height)
self.filename = filename
# Available dialogues.
available = [Question, Warning, Message, Error, Menu, CheckList, RadioList, Input, Password, Pulldown, TextFile]
# Supported desktop environments.
supported = Dialogue.commands.keys()
# vim: tabstop=4 expandtab shiftwidth=4

View File

@@ -0,0 +1,273 @@
#!/usr/bin/env python
"""
Simple desktop window enumeration for Python.
Copyright (C) 2007, 2008, 2009 Paul Boddie <paul@boddie.org.uk>
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
--------
Finding Open Windows on the Desktop
-----------------------------------
To obtain a list of windows, use the desktop.windows.list function as follows:
windows = desktop.windows.list()
To obtain the root window, typically the desktop background, use the
desktop.windows.root function as follows:
root = desktop.windows.root()
Each window object can be inspected through a number of methods. For example:
name = window.name()
width, height = window.size()
x, y = window.position()
child_windows = window.children()
See the desktop.windows.Window class for more information.
"""
from desktop import _is_x11, _get_x11_vars, _readfrom, use_desktop
import re
# System functions.
def _xwininfo(identifier, action):
if identifier is None:
args = "-root"
else:
args = "-id " + identifier
s = _readfrom(_get_x11_vars() + "xwininfo %s -%s" % (args, action), shell=1)
# Return a mapping of keys to values for the "stats" action.
if action == "stats":
d = {}
for line in s.split("\n"):
fields = line.split(":")
if len(fields) < 2:
continue
key, value = fields[0].strip(), ":".join(fields[1:]).strip()
d[key] = value
return d
# Otherwise, return the raw output.
else:
return s
def _get_int_properties(d, properties):
results = []
for property in properties:
results.append(int(d[property]))
return results
# Finder functions.
def find_all(name):
return 1
def find_named(name):
return name is not None
def find_by_name(name):
return lambda n, t=name: n == t
# Window classes.
# NOTE: X11 is the only supported desktop so far.
class Window:
"A window on the desktop."
_name_pattern = re.compile(r':\s+\(.*?\)\s+[-0-9x+]+\s+[-0-9+]+$')
_absent_names = "(has no name)", "(the root window) (has no name)"
def __init__(self, identifier):
"Initialise the window with the given 'identifier'."
self.identifier = identifier
# Finder methods (from above).
self.find_all = find_all
self.find_named = find_named
self.find_by_name = find_by_name
def __repr__(self):
return "Window(%r)" % self.identifier
# Methods which deal with the underlying commands.
def _get_handle_and_name(self, text):
fields = text.strip().split(" ")
handle = fields[0]
# Get the "<name>" part, stripping off the quotes.
name = " ".join(fields[1:])
if len(name) > 1 and name[0] == '"' and name[-1] == '"':
name = name[1:-1]
if name in self._absent_names:
return handle, None
else:
return handle, name
def _get_this_handle_and_name(self, line):
fields = line.split(":")
return self._get_handle_and_name(":".join(fields[1:]))
def _get_descendant_handle_and_name(self, line):
match = self._name_pattern.search(line)
if match:
return self._get_handle_and_name(line[:match.start()].strip())
else:
raise OSError, "Window information from %r did not contain window details." % line
def _descendants(self, s, fn):
handles = []
adding = 0
for line in s.split("\n"):
if line.endswith("child:") or line.endswith("children:"):
if not adding:
adding = 1
elif adding and line:
handle, name = self._get_descendant_handle_and_name(line)
if fn(name):
handles.append(handle)
return [Window(handle) for handle in handles]
# Public methods.
def children(self, all=0):
"""
Return a list of windows which are children of this window. If the
optional 'all' parameter is set to a true value, all such windows will
be returned regardless of whether they have any name information.
"""
s = _xwininfo(self.identifier, "children")
return self._descendants(s, all and self.find_all or self.find_named)
def descendants(self, all=0):
"""
Return a list of windows which are descendants of this window. If the
optional 'all' parameter is set to a true value, all such windows will
be returned regardless of whether they have any name information.
"""
s = _xwininfo(self.identifier, "tree")
return self._descendants(s, all and self.find_all or self.find_named)
def find(self, callable):
"""
Return windows using the given 'callable' (returning a true or a false
value when invoked with a window name) for descendants of this window.
"""
s = _xwininfo(self.identifier, "tree")
return self._descendants(s, callable)
def name(self):
"Return the name of the window."
d = _xwininfo(self.identifier, "stats")
# Format is 'xwininfo: Window id: <handle> "<name>"
return self._get_this_handle_and_name(d["xwininfo"])[1]
def size(self):
"Return a tuple containing the width and height of this window."
d = _xwininfo(self.identifier, "stats")
return _get_int_properties(d, ["Width", "Height"])
def position(self):
"Return a tuple containing the upper left co-ordinates of this window."
d = _xwininfo(self.identifier, "stats")
return _get_int_properties(d, ["Absolute upper-left X", "Absolute upper-left Y"])
def displayed(self):
"""
Return whether the window is displayed in some way (but not necessarily
visible on the current screen).
"""
d = _xwininfo(self.identifier, "stats")
return d["Map State"] != "IsUnviewable"
def visible(self):
"Return whether the window is displayed and visible."
d = _xwininfo(self.identifier, "stats")
return d["Map State"] == "IsViewable"
def list(desktop=None):
"""
Return a list of windows for the current desktop. If the optional 'desktop'
parameter is specified then attempt to use that particular desktop
environment's mechanisms to look for windows.
"""
root_window = root(desktop)
window_list = [window for window in root_window.descendants() if window.displayed()]
window_list.insert(0, root_window)
return window_list
def root(desktop=None):
"""
Return the root window for the current desktop. If the optional 'desktop'
parameter is specified then attempt to use that particular desktop
environment's mechanisms to look for windows.
"""
# NOTE: The desktop parameter is currently ignored and X11 is tested for
# NOTE: directly.
if _is_x11():
return Window(None)
else:
raise OSError, "Desktop '%s' not supported" % use_desktop(desktop)
def find(callable, desktop=None):
"""
Find and return windows using the given 'callable' for the current desktop.
If the optional 'desktop' parameter is specified then attempt to use that
particular desktop environment's mechanisms to look for windows.
"""
return root(desktop).find(callable)
# vim: tabstop=4 expandtab shiftwidth=4