lemonbar: Replace queue with Condition object in DateTime module

This commit is contained in:
kuben
2019-12-29 23:43:12 +01:00
committed by Jakub Fojt
parent 5195ae47bc
commit c4e760d5e7

View File

@@ -2,7 +2,6 @@ import threading
import subprocess import subprocess
import contextlib import contextlib
import time, os, signal, getpass import time, os, signal, getpass
import queue
import i3_lemonbar_config as config import i3_lemonbar_config as config
import i3_lemonbar_common as common import i3_lemonbar_common as common
@@ -87,46 +86,62 @@ def format_load(data, module, alert):
class DateTimeModule(LemonModule): class DateTimeModule(LemonModule):
def __init__(self): def __init__(self):
self.show_secs = False
super().__init__() super().__init__()
def _start_module(self): def _start_module(self):
class DateTimeThread(threading.Thread): class DateTimeThread(threading.Thread):
def __init__(self, secs_mode = False): def __init__(self, secs_mode = False):
self.secs_mode = secs_mode self.secs_mode = secs_mode
self.last_out = '' self.readline = self.__readline_first
self.w_condition = threading.Condition() self.output = ''
self.out_queue = queue.Queue()
self.out_queue.readline = self.out_queue.get lock = threading.Lock()
self.output_ready = threading.Condition(lock)
self.clock_tick = threading.Condition(lock) # Needed, because sleep may be interrupted when user
# changes H:M to H:M:S
super().__init__() super().__init__()
def __readline_first(self):
# Should return instantly the first time
self.readline = self.__readline_blocking
return self.output
def __readline_blocking(self):
self.output_ready.acquire()
self.output_ready.wait()
self.output_ready.release()
return self.output
def run(self): def run(self):
while True: while True:
fmt = "%a %d %b %H:%M:%S" if self.secs_mode else "%a %d %b %H:%M" fmt = "%a %d %b %H:%M:%S" if self.secs_mode else "%a %d %b %H:%M"
timestr = time.strftime(fmt, time.localtime()) timestr = time.strftime(fmt, time.localtime())
if timestr != self.last_out: if timestr != self.output:
self.last_out = timestr self.output = timestr
self.out_queue.put('{}\n'.format(timestr)) self.output_ready.acquire()
self.output_ready.notify()
self.output_ready.release()
self.sleep_until_change() self.sleep_until_change()
def sleep_until_change(self): def sleep_until_change(self):
# Sleep for an appropriate amount of time (depending on if showing seconds or not) # Sleep for an appropriate amount of time (depending on if showing seconds or not)
# with the possibility of being woken early # with the possibility of being woken early
if self.secs_mode: if self.secs_mode:
rem = 0.1 rem = 0.1 # TODO fiddle with this, benchmarking it
else: else:
rem = time.time() % 5.0 # 5 seconds, 60 is unnecessarily long rem = time.time() % 5.0 # 5 seconds, 60 is unnecessarily long
self.w_condition.acquire() self.clock_tick.acquire()
self.w_condition.wait(rem) self.clock_tick.wait(rem)
self.clock_tick.release()
def wake(self): def wake(self):
self.w_condition.acquire() self.clock_tick.acquire()
self.w_condition.notify() self.clock_tick.notify()
self.w_condition.release() self.clock_tick.release()
self.dt_thread = DateTimeThread() self.dt_thread = DateTimeThread()
self.dt_thread.start() self.dt_thread.start()
self.status_handle = self.dt_thread.out_queue self.status_handle = self.dt_thread # Only readline() is used
self.date = parser.IconTextUnit('date', action='date', order=40) self.date = parser.IconTextUnit('date', action='date', order=40)
self.time = parser.IconTextUnit('time', action='toggle_secs', order=41 self.time = parser.IconTextUnit('time', action='toggle_secs', order=41