2022-02-13 13:55:34 +01:00
|
|
|
"""Main script to execute the application
|
|
|
|
|
|
|
|
This module provides the entrypoint to CLI app/script
|
|
|
|
"""
|
2022-01-15 19:03:18 +01:00
|
|
|
import logging
|
|
|
|
import sys
|
|
|
|
from argparse import ArgumentParser
|
2022-01-27 00:45:08 +01:00
|
|
|
from threading import Thread
|
|
|
|
from queue import Queue
|
2022-01-15 19:03:18 +01:00
|
|
|
|
|
|
|
from Xlib import X, display
|
|
|
|
|
|
|
|
from .models import ClipboardData
|
|
|
|
from .xoperations import process_event_loop
|
2022-01-27 00:45:08 +01:00
|
|
|
from .notifications import display_desktop_notification
|
2022-01-15 19:03:18 +01:00
|
|
|
|
|
|
|
|
2022-01-27 00:45:08 +01:00
|
|
|
logger = logging.getLogger("ClipboardWatcher")
|
2022-01-15 19:03:18 +01:00
|
|
|
|
|
|
|
|
|
|
|
def set_logger_settings(level_name: str) -> None:
|
|
|
|
level = logging.getLevelName(level_name)
|
|
|
|
logging.basicConfig(stream=sys.stdout, level=level)
|
|
|
|
|
|
|
|
|
2022-01-27 00:45:08 +01:00
|
|
|
def process_notifications(q: Queue):
|
|
|
|
while True:
|
|
|
|
req = q.get(block=True)
|
2022-02-13 13:55:34 +01:00
|
|
|
window_info = f"Window info: {req['window_name']} (id: {req['id']})"
|
|
|
|
if process := req.get("process"):
|
|
|
|
process_info = f"Process info: {process.path} (pid: {process.pid})"
|
|
|
|
else:
|
|
|
|
process_info = "Process info: Unknown"
|
|
|
|
|
2022-01-27 00:45:08 +01:00
|
|
|
display_desktop_notification(
|
2022-02-13 13:55:34 +01:00
|
|
|
f"Access to Clipboard ({req['selection']}) detected.",
|
|
|
|
f"{window_info}\n{process_info}",
|
2022-01-27 00:45:08 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-01-15 19:03:18 +01:00
|
|
|
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:
|
2022-01-27 00:45:08 +01:00
|
|
|
set_logger_settings("INFO")
|
2022-01-15 19:03:18 +01:00
|
|
|
|
2022-01-27 00:45:08 +01:00
|
|
|
logger.info("Initializing X client")
|
|
|
|
disp = display.Display()
|
2022-01-15 19:03:18 +01:00
|
|
|
# Create ourselves a window and a property for the returned data
|
2022-01-27 00:45:08 +01:00
|
|
|
window = disp.screen().root.create_window(0, 0, 10, 10, 0, X.CopyFromParent)
|
|
|
|
window.set_wm_name("clipboard_watcher")
|
2022-01-15 19:03:18 +01:00
|
|
|
|
|
|
|
logger.debug("Getting selection data")
|
2022-01-27 00:45:08 +01:00
|
|
|
cb_data = ClipboardData(disp, window, {}, {})
|
2022-01-15 19:03:18 +01:00
|
|
|
cb_data.refresh_all()
|
|
|
|
logger.debug("Taken ownership of all selections")
|
|
|
|
|
2022-01-27 00:45:08 +01:00
|
|
|
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")
|
2022-01-15 19:03:18 +01:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|