SafeEyes/safeeyes/plugins/donotdisturb/plugin.py

164 lines
5.7 KiB
Python
Raw Normal View History

2017-10-07 15:10:31 +02:00
#!/usr/bin/env python
# Safe Eyes is a utility to remind you to take break frequently
# to protect your eyes from eye strain.
# Copyright (C) 2017 Gobinath
# 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 <http://www.gnu.org/licenses/>.
"""
Skip Fullscreen plugin skips the break if the active window is fullscreen.
2021-01-27 04:55:59 +01:00
NOTE: Do not remove the unused import 'GdkX11' because it is required in Ubuntu 14.04
2017-10-07 15:10:31 +02:00
"""
2018-06-22 21:11:09 +02:00
import os
2017-10-07 15:10:31 +02:00
import logging
import re
import subprocess
import gi
gi.require_version('Gdk', '3.0')
from gi.repository import Gdk
from gi.repository import GdkX11 # noqa F401
from safeeyes import utility
2017-10-07 15:10:31 +02:00
context = None
skip_break_window_classes = []
take_break_window_classes = []
unfullscreen_allowed = True
2018-06-23 00:22:14 +02:00
dnd_while_on_battery = False
2017-10-07 15:10:31 +02:00
2018-06-23 13:38:13 +02:00
def is_active_window_skipped_wayland(pre_break):
cmdlist = ['wlrctl', 'toplevel', 'find', 'state:fullscreen']
try:
process = subprocess.Popen(cmdlist, stdout=subprocess.PIPE)
process.communicate()[0]
if process.returncode == 0:
return True
elif process.returncode == 1:
return False
elif process.returncode == 127:
logging.warning('Could not find wlrctl needed to detect fullscreen under wayland')
return False
except subprocess.CalledProcessError:
logging.warning('Error in finding full-screen application')
return False
def is_active_window_skipped_xorg(pre_break):
2017-10-07 15:10:31 +02:00
"""
Check for full-screen applications.
2018-06-22 21:11:09 +02:00
This method must be executed by the main thread. If not, it will cause random failure.
2017-10-07 15:10:31 +02:00
"""
logging.info('Searching for full-screen application')
screen = Gdk.Screen.get_default()
active_window = screen.get_active_window()
if active_window:
active_xid = str(active_window.get_xid())
2018-06-22 21:11:09 +02:00
cmdlist = ['xprop', '-root', '-notype', '-id',
active_xid, 'WM_CLASS', '_NET_WM_STATE']
2017-10-07 15:10:31 +02:00
try:
stdout = subprocess.check_output(cmdlist).decode('utf-8')
except subprocess.CalledProcessError:
logging.warning('Error in finding full-screen application')
else:
if stdout:
is_fullscreen = 'FULLSCREEN' in stdout
# Extract the process name
process_names = re.findall('"(.+?)"', stdout)
if process_names:
process = process_names[1].lower()
if process in skip_break_window_classes:
return True
elif process in take_break_window_classes:
if is_fullscreen and unfullscreen_allowed and not pre_break:
2017-10-07 15:10:31 +02:00
try:
active_window.unfullscreen()
except BaseException:
2018-06-22 21:11:09 +02:00
logging.error(
'Error in unfullscreen the window ' + process)
2017-10-07 15:10:31 +02:00
return False
return is_fullscreen
return False
2018-06-22 21:11:09 +02:00
def is_on_battery():
"""
Check if the computer is running on battery.
"""
2018-06-24 13:52:34 +02:00
on_battery = False
2018-06-22 21:11:09 +02:00
available_power_sources = os.listdir('/sys/class/power_supply')
2018-06-23 13:38:13 +02:00
logging.info('Looking for battery status in available power sources: %s' % str(
available_power_sources))
2018-06-22 21:11:09 +02:00
for power_source in available_power_sources:
if 'BAT' in power_source:
# Found battery
battery_status = os.path.join(
'/sys/class/power_supply', power_source, 'status')
if os.path.isfile(battery_status):
# Additional check to confirm that the status file exists
try:
with open(battery_status, 'r') as status_file:
status = status_file.read()
if status:
2018-06-24 13:52:34 +02:00
on_battery = 'discharging' in status.lower()
2018-06-22 21:11:09 +02:00
except BaseException:
logging.error('Failed to read %s' % battery_status)
break
2018-06-24 13:52:34 +02:00
return on_battery
2018-06-22 21:11:09 +02:00
2017-10-07 15:10:31 +02:00
def init(ctx, safeeyes_config, plugin_config):
global context
global skip_break_window_classes
global take_break_window_classes
global unfullscreen_allowed
2018-06-22 21:11:09 +02:00
global dnd_while_on_battery
2017-10-07 15:10:31 +02:00
logging.debug('Initialize Skip Fullscreen plugin')
context = ctx
skip_break_window_classes = plugin_config['skip_break_windows'].split()
take_break_window_classes = plugin_config['take_break_windows'].split()
unfullscreen_allowed = plugin_config['unfullscreen']
2018-06-22 21:11:09 +02:00
dnd_while_on_battery = plugin_config['while_on_battery']
2017-10-07 15:10:31 +02:00
def on_pre_break(break_obj):
"""
2018-06-22 21:11:09 +02:00
Lifecycle method executes before the pre-break period.
"""
if utility.IS_WAYLAND:
skip_break = is_active_window_skipped_wayland(True)
else:
skip_break = is_active_window_skipped_xorg(True)
2018-06-22 21:11:09 +02:00
if dnd_while_on_battery and not skip_break:
skip_break = is_on_battery()
return skip_break
2017-10-07 15:10:31 +02:00
def on_start_break(break_obj):
"""
2018-06-22 21:11:09 +02:00
Lifecycle method executes just before the break.
2017-10-07 15:10:31 +02:00
"""
if utility.IS_WAYLAND:
skip_break = is_active_window_skipped_wayland(True)
else:
skip_break = is_active_window_skipped_xorg(True)
2018-06-22 21:11:09 +02:00
if dnd_while_on_battery and not skip_break:
skip_break = is_on_battery()
return skip_break