def __init__(self, x11_connection): self.display = x11_connection self.windows = set() self.screen = self.display.screen() self.root = self.screen.root self.ewmh = ewmh.EWMH(self.display, self.root) self.hlwm = hlwm
def init_window_dimensions(self): if IS_WINDOWS: max_width, max_height = map( win32api.GetSystemMetrics, (win32con.SM_CXFULLSCREEN, win32con.SM_CYFULLSCREEN)) elif IS_MACOS: frame_size = AppKit.NSScreen.mainScreen().frame().size max_width, max_height = map(int, (frame_size.width, frame_size.height)) elif IS_LINUX: self.ewmh = ewmh.EWMH() desktop = self.ewmh.getCurrentDesktop() max_width, max_height = self.ewmh.getWorkArea()[4 * desktop + 2:4 * (desktop + 1)] self.width = min(self.conf.width, max_width) self.height = min(self.conf.height, max_height) self.x_pos, self.y_pos = (max_width - self.width) // 2, ( max_height - self.height) // 2 # 15 pixel buffer between max screen dimension, for maximizing window self.should_maximize = self.width >= ( max_width - 15) or self.height >= (max_height - 15) logger.info( f'Dimensions: {self.width}x{self.height} [{max_width}x{max_height} max] ' f'@ ({self.x_pos}, {self.y_pos}), will maximize: {self.should_maximize}' )
def set_position_normal(self): e = ewmh.EWMH() for w in e.getClientList(): if w.get_wm_name() == 'mynotes%s' % self.id: e.setWmState(w, 0, '_NET_WM_STATE_BELOW') e.setWmState(w, 0, '_NET_WM_STATE_ABOVE') e.display.flush() self.save_note()
def listen_for_events(self) -> None: """ Listen for X11 events covering window creation and movement between workspaces and, upon receiving such an event, count the number of windows on the currently focused workspace. If the number of open windows is equal to or above the set threshold, initiate a blur, otherwise an unblur transition. The following events are monitored and should be enough to cover any situation in which a blur operation is necessary: MapNotify is sent when windows are drawn, e.g. a window - is opened on the current workspace - is moved to the current workspace - is shown by switching to the workspace it's on UnmapNotify is sent when windows are undrawn, e.g. a window - on the current workspace is closed - is moved to a different workspace - is hidden by switching to a different workspace :return: None """ # Connect to X server display = Xlib.display.Display() ewmh_instance = ewmh.EWMH(display) root = display.screen().root root.change_attributes(event_mask=X.SubstructureNotifyMask) print(':: Ready and waiting for window events...') blur = Transition(0, 0) unblur = Transition(0, 0) while True: event = display.next_event() if event.type in (X.MapNotify, X.UnmapNotify): if wallpaper.changed_externally(): wallpaper.set_original(wallpaper.get_current()) if self.frames_are_outdated(): self.generate_transition_frames() window_count = window.count_on_current_ws( self.ignored_classes, ewmh_instance) blur, unblur = self.init_transition(window_count, blur, unblur)
#!/usr/bin/python # -*- coding: utf-8 -*- import os import sys import platform import time import Xlib.X import Xlib.display import ewmh import pyautogui from pygetwindow import PyGetWindowException, pointInRect, BaseWindow, Rect, Point, Size DISP = Xlib.display.Display() ROOT = DISP.screen().root EWMH = ewmh.EWMH(_display=DISP, root=ROOT) # WARNING: Changes are not immediately applied, specially for hide/show (unmap/map) # You may set wait to True in case you need to effectively know if/when change has been applied. WAIT_ATTEMPTS = 10 WAIT_DELAY = 0.025 # Will be progressively increased on every retry # These _NET_WM_STATE_ constants are used to manage Window state and are documented at # https://ewmh.readthedocs.io/en/latest/ewmh.html STATE_NULL = 0 STATE_MODAL = '_NET_WM_STATE_MODAL' STATE_STICKY = '_NET_WM_STATE_STICKY' STATE_MAX_VERT = '_NET_WM_STATE_MAXIMIZED_VERT' STATE_MAX_HORZ = '_NET_WM_STATE_MAXIMIZED_HORZ' STATE_SHADED = '_NET_WM_STATE_SHADED' STATE_SKIP_TASKBAR = '_NET_WM_STATE_SKIP_TASKBAR' STATE_SKIP_PAGER = '_NET_WM_STATE_SKIP_PAGER'
if sleeping: wake_windows_up() sleeping = False sleep(0.25) if __name__ == "__main__": uid = os.getuid() home = os.getenv("HOME") system_whitelist = "/etc/sleep-walker/whitelist" user_whitelist = "%s/.sleep-walker/whitelist" % home ewmh = ewmh.EWMH() xc = xcovered.XCovered(ewmh) # get_idle_time(xlib, dpy, root, xss) xlib = ctypes.cdll.LoadLibrary('libX11.so') dpy = xlib.XOpenDisplay(os.environ['DISPLAY']) root = xlib.XDefaultRootWindow(dpy) xss = ctypes.cdll.LoadLibrary('libXss.so.1') timeout = 5.0 # debug: need to find the sweet spot... notifications = True whitelist = load_whitelist() signal.signal(signal.SIGTERM, sigterm_handler)
def __init__(self): Tk.__init__(self) self.withdraw() self.notes = {} self.img = PhotoImage(file=cst.IM_ICON) self.icon = PhotoImage(master=self, file=cst.IM_ICON_48) self.iconphoto(True, self.icon) self.ewmh = ewmh.EWMH() style = Style(self) style.theme_use("clam") self.close1 = PhotoImage("img_close", file=cst.IM_CLOSE) self.close2 = PhotoImage("img_closeactive", file=cst.IM_CLOSE_ACTIVE) self.roll1 = PhotoImage("img_roll", file=cst.IM_ROLL) self.roll2 = PhotoImage("img_rollactive", file=cst.IM_ROLL_ACTIVE) self.protocol("WM_DELETE_WINDOW", self.quit) self.icon = tktray.Icon(self, docked=True) # --- Menu self.menu_notes = Menu(self.icon.menu, tearoff=False) self.hidden_notes = {cat: {} for cat in CONFIG.options("Categories")} self.menu_show_cat = Menu(self.icon.menu, tearoff=False) self.menu_hide_cat = Menu(self.icon.menu, tearoff=False) self.icon.configure(image=self.img) self.icon.menu.add_command(label=_("New Note"), command=self.new) self.icon.menu.add_separator() self.icon.menu.add_command(label=_('Show All'), command=self.show_all) self.icon.menu.add_cascade(label=_('Show Category'), menu=self.menu_show_cat) self.icon.menu.add_cascade(label=_('Show Note'), menu=self.menu_notes, state="disabled") self.icon.menu.add_separator() self.icon.menu.add_command(label=_('Hide All'), command=self.hide_all) self.icon.menu.add_cascade(label=_('Hide Category'), menu=self.menu_hide_cat) self.icon.menu.add_separator() self.icon.menu.add_command(label=_("Preferences"), command=self.config) self.icon.menu.add_command(label=_("Note Manager"), command=self.manage) self.icon.menu.add_separator() self.icon.menu.add_command(label=_("Backup Notes"), command=self.backup) self.icon.menu.add_command(label=_("Restore Backup"), command=self.restore) self.icon.menu.add_separator() self.icon.menu.add_command(label=_("Export"), command=self.export_notes) self.icon.menu.add_command(label=_("Import"), command=self.import_notes) self.icon.menu.add_separator() self.icon.menu.add_command(label=_('Check for Updates'), command=lambda: UpdateChecker(self)) self.icon.menu.add_command(label=_('About'), command=lambda: About(self)) self.icon.menu.add_command(label=_('Quit'), command=self.quit) # --- Restore notes self.note_data = {} if os.path.exists(PATH_DATA): with open(PATH_DATA, "rb") as fich: dp = pickle.Unpickler(fich) note_data = dp.load() for i, key in enumerate(note_data): self.note_data["%i" % i] = note_data[key] backup() for key in self.note_data: data = self.note_data[key] cat = data["category"] if not CONFIG.has_option("Categories", cat): CONFIG.set("Categories", cat, data["color"]) if data["visible"]: self.notes[key] = Sticky(self, key, **data) else: self.add_note_to_menu(key, data["title"], cat) self.nb = len(self.note_data) self.update_menu() self.update_notes() self.make_notes_sticky() # --- class bindings # newline depending on mode self.bind_class("Text", "<Return>", self.insert_newline) # char deletion taking into account list type self.bind_class("Text", "<BackSpace>", self.delete_char) # change Ctrl+A to select all instead of go to the beginning of the line self.bind_class('Text', '<Control-a>', self.select_all_text) self.bind_class('TEntry', '<Control-a>', self.select_all_entry) # bind Ctrl+Y to redo self.bind_class('Text', '<Control-y>', self.redo_event) # unbind Ctrl+I and Ctrl+B self.bind_class('Text', '<Control-i>', lambda e: None) self.bind_class('Text', '<Control-b>', lambda e: None) # highlight checkboxes when inside text selection self.bind_class("Text", "<ButtonPress-1>", self.highlight_checkboxes, True) self.bind_class("Text", "<ButtonRelease-1>", self.highlight_checkboxes, True) self.bind_class("Text", "<B1-Motion>", self.highlight_checkboxes, True) evs = [ '<<SelectAll>>', '<<SelectLineEnd>>', '<<SelectLineStart>>', '<<SelectNextChar>>', '<<SelectNextLine>>', '<<SelectNextPara>>', '<<SelectNextWord>>', '<<SelectNone>>', '<<SelectPrevChar>>', '<<SelectPrevLine>>', '<<SelectPrevPara>>', '<<SelectPrevWord>>' ] for ev in evs: self.bind_class("Text", ev, self.highlight_checkboxes, True) # check for updates if CONFIG.getboolean("General", "check_update"): UpdateChecker(self)
Constants and functions """ import os import gettext import warnings from subprocess import Popen from configparser import ConfigParser from locale import getdefaultlocale, setlocale, LC_ALL from subprocess import check_output, CalledProcessError import ewmh from PIL import Image, ImageDraw EWMH = ewmh.EWMH() SYMBOLS = 'ΓΔΘΛΞΠΣΦΨΩαβγδεζηθικλμνξοπρςστυφχψωϐϑϒϕϖ末»¡¿£¥$€§ø∞∀∃∄∈∉∫∧∨∩∪÷±√∝∼≃≅≡≤≥≪≫≲≳▪•✭✦➔➢✔▴▸✗✚✳☎✉✎♫⚠⇒⇔' # --- paths PATH = os.path.dirname(__file__) if os.access(PATH, os.W_OK) and os.path.exists(os.path.join(PATH, "images")): # the app is not installed # local directory containing config files and sticky notes data LOCAL_PATH = PATH PATH_LOCALE = os.path.join(PATH, "locale") PATH_IMAGES = os.path.join(PATH, "images") PATH_DATA_BACKUP = os.path.join(LOCAL_PATH, "backup", "notes.backup%i") PATH_DATA = os.path.join(LOCAL_PATH, "backup", "notes") if not os.path.exists(os.path.join(LOCAL_PATH, "backup")):
def iter_window(cls) -> Iterator['_Window']: for win in ewmh.EWMH().getClientList(): yield Window(win)
def __init__(self): self.ew = ewmh.EWMH() self.windows = None
def main(): e = ewmh.EWMH() cr = CommandReader() global mpv_desktop_active global layout_tiled global layout_pip while True: try: # we don't want to get hammered, nor do we want to hammer # the mpv processes with mute/unmute requests sleep(0.25) cmd = cr.get_next() debug_obj(cr) if not cmd: error('main: get_next command failure') continue debug_obj(cmd) s = Screen(e) debug_obj(s) # we can choose to manage windows on one fixed desktop # only, even when we're currently on another one; or # always manage mpv windows on the current desktop only; # 'None' means always manage windows only on current # desktop if mpv_desktop == None: mpv_desktop_active = s.desktop mpv_list = MPVClientList(s) if not mpv_list: error('main: mpv list initialization trouble, stopping iteration') continue mpv_list.inc = cmd.inc # limit client list to top windows if we're just toggling if cmd.toggle_top: mpv_list.limit_to_top() debug_obj(mpv_list) # the mpv_list methods we are going to execute in # succession call_list = [] call_list.append(mpv_list.rotate_focus) # move focus if not cmd.focus_only: call_list.append(mpv_list.rotate_audio) # move unmute status if not (cmd.audio_only or s.desktop != mpv_desktop_active): if cmd.next_l_tile : layout_tiled = (layout_tiled + 1) % 8 func = mpv_list.reset_tile elif cmd.next_l_pip : layout_pip = (layout_pip + 1) % 8 func = mpv_list.reset_pip elif cmd.reset_tile : func = mpv_list.reset_tile elif cmd.reset_pip : func = mpv_list.reset_pip elif cmd.toggle_top : func = mpv_list.toggle_top #elif cmd.toggle_top : func = mpv_list.test else : func = mpv_list.rotate_or_shift call_list.append(func) # do window manipulation first, then audio, then focus; # implementation depends on this order for f in reversed(call_list): f() except (KeyboardInterrupt, SystemExit): raise except: traceback.print_exc(file=sys.stdout) pass finally: if s and getattr(s, "e", None) and s.e: s.e.display.flush() mpv_list.close_sockets() debug(80 * '-') debug('')