From 6d1dafda8466d32797e3458aaee9fb9977da1f7e Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Thu, 10 Apr 2014 18:54:25 +0200 Subject: move source into src MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- nightshift.py | 234 ------------------------------------------------------ src/nightshift.py | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+), 234 deletions(-) delete mode 100755 nightshift.py create mode 100755 src/nightshift.py diff --git a/nightshift.py b/nightshift.py deleted file mode 100755 index 72aebbb..0000000 --- a/nightshift.py +++ /dev/null @@ -1,234 +0,0 @@ -#!/usr/bin/env python3 -# -*- python -*- -copyright=''' -Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) - -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 . -''' - -import os -import sys -import socket -import threading -from subprocess import Popen, PIPE - - -PROGRAM_NAME = 'nightshift' -''' -:str The name of the program -''' - -PROGRAM_VERSION = '1.0' -''' -:str The version of the program -''' - - -## Set process title -def setproctitle(title): - ''' - Set process title - - @param title:str The title of the process - ''' - import ctypes - try: - # Remove path, keep only the file, - # otherwise we get really bad effects, namely - # the name title is truncates by the number - # of slashes in the title. At least that is - # the observed behaviour when using procps-ng. - title = title.split('/')[-1] - # Create strng buffer with title - title = title.encode(sys.getdefaultencoding(), 'replace') - title = ctypes.create_string_buffer(title) - if 'linux' in sys.platform: - # Set process title on Linux - libc = ctypes.cdll.LoadLibrary('libc.so.6') - libc.prctl(15, ctypes.byref(title), 0, 0, 0) - elif 'bsd' in sys.platform: - # Set process title on at least FreeBSD - libc = ctypes.cdll.LoadLibrary('libc.so.7') - libc.setproctitle(ctypes.create_string_buffer(b'-%s'), title) - except: - pass -setproctitle(sys.argv[0]) - - -## Parse options -for arg in sys.argv[1:]: - if arg in ('-V', '--version'): - ## Print the version of nightshift and of redshift - print('%s %s' % (PROGRAM_NAME, PROGRAM_VERSION)) - Popen(['redshift', '-V'], stdout = sys.stdout).wait() - sys.exit(0) - elif arg in ('-C', '--copyright'): - ## Print copyright information - print(copyright[1 : -1]) - sys.exit(0) - elif arg in ('-W', '--warranty'): - ## Print warranty disclaimer - print(copyright.split('\n\n')[-2]) - sys.exit(0) - elif arg in ('-h', '--help'): - ## Display help message - text = '''USAGE: nightshift [OPTIONS...] [-- REDSHIFT-OPTIONS...] - - Terminal user interface for redshift, a program for setting the colour - temperature of the display according to the time of day. - - -h --help Display this help message - -V --version Show program version - -C --copyright Show program copyright information - -W --warranty Show program warrantly disclaimer - - -d --daemon Start as daemon - -x --reset Reset mode (remove adjustment from screen) - +x --toggle Temporarily disable or enable adjustments - -s --status Print status information - - -c --config FILE Load settings from specified configuration file - -b --brightness DAY:NIGHT Screen brightness to set at daytime/night - -b --brightness BRIGHTNESS Screen brightness to apply - -t --temperature DAY:NIGHT Colour temperature to set at daytime/night - -t --temperature TEMP Colour temperature to apply - -l --location LAT:LON Your current location - -l --location PROVIDER Select provider for automatic location updates - (Type `list' to see available providers) - -m --method METHOD Method to use to set colour temperature - (Type `list' to see available methods) - -r --no-transition Disable temperature transitions - - Please report bugs to - ''' - text = text.split('\n')[:-1] - indent = min([len(line) - len(line.lstrip()) for line in text if line.rstrip().startswith(' ')]) - print('\n'.join([line[indent:] if line.startswith(' ') else line for line in text])) - sys.exit(0) - else: - ## Unrecognised option - sys.stderr.write('%s: error: unrecognised option: %s\n' % (sys.argv[0], arg)) - sys.exit(1) - - -socket_path = '%s.%s-%s' % ('/dev/shm/', PROGRAM_NAME, os.environ['USER']) -sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) -try: - # Connect to the server - sock.connect(socket_path) -except: - # The process need separate sockets, lets close it - # and let both process recreate it - sock.close() - sock = None - -if sock is None: - ## Server is not running - # Create pipe for interprocess signal - (r_end, w_end) = os.pipe() - - # Duplicate process. - pid = os.fork() - - if pid == 0: - ## Daemon (child) - # Close stdin - os.close(sys.stdin.fileno()) - - # Create server socket - os.unlink(socket_path) - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.bind(socket_path) - sock.listen(5) - - # Send signal - with os.fdopen(w_end, 'wb') as file: - file.write(b'\n') - file.flush() - - # Close the pipe - os.close(r_end) - - ## TODO (for testing) - import signal - while True: - signal.pause() - - # Close socket - sock.close() - # Close process - sys.exit(0) - else: - ## Front-end (parent) - # Wait for a signal - rc = None - with os.fdopen(r_end, 'rb') as file: - file.read(1) - - # Close the pipe - os.close(w_end) - - # Connect to the server - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - print('connecting') - sock.connect(socket_path) - print('connected') - - -try: - proc = Popen(['redshift', '-v'], stdout = PIPE, stderr = open(os.devnull)) - red_brightness, red_period, red_temperature, red_running = 1, 1, 6500, True - red_condition = threading.Condition() - - def read_status(): - global red_brightness, red_period, red_temperature, red_running - while True: - got = proc.stdout.readline() - if (got is None) or (len(got) == 0): - break - got = got.decode('utf-8', 'replace')[:-1] - (key, value) = got.split(': ') - red_condition.acquire() - try: - if key == 'Brightness': - red_brightness = float(value) - elif key == 'Period': - if value == 'Night': - red_period = 0 - elif value == 'Daytime': - red_period = 1 - else: - red_period = float(value.split(' ')[1][1 : -1]) / 100 - elif key == 'Color temperature': - red_temperature = float(value[:-1]) - except: - pass - red_condition.notify() - red_condition.release() - red_running = False - - thread = threading.Thread(target = read_status) - thread.setDaemon(True) - thread.start() - - while red_running: - red_condition.acquire() - red_condition.wait() - print('%f: %f, %f' % (red_period, red_temperature, red_brightness)) - red_condition.release() - -finally: - # Close socket - sock.close() - diff --git a/src/nightshift.py b/src/nightshift.py new file mode 100755 index 0000000..72aebbb --- /dev/null +++ b/src/nightshift.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python3 +# -*- python -*- +copyright=''' +Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + +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 . +''' + +import os +import sys +import socket +import threading +from subprocess import Popen, PIPE + + +PROGRAM_NAME = 'nightshift' +''' +:str The name of the program +''' + +PROGRAM_VERSION = '1.0' +''' +:str The version of the program +''' + + +## Set process title +def setproctitle(title): + ''' + Set process title + + @param title:str The title of the process + ''' + import ctypes + try: + # Remove path, keep only the file, + # otherwise we get really bad effects, namely + # the name title is truncates by the number + # of slashes in the title. At least that is + # the observed behaviour when using procps-ng. + title = title.split('/')[-1] + # Create strng buffer with title + title = title.encode(sys.getdefaultencoding(), 'replace') + title = ctypes.create_string_buffer(title) + if 'linux' in sys.platform: + # Set process title on Linux + libc = ctypes.cdll.LoadLibrary('libc.so.6') + libc.prctl(15, ctypes.byref(title), 0, 0, 0) + elif 'bsd' in sys.platform: + # Set process title on at least FreeBSD + libc = ctypes.cdll.LoadLibrary('libc.so.7') + libc.setproctitle(ctypes.create_string_buffer(b'-%s'), title) + except: + pass +setproctitle(sys.argv[0]) + + +## Parse options +for arg in sys.argv[1:]: + if arg in ('-V', '--version'): + ## Print the version of nightshift and of redshift + print('%s %s' % (PROGRAM_NAME, PROGRAM_VERSION)) + Popen(['redshift', '-V'], stdout = sys.stdout).wait() + sys.exit(0) + elif arg in ('-C', '--copyright'): + ## Print copyright information + print(copyright[1 : -1]) + sys.exit(0) + elif arg in ('-W', '--warranty'): + ## Print warranty disclaimer + print(copyright.split('\n\n')[-2]) + sys.exit(0) + elif arg in ('-h', '--help'): + ## Display help message + text = '''USAGE: nightshift [OPTIONS...] [-- REDSHIFT-OPTIONS...] + + Terminal user interface for redshift, a program for setting the colour + temperature of the display according to the time of day. + + -h --help Display this help message + -V --version Show program version + -C --copyright Show program copyright information + -W --warranty Show program warrantly disclaimer + + -d --daemon Start as daemon + -x --reset Reset mode (remove adjustment from screen) + +x --toggle Temporarily disable or enable adjustments + -s --status Print status information + + -c --config FILE Load settings from specified configuration file + -b --brightness DAY:NIGHT Screen brightness to set at daytime/night + -b --brightness BRIGHTNESS Screen brightness to apply + -t --temperature DAY:NIGHT Colour temperature to set at daytime/night + -t --temperature TEMP Colour temperature to apply + -l --location LAT:LON Your current location + -l --location PROVIDER Select provider for automatic location updates + (Type `list' to see available providers) + -m --method METHOD Method to use to set colour temperature + (Type `list' to see available methods) + -r --no-transition Disable temperature transitions + + Please report bugs to + ''' + text = text.split('\n')[:-1] + indent = min([len(line) - len(line.lstrip()) for line in text if line.rstrip().startswith(' ')]) + print('\n'.join([line[indent:] if line.startswith(' ') else line for line in text])) + sys.exit(0) + else: + ## Unrecognised option + sys.stderr.write('%s: error: unrecognised option: %s\n' % (sys.argv[0], arg)) + sys.exit(1) + + +socket_path = '%s.%s-%s' % ('/dev/shm/', PROGRAM_NAME, os.environ['USER']) +sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) +try: + # Connect to the server + sock.connect(socket_path) +except: + # The process need separate sockets, lets close it + # and let both process recreate it + sock.close() + sock = None + +if sock is None: + ## Server is not running + # Create pipe for interprocess signal + (r_end, w_end) = os.pipe() + + # Duplicate process. + pid = os.fork() + + if pid == 0: + ## Daemon (child) + # Close stdin + os.close(sys.stdin.fileno()) + + # Create server socket + os.unlink(socket_path) + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.bind(socket_path) + sock.listen(5) + + # Send signal + with os.fdopen(w_end, 'wb') as file: + file.write(b'\n') + file.flush() + + # Close the pipe + os.close(r_end) + + ## TODO (for testing) + import signal + while True: + signal.pause() + + # Close socket + sock.close() + # Close process + sys.exit(0) + else: + ## Front-end (parent) + # Wait for a signal + rc = None + with os.fdopen(r_end, 'rb') as file: + file.read(1) + + # Close the pipe + os.close(w_end) + + # Connect to the server + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + print('connecting') + sock.connect(socket_path) + print('connected') + + +try: + proc = Popen(['redshift', '-v'], stdout = PIPE, stderr = open(os.devnull)) + red_brightness, red_period, red_temperature, red_running = 1, 1, 6500, True + red_condition = threading.Condition() + + def read_status(): + global red_brightness, red_period, red_temperature, red_running + while True: + got = proc.stdout.readline() + if (got is None) or (len(got) == 0): + break + got = got.decode('utf-8', 'replace')[:-1] + (key, value) = got.split(': ') + red_condition.acquire() + try: + if key == 'Brightness': + red_brightness = float(value) + elif key == 'Period': + if value == 'Night': + red_period = 0 + elif value == 'Daytime': + red_period = 1 + else: + red_period = float(value.split(' ')[1][1 : -1]) / 100 + elif key == 'Color temperature': + red_temperature = float(value[:-1]) + except: + pass + red_condition.notify() + red_condition.release() + red_running = False + + thread = threading.Thread(target = read_status) + thread.setDaemon(True) + thread.start() + + while red_running: + red_condition.acquire() + red_condition.wait() + print('%f: %f, %f' % (red_period, red_temperature, red_brightness)) + red_condition.release() + +finally: + # Close socket + sock.close() + -- cgit v1.2.3-70-g09d2