mirror of
https://github.com/0intro/wmii
synced 2024-11-21 21:31:33 +03:00
[python] Fix some deadlock issues.
This commit is contained in:
parent
c7994d542e
commit
bdf6dacdc5
@ -164,7 +164,7 @@ class Keys(object):
|
||||
"""
|
||||
self.modes = {}
|
||||
self.modelist = []
|
||||
self._set_mode('main', False)
|
||||
self.mode = 'main'
|
||||
self.defs = {}
|
||||
events.bind(Key=self.dispatch)
|
||||
|
||||
@ -179,17 +179,18 @@ class Keys(object):
|
||||
}
|
||||
self.modelist.append(mode)
|
||||
|
||||
def _set_mode(self, mode, execute=True):
|
||||
mode = property(lambda self: self._mode,
|
||||
doc="The current mode for which to dispatch keys")
|
||||
@mode.setter
|
||||
def mode(self, mode):
|
||||
self._add_mode(mode)
|
||||
self._mode = mode
|
||||
self._keys = dict((k % self.defs, v) for k, v in
|
||||
self.modes[mode]['keys'].items() +
|
||||
self.modes[mode]['import'].items());
|
||||
if execute:
|
||||
if hasattr(self, 'defs'):
|
||||
client.write('/keys', '\n'.join(self._keys.keys()) + '\n')
|
||||
|
||||
mode = property(lambda self: self._mode, _set_mode,
|
||||
doc="The current mode for which to dispatch keys")
|
||||
|
||||
@prop(doc="Returns a short help text describing the bound keys in all modes")
|
||||
def help(self):
|
||||
|
@ -11,6 +11,7 @@ __all__ = ('wmii', 'Tags', 'Tag', 'Area', 'Frame', 'Client',
|
||||
'Button', 'Colors', 'Color', 'Toggle', 'Always', 'Never')
|
||||
|
||||
spacere = re.compile(r'\s')
|
||||
sentinel = {}
|
||||
|
||||
class utf8(object):
|
||||
def __str__(self):
|
||||
@ -67,7 +68,6 @@ class Ctl(object):
|
||||
tuples, each containing a decoder and encoder function for the
|
||||
property's plain text value.
|
||||
"""
|
||||
sentinel = {}
|
||||
ctl_types = {}
|
||||
ctl_hasid = False
|
||||
ctl_open = 'aopen'
|
||||
@ -312,14 +312,14 @@ class liveprop(object):
|
||||
self.get = get
|
||||
self.attr = str(self)
|
||||
def __get__(self, area, cls):
|
||||
if getattr(area, self.attr, None) is not None:
|
||||
if getattr(area, self.attr, sentinel) is not sentinel:
|
||||
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, screen='sel', offset=None, width=None, height=None, frames=None):
|
||||
def __init__(self, tag, ord, screen='sel', offset=sentinel, width=sentinel, height=sentinel, frames=sentinel):
|
||||
self.tag = tag
|
||||
if ':' in str(ord):
|
||||
screen, ord = ord.split(':', 2)
|
||||
@ -344,17 +344,20 @@ class Area(object):
|
||||
|
||||
@property
|
||||
def spec(self):
|
||||
return '%s:%s' % (self.screen, self.ord)
|
||||
if self.screen is not None:
|
||||
return '%s:%s' % (self.screen, self.ord)
|
||||
return self.ord
|
||||
|
||||
def _get_mode(self):
|
||||
@property
|
||||
def 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.spec, val))
|
||||
@mode.setter
|
||||
def mode(self, val):
|
||||
self.tag['colmode %s' % self.spec] = val
|
||||
|
||||
def grow(self, dir, amount=None):
|
||||
self.tag.grow(self, dir, amount)
|
||||
@ -364,7 +367,7 @@ class Area(object):
|
||||
class Frame(object):
|
||||
live = False
|
||||
|
||||
def __init__(self, client, area=None, ord=None, offset=None, height=None):
|
||||
def __init__(self, client, area=sentinel, ord=sentinel, offset=sentinel, height=sentinel):
|
||||
self.client = client
|
||||
self.ord = ord
|
||||
self.offset = offset
|
||||
@ -414,21 +417,24 @@ class Tag(Dir):
|
||||
dir = ' '.join(dir)
|
||||
return dir
|
||||
|
||||
def _set_selected(self, frame):
|
||||
@property
|
||||
def selected(self):
|
||||
return tuple(self['select'].split(' '))
|
||||
@selected.setter
|
||||
def 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):
|
||||
@property
|
||||
def 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)))
|
||||
@selclient.setter
|
||||
def selclient(self, val):
|
||||
self['select'] = self.framespec(val)
|
||||
|
||||
@property
|
||||
def selcol(self):
|
||||
@ -437,9 +443,9 @@ class Tag(Dir):
|
||||
@property
|
||||
def index(self):
|
||||
areas = []
|
||||
for l in [l.split(' ')
|
||||
for l in (l.split(' ')
|
||||
for l in client.readlines('%s/index' % self.path)
|
||||
if l]:
|
||||
if l):
|
||||
if l[0] == '#':
|
||||
m = re.match(r'(?:(\d+):)?(\d+|~)', l[1])
|
||||
if m.group(2) == '~':
|
||||
@ -447,7 +453,7 @@ class Tag(Dir):
|
||||
height=l[3], frames=[])
|
||||
else:
|
||||
area = Area(tag=self, screen=m.group(1) or 0,
|
||||
ord=m.group(2), offset=l[2], width=l[3],
|
||||
height=None, ord=m.group(2), offset=l[2], width=l[3],
|
||||
frames=[])
|
||||
areas.append(area)
|
||||
i = 0
|
||||
@ -797,12 +803,12 @@ class Tags(object):
|
||||
self.tags[tag].button.label = urgent and '*' + tag or tag
|
||||
|
||||
def next(self, reverse=False):
|
||||
tags = [t for t in wmii.tags if t.id not in self.ignore]
|
||||
tags = [t for t in wmii.tags if t not in self.ignore]
|
||||
tags.append(tags[0])
|
||||
if reverse:
|
||||
tags.reverse()
|
||||
for i in range(0, len(tags)):
|
||||
if tags[i] == self.sel:
|
||||
if tags[i] == self.sel.id:
|
||||
return tags[i+1]
|
||||
return self.sel
|
||||
|
||||
|
@ -107,7 +107,12 @@ class Monitor(object):
|
||||
return None
|
||||
|
||||
_active = True
|
||||
def _set_active(self, val):
|
||||
@property
|
||||
def active(self):
|
||||
return self._active
|
||||
|
||||
@active.setter
|
||||
def active(self, val):
|
||||
with self.lock:
|
||||
self._active = bool(val)
|
||||
if val:
|
||||
@ -115,8 +120,4 @@ class Monitor(object):
|
||||
else:
|
||||
self.button.remove()
|
||||
|
||||
active = property(
|
||||
lambda self: self._active,
|
||||
_set_active)
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
||||
|
@ -39,6 +39,9 @@ class Mux(object):
|
||||
self.maxtag = maxtag
|
||||
self.muxer = None
|
||||
|
||||
self.async_mux = Queue(self.mux)
|
||||
self.async_dispatch = Queue(self.async_dispatch)
|
||||
|
||||
if isinstance(con, basestring):
|
||||
con = dial(con)
|
||||
self.fd = con
|
||||
@ -48,8 +51,8 @@ class Mux(object):
|
||||
|
||||
def mux(self, rpc):
|
||||
try:
|
||||
rpc.waiting = True
|
||||
self.lock.acquire()
|
||||
rpc.waiting = True
|
||||
while self.muxer and self.muxer != rpc and rpc.data is None:
|
||||
rpc.wait()
|
||||
|
||||
@ -69,7 +72,7 @@ class Mux(object):
|
||||
self.lock.acquire()
|
||||
self.electmuxer()
|
||||
except Exception, e:
|
||||
traceback.print_exc(sys.stdout)
|
||||
traceback.print_exc(sys.stderr)
|
||||
if self.flush:
|
||||
self.flush(self, rpc.data)
|
||||
raise e
|
||||
@ -77,36 +80,26 @@ class Mux(object):
|
||||
if self.lock._is_owned():
|
||||
self.lock.release()
|
||||
|
||||
if rpc.async:
|
||||
if callable(rpc.async):
|
||||
rpc.async(self, rpc.data)
|
||||
else:
|
||||
return rpc.data
|
||||
return rpc.data
|
||||
|
||||
def rpc(self, dat, async=None):
|
||||
rpc = self.newrpc(dat, async)
|
||||
if async:
|
||||
with self.lock:
|
||||
if self.muxer is None:
|
||||
self.electmuxer()
|
||||
self.async_mux.push(rpc)
|
||||
else:
|
||||
return self.mux(rpc)
|
||||
|
||||
def async_dispatch(self, rpc):
|
||||
self.async_mux.pop(rpc)
|
||||
rpc.async(self, rpc.data)
|
||||
|
||||
def electmuxer(self):
|
||||
async = None
|
||||
for rpc in self.queue:
|
||||
if self.muxer != rpc:
|
||||
if rpc.async:
|
||||
async = rpc
|
||||
else:
|
||||
self.muxer = rpc
|
||||
rpc.notify()
|
||||
return
|
||||
if self.muxer != rpc and rpc.waiting:
|
||||
self.muxer = rpc
|
||||
rpc.notify()
|
||||
return
|
||||
self.muxer = None
|
||||
if async:
|
||||
self.muxer = async
|
||||
t = Thread(target=self.mux, args=(async,))
|
||||
t.start()
|
||||
|
||||
def dispatch(self, dat):
|
||||
tag = dat.tag
|
||||
@ -156,8 +149,7 @@ class Mux(object):
|
||||
data += self.fd.recv(len - 4)
|
||||
return self.process(data)
|
||||
except Exception, e:
|
||||
traceback.print_exc(sys.stdout)
|
||||
print repr(data)
|
||||
traceback.print_exc(sys.stderr)
|
||||
return None
|
||||
|
||||
def newrpc(self, dat, async=None):
|
||||
@ -181,14 +173,50 @@ class Rpc(Condition):
|
||||
self.mux = mux
|
||||
self.orig = data
|
||||
self.data = None
|
||||
self.waiting = False
|
||||
self.async = async
|
||||
self.waiting = False
|
||||
|
||||
def dispatch(self, data=None):
|
||||
self.data = data
|
||||
if not self.async or self.waiting:
|
||||
self.notify()
|
||||
elif callable(self.async):
|
||||
Thread(target=self.async, args=(self.mux, data)).start()
|
||||
self.notify()
|
||||
if callable(self.async):
|
||||
self.mux.async_dispatch(self)
|
||||
|
||||
class Queue(Thread):
|
||||
def __init__(self, op):
|
||||
super(Queue, self).__init__()
|
||||
self.cond = Condition()
|
||||
self.op = op
|
||||
self.queue = []
|
||||
self.daemon = True
|
||||
|
||||
def __call__(self, item):
|
||||
return self.push(item)
|
||||
|
||||
def push(self, item):
|
||||
with self.cond:
|
||||
self.queue.append(item)
|
||||
if not self.is_alive():
|
||||
self.start()
|
||||
self.cond.notify()
|
||||
def pop(self, item):
|
||||
with self.cond:
|
||||
if item in self.queue:
|
||||
self.queue.remove(item)
|
||||
return True
|
||||
return False
|
||||
|
||||
def run(self):
|
||||
self.cond.acquire()
|
||||
while True:
|
||||
while self.queue:
|
||||
item = self.queue.pop(0)
|
||||
self.cond.release()
|
||||
try:
|
||||
self.op(item)
|
||||
except Exception, e:
|
||||
traceback.print_exc(sys.stderr)
|
||||
self.cond.acquire()
|
||||
self.cond.wait()
|
||||
|
||||
# vim:se sts=4 sw=4 et:
|
||||
|
Loading…
Reference in New Issue
Block a user