Do curses draw in one thread

This commit is contained in:
Paul Nameless 2020-06-03 09:35:59 +08:00
parent e41ab35a9e
commit ca81118f48
3 changed files with 75 additions and 47 deletions

View file

@ -1,6 +1,7 @@
import curses
import logging
import os
import queue
import threading
from datetime import datetime
from functools import partial
@ -45,8 +46,8 @@ class Controller:
def __init__(self, model: Model, view: View, tg: Tdlib) -> None:
self.model = model
self.view = view
self.render_lock = threading.RLock()
self.render_status_lock = threading.RLock()
self.queue = queue.Queue()
self.is_running = True
self.tg = tg
self.chat_size = 0.5
@ -363,8 +364,10 @@ class Controller:
return self.update_status("Info", msg)
def update_status(self, level: str, msg: str):
with self.render_status_lock:
self.view.status.draw(f"{level}: {msg}")
self.queue.put(partial(self._update_status, level, msg))
def _update_status(self, level: str, msg: str):
self.view.status.draw(f"{level}: {msg}")
def edit_msg(self):
msg = MsgProxy(self.model.current_msg)
@ -400,9 +403,13 @@ class Controller:
def run(self) -> None:
try:
self.handle(self.chat_bindings, 0.5)
self.queue.put(self.close)
except Exception:
log.exception("Error happened in main loop")
def close(self):
self.is_running = False
def handle_msgs(self, _: int):
rc = self.handle(self.msg_bindings, 0.2)
if rc == "QUIT":
@ -431,6 +438,9 @@ class Controller:
self.resize()
def resize(self):
self.queue.put(self._resize)
def _resize(self):
rows, cols = self.view.stdscr.getmaxyx()
# If we didn't clear the screen before doing this,
# the original window contents would remain on the screen
@ -443,24 +453,35 @@ class Controller:
self.view.status.resize(rows, cols)
self.render()
def render(self) -> None:
with self.render_lock:
# using lock here, because render is used from another
# thread by tdlib python wrapper
page_size = self.view.chats.h
chats = self.model.get_chats(
self.model.current_chat, page_size, MSGS_LEFT_SCROLL_THRESHOLD
)
selected_chat = min(
self.model.current_chat, page_size - MSGS_LEFT_SCROLL_THRESHOLD
)
def draw(self):
while self.is_running:
try:
log.info("Queue size: %d", self.queue.qsize())
fun = self.queue.get()
fun()
except Exception:
log.exception("Error happened in draw loop")
self.view.chats.draw(selected_chat, chats)
self.render_msgs()
with self.render_status_lock:
self.view.status.draw()
def render(self) -> None:
self.queue.put(self._render)
def _render(self) -> None:
page_size = self.view.chats.h
chats = self.model.get_chats(
self.model.current_chat, page_size, MSGS_LEFT_SCROLL_THRESHOLD
)
selected_chat = min(
self.model.current_chat, page_size - MSGS_LEFT_SCROLL_THRESHOLD
)
self.view.chats.draw(selected_chat, chats)
self.render_msgs()
self.view.status.draw()
def render_msgs(self) -> None:
self.queue.put(self._render_msgs)
def _render_msgs(self) -> None:
current_msg_idx = self.model.get_current_chat_msg_idx()
if current_msg_idx is None:
return

View file

@ -36,9 +36,11 @@ def run(tg: Tdlib, stdscr: window) -> None:
for msg_type, handler in update_handlers.handlers.items():
tg.add_update_handler(msg_type, partial(handler, controller))
t = threading.Thread(target=controller.run,)
t.start()
t.join()
thread = threading.Thread(target=controller.run,)
thread.daemon = True
thread.start()
controller.draw()
def main():

View file

@ -1,4 +1,5 @@
import logging
from datetime import datetime
from functools import wraps
from typing import Any, Callable, Dict
@ -69,8 +70,8 @@ def update_chat_order(controller: Controller, update: Dict[str, Any]):
chat_id = update["chat_id"]
order = update["order"]
controller.model.chats.update_chat(chat_id, order=order)
controller._refresh_current_chat(current_chat_id)
if controller.model.chats.update_chat(chat_id, order=order):
controller._refresh_current_chat(current_chat_id)
@update_handler("updateChatTitle")
@ -80,8 +81,8 @@ def update_chat_title(controller: Controller, update: Dict[str, Any]):
title = update["title"]
current_chat_id = controller.model.current_chat_id
controller.model.chats.update_chat(chat_id, title=title)
controller._refresh_current_chat(current_chat_id)
if controller.model.chats.update_chat(chat_id, title=title):
controller._refresh_current_chat(current_chat_id)
@update_handler("updateChatIsMarkedAsUnread")
@ -93,10 +94,10 @@ def update_chat_marked_as_unread(
is_marked_as_unread = update["is_marked_as_unread"]
current_chat_id = controller.model.current_chat_id
controller.model.chats.update_chat(
if controller.model.chats.update_chat(
chat_id, is_marked_as_unread=is_marked_as_unread
)
controller._refresh_current_chat(current_chat_id)
):
controller._refresh_current_chat(current_chat_id)
@update_handler("updateChatIsPinned")
@ -107,10 +108,10 @@ def update_chat_is_pinned(controller: Controller, update: Dict[str, Any]):
order = update["order"]
current_chat_id = controller.model.current_chat_id
controller.model.chats.update_chat(
if controller.model.chats.update_chat(
chat_id, is_pinned=is_pinned, order=order
)
controller._refresh_current_chat(current_chat_id)
):
controller._refresh_current_chat(current_chat_id)
@update_handler("updateChatReadOutbox")
@ -120,10 +121,10 @@ def update_chat_read_outbox(controller: Controller, update: Dict[str, Any]):
last_read_outbox_message_id = update["last_read_outbox_message_id"]
current_chat_id = controller.model.current_chat_id
controller.model.chats.update_chat(
if controller.model.chats.update_chat(
chat_id, last_read_outbox_message_id=last_read_outbox_message_id,
)
controller._refresh_current_chat(current_chat_id)
):
controller._refresh_current_chat(current_chat_id)
@update_handler("updateChatReadInbox")
@ -134,12 +135,12 @@ def update_chat_read_inbox(controller: Controller, update: Dict[str, Any]):
unread_count = update["unread_count"]
current_chat_id = controller.model.current_chat_id
controller.model.chats.update_chat(
if controller.model.chats.update_chat(
chat_id,
last_read_inbox_message_id=last_read_inbox_message_id,
unread_count=unread_count,
)
controller._refresh_current_chat(current_chat_id)
):
controller._refresh_current_chat(current_chat_id)
@update_handler("updateChatDraftMessage")
@ -151,22 +152,26 @@ def update_chat_draft_msg(controller: Controller, update: Dict[str, Any]):
order = update["order"]
current_chat_id = controller.model.current_chat_id
controller.model.chats.update_chat(chat_id, order=order)
controller._refresh_current_chat(current_chat_id)
if controller.model.chats.update_chat(chat_id, order=order):
controller._refresh_current_chat(current_chat_id)
@update_handler("updateChatLastMessage")
def update_chat_last_msg(controller: Controller, update: Dict[str, Any]):
log.info("Proccessing updateChatLastMessage")
chat_id = update["chat_id"]
message = update["last_message"]
last_message = update.get("last_message")
if not last_message:
# according to documentation it can be null
log.warning("last_message is null: %s", update)
return
order = update["order"]
current_chat_id = controller.model.current_chat_id
controller.model.chats.update_chat(
if controller.model.chats.update_chat(
chat_id, last_message=message, order=order
)
controller._refresh_current_chat(current_chat_id)
):
controller._refresh_current_chat(current_chat_id)
@update_handler("updateChatNotificationSettings")
@ -174,10 +179,10 @@ def update_chat_notification_settings(controller: Controller, update):
log.info("Proccessing update_chat_notification_settings")
chat_id = update["chat_id"]
notification_settings = update["notification_settings"]
controller.model.chats.update_chat(
if controller.model.chats.update_chat(
chat_id, notification_settings=notification_settings
)
controller.render()
):
controller.render()
@update_handler("updateMessageSendSucceeded")