clipboard-watcher/clipboard_watcher/app.py

77 lines
2.2 KiB
Python

import logging
import sys
from argparse import ArgumentParser
from threading import Thread
from queue import Queue
from Xlib import X, display
from .models import ClipboardData
from .xoperations import process_event_loop
from .notifications import display_desktop_notification
logger = logging.getLogger("ClipboardWatcher")
def set_logger_settings(level_name: str) -> None:
level = logging.getLevelName(level_name)
logging.basicConfig(stream=sys.stdout, level=level)
def process_notifications(q: Queue):
while True:
req = q.get(block=True)
display_desktop_notification(
f"New access to {req['selection']}({req['target']}) detected.",
f"Window: {req['window_name']} (id: {req['id']})\nPossible PID: {req['pid']} | Extra Info: {req['extra']}",
)
def main() -> None:
parser = ArgumentParser(
"Monitors the access of other processes to the clipboard contents."
)
parser.add_argument("-l", "--loglevel", help="Choose the log level")
args = parser.parse_args()
if args.loglevel and args.loglevel in ["DEBUG", "INFO", "WARNING", "ERROR"]:
set_logger_settings(args.loglevel)
else:
set_logger_settings("INFO")
logger.info("Initializing X client")
disp = display.Display()
# Create ourselves a window and a property for the returned data
window = disp.screen().root.create_window(0, 0, 10, 10, 0, X.CopyFromParent)
window.set_wm_name("clipboard_watcher")
logger.debug("Getting selection data")
cb_data = ClipboardData(disp, window, {}, {})
cb_data.refresh_all()
logger.debug("Taken ownership of all selections")
job_queue = Queue()
# Thread 1
event_worker = Thread(
target=process_event_loop, args=(disp, window, job_queue, cb_data), daemon=True
)
# Thread 2
notif_worker = Thread(
target=process_notifications,
args=(job_queue,),
daemon=True,
)
event_worker.start()
notif_worker.start()
logger.info("Setup done. Keeping an eye on the clipboard")
try:
event_worker.join()
notif_worker.join()
except KeyboardInterrupt:
logger.info("Shutting down")
if __name__ == "__main__":
main()