mirror of
https://github.com/0intro/wmii
synced 2024-11-24 14:50:02 +03:00
Add python wmiirc/9P client library
This commit is contained in:
parent
69aec39fa1
commit
9ff6791633
@ -1,7 +1,7 @@
|
||||
syntax: regexp
|
||||
(^|/)\.((.*\.)?sw.|depend|hgignore)$
|
||||
(^|/)(tags|mkfile)$
|
||||
\.([oOa]|o_pic|so|orig|bak)$
|
||||
\.([oOa]|o_pic|so|orig|bak|pyc|pyo)$
|
||||
^cmd/(stfo|osd|wiwarp)(/|$)
|
||||
syntax: glob
|
||||
config.local.mk
|
||||
|
47
alternative_wmiircs/python/pygmi/__init__.py
Normal file
47
alternative_wmiircs/python/pygmi/__init__.py
Normal file
@ -0,0 +1,47 @@
|
||||
import os
|
||||
|
||||
from pyxp import Client
|
||||
|
||||
if 'WMII_ADDRESS' in os.environ:
|
||||
client = Client(os.environ['WMII_ADDRESS'])
|
||||
else:
|
||||
client = Client(namespace='wmii')
|
||||
|
||||
def call(*args, **kwargs):
|
||||
background = kwargs.pop('background', False)
|
||||
input = kwargs.pop('input', None)
|
||||
import subprocess
|
||||
p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, cwd=os.environ['HOME'],
|
||||
**kwargs)
|
||||
if not background:
|
||||
return p.communicate(input)[0].rstrip('\n')
|
||||
|
||||
def program_list(path):
|
||||
names = []
|
||||
for d in path:
|
||||
try:
|
||||
for f in os.listdir(d):
|
||||
if f not in names and os.access('%s/%s' % (d, f),
|
||||
os.X_OK):
|
||||
names.append(f)
|
||||
except Exception:
|
||||
pass
|
||||
return sorted(names)
|
||||
|
||||
def curry(func, *args, **kwargs):
|
||||
def curried(*newargs, **newkwargs):
|
||||
return func(*(args + newargs), **dict(kwargs, **newkwargs))
|
||||
curried.__name__ = func.__name__ + '__curried__'
|
||||
return curried
|
||||
|
||||
from pygmi import events, fs, menu, monitor
|
||||
from pygmi.events import *
|
||||
from pygmi.fs import *
|
||||
from pygmi.menu import *
|
||||
from pygmi.monitor import *
|
||||
|
||||
__all__ = (fs.__all__ + monitor.__all__ + events.__all__ +
|
||||
menu.__all__ + ('client', 'call', 'curry', 'program_list'))
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
95
alternative_wmiircs/python/pygmi/events.py
Normal file
95
alternative_wmiircs/python/pygmi/events.py
Normal file
@ -0,0 +1,95 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from pygmi import monitor, client, call, program_list
|
||||
|
||||
__all__ = ('bind_keys', 'bind_events', 'toggle_keys', 'event_loop',
|
||||
'event')
|
||||
|
||||
keydefs = {}
|
||||
keys = {}
|
||||
events = {}
|
||||
|
||||
alive = True
|
||||
|
||||
def flatten(items):
|
||||
for k, v in items.iteritems():
|
||||
if not isinstance(k, (list, tuple)):
|
||||
k = k,
|
||||
for key in k:
|
||||
yield key, v
|
||||
|
||||
def bind_keys(items):
|
||||
for k, v in flatten(items):
|
||||
keys[k % keydefs] = v
|
||||
|
||||
def bind_events(items):
|
||||
for k, v in flatten(items):
|
||||
events[k] = v
|
||||
|
||||
def event(fn):
|
||||
bind_events({fn.__name__: fn})
|
||||
|
||||
@event
|
||||
def Key(args):
|
||||
if args in keys:
|
||||
keys[args](args)
|
||||
|
||||
keys_enabled = False
|
||||
keys_restore = None
|
||||
def toggle_keys(on=None, restore=None):
|
||||
if on is None:
|
||||
on = not keys_enabled
|
||||
keys_restore = restore
|
||||
if on:
|
||||
client.write('/keys', '\n'.join(keys.keys()))
|
||||
else:
|
||||
client.write('/keys', restore or ' ')
|
||||
|
||||
def dispatch(event, args=''):
|
||||
if event in events:
|
||||
try:
|
||||
events[event](args)
|
||||
except Exception, e:
|
||||
traceback.print_exc(sys.stderr)
|
||||
|
||||
def event_loop():
|
||||
from pygmi import events
|
||||
toggle_keys(on=True)
|
||||
for line in client.readlines('/event'):
|
||||
if not events.alive:
|
||||
break
|
||||
dispatch(*line.split(' ', 1))
|
||||
events.alive = False
|
||||
|
||||
class Actions(object):
|
||||
which = call('which', 'which')
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name.startswith('_') or name.endswith('_'):
|
||||
raise AttributeError()
|
||||
if hasattr(self, name + '_'):
|
||||
return getattr(self, name + '_')
|
||||
def action(args=''):
|
||||
cmd = call(self.which, name,
|
||||
env=dict(os.environ, PATH=':'.join(confpath)))
|
||||
call(shell, '-c', '$* %s' % args, '--', cmd,
|
||||
background=True)
|
||||
return action
|
||||
|
||||
def _call(self, args):
|
||||
a = args.split(' ')
|
||||
if a:
|
||||
getattr(self, a[0])(*a[1:])
|
||||
|
||||
@property
|
||||
def _choices(self):
|
||||
return sorted(
|
||||
program_list(confpath) +
|
||||
[re.sub('_$', '', k) for k in dir(self)
|
||||
if not re.match('^_', k) and callable(getattr(self, k))])
|
||||
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
588
alternative_wmiircs/python/pygmi/fs.py
Normal file
588
alternative_wmiircs/python/pygmi/fs.py
Normal file
@ -0,0 +1,588 @@
|
||||
import collections
|
||||
|
||||
from pyxp import *
|
||||
from pyxp.client import *
|
||||
from pygmi import *
|
||||
|
||||
__all__ = ('wmii', 'Tags', 'Tag', 'Area', 'Frame', 'Client',
|
||||
'Button', 'Colors', 'Color')
|
||||
|
||||
class Ctl(object):
|
||||
sentinel = {}
|
||||
ctl_types = {}
|
||||
ctl_hasid = False
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def ctl(self, msg):
|
||||
client.write(self.ctl_path, msg)
|
||||
|
||||
def __getitem__(self, key):
|
||||
for line in self.ctl_lines():
|
||||
key_, rest = line.split(' ', 1)
|
||||
if key_ == key:
|
||||
if key in self.ctl_types:
|
||||
return self.ctl_types[key][0](rest)
|
||||
return rest
|
||||
raise KeyError()
|
||||
def __hasitem__(self, key):
|
||||
return key in self.keys()
|
||||
def __setitem__(self, key, val):
|
||||
assert '\n' not in key
|
||||
if key in self.ctl_types:
|
||||
val = self.ctl_types[key][1](val)
|
||||
self.ctl('%s %s\n' % (key, val))
|
||||
|
||||
def get(self, key, default=sentinel):
|
||||
try:
|
||||
val = self[key]
|
||||
except KeyError, e:
|
||||
if default is not self.sentinel:
|
||||
return default
|
||||
raise e
|
||||
def set(self, key, val):
|
||||
self[key] = val
|
||||
|
||||
def keys(self):
|
||||
return [line.split(' ', 1)[0]
|
||||
for line in self.ctl_lines()]
|
||||
def iteritems(self):
|
||||
return (tuple(line.split(' ', 1))
|
||||
for line in self.ctl_lines())
|
||||
def items(self):
|
||||
return [tuple(line.split(' ', 1))
|
||||
for line in self.ctl_lines()]
|
||||
|
||||
def ctl_lines(self):
|
||||
lines = tuple(client.readlines(self.ctl_path))
|
||||
if self.ctl_hasid:
|
||||
lines = lines[1:]
|
||||
return lines[:-1]
|
||||
|
||||
_id = None
|
||||
@property
|
||||
def id(self):
|
||||
if self._id is None and self.ctl_hasid:
|
||||
return client.read(self.ctl_path).split('\n', 1)[0]
|
||||
return self._id
|
||||
|
||||
class Dir(Ctl):
|
||||
ctl_hasid = True
|
||||
|
||||
def __init__(self, id):
|
||||
if id != 'sel':
|
||||
self._id = id
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.__class__ == other.__class__ and
|
||||
self.id == other.id)
|
||||
|
||||
class ctl_property(object):
|
||||
def __init__(self, key):
|
||||
self.key = key
|
||||
def __get__(self, dir, cls):
|
||||
return dir[self.key]
|
||||
def __set__(self, dir, val):
|
||||
dir[self.key] = val
|
||||
class toggle_property(ctl_property):
|
||||
props = {
|
||||
'on': True,
|
||||
'off': False,
|
||||
}
|
||||
def __get__(self, dir, cls):
|
||||
val = dir[self.key]
|
||||
if val in self.props:
|
||||
return self.props[val]
|
||||
return val
|
||||
def __set__(self, dir, val):
|
||||
for k, v in self.props.iteritems():
|
||||
if v == val:
|
||||
val = k
|
||||
break
|
||||
dir[self.key] = val
|
||||
|
||||
class file_property(object):
|
||||
def __init__(self, name, writable=False):
|
||||
self.name = name
|
||||
self.writable = writable
|
||||
def __get__(self, dir, cls):
|
||||
return client.read('%s/%s' % (dir.path, self.name))
|
||||
def __set__(self, dir, val):
|
||||
if not self.writable:
|
||||
raise NotImplementedError('File %s is not writable' % self.name)
|
||||
return client.write('%s/%s' % (dir.path, self.name), val)
|
||||
|
||||
@property
|
||||
def ctl_path(self):
|
||||
return '%s/ctl' % self.path
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
return '%s/%s' % (self.base_path, self._id or 'sel')
|
||||
|
||||
@classmethod
|
||||
def all(cls):
|
||||
return (cls(s.name)
|
||||
for s in client.readdir(cls.base_path)
|
||||
if s.name != 'sel')
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%s)' % (self.__class__.__name__,
|
||||
repr(self._id or 'sel'))
|
||||
|
||||
class Client(Dir):
|
||||
base_path = '/client'
|
||||
|
||||
fullscreen = Dir.toggle_property('Fullscreen')
|
||||
urgent = Dir.toggle_property('Urgent')
|
||||
|
||||
label = Dir.file_property('label', writable=True)
|
||||
tags = Dir.file_property('tags', writable=True)
|
||||
props = Dir.file_property('props')
|
||||
|
||||
def kill(self):
|
||||
self.ctl('kill')
|
||||
def slay(self):
|
||||
self.ctl('slay')
|
||||
|
||||
class liveprop(object):
|
||||
def __init__(self, get):
|
||||
self.get = get
|
||||
self.attr = str(self)
|
||||
def __get__(self, area, cls):
|
||||
if getattr(area, self.attr, None) is not None:
|
||||
return getattr(area, self.attr)
|
||||
return self.get(area)
|
||||
def __set__(self, area, val):
|
||||
setattr(area, self.attr, val)
|
||||
|
||||
class Area(object):
|
||||
def __init__(self, tag, ord, offset=None, width=None, height=None, frames=None):
|
||||
self.tag = tag
|
||||
self.ord = str(ord)
|
||||
self.offset = offset
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.frames = frames
|
||||
|
||||
def prop(key):
|
||||
@liveprop
|
||||
def prop(self):
|
||||
for area in self.tag.index:
|
||||
if str(area.ord) == str(self.ord):
|
||||
return getattr(area, key)
|
||||
return prop
|
||||
offset = prop('offset')
|
||||
width = prop('width')
|
||||
height = prop('height')
|
||||
frames = prop('frames')
|
||||
|
||||
def _get_mode(self):
|
||||
for k, v in self.tag.iteritems():
|
||||
if k == 'colmode':
|
||||
v = v.split(' ')
|
||||
if v[0] == self.ord:
|
||||
return v[1]
|
||||
mode = property(
|
||||
_get_mode,
|
||||
lambda self, val: self.tag.set('colmode %s' % self.ord, val))
|
||||
|
||||
def grow(self, dir, amount=None):
|
||||
self.tag.grow(self, dir, amount)
|
||||
def nudge(self, dir, amount=None):
|
||||
self.tag.nudge(self, dir, amount)
|
||||
|
||||
class Frame(object):
|
||||
live = False
|
||||
|
||||
def __init__(self, client, area=None, ord=None, offset=None, height=None):
|
||||
self.client = client
|
||||
self.ord = ord
|
||||
self.offset = offset
|
||||
self.height = height
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self.area.width
|
||||
|
||||
def prop(key):
|
||||
@liveprop
|
||||
def prop(self):
|
||||
for area in self.tag.index:
|
||||
for frame in area.frames:
|
||||
if frame.client == self.client:
|
||||
return getattr(frame, key)
|
||||
return prop
|
||||
offset = prop('area')
|
||||
offset = prop('ord')
|
||||
offset = prop('offset')
|
||||
height = prop('height')
|
||||
|
||||
def grow(self, dir, amount=None):
|
||||
self.area.tag.grow(self, dir, amount)
|
||||
def nudge(self, dir, amount=None):
|
||||
self.area.tag.nudge(self, dir, amount)
|
||||
|
||||
class Tag(Dir):
|
||||
base_path = '/tag'
|
||||
|
||||
@classmethod
|
||||
def framespec(cls, frame):
|
||||
if isinstance(frame, Frame):
|
||||
frame = frame.client
|
||||
if isinstance(frame, Area):
|
||||
frame = (frame.ord, 'sel')
|
||||
if isinstance(frame, Client):
|
||||
if frame._id is None:
|
||||
return 'sel sel'
|
||||
return 'client %s' % frame.id
|
||||
elif isinstance(frame, basestring):
|
||||
return frame
|
||||
else:
|
||||
return '%s %s' % tuple(map(str, frame))
|
||||
def dirspec(cls, dir):
|
||||
if isinstance(dir, tuple):
|
||||
dir = ' '.join(dir)
|
||||
return dir
|
||||
|
||||
def _set_selected(self, frame):
|
||||
if not isinstance(frame, basestring) or ' ' not in frame:
|
||||
frame = self.framespec(frame)
|
||||
self['select'] = frame
|
||||
selected = property(lambda self: tuple(self['select'].split(' ')),
|
||||
_set_selected)
|
||||
|
||||
def _get_selclient(self):
|
||||
for k, v in self.iteritems():
|
||||
if k == 'select' and 'client' in v:
|
||||
return Client(v.split(' ')[1])
|
||||
return None
|
||||
selclient = property(_get_selclient,
|
||||
lambda self, val: self.set('select',
|
||||
self.framespec(val)))
|
||||
|
||||
@property
|
||||
def selcol(self):
|
||||
return Area(self, self.selected[0])
|
||||
|
||||
@property
|
||||
def index(self):
|
||||
areas = []
|
||||
for l in [l.split(' ')
|
||||
for l in client.readlines('%s/index' % self.path)
|
||||
if l]:
|
||||
if l[0] == '#':
|
||||
if l[1] == '~':
|
||||
area = Area(tag=self, ord=l[1], width=l[2], height=l[3],
|
||||
frames=[])
|
||||
else:
|
||||
area = Area(tag=self, ord=l[1], offset=l[2], width=l[3],
|
||||
frames=[])
|
||||
areas.append(area)
|
||||
i = 0
|
||||
else:
|
||||
area.frames.append(
|
||||
Frame(client=Client(l[1]), area=area, ord=i,
|
||||
offset=l[2], height=l[3]))
|
||||
i += 1
|
||||
return areas
|
||||
|
||||
def delete(self):
|
||||
id = self.id
|
||||
for a in self.index:
|
||||
for f in a.frames:
|
||||
if f.client.tags == id:
|
||||
f.client.kill()
|
||||
else:
|
||||
f.client.tags = '-%s' % id
|
||||
if self == Tag('sel'):
|
||||
Tags.instance.select(Tags.instance.next())
|
||||
|
||||
def select(self, frame, stack=False):
|
||||
self['select'] = '%s %s' % (
|
||||
self.framespec(frame),
|
||||
stack and 'stack' or '')
|
||||
|
||||
def send(self, src, dest, stack=False, cmd='send'):
|
||||
if isinstance(src, tuple):
|
||||
src = ' '.join(src)
|
||||
if isinstance(src, Frame):
|
||||
src = src.client
|
||||
if isinstance(src, Client):
|
||||
src = src._id or 'sel'
|
||||
|
||||
if isinstance(dest, tuple):
|
||||
dest = ' '.join(dest)
|
||||
|
||||
self[cmd] = '%s %s' % (src, dest)
|
||||
|
||||
def swap(self, src, dest):
|
||||
self.send(src, dest, cmd='swap')
|
||||
|
||||
def nudge(self, frame, dir, amount=None):
|
||||
frame = self.framespec(frame)
|
||||
self['nudge'] = '%s %s %s' % (frame, dir, str(amount or ''))
|
||||
def grow(self, frame, dir, amount=None):
|
||||
frame = self.framespec(frame)
|
||||
self['grow'] = '%s %s %s' % (frame, dir, str(amount or ''))
|
||||
|
||||
class Button(object):
|
||||
sides = {
|
||||
'left': 'lbar',
|
||||
'right': 'rbar',
|
||||
}
|
||||
def __init__(self, side, name, colors=None, label=None):
|
||||
self.side = side
|
||||
self.name = name
|
||||
self.base_path = self.sides[side]
|
||||
self.path = '%s/%s' % (self.base_path, self.name)
|
||||
self.create(colors, label)
|
||||
|
||||
def create(self, colors=None, label=None):
|
||||
with client.create(self.path, OWRITE) as f:
|
||||
if colors or label:
|
||||
f.write(self.getval(colors, label))
|
||||
def remove(self):
|
||||
client.remove(self.path)
|
||||
|
||||
def getval(self, colors=None, label=None):
|
||||
if colors is None:
|
||||
colors = self.colors
|
||||
if label is None:
|
||||
label = self.label
|
||||
return ' '.join([Color(c).hex for c in colors] + [label])
|
||||
|
||||
colors = property(
|
||||
lambda self: tuple(map(Color, client.read(self.path).split(' ')[:3])),
|
||||
lambda self, val: client.write(self.path, self.getval(colors=val)))
|
||||
|
||||
label = property(
|
||||
lambda self: client.read(self.path).split(' ', 3)[3],
|
||||
lambda self, val: client.write(self.path, self.getval(label=val)))
|
||||
|
||||
@classmethod
|
||||
def all(cls, side):
|
||||
return (Button(side, s.name)
|
||||
for s in client.readdir(cls.sides[side])
|
||||
if s.name != 'sel')
|
||||
|
||||
class Colors(object):
|
||||
def __init__(self, foreground=None, background=None, border=None):
|
||||
vals = foreground, background, border
|
||||
self.vals = tuple(map(Color, vals))
|
||||
|
||||
@classmethod
|
||||
def from_string(cls, val):
|
||||
return cls(*val.split(' '))
|
||||
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, basestring):
|
||||
key = {'foreground': 0, 'background': 1, 'border': 2}[key]
|
||||
return self.vals[key]
|
||||
|
||||
def __str__(self):
|
||||
return str(unicode(self))
|
||||
def __unicode__(self):
|
||||
return ' '.join(c.hex for c in self.vals)
|
||||
def __repr__(self):
|
||||
return 'Colors(%s, %s, %s)' % tuple(repr(c.rgb) for c in self.vals)
|
||||
|
||||
class Color(object):
|
||||
def __init__(self, colors):
|
||||
if isinstance(colors, Color):
|
||||
colors = colors.rgb
|
||||
elif isinstance(colors, basestring):
|
||||
match = re.match(r'^#(..)(..)(..)$', colors)
|
||||
colors = tuple(int(match.group(group), 16) for group in range(1, 4))
|
||||
def toint(val):
|
||||
if isinstance(val, float):
|
||||
val = int(255 * val)
|
||||
assert 0 <= val <= 255
|
||||
return val
|
||||
self.rgb = tuple(map(toint, colors))
|
||||
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, basestring):
|
||||
key = {'red': 0, 'green': 1, 'blue': 2}[key]
|
||||
return self.rgb[key]
|
||||
|
||||
@property
|
||||
def hex(self):
|
||||
return '#%02x%02x%02x' % self.rgb
|
||||
|
||||
def __str__(self):
|
||||
return str(unicode(self))
|
||||
def __unicode__(self):
|
||||
return 'rgb(%d, %d, %d)' % self.rgb
|
||||
def __repr__(self):
|
||||
return 'Color(%s)' % repr(self.rgb)
|
||||
|
||||
class Rules(collections.MutableMapping):
|
||||
regex = re.compile(r'^\s*/(.*?)/\s*(?:->)?\s*(.*)$')
|
||||
|
||||
def __get__(self, obj, cls):
|
||||
return self
|
||||
def __set__(self, obj, val):
|
||||
self.setitems(val)
|
||||
|
||||
def __init__(self, path, rules=None):
|
||||
self.path = path
|
||||
if rules:
|
||||
self.setitems(rules)
|
||||
|
||||
def __getitem__(self, key):
|
||||
for k, v in self.iteritems():
|
||||
if k == key:
|
||||
return v
|
||||
raise KeyError()
|
||||
def __setitem__(self, key, val):
|
||||
items = []
|
||||
for k, v in self.iteritems():
|
||||
if key == k:
|
||||
v = val
|
||||
key = None
|
||||
items.append((k, v))
|
||||
if key is not None:
|
||||
items.append((key, val))
|
||||
self.setitems(items)
|
||||
def __delitem__(self, key):
|
||||
self.setitems((k, v) for k, v in self.iteritems() if k != key)
|
||||
|
||||
def __len__(self):
|
||||
return len(tuple(self.iteritems()))
|
||||
def __iter__(self):
|
||||
for k, v in self.iteritems():
|
||||
yield k
|
||||
def __list__(self):
|
||||
return list(iter(self))
|
||||
def __tuple__(self):
|
||||
return tuple(iter(self))
|
||||
|
||||
def append(self, item):
|
||||
self.setitems(self + (item,))
|
||||
def __add__(self, items):
|
||||
return tuple(self.iteritems()) + tuple(items)
|
||||
|
||||
def setitems(self, items):
|
||||
lines = []
|
||||
for k, v in items:
|
||||
assert '/' not in k and '\n' not in v
|
||||
lines.append('/%s/ -> %s' % (k, v))
|
||||
lines.append('')
|
||||
client.write(self.path, '\n'.join(lines))
|
||||
|
||||
def iteritems(self):
|
||||
for line in client.readlines(self.path):
|
||||
match = self.regex.match(line)
|
||||
if match:
|
||||
yield match.groups()
|
||||
def items(self):
|
||||
return list(self.iteritems())
|
||||
|
||||
@apply
|
||||
class wmii(Ctl):
|
||||
ctl_path = '/ctl'
|
||||
ctl_types = {
|
||||
'normcolors': (Colors.from_string, lambda c: str(Colors(c))),
|
||||
'focuscolors': (Colors.from_string, lambda c: str(Colors(c))),
|
||||
'border': (int, str),
|
||||
}
|
||||
|
||||
clients = property(lambda self: Client.all())
|
||||
tags = property(lambda self: Tag.all())
|
||||
lbuttons = property(lambda self: Button.all('left'))
|
||||
rbuttons = property(lambda self: Button.all('right'))
|
||||
|
||||
tagrules = Rules('/tagrules')
|
||||
colrules = Rules('/colrules')
|
||||
|
||||
class Tags(object):
|
||||
PREV = []
|
||||
NEXT = []
|
||||
|
||||
def __init__(self, normcol=None, focuscol=None):
|
||||
self.tags = {}
|
||||
self.sel = None
|
||||
self.normcol = normcol or wmii['normcolors']
|
||||
self.focuscol = focuscol or wmii['focuscolors']
|
||||
for t in wmii.tags:
|
||||
self.add(t.id)
|
||||
for b in wmii.lbuttons:
|
||||
if b.name not in self.tags:
|
||||
b.remove()
|
||||
self.focus(Tag('sel').id)
|
||||
|
||||
self.mru = [self.sel.id]
|
||||
self.idx = -1
|
||||
Tags.instance = self
|
||||
|
||||
def add(self, tag):
|
||||
self.tags[tag] = Tag(tag)
|
||||
self.tags[tag].button = Button('left', tag, self.normcol, tag)
|
||||
def delete(self, tag):
|
||||
self.tags.pop(tag).button.remove()
|
||||
|
||||
def focus(self, tag):
|
||||
self.sel = self.tags[tag]
|
||||
self.sel.button.colors = self.focuscol
|
||||
def unfocus(self, tag):
|
||||
self.tags[tag].button.colors = self.normcol
|
||||
|
||||
def set_urgent(self, tag, urgent=True):
|
||||
self.tags[tag].button.label = urgent and '*' + tag or tag
|
||||
|
||||
def next(self, reverse=False):
|
||||
tags = list(wmii.tags)
|
||||
tags.append(tags[0])
|
||||
if reverse:
|
||||
tags.reverse()
|
||||
for i in range(0, len(tags)):
|
||||
if tags[i] == self.sel:
|
||||
return tags[i+1]
|
||||
return self.sel
|
||||
|
||||
def select(self, tag):
|
||||
if tag is self.PREV:
|
||||
self.idx -= 1
|
||||
elif tag is self.NEXT:
|
||||
self.idx += 1
|
||||
else:
|
||||
if isinstance(tag, Tag):
|
||||
tag = tag.id
|
||||
wmii['view'] = tag
|
||||
|
||||
if tag != self.mru[-1]:
|
||||
self.mru.append(tag)
|
||||
self.mru = self.mru[-10:]
|
||||
return
|
||||
|
||||
self.idx = min(-1, max(-len(self.mru), self.idx))
|
||||
wmii['view'] = self.mru[self.idx]
|
||||
|
||||
if __name__ == '__main__':
|
||||
c = Client('sel')
|
||||
#print c.id
|
||||
#print c.items()
|
||||
#print c.urgent
|
||||
|
||||
#print list(wmii.clients)
|
||||
#print list(wmii.tags)
|
||||
|
||||
#print [a.frames for a in Tag('sel').index]
|
||||
#print Tag('sel').selclient
|
||||
#print Tag('sel').selclient.label
|
||||
#print Tag('sel').selclient.tags
|
||||
#print Tag('sel').selclient.props
|
||||
#a = Area(Tag('sel'), 1)
|
||||
#print a.width
|
||||
#print a.frames
|
||||
|
||||
#print [[c.hex for c in b.colors] for b in wmii.lbuttons]
|
||||
#print [[c.hex for c in b.colors] for b in wmii.rbuttons]
|
||||
Button('left', '1').colors = ((0., 0., 0.), (1., 1., 1.), (0., 0., 0.))
|
||||
Button('left', '1').label = 'foo'
|
||||
Button('left', '5', label='baz')
|
||||
print repr(wmii['normcolors'])
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
58
alternative_wmiircs/python/pygmi/menu.py
Normal file
58
alternative_wmiircs/python/pygmi/menu.py
Normal file
@ -0,0 +1,58 @@
|
||||
from pygmi import call
|
||||
|
||||
__all__ = 'Menu', 'ClickMenu'
|
||||
|
||||
def inthread(fn, action):
|
||||
def run():
|
||||
res = fn()
|
||||
if action:
|
||||
return action(res)
|
||||
return res
|
||||
if not action:
|
||||
return run()
|
||||
from threading import Thread
|
||||
Thread(target=run).start()
|
||||
|
||||
class Menu(object):
|
||||
def __init__(self, choices=(), action=None,
|
||||
histfile=None, nhist=None):
|
||||
self.choices = choices
|
||||
self.action = action
|
||||
self.histfile = histfile
|
||||
self.nhist = nhist
|
||||
|
||||
def call(self, choices=None):
|
||||
if choices is None:
|
||||
choices = self.choices
|
||||
if callable(choices):
|
||||
choices = choices()
|
||||
def act():
|
||||
args = ['wimenu']
|
||||
if self.histfile:
|
||||
args += ['-h', self.histfile]
|
||||
if self.nhist:
|
||||
args += ['-n', self.nhist]
|
||||
return call(*map(str, args), input='\n'.join(choices))
|
||||
return inthread(act, self.action)
|
||||
|
||||
class ClickMenu(object):
|
||||
def __init__(self, choices=(), action=None,
|
||||
histfile=None, nhist=None):
|
||||
self.choices = choices
|
||||
self.action = action
|
||||
self.prev = None
|
||||
|
||||
def call(self, choices=None):
|
||||
if choices is None:
|
||||
choices = self.choices
|
||||
if callable(choices):
|
||||
choices = choices()
|
||||
def act():
|
||||
args = ['wmii9menu']
|
||||
if self.prev:
|
||||
args += ['-i', self.prev]
|
||||
args += ['--'] + list(choices)
|
||||
return call(*map(str, args)).replace('\n', '')
|
||||
return inthread(act, self.action)
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
86
alternative_wmiircs/python/pygmi/monitor.py
Normal file
86
alternative_wmiircs/python/pygmi/monitor.py
Normal file
@ -0,0 +1,86 @@
|
||||
from pygmi import client
|
||||
from pygmi.fs import *
|
||||
|
||||
__all__ = 'monitors', 'defmonitor', 'Monitor'
|
||||
|
||||
monitors = {}
|
||||
|
||||
def defmonitor(*args, **kwargs):
|
||||
def monitor(fn):
|
||||
kwargs['action'] = fn
|
||||
if not args and 'name' not in kwargs:
|
||||
kwargs['name'] = fn.__name__
|
||||
monitor = Monitor(*args, **kwargs)
|
||||
monitors[monitor.name] = monitor
|
||||
return monitor
|
||||
if args and callable(args[0]):
|
||||
fn = args[0]
|
||||
args = args[1:]
|
||||
return monitor(fn)
|
||||
return monitor
|
||||
|
||||
class MonitorBase(type):
|
||||
def __new__(cls, name, bases, attrs):
|
||||
new_cls = super(MonitorBase, cls).__new__(cls, name, bases, attrs)
|
||||
if name not in attrs:
|
||||
new_cls.name = new_cls.__name__.lower()
|
||||
try:
|
||||
Monitor
|
||||
if new_cls.name not in monitors:
|
||||
monitors[new_cls.name] = new_cls()
|
||||
except Exception, e:
|
||||
pass
|
||||
return new_cls
|
||||
|
||||
class Monitor(object):
|
||||
|
||||
side = 'right'
|
||||
interval = 1.0
|
||||
|
||||
def __init__(self, name=None, interval=None, side=None,
|
||||
action=None):
|
||||
if side:
|
||||
self.side = side
|
||||
if name:
|
||||
self.name = name
|
||||
if interval:
|
||||
self.interval = interval
|
||||
if action:
|
||||
self.action = action
|
||||
|
||||
self.button = Button(self.side, self.name)
|
||||
self.tick()
|
||||
|
||||
def tick(self):
|
||||
from pygmi import events
|
||||
if not events.alive:
|
||||
if client:
|
||||
self.button.remove()
|
||||
return
|
||||
if self.active:
|
||||
from threading import Timer
|
||||
label = self.getlabel()
|
||||
if isinstance(label, basestring):
|
||||
label = None, label
|
||||
self.button.create(*label)
|
||||
self.timer = Timer(self.interval, self.tick)
|
||||
self.timer.start()
|
||||
|
||||
def getlabel(self):
|
||||
if self.action:
|
||||
return self.action()
|
||||
return ()
|
||||
|
||||
_active = True
|
||||
def _set_active(self, val):
|
||||
self._active = bool(val)
|
||||
if val:
|
||||
self.tick()
|
||||
else:
|
||||
self.button.remove()
|
||||
|
||||
active = property(
|
||||
lambda self: self._active,
|
||||
_set_active)
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
7
alternative_wmiircs/python/pyxp/__init__.py
Normal file
7
alternative_wmiircs/python/pyxp/__init__.py
Normal file
@ -0,0 +1,7 @@
|
||||
from pyxp.client import Client
|
||||
from pyxp.dial import dial
|
||||
from pyxp.types import Qid, Stat
|
||||
|
||||
VERSION = '9P2000'
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
328
alternative_wmiircs/python/pyxp/client.py
Normal file
328
alternative_wmiircs/python/pyxp/client.py
Normal file
@ -0,0 +1,328 @@
|
||||
# Copyright (C) 2007 Kris Maglione
|
||||
# See PERMISSIONS
|
||||
|
||||
import operator
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from threading import *
|
||||
import traceback
|
||||
|
||||
import pyxp
|
||||
from pyxp import fcall, fields
|
||||
from pyxp.mux import Mux
|
||||
from pyxp.types import *
|
||||
|
||||
if os.environ.get('NAMESPACE', None):
|
||||
namespace = os.environ['NAMESPACE']
|
||||
else:
|
||||
try:
|
||||
namespace = '/tmp/ns.%s.%s' % (
|
||||
os.environ['USER'],
|
||||
re.sub(r'\.0$', '', os.environ['DISPLAY']))
|
||||
except Exception:
|
||||
pass
|
||||
NAMESPACE = namespace
|
||||
|
||||
OREAD = 0x00
|
||||
OWRITE = 0x01
|
||||
ORDWR = 0x02
|
||||
OEXEC = 0x03
|
||||
OEXCL = 0x04
|
||||
OTRUNC = 0x10
|
||||
OREXEC = 0x20
|
||||
ORCLOSE = 0x40
|
||||
OAPPEND = 0x80
|
||||
|
||||
ROOT_FID = 0
|
||||
|
||||
class ProtocolException(Exception):
|
||||
pass
|
||||
class RPCError(Exception):
|
||||
pass
|
||||
|
||||
class Client(object):
|
||||
ROOT_FID = 0
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __exit__(self, *args):
|
||||
self.cleanup()
|
||||
|
||||
def __init__(self, conn=None, namespace=None, root=None):
|
||||
if not conn and namespace:
|
||||
conn = 'unix!%s/%s' % (NAMESPACE, namespace)
|
||||
try:
|
||||
self.lastfid = ROOT_FID
|
||||
self.fids = []
|
||||
self.files = {}
|
||||
self.lock = RLock()
|
||||
|
||||
def process(data):
|
||||
return fcall.Fcall.unmarshall(data)[1]
|
||||
self.mux = Mux(conn, process, maxtag=256)
|
||||
|
||||
resp = self.dorpc(fcall.Tversion(version=pyxp.VERSION, msize=65535))
|
||||
if resp.version != pyxp.VERSION:
|
||||
raise ProtocolException, "Can't speak 9P version '%s'" % resp.version
|
||||
self.msize = resp.msize
|
||||
|
||||
self.dorpc(fcall.Tattach(fid=ROOT_FID, afid=fcall.NO_FID,
|
||||
uname=os.environ['USER'], aname=''))
|
||||
|
||||
if root:
|
||||
path = self.splitpath(root)
|
||||
resp = self.dorpc(fcall.Twalk(fid=ROOT_FID,
|
||||
newfid=ROOT_FID,
|
||||
wname=path))
|
||||
except Exception, e:
|
||||
traceback.print_exc(sys.stdout)
|
||||
if getattr(self, 'mux', None):
|
||||
self.mux.fd.close()
|
||||
raise e
|
||||
|
||||
def cleanup(self):
|
||||
try:
|
||||
for f in self.files:
|
||||
f.close()
|
||||
finally:
|
||||
self.mux.fd.close()
|
||||
self.mux = None
|
||||
|
||||
def dorpc(self, req):
|
||||
resp = self.mux.rpc(req)
|
||||
if isinstance(resp, fcall.Rerror):
|
||||
raise RPCError, "RPC returned error (%s): %s" % (
|
||||
req.__class__.__name__, resp.ename)
|
||||
if req.type != resp.type ^ 1:
|
||||
raise ProtocolException, "Missmatched RPC message types: %s => %s" % (
|
||||
req.__class__.__name__, resp.__class__.__name__)
|
||||
return resp
|
||||
|
||||
def splitpath(self, path):
|
||||
return [v for v in path.split('/') if v != '']
|
||||
|
||||
def getfid(self):
|
||||
with self.lock:
|
||||
if len(self.fids):
|
||||
return self.fids.pop()
|
||||
else:
|
||||
self.lastfid += 1
|
||||
return self.lastfid
|
||||
def putfid(self, fid):
|
||||
with self.lock:
|
||||
self.files.pop(fid)
|
||||
self.fids.append(fid)
|
||||
|
||||
def clunk(self, fid):
|
||||
try:
|
||||
self.dorpc(fcall.Tclunk(fid=fid))
|
||||
finally:
|
||||
self.putfid(fid)
|
||||
|
||||
def walk(self, path):
|
||||
fid = self.getfid()
|
||||
ofid = ROOT_FID
|
||||
while True:
|
||||
self.dorpc(fcall.Twalk(fid=ofid, newfid=fid,
|
||||
wname=path[0:fcall.MAX_WELEM]))
|
||||
path = path[fcall.MAX_WELEM:]
|
||||
ofid = fid
|
||||
if len(path) == 0:
|
||||
break
|
||||
|
||||
@apply
|
||||
class Res:
|
||||
def __enter__(self):
|
||||
return fid
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
if exc_type:
|
||||
self.clunk(fid)
|
||||
return Res
|
||||
|
||||
def _open(self, path, mode, open):
|
||||
resp = None
|
||||
|
||||
with self.walk(path) as nfid:
|
||||
fid = nfid
|
||||
resp = self.dorpc(open(fid))
|
||||
|
||||
def cleanup():
|
||||
self.clunk(fid)
|
||||
file = File(self, resp, fid, mode, cleanup)
|
||||
self.files[fid] = file
|
||||
|
||||
return file
|
||||
|
||||
def open(self, path, mode = OREAD):
|
||||
path = self.splitpath(path)
|
||||
|
||||
def open(fid):
|
||||
return fcall.Topen(fid=fid, mode=mode)
|
||||
return self._open(path, mode, open)
|
||||
|
||||
def create(self, path, mode = OREAD, perm = 0):
|
||||
path = self.splitpath(path)
|
||||
name = path.pop()
|
||||
|
||||
def open(fid):
|
||||
return fcall.Tcreate(fid=fid, mode=mode, name=name, perm=perm)
|
||||
return self._open(path, mode, open)
|
||||
|
||||
def remove(self, path):
|
||||
path = self.splitpath(path)
|
||||
|
||||
with self.walk(path) as fid:
|
||||
self.dorpc(fcall.Tremove(fid=fid))
|
||||
|
||||
def stat(self, path):
|
||||
path = self.splitpath(path)
|
||||
|
||||
try:
|
||||
with self.walk(path) as fid:
|
||||
resp = self.dorpc(fcall.Tstat(fid= fid))
|
||||
st = resp.stat()
|
||||
self.clunk(fid)
|
||||
return st
|
||||
except RPCError:
|
||||
return None
|
||||
|
||||
def read(self, path, *args, **kwargs):
|
||||
with self.open(path) as f:
|
||||
return f.read(*args, **kwargs)
|
||||
def readlines(self, path, *args, **kwargs):
|
||||
with self.open(path) as f:
|
||||
for l in f.readlines(*args, **kwargs):
|
||||
yield l
|
||||
def readdir(self, path, *args, **kwargs):
|
||||
with self.open(path) as f:
|
||||
for s in f.readdir(*args, **kwargs):
|
||||
yield s
|
||||
def write(self, path, *args, **kwargs):
|
||||
with self.open(path, OWRITE) as f:
|
||||
return f.write(*args, **kwargs)
|
||||
|
||||
class File(object):
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __exit__(self, *args):
|
||||
self.close()
|
||||
|
||||
def __init__(self, client, fcall, fid, mode, cleanup):
|
||||
self.lock = RLock()
|
||||
self.client = client
|
||||
self.fid = fid
|
||||
self.cleanup = cleanup
|
||||
self.mode = mode
|
||||
self.iounit = fcall.iounit
|
||||
self.qid = fcall.qid
|
||||
|
||||
self.offset = 0
|
||||
self.fd = None
|
||||
|
||||
def dorpc(self, fcall):
|
||||
if hasattr(fcall, 'fid'):
|
||||
fcall.fid = self.fid
|
||||
return self.client.dorpc(fcall)
|
||||
|
||||
def stat(self):
|
||||
resp = self.dorpc(fcall.Tstat())
|
||||
return resp.stat
|
||||
|
||||
def read(self, count=None, offset=None, buf=''):
|
||||
if count is None:
|
||||
count = self.iounit
|
||||
res = []
|
||||
with self.lock:
|
||||
offs = self.offset
|
||||
if offset is not None:
|
||||
offs = offset
|
||||
while count > 0:
|
||||
n = min(count, self.iounit)
|
||||
count -= n
|
||||
|
||||
resp = self.dorpc(fcall.Tread(offset=offs, count=n))
|
||||
data = resp.data
|
||||
|
||||
offs += len(data)
|
||||
res.append(data)
|
||||
|
||||
if len(data) < n:
|
||||
break
|
||||
if offset is None:
|
||||
self.offset = offs
|
||||
res = ''.join(res)
|
||||
if len(res) > 0:
|
||||
return res
|
||||
def readlines(self):
|
||||
last = None
|
||||
while True:
|
||||
data = self.read()
|
||||
if not data:
|
||||
break
|
||||
lines = data.split('\n')
|
||||
for i in range(0, len(lines) - 1):
|
||||
yield lines[i]
|
||||
last = lines[-1]
|
||||
if last:
|
||||
yield last
|
||||
def write(self, data, offset=None):
|
||||
if offset is None:
|
||||
offset = self.offset
|
||||
off = 0
|
||||
with self.lock:
|
||||
offs = self.offset
|
||||
if offset is not None:
|
||||
offs = offset
|
||||
while off < len(data):
|
||||
n = min(len(data), self.iounit)
|
||||
|
||||
resp = self.dorpc(fcall.Twrite(offset=offs,
|
||||
data=data[off:off+n]))
|
||||
off += resp.count
|
||||
offs += resp.count
|
||||
if resp.count < n:
|
||||
break
|
||||
if offset is None:
|
||||
self.offset = offs
|
||||
return off
|
||||
def readdir(self):
|
||||
if not self.qid.type & Qid.QTDIR:
|
||||
raise Exception, "Can only call readdir on a directory"
|
||||
off = 0
|
||||
while True:
|
||||
data = self.read(self.iounit, off)
|
||||
if not data:
|
||||
break
|
||||
off += len(data)
|
||||
for s in Stat.unmarshall_list(data):
|
||||
yield s
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
if self.fd:
|
||||
self.fd_close()
|
||||
finally:
|
||||
self.cleanup()
|
||||
self.tg = None
|
||||
self.fid = None
|
||||
self.client = None
|
||||
self.qid = None
|
||||
|
||||
def remove(self):
|
||||
try:
|
||||
self.dorpc(fcall.Tremove())
|
||||
finally:
|
||||
try:
|
||||
self.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def fd_close(self):
|
||||
try:
|
||||
self.fd.close()
|
||||
finally:
|
||||
self.fd = None
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
35
alternative_wmiircs/python/pyxp/dial.py
Normal file
35
alternative_wmiircs/python/pyxp/dial.py
Normal file
@ -0,0 +1,35 @@
|
||||
from socket import *
|
||||
|
||||
__all__ = 'dial',
|
||||
|
||||
def dial_unix(address):
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0)
|
||||
sock.connect(address)
|
||||
return sock
|
||||
|
||||
def dial_tcp(host):
|
||||
host = host.split('!')
|
||||
if len(host) != 2:
|
||||
return
|
||||
host, port = host
|
||||
|
||||
res = getaddrinfo(host, port, AF_INET, SOCK_STREAM, 0, AI_PASSIVE)
|
||||
for family, socktype, protocol, name, addr in res:
|
||||
try:
|
||||
sock = socket(family, socktype, protocol)
|
||||
sock.connect(addr)
|
||||
return sock
|
||||
except error:
|
||||
if sock:
|
||||
sock.close()
|
||||
|
||||
def dial(address):
|
||||
proto, address = address.split('!', 1)
|
||||
if proto == 'unix':
|
||||
return dial_unix(address)
|
||||
elif proto == 'tcp':
|
||||
return dial_tcp(address)
|
||||
else:
|
||||
raise Exception('invalid protocol')
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
131
alternative_wmiircs/python/pyxp/fcall.py
Normal file
131
alternative_wmiircs/python/pyxp/fcall.py
Normal file
@ -0,0 +1,131 @@
|
||||
from pyxp.messages import MessageBase, Message
|
||||
from pyxp.fields import *
|
||||
from types import Qid, Stat
|
||||
|
||||
__all__ = 'Fcall',
|
||||
|
||||
NO_FID = 1<<32 - 1
|
||||
MAX_WELEM = 16
|
||||
|
||||
class FcallBase(MessageBase):
|
||||
idx = 99
|
||||
def __new__(cls, name, bases, attrs):
|
||||
new_cls = super(FcallBase, cls).__new__(cls, name, bases, attrs)
|
||||
new_cls.type = FcallBase.idx
|
||||
if new_cls.type > 99:
|
||||
new_cls.types[new_cls.type] = new_cls
|
||||
FcallBase.idx += 1
|
||||
return new_cls
|
||||
|
||||
class Fcall(Message):
|
||||
__metaclass__ = FcallBase
|
||||
types = {}
|
||||
|
||||
def response(self, *args, **kwargs):
|
||||
assert self.type % 2 == 0, "No respense type for response fcalls"
|
||||
kwargs['tag'] = self.tag
|
||||
return self.types[self.type + 1]()
|
||||
|
||||
@classmethod
|
||||
def unmarshall(cls, data, offset=0):
|
||||
res = super(Fcall, cls).unmarshall(data, offset)
|
||||
if cls.type < 100:
|
||||
res = cls.types[res[1].type].unmarshall(data, offset)
|
||||
return res
|
||||
|
||||
size = Size(4, 4)
|
||||
type = Int(1)
|
||||
tag = Int(2)
|
||||
|
||||
class Tversion(Fcall):
|
||||
msize = Int(4)
|
||||
version = String()
|
||||
class Rversion(Fcall):
|
||||
msize = Int(4)
|
||||
version = String()
|
||||
|
||||
class Tauth(Fcall):
|
||||
afid = Int(4)
|
||||
uname = String()
|
||||
aname = String()
|
||||
class Rauth(Fcall):
|
||||
aqid = Qid.field()
|
||||
|
||||
class Tattach(Fcall):
|
||||
fid = Int(4)
|
||||
afid = Int(4)
|
||||
uname = String()
|
||||
aname = String()
|
||||
class Rattach(Fcall):
|
||||
qid = Qid.field()
|
||||
|
||||
class Terror(Fcall):
|
||||
def __init__(self):
|
||||
raise Error("Illegal 9P tag 'Terror' encountered")
|
||||
class Rerror(Fcall):
|
||||
ename = String()
|
||||
|
||||
class Tflush(Fcall):
|
||||
oldtag = Int(2)
|
||||
class Rflush(Fcall):
|
||||
pass
|
||||
|
||||
class Twalk(Fcall):
|
||||
fid = Int(4)
|
||||
newfid = Int(4)
|
||||
wname = Array(2, String())
|
||||
class Rwalk(Fcall):
|
||||
wqid = Array(2, Qid.field())
|
||||
|
||||
class Topen(Fcall):
|
||||
fid = Int(4)
|
||||
mode = Int(1)
|
||||
class Ropen(Fcall):
|
||||
qid = Qid.field()
|
||||
iounit = Int(4)
|
||||
|
||||
class Tcreate(Fcall):
|
||||
fid = Int(4)
|
||||
name = String()
|
||||
perm = Int(4)
|
||||
mode = Int(1)
|
||||
class Rcreate(Fcall):
|
||||
qid = Qid.field()
|
||||
iounit = Int(4)
|
||||
|
||||
class Tread(Fcall):
|
||||
fid = Int(4)
|
||||
offset = Int(8)
|
||||
count = Int(4)
|
||||
class Rread(Fcall):
|
||||
data = Data(4)
|
||||
|
||||
class Twrite(Fcall):
|
||||
fid = Int(4)
|
||||
offset = Int(8)
|
||||
data = Data(4)
|
||||
class Rwrite(Fcall):
|
||||
count = Int(4)
|
||||
|
||||
class Tclunk(Fcall):
|
||||
fid = Int(4)
|
||||
class Rclunk(Fcall):
|
||||
pass
|
||||
|
||||
class Tremove(Tclunk):
|
||||
pass
|
||||
class Rremove(Fcall):
|
||||
pass
|
||||
|
||||
class Tstat(Tclunk):
|
||||
pass
|
||||
class Rstat(Fcall):
|
||||
sstat = Size(2)
|
||||
stat = Stat.field()
|
||||
|
||||
class Twstat(Rstat):
|
||||
pass
|
||||
class Rwstat(Fcall):
|
||||
pass
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
123
alternative_wmiircs/python/pyxp/fields.py
Normal file
123
alternative_wmiircs/python/pyxp/fields.py
Normal file
@ -0,0 +1,123 @@
|
||||
from datetime import datetime
|
||||
import operator
|
||||
|
||||
class Field(object):
|
||||
idx = 0
|
||||
|
||||
def __init__(self):
|
||||
Field.idx += 1
|
||||
self.id = Field.idx
|
||||
|
||||
def repr(self):
|
||||
return self.__class__.__name__
|
||||
|
||||
def __repr__(self):
|
||||
if hasattr(self, 'name'):
|
||||
return '<Field %s "%s">' % (self.repr(), self.name)
|
||||
return super(Field, self).__repr__()
|
||||
|
||||
class Int(Field):
|
||||
encoders = {}
|
||||
decoders = {}
|
||||
@classmethod
|
||||
def encoder(cls, n):
|
||||
if n not in cls.encoders:
|
||||
exec ('def enc(n):\n' +
|
||||
' assert n == n & 0x%s, "Arithmetic overflow"\n' % ('ff' * n) +
|
||||
' return "".join((' + ','.join(
|
||||
'chr((n >> %d) & 0xff)' % (i * 8)
|
||||
for i in range(0, n)) + ',))\n')
|
||||
cls.encoders[n] = enc
|
||||
return cls.encoders[n]
|
||||
@classmethod
|
||||
def decoder(cls, n):
|
||||
if n not in cls.decoders:
|
||||
cls.decoders[n] = eval('lambda data, offset: ' + '|'.join(
|
||||
'ord(data[offset + %d]) << %d' % (i, i * 8)
|
||||
for i in range(0, n)))
|
||||
return cls.decoders[n]
|
||||
|
||||
def __init__(self, size):
|
||||
super(Int, self).__init__()
|
||||
self.size = size
|
||||
self.encode = self.encoder(size)
|
||||
self.decode = self.decoder(size)
|
||||
if self.__class__ == Int:
|
||||
self.marshall = self.encode
|
||||
|
||||
def unmarshall(self, data, offset):
|
||||
return self.size, self.decode(data, offset)
|
||||
def marshall(self, val):
|
||||
return self.encode(val)
|
||||
|
||||
def repr(self):
|
||||
return '%s(%d)' % (self.__class__.__name__, self.size)
|
||||
|
||||
class Size(Int):
|
||||
def __init__(self, size, extra=0):
|
||||
super(Size, self).__init__(size)
|
||||
self.extra = extra
|
||||
|
||||
def marshall(self, val):
|
||||
return lambda vals, i: self.encode(
|
||||
reduce(lambda n, i: n + len(vals[i]),
|
||||
range(i + 1, len(vals)),
|
||||
self.extra))
|
||||
|
||||
class Date(Int):
|
||||
def __init__(self):
|
||||
super(Date, self).__init__(4)
|
||||
|
||||
def unmarshall(self, data, offset):
|
||||
val = self.decode(data, offset)
|
||||
return 4, datetime.fromtimestamp(val)
|
||||
def marshall(self, val):
|
||||
return self.encode(int(val.strftime('%s')))
|
||||
|
||||
# To do: use unicode strings, ensure UTF-8.
|
||||
# Not a problem in Python 3K, but there the other
|
||||
# data blobs are.
|
||||
class String(Int):
|
||||
def __init__(self, size=2):
|
||||
super(String, self).__init__(size)
|
||||
|
||||
def unmarshall(self, data, offset):
|
||||
n = self.decode(data, offset)
|
||||
offset += self.size
|
||||
assert offset + n <= len(data), "String too long to unpack"
|
||||
return self.size + n, data[offset:offset + n]
|
||||
def marshall(self, val):
|
||||
return [self.encode(len(val)), val]
|
||||
|
||||
class Data(String):
|
||||
pass
|
||||
|
||||
class Array(Int):
|
||||
def __init__(self, size, spec):
|
||||
super(Array, self).__init__(size)
|
||||
self.spec = spec
|
||||
|
||||
def unmarshall(self, data, offset):
|
||||
start = offset
|
||||
n = self.decode(data, offset)
|
||||
offset += self.size
|
||||
res = []
|
||||
for i in range(0, n):
|
||||
size, val = self.spec.unmarshall(data, offset)
|
||||
if isinstance(val, list):
|
||||
res += val
|
||||
else:
|
||||
res.append(val)
|
||||
offset += size
|
||||
return offset - start, res
|
||||
def marshall(self, vals):
|
||||
res = [self.encode(len(vals))]
|
||||
for val in vals:
|
||||
val = self.spec.marshall(val)
|
||||
if isinstance(val, list):
|
||||
res += val
|
||||
else:
|
||||
res.append(val)
|
||||
return res
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
73
alternative_wmiircs/python/pyxp/messages.py
Normal file
73
alternative_wmiircs/python/pyxp/messages.py
Normal file
@ -0,0 +1,73 @@
|
||||
from pyxp.fields import *
|
||||
|
||||
class MessageBase(type):
|
||||
idx = 0
|
||||
|
||||
def __new__(cls, name, bases, attrs):
|
||||
fields = []
|
||||
fieldmap = {}
|
||||
for k, v in attrs.items():
|
||||
if isinstance(v, Field):
|
||||
attrs[k] = None
|
||||
fields.append(v)
|
||||
fieldmap[k] = v
|
||||
v.name = k
|
||||
fields.sort(lambda a, b: cmp(a.id, b.id))
|
||||
|
||||
new_cls = super(MessageBase, cls).__new__(cls, name, bases, attrs)
|
||||
|
||||
map = getattr(new_cls, 'fieldmap', {})
|
||||
map.update(fieldmap)
|
||||
new_cls.fields = getattr(new_cls, 'fields', ()) + tuple(fields)
|
||||
new_cls.fieldmap = map
|
||||
for f in fields:
|
||||
f.message = new_cls
|
||||
return new_cls
|
||||
|
||||
class Message(object):
|
||||
__metaclass__ = MessageBase
|
||||
def __init__(self, *args, **kwargs):
|
||||
if args:
|
||||
args = dict(zip([f.name for f in self.fields], args))
|
||||
args.update(kwargs)
|
||||
kwargs = args;
|
||||
for k, v in kwargs.iteritems():
|
||||
assert k in self.fieldmap, "Invalid keyword argument"
|
||||
setattr(self, k, v)
|
||||
|
||||
@classmethod
|
||||
def field(cls):
|
||||
class MessageField(Field):
|
||||
def repr(self):
|
||||
return cls.__name__
|
||||
def unmarshall(self, data, offset):
|
||||
return cls.unmarshall(data, offset)
|
||||
def marshall(self, val):
|
||||
return val.marshall()
|
||||
return MessageField()
|
||||
|
||||
@classmethod
|
||||
def unmarshall(cls, data, offset=0):
|
||||
vals = {}
|
||||
start = offset
|
||||
for field in cls.fields:
|
||||
size, val = field.unmarshall(data, offset)
|
||||
offset += size
|
||||
vals[field.name] = val
|
||||
return offset - start, cls(**vals)
|
||||
def marshall(self):
|
||||
res = []
|
||||
callbacks = []
|
||||
for field in self.fields:
|
||||
val = field.marshall(getattr(self, field.name, None))
|
||||
if callable(val):
|
||||
callbacks.append((val, len(res)))
|
||||
if isinstance(val, list):
|
||||
res += val
|
||||
else:
|
||||
res.append(val)
|
||||
for fn, i in reversed(callbacks):
|
||||
res[i] = fn(res, i)
|
||||
return res
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
163
alternative_wmiircs/python/pyxp/mux.py
Normal file
163
alternative_wmiircs/python/pyxp/mux.py
Normal file
@ -0,0 +1,163 @@
|
||||
# Derived from libmux, available in Plan 9 under /sys/src/libmux
|
||||
# under the following terms:
|
||||
#
|
||||
# Copyright (C) 2003-2006 Russ Cox, Massachusetts Institute of Technology
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
from pyxp import fields
|
||||
from pyxp.dial import dial
|
||||
from threading import *
|
||||
Condition = Condition().__class__
|
||||
|
||||
__all__ = 'Mux',
|
||||
|
||||
class Mux(object):
|
||||
def __init__(self, con, process, mintag=0, maxtag=1<<16 - 1):
|
||||
self.queue = set()
|
||||
self.lock = RLock()
|
||||
self.rendez = Condition(self.lock)
|
||||
self.outlock = RLock()
|
||||
self.inlock = RLock()
|
||||
self.process = process
|
||||
self.wait = {}
|
||||
self.free = set(range(mintag, maxtag))
|
||||
self.mintag = mintag
|
||||
self.maxtag = maxtag
|
||||
self.muxer = None
|
||||
|
||||
if isinstance(con, basestring):
|
||||
con = dial(con)
|
||||
self.fd = con
|
||||
|
||||
if self.fd is None:
|
||||
raise Exception("No connection")
|
||||
|
||||
def rpc(self, dat):
|
||||
r = self.newrpc(dat)
|
||||
|
||||
try:
|
||||
self.lock.acquire()
|
||||
while self.muxer and self.muxer != r and r.data is None:
|
||||
r.wait()
|
||||
|
||||
if r.data is None:
|
||||
if self.muxer and self.muxer != r:
|
||||
self.fail()
|
||||
self.muxer = r
|
||||
self.lock.release()
|
||||
try:
|
||||
while r.data is None:
|
||||
data = self.recv()
|
||||
if data is None:
|
||||
self.lock.acquire()
|
||||
self.queue.remove(r)
|
||||
raise Exception("unexpected eof")
|
||||
self.dispatch(data)
|
||||
self.lock.acquire()
|
||||
finally:
|
||||
self.electmuxer()
|
||||
self.puttag(r)
|
||||
except Exception, e:
|
||||
import sys
|
||||
import traceback
|
||||
traceback.print_exc(sys.stdout)
|
||||
print e
|
||||
finally:
|
||||
if self.lock._is_owned():
|
||||
self.lock.release()
|
||||
return r.data
|
||||
|
||||
def electmuxer(self):
|
||||
for rpc in self.queue:
|
||||
if self.muxer != rpc and rpc.async == False:
|
||||
self.muxer = rpc
|
||||
rpc.notify()
|
||||
return
|
||||
self.muxer = None
|
||||
|
||||
def dispatch(self, dat):
|
||||
tag = dat.tag - self.mintag
|
||||
r = None
|
||||
with self.lock:
|
||||
r = self.wait.get(tag, None)
|
||||
if r is None or r not in self.queue:
|
||||
print "bad rpc tag: %u (no one waiting on it)" % dat.tag
|
||||
return
|
||||
self.queue.remove(r)
|
||||
r.data = dat
|
||||
r.notify()
|
||||
|
||||
def gettag(self, r):
|
||||
tag = 0
|
||||
|
||||
while not self.free:
|
||||
self.rendez.wait()
|
||||
|
||||
tag = self.free.pop()
|
||||
|
||||
if tag in self.wait:
|
||||
raise Exception("nwait botch")
|
||||
|
||||
self.wait[tag] = r
|
||||
|
||||
r.tag = tag
|
||||
r.data.tag = r.tag
|
||||
r.data = None
|
||||
return r.tag
|
||||
|
||||
def puttag(self, r):
|
||||
t = r.tag
|
||||
if self.wait.get(t, None) != r:
|
||||
self.fail()
|
||||
del self.wait[t]
|
||||
self.free.add(t)
|
||||
self.rendez.notify()
|
||||
|
||||
def send(self, dat):
|
||||
data = ''.join(dat.marshall())
|
||||
n = self.fd.send(data)
|
||||
return n == len(data)
|
||||
def recv(self):
|
||||
data = self.fd.recv(4)
|
||||
if data:
|
||||
len = fields.Int.decoders[4](data, 0)
|
||||
data += self.fd.recv(len - 4)
|
||||
return self.process(data)
|
||||
|
||||
def fail():
|
||||
raise Exception()
|
||||
|
||||
def newrpc(self, dat):
|
||||
rpc = Rpc(self, dat)
|
||||
tag = None
|
||||
|
||||
with self.lock:
|
||||
self.gettag(rpc)
|
||||
self.queue.add(rpc)
|
||||
|
||||
if rpc.tag >= 0 and self.send(dat):
|
||||
return rpc
|
||||
|
||||
with self.lock:
|
||||
self.queue.remove(rpc)
|
||||
self.puttag(rpc)
|
||||
|
||||
class Rpc(Condition):
|
||||
def __init__(self, mux, data):
|
||||
super(Rpc, self).__init__(mux.lock)
|
||||
self.mux = mux
|
||||
self.data = data
|
||||
self.waiting = True
|
||||
self.async = False
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
55
alternative_wmiircs/python/pyxp/types.py
Normal file
55
alternative_wmiircs/python/pyxp/types.py
Normal file
@ -0,0 +1,55 @@
|
||||
from pyxp.messages import Message
|
||||
from pyxp.fields import *
|
||||
|
||||
__all__ = 'Qid', 'Stat'
|
||||
|
||||
class Qid(Message):
|
||||
QTFILE = 0x00
|
||||
QTLINK = 0x01
|
||||
QTSYMLINK = 0x02
|
||||
QTTMP = 0x04
|
||||
QTAUTH = 0x08
|
||||
QTMOUNT = 0x10
|
||||
QTEXCL = 0x20
|
||||
QTAPPEND = 0x40
|
||||
QTDIR = 0x80
|
||||
|
||||
type = Int(1)
|
||||
version = Int(4)
|
||||
path = Int(8)
|
||||
|
||||
class Stat(Message):
|
||||
DMDIR = 0x80000000
|
||||
DMAPPEND = 0x40000000
|
||||
DMEXCL = 0x20000000
|
||||
DMMOUNT = 0x10000000
|
||||
DMAUTH = 0x08000000
|
||||
DMTMP = 0x04000000
|
||||
DMSYMLINK = 0x02000000
|
||||
DMDEVICE = 0x00800000
|
||||
DMNAMEDPIPE = 0x00200000
|
||||
DMSOCKET = 0x00100000
|
||||
DMSETUID = 0x00080000
|
||||
DMSETGID = 0x00040000
|
||||
|
||||
@classmethod
|
||||
def unmarshall_list(cls, data, offset=0):
|
||||
while offset < len(data):
|
||||
n, stat = cls.unmarshall(data, offset)
|
||||
offset += n
|
||||
yield stat
|
||||
|
||||
size = Size(2)
|
||||
type = Int(2)
|
||||
dev = Int(4)
|
||||
qid = Qid.field()
|
||||
mode = Int(4)
|
||||
atime = Date()
|
||||
mtime = Date()
|
||||
length = Int(8)
|
||||
name = String()
|
||||
uid = String()
|
||||
gid = String()
|
||||
muid = String()
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
208
alternative_wmiircs/python/wmiirc
Normal file
208
alternative_wmiircs/python/wmiirc
Normal file
@ -0,0 +1,208 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from pygmi import *
|
||||
from pygmi import events
|
||||
|
||||
identity = lambda k: k
|
||||
|
||||
# Keys
|
||||
events.keydefs = dict(
|
||||
mod='Mod4',
|
||||
left='h',
|
||||
down='j',
|
||||
up='k',
|
||||
right='l')
|
||||
|
||||
# Bars
|
||||
noticetimeout=5
|
||||
noticebar=('right', '!notice')
|
||||
|
||||
# Theme
|
||||
background = '#333333'
|
||||
floatbackground='#222222'
|
||||
|
||||
wmii.font = 'drift,-*-fixed-*-*-*-*-9-*-*-*-*-*-*-*'
|
||||
wmii.normcolors = '#000000', '#c1c48b', '#81654f'
|
||||
wmii.focuscolors = '#000000', '#81654f', '#000000'
|
||||
wmii.grabmod = events.keydefs['mod']
|
||||
wmii.border = 2
|
||||
|
||||
def setbackground(color):
|
||||
call('xsetroot', '-solid', color)
|
||||
setbackground(background)
|
||||
|
||||
terminal = 'wmiir', 'setsid', 'xterm'
|
||||
shell = os.environ.get('SHELL', 'sh')
|
||||
|
||||
@defmonitor
|
||||
def load():
|
||||
return re.sub(r'^.*: ', '', call('uptime')).replace(', ', ' ')
|
||||
@defmonitor
|
||||
def time():
|
||||
from datetime import datetime
|
||||
return datetime.now().strftime('%c')
|
||||
|
||||
wmii.colrules = (
|
||||
('gimp', '17+83+41'),
|
||||
('.*', '62+38 # Golden Ratio'),
|
||||
)
|
||||
|
||||
wmii.tagrules = (
|
||||
('MPlayer|VLC', '~'),
|
||||
)
|
||||
|
||||
def unresponsive_client(client):
|
||||
msg = 'The following client is not responding. What would you like to do?'
|
||||
resp = call('wihack', '-transient', client.id,
|
||||
'xmessage', '-nearmouse', '-buttons', 'Kill,Wait', '-print',
|
||||
'%s\n %s' % (client, client.label))
|
||||
if resp == 'Kill':
|
||||
client.slay()
|
||||
|
||||
# End Configuration
|
||||
|
||||
confpath = os.environ['WMII_CONFPATH'].split(':')
|
||||
events.confpath = confpath
|
||||
events.shell = shell
|
||||
|
||||
client.write('/event', 'Start wmiirc')
|
||||
|
||||
tags = Tags()
|
||||
bind_events({
|
||||
'Quit': lambda args: sys.exit(),
|
||||
'Start': lambda args: args == 'wmiirc' and sys.exit(),
|
||||
'CreateTag': tags.add,
|
||||
'DestroyTag': tags.delete,
|
||||
'FocusTag': tags.focus,
|
||||
'UnfocusTag': tags.unfocus,
|
||||
'UrgentTag': lambda args: tags.set_urgent(args.split(' ')[1], True),
|
||||
'NotUrgentTag': lambda args: tags.set_urgent(args.split(' ')[1], False),
|
||||
|
||||
'AreaFocus': lambda args: (args == '~' and
|
||||
(setbackground(floatbackground), True) or
|
||||
setbackground(background)),
|
||||
|
||||
'Unresponsive': lambda args: Thread(target=unresponsive_client,
|
||||
args=(Client(args),)).start(),
|
||||
|
||||
'Notice': lambda args: notice.show(args),
|
||||
|
||||
('LeftBarClick', 'LeftBarDND'):
|
||||
lambda args: args.split(' ')[0] == '1' and tags.select(args.split(' ', 1)[1]),
|
||||
|
||||
'ClientMouseDown': lambda args: menu(*args.split(' '), type='client'),
|
||||
'LeftBarMouseDown': lambda args: menu(*reversed(args.split(' ')), type='lbar'),
|
||||
})
|
||||
|
||||
@apply
|
||||
class Actions(events.Actions):
|
||||
def rehash(self, args=''):
|
||||
program_menu.choices = program_list(os.environ['PATH'].split(':'))
|
||||
def quit(self, args=''):
|
||||
wmii.ctl('quit')
|
||||
def eval_(self, args=''):
|
||||
exec args
|
||||
def exec_(self, args=''):
|
||||
wmii['exec'] = args
|
||||
def exit(self, args=''):
|
||||
client.write('/event', 'Quit')
|
||||
|
||||
program_menu = Menu(histfile='%s/history.prog' % confpath[0], nhist=5000,
|
||||
action=curry(call, 'wmiir', 'setsid',
|
||||
shell, '-c', background=True))
|
||||
action_menu = Menu(histfile='%s/history.action' % confpath[0], nhist=500,
|
||||
choices=lambda: Actions._choices,
|
||||
action=Actions._call)
|
||||
tag_menu = Menu(histfile='%s/history.tags' % confpath[0], nhist=100,
|
||||
choices=lambda: sorted(tags.tags.keys()))
|
||||
|
||||
def menu(target, button, type):
|
||||
MENUS = {
|
||||
('client', '3'): (
|
||||
('Delete', lambda c: Client(c).kill()),
|
||||
('Kill', lambda c: Client(c).slay()),
|
||||
('Fullscreen', lambda c: Client(c).set('Fullscreen', 'on'))),
|
||||
('lbar', '3'): (
|
||||
('Delete', lambda t: Tag(t).delete())),
|
||||
}
|
||||
choices = MENUS.get((type, button), None)
|
||||
if choices:
|
||||
ClickMenu(choices=(k for k, v in choices),
|
||||
action=lambda k: dict(choices).get(k, identity)(target)
|
||||
).call()
|
||||
|
||||
class Notice(Button):
|
||||
def __init__(self):
|
||||
super(Notice, self).__init__(*noticebar)
|
||||
self.timer = None
|
||||
|
||||
def tick(self):
|
||||
self.label = ''
|
||||
|
||||
def show(self, notice):
|
||||
if self.timer:
|
||||
self.timer.stop()
|
||||
self.label = notice
|
||||
from threading import Timer
|
||||
self.timer = Timer(noticetimeout, self.tick)
|
||||
self.timer.start()
|
||||
notice = Notice()
|
||||
|
||||
bind_keys({
|
||||
'%(mod)s-Control-t': lambda k: events.toggle_keys(restore='%(mod)s-Control-t'),
|
||||
|
||||
'%(mod)s-%(left)s': lambda k: Tag('sel').select('left'),
|
||||
'%(mod)s-%(right)s': lambda k: Tag('sel').select('right'),
|
||||
'%(mod)s-%(up)s': lambda k: Tag('sel').select('up'),
|
||||
'%(mod)s-%(down)s': lambda k: Tag('sel').select('down'),
|
||||
|
||||
'%(mod)s-Control-%(up)s': lambda k: Tag('sel').select('up', stack=True),
|
||||
'%(mod)s-Control-%(down)s': lambda k: Tag('sel').select('down', stack=True),
|
||||
|
||||
'%(mod)s-space': lambda k: Tag('sel').select('toggle'),
|
||||
|
||||
'%(mod)s-Shift-%(left)s': lambda k: Tag('sel').send(Client('sel'), 'left'),
|
||||
'%(mod)s-Shift-%(right)s': lambda k: Tag('sel').send(Client('sel'), 'right'),
|
||||
'%(mod)s-Shift-%(up)s': lambda k: Tag('sel').send(Client('sel'), 'up'),
|
||||
'%(mod)s-Shift-%(down)s': lambda k: Tag('sel').send(Client('sel'), 'down'),
|
||||
|
||||
'%(mod)s-Shift-space': lambda k: Tag('sel').send(Client('sel'), 'toggle'),
|
||||
|
||||
'%(mod)s-d': lambda k: setattr(Tag('sel').selcol, 'mode', 'default-max'),
|
||||
'%(mod)s-s': lambda k: setattr(Tag('sel').selcol, 'mode', 'stack-max'),
|
||||
'%(mod)s-m': lambda k: setattr(Tag('sel').selcol, 'mode', 'stack+max'),
|
||||
|
||||
'%(mod)s-f': lambda k: Client('sel').set('Fullscreen', 'toggle'),
|
||||
'%(mod)s-Shift-c': lambda k: Client('sel').kill(),
|
||||
|
||||
'%(mod)s-a': lambda k: action_menu.call(),
|
||||
'%(mod)s-p': lambda k: program_menu.call(),
|
||||
|
||||
'%(mod)s-Return': lambda k: call(*terminal, background=True),
|
||||
|
||||
'%(mod)s-t': lambda k: tags.select(tag_menu.call()),
|
||||
'%(mod)s-Shift-t': lambda k: setattr(Client('sel'), 'tags', tag_menu.call()),
|
||||
|
||||
'%(mod)s-n': lambda k: tags.select(tags.next()),
|
||||
'%(mod)s-b': lambda k: tags.select(tags.next(True)),
|
||||
'%(mod)s-i': lambda k: tags.select(tags.NEXT),
|
||||
'%(mod)s-o': lambda k: tags.select(tags.PREV),
|
||||
})
|
||||
def bind_num(i):
|
||||
bind_keys({
|
||||
'%%(mod)s-%d' % i: lambda k: tags.select(str(i)),
|
||||
'%%(mod)s-Shift-%d' % i: lambda k: setattr(Client('sel'), 'tags', i),
|
||||
})
|
||||
map(bind_num, range(0, 10))
|
||||
|
||||
Actions.rehash()
|
||||
|
||||
# Misc Setup
|
||||
#progs_file=`{namespace}^/proglist.$pid
|
||||
|
||||
event_loop()
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
@ -155,6 +155,10 @@ fn Event-Key {
|
||||
Key-$1 $1
|
||||
}
|
||||
|
||||
fn Event-Quit {
|
||||
exit
|
||||
}
|
||||
|
||||
fn Event-Start {
|
||||
if(~ $1 $wmiiscript)
|
||||
exit
|
||||
|
@ -85,6 +85,10 @@ bar_create(Bar **bp, const char *name) {
|
||||
b->id = id++;
|
||||
utflcpy(b->name, name, sizeof b->name);
|
||||
b->col = def.normcolor;
|
||||
|
||||
strlcat(b->buf, b->col.colstr, sizeof(b->buf));
|
||||
strlcat(b->buf, " ", sizeof(b->buf));
|
||||
strlcat(b->buf, b->text, sizeof(b->buf));
|
||||
|
||||
for(sp=screens; (s = *sp); sp++) {
|
||||
i = bp - s->bar;
|
||||
|
@ -64,9 +64,9 @@ enum {
|
||||
extern char* modes[];
|
||||
|
||||
#define TOGGLE(x) \
|
||||
(x == On ? "On" : \
|
||||
x == Off ? "Off" : \
|
||||
x == Toggle ? "Toggle" : \
|
||||
(x == On ? "on" : \
|
||||
x == Off ? "off" : \
|
||||
x == Toggle ? "toggle" : \
|
||||
"<toggle>")
|
||||
enum {
|
||||
Off,
|
||||
|
@ -11,9 +11,9 @@ static void ewmh_getwinstate(Client*);
|
||||
static void ewmh_setstate(Client*, Atom, int);
|
||||
|
||||
#define Net(x) ("_NET_" x)
|
||||
#define Action(x) ("_NET_WM_ACTION_" x)
|
||||
#define State(x) ("_NET_WM_STATE_" x)
|
||||
#define Type(x) ("_NET_WM_WINDOW_TYPE_" x)
|
||||
#define Action(x) Net("WM_ACTION_" x)
|
||||
#define State(x) Net("WM_STATE_" x)
|
||||
#define Type(x) Net("WM_WINDOW_TYPE_" x)
|
||||
#define NET(x) xatom(Net(x))
|
||||
#define ACTION(x) xatom(Action(x))
|
||||
#define STATE(x) xatom(State(x))
|
||||
@ -223,13 +223,13 @@ void
|
||||
ewmh_getwintype(Client *c) {
|
||||
static Prop props[] = {
|
||||
{Type("DESKTOP"), TypeDesktop},
|
||||
{Type("DOCK"), TypeDock},
|
||||
{Type("DOCK"), TypeDock},
|
||||
{Type("TOOLBAR"), TypeToolbar},
|
||||
{Type("MENU"), TypeMenu},
|
||||
{Type("MENU"), TypeMenu},
|
||||
{Type("UTILITY"), TypeUtility},
|
||||
{Type("SPLASH"), TypeSplash},
|
||||
{Type("DIALOG"), TypeDialog},
|
||||
{Type("NORMAL"), TypeNormal},
|
||||
{Type("SPLASH"), TypeSplash},
|
||||
{Type("DIALOG"), TypeDialog},
|
||||
{Type("NORMAL"), TypeNormal},
|
||||
{0, }
|
||||
};
|
||||
long mask;
|
||||
@ -356,8 +356,7 @@ ewmh_clientmessage(XClientMessageEvent *e) {
|
||||
case StateUnset: action = Off; break;
|
||||
case StateSet: action = On; break;
|
||||
case StateToggle: action = Toggle; break;
|
||||
default:
|
||||
return -1;
|
||||
default: return -1;
|
||||
}
|
||||
Dprint(DEwmh, "\tAction: %s\n", TOGGLE(action));
|
||||
ewmh_setstate(c, l[1], action);
|
||||
|
@ -245,7 +245,7 @@ void mouse_resize(Client*, Align, bool);
|
||||
void mouse_resizecol(Divide*);
|
||||
bool readmotion(Point*);
|
||||
int readmouse(Point*, uint*);
|
||||
Align snap_rect(Rectangle *rects, int num, Rectangle *current, Align *mask, int snapw);
|
||||
Align snap_rect(const Rectangle *rects, int num, Rectangle *current, Align *mask, int snapw);
|
||||
|
||||
/* printevent.c */
|
||||
void printevent(XEvent*);
|
||||
|
@ -535,6 +535,8 @@ fs_write(Ixp9Req *r) {
|
||||
return;
|
||||
case FsFCtags:
|
||||
ixp_srv_data2cstring(r);
|
||||
print("%d\n", r->ifcall.io.count);
|
||||
print("%s\n", r->ifcall.io.data);
|
||||
apply_tags(f->p.client, r->ifcall.io.data);
|
||||
r->ofcall.io.count = r->ifcall.io.count;
|
||||
respond(r, nil);
|
||||
@ -707,6 +709,11 @@ fs_clunk(Ixp9Req *r) {
|
||||
q = f->p.bar->text;
|
||||
utflcpy(q, (char*)m.pos, sizeof ((Bar*)0)->text);
|
||||
|
||||
p[0] = '\0';
|
||||
strlcat(p, f->p.bar->col.colstr, sizeof(f->p.bar->buf));
|
||||
strlcat(p, " ", sizeof(f->p.bar->buf));
|
||||
strlcat(p, f->p.bar->text, sizeof(f->p.bar->buf));
|
||||
|
||||
bar_draw(f->p.bar->screen);
|
||||
break;
|
||||
}
|
||||
|
@ -424,6 +424,8 @@ extern int fmtevent(Fmt*);
|
||||
i = ixp_serverloop(&srv);
|
||||
if(i)
|
||||
fprint(2, "%s: error: %r\n", argv0);
|
||||
else
|
||||
event("Quit");
|
||||
|
||||
cleanup();
|
||||
|
||||
|
@ -99,7 +99,7 @@ rect_morph(Rectangle *r, Point d, Align *mask) {
|
||||
|
||||
/* Yes, yes, macros are evil. So are patterns. */
|
||||
#define frob(x, y) \
|
||||
Rectangle *rp; \
|
||||
const Rectangle *rp; \
|
||||
int i, tx; \
|
||||
\
|
||||
for(i=0; i < nrect; i++) { \
|
||||
@ -117,12 +117,12 @@ rect_morph(Rectangle *r, Point d, Align *mask) {
|
||||
return dx \
|
||||
|
||||
static int
|
||||
snap_hline(Rectangle *rects, int nrect, int dx, Rectangle *r, int y) {
|
||||
snap_hline(const Rectangle *rects, int nrect, int dx, const Rectangle *r, int y) {
|
||||
frob(y, x);
|
||||
}
|
||||
|
||||
static int
|
||||
snap_vline(Rectangle *rects, int nrect, int dx, Rectangle *r, int x) {
|
||||
snap_vline(const Rectangle *rects, int nrect, int dx, const Rectangle *r, int x) {
|
||||
frob(x, y);
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ snap_vline(Rectangle *rects, int nrect, int dx, Rectangle *r, int x) {
|
||||
* snap.
|
||||
*/
|
||||
Align
|
||||
snap_rect(Rectangle *rects, int num, Rectangle *r, Align *mask, int snap) {
|
||||
snap_rect(const Rectangle *rects, int num, Rectangle *r, Align *mask, int snap) {
|
||||
Align ret;
|
||||
Point d;
|
||||
|
||||
|
@ -2,8 +2,6 @@
|
||||
* See LICENSE file for license details.
|
||||
*/
|
||||
#define _X11_VISIBLE
|
||||
#define ZP _ZP
|
||||
#define ZR _ZR
|
||||
#define pointerwin __pointerwin
|
||||
#include "dat.h"
|
||||
#include <limits.h>
|
||||
@ -12,9 +10,6 @@
|
||||
#include <unistd.h>
|
||||
#include <bio.h>
|
||||
#include "fns.h"
|
||||
#undef ZP /* These should be allocated in read-only memory, */
|
||||
#undef ZR /* but declaring them const causes too much trouble
|
||||
* elsewhere. */
|
||||
#undef pointerwin
|
||||
|
||||
const Point ZP = {0, 0};
|
||||
@ -897,7 +892,8 @@ getprop_ulong(Window *w, char *prop, char *type,
|
||||
|
||||
char**
|
||||
strlistdup(char *list[]) {
|
||||
char **p, *q;
|
||||
char **p;
|
||||
char *q;
|
||||
int i, m, n;
|
||||
|
||||
n = 0;
|
||||
@ -1120,11 +1116,11 @@ sethints(Window *w) {
|
||||
h->aspect.max.y = xs.max_aspect.y;
|
||||
}
|
||||
|
||||
h->position = ((xs.flags & (USPosition|PPosition)) != 0);
|
||||
h->position = (xs.flags & (USPosition|PPosition)) != 0;
|
||||
|
||||
p = ZP;
|
||||
if(!(xs.flags & PWinGravity))
|
||||
xs.win_gravity = NorthWestGravity;
|
||||
p = ZP;
|
||||
switch (xs.win_gravity) {
|
||||
case EastGravity:
|
||||
case CenterGravity:
|
||||
@ -1150,7 +1146,7 @@ sethints(Window *w) {
|
||||
break;
|
||||
}
|
||||
h->grav = p;
|
||||
h->gravstatic = (xs.win_gravity==StaticGravity);
|
||||
h->gravstatic = (xs.win_gravity == StaticGravity);
|
||||
}
|
||||
|
||||
Rectangle
|
||||
|
@ -160,8 +160,8 @@ struct Screen {
|
||||
Display *display;
|
||||
Screen scr;
|
||||
|
||||
extern Point ZP;
|
||||
extern Rectangle ZR;
|
||||
extern const Point ZP;
|
||||
extern const Rectangle ZR;
|
||||
extern Window* pointerwin;
|
||||
|
||||
Point Pt(int x, int y);
|
||||
|
Loading…
Reference in New Issue
Block a user