# -*- python -*- # This configuration scripts can enable or disable Redshift # depending on that window is in focus, by class or title. # However this is actually window manager dependent and have # only been tested on twm and xmonad. # Copyright © 2014 Mattias Andrée (m@maandree.se) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # This requires that python3-xlib is installed. import signal import threading import Xlib.display # TODO: cannot re-exec when this script is used # TODO: does not wait with toggling of redshift is froozen def x_window_focus_thread_function(proc): ''' The function that our thread runs @param proc:Popen The redshift process ''' # Acquire connection to X x_display = Xlib.display.Display() # Get root windows for each screen and list on most events mask = ((1 << 2) - 1) ^ ((1 << 0) - 1) mask |= ((1 << 14) - 1) ^ ((1 << 3) - 1) mask |= ((1 << 20) - 1) ^ ((1 << 15) - 1) mask |= ((1 << 25) - 1) ^ ((1 << 21) - 1) for x_screen_i in range(x_display.screen_count()): x_screen = x_display.screen(x_screen_i) x_root = x_screen.root x_root.change_attributes(event_mask = mask) x_display.flush() try: last = None we_disabled = False while True: try: # Get focused window window = x_display.get_input_focus().focus if isinstance(window, int): x_display.next_event() continue # Get window specifications wm_class = window.get_wm_class() wm_name = None try: wm_name = window.get_wm_name() except: pass ## Bug in python3-xlib (?) if (wm_class is None) and (wm_name is None): x_display.next_event() continue if (wm_name is not None) and (not isinstance(wm_name, str)): wm_name = wm_name.decode('utf-8', 'replace') window = (None if wm_class is None else wm_class[0], None if wm_class is None else wm_class[1], wm_name) #sys.stderr.buffer.write((repr(window) + '\n').encode('utf-8')) #sys.stderr.buffer.flush() except: x_display.next_event() continue # Check that something changed if (last is not None) and (last == window): x_display.next_event() continue last = window # Check what window is in focus should_be_disabled = False if window[0] == 'inkscape': should_be_disabled = True elif window[0].startswith('gimp-'): # continues with the version number should_be_disabled = True # Perhaps toggle if red_running and (should_be_disabled == red_status) and (not red_dying) and (not red_froozen): if red_status or we_disabled: we_disabled = should_be_disabled proc.send_signal(signal.SIGUSR1) # Wait for next update x_display.next_event() finally: # Close X connection on exit x_display.close() start_daemon_threads_ = start_daemon_threads def start_daemon_threads(proc, sock): ''' Start the threads for the daemon @param sock:socket The server socket @param proc:Popen The redshift process ''' start_daemon_threads_(proc, sock) # Start our thread thread = threading.Thread(target = x_window_focus_thread_function, args = (proc,)) thread.setDaemon(True) thread.start()