Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fullscreen bypass support #808

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ Dependencies

* autotools, gettext
* intltool, libtool
* libX11
* libdrm (Optional, for DRM support)
* libxcb, libxcb-randr (Optional, for RandR support)
* libX11, libXxf86vm (Optional, for VidMode support)
* libXxf86vm (Optional, for VidMode support)
* Glib 2 (Optional, for GeoClue2 support)

* python3, pygobject, pyxdg (Optional, for GUI support)
Expand Down
1 change: 1 addition & 0 deletions po/POTFILES.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ data/applications/redshift-gtk.desktop.in
src/redshift.c
src/options.c
src/config-ini.c
src/fullscreen.c

src/gamma-drm.c
src/gamma-randr.c
Expand Down
3 changes: 2 additions & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ redshift_SOURCES = \
redshift.c redshift.h \
signals.c signals.h \
solar.c solar.h \
systemtime.c systemtime.h
systemtime.c systemtime.h \
fullscreen.c fullscreen.h

EXTRA_redshift_SOURCES = \
gamma-drm.c gamma-drm.h \
Expand Down
93 changes: 93 additions & 0 deletions src/fullscreen.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/* fullscreen.h -- Fullscreen detector
This file is part of Redshift.

Redshift 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.

Redshift 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 Redshift. If not, see <http://www.gnu.org/licenses/>.

Copyright (c) 2021 Angelo Elias Dalzotto <angelodalzotto97@gmail.com>
*/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

#ifdef ENABLE_NLS
# include <libintl.h>
# define _(s) gettext(s)
#else
# define _(s) s
#endif

#ifndef _WIN32
# include <X11/Xlib.h>
#endif

#include "fullscreen.h"
#include "redshift.h"

#ifndef _WIN32
static Display *display;
#endif

static int
fullscreen_init()
{
#ifndef _WIN32
display = XOpenDisplay(NULL);
if (display == NULL) {
fprintf(stderr, _("X request failed: %s\n"), "XOpenDisplay");
return -1;
}
#endif

return 0;
}

static int
fullscreen_check()
{
#ifndef _WIN32
Window window;
int revert_to = RevertToParent;
int result = XGetInputFocus(display, &window, &revert_to);

int win_x, win_y, win_w, win_h, win_b, win_d;
int scr_x, scr_y, scr_w, scr_h, scr_b, scr_d;
if (result) {
Window rootWindow;
result = XGetGeometry(display, window, &rootWindow, &win_x, &win_y, &win_w, &win_h, &win_b, &win_d);
if (rootWindow) {
result = XGetGeometry(display, rootWindow, &rootWindow, &scr_x, &scr_y, &scr_w, &scr_h, &scr_b, &scr_d);
}
}

if (result && win_w == scr_w && win_h == scr_h) {
return 1;
} else {
#endif
return 0;
#ifndef _WIN32
}
#endif
}

const fullscreen_t fullscreen = {
"fullscreen",
(fullscreen_init_func *)fullscreen_init,
(fullscreen_check_func *)fullscreen_check,
};
28 changes: 28 additions & 0 deletions src/fullscreen.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* fullscreen.h -- Fullscreen detector header
This file is part of Redshift.

Redshift 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.

Redshift 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 Redshift. If not, see <http://www.gnu.org/licenses/>.

Copyright (c) 2021 Angelo Elias Dalzotto <angelodalzotto97@gmail.com>
*/

#ifndef REDSHIFT_FULLSCREEN_H
#define REDSHIFT_FULLSCREEN_H

#include "redshift.h"

extern const fullscreen_t fullscreen;

#endif /* ! REDSHIFT_FULLSCREEN_H */

7 changes: 6 additions & 1 deletion src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ print_help(const char *program_name)
no-wrap */
fputs(_(" -b DAY:NIGHT\tScreen brightness to apply (between 0.1 and 1.0)\n"
" -c FILE\tLoad settings from specified configuration file\n"
" -f BOOL\tEnable or disable fullscreen windows bypass\n"
" -g R:G:B\tAdditional gamma correction to apply\n"
" -l LAT:LON\tYour current location\n"
" -l PROVIDER\tSelect provider for automatic"
Expand Down Expand Up @@ -323,6 +324,7 @@ options_init(options_t *options)
options->preserve_gamma = 1;
options->mode = PROGRAM_MODE_CONTINUAL;
options->verbose = 0;
options->fullscreen_check = 1;
}

/* Parse a single option from the command-line. */
Expand All @@ -345,6 +347,9 @@ parse_command_line_option(
free(options->config_filepath);
options->config_filepath = strdup(value);
break;
case 'f':
options->fullscreen_check = atoi(value);
break;
case 'g':
r = parse_gamma_string(value, options->scheme.day.gamma);
if (r < 0) {
Expand Down Expand Up @@ -495,7 +500,7 @@ options_parse_args(
{
const char* program_name = argv[0];
int opt;
while ((opt = getopt(argc, argv, "b:c:g:hl:m:oO:pPrt:vVx")) != -1) {
while ((opt = getopt(argc, argv, "b:c:f:g:hl:m:oO:pPrt:vVx")) != -1) {
char option = opt;
int r = parse_command_line_option(
option, optarg, options, program_name, gamma_methods,
Expand Down
1 change: 1 addition & 0 deletions src/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ typedef struct {
transition_scheme_t scheme;
program_mode_t mode;
int verbose;
int fullscreen_check;

/* Temperature to set in manual mode. */
int temp_set;
Expand Down
21 changes: 21 additions & 0 deletions src/redshift-gtk/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class RedshiftController(GObject.GObject):

__gsignals__ = {
'inhibit-changed': (GObject.SIGNAL_RUN_FIRST, None, (bool,)),
'fs_bypass_inhibit-changed': (GObject.SIGNAL_RUN_FIRST, None, (bool,)),
'temperature-changed': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'period-changed': (GObject.SIGNAL_RUN_FIRST, None, (str,)),
'location-changed': (GObject.SIGNAL_RUN_FIRST, None, (float, float)),
Expand All @@ -51,6 +52,7 @@ def __init__(self, args):

# Initialize state variables
self._inhibited = False
self._fs_bypass_inhibited = False
self._temperature = 0
self._period = 'Unknown'
self._location = (0.0, 0.0)
Expand Down Expand Up @@ -112,6 +114,11 @@ def relay_signal_handler(signal):
def inhibited(self):
"""Current inhibition state."""
return self._inhibited

@property
def fs_bypass_inhibited(self):
"""Current fullscreen bypass inhibition state."""
return self._fs_bypass_inhibited

@property
def temperature(self):
Expand All @@ -133,6 +140,11 @@ def set_inhibit(self, inhibit):
if inhibit != self._inhibited:
self._child_toggle_inhibit()

def set_fs_bypass_inhibit(self, fs_bypass_inhibit):
"""Set inhibition state."""
if fs_bypass_inhibit != self._fs_bypass_inhibited:
self._child_toggle_fs_bypass_inhibit()

def _child_signal(self, sg):
"""Send signal to child process."""
os.kill(self._process[0], sg)
Expand All @@ -141,6 +153,10 @@ def _child_toggle_inhibit(self):
"""Sends a request to the child process to toggle state."""
self._child_signal(signal.SIGUSR1)

def _child_toggle_fs_bypass_inhibit(self):
"""Sends a request to the child process to toggle fullscreen bypass state."""
self._child_signal(signal.SIGUSR2)

def _child_cb(self, pid, status, data=None):
"""Called when the child process exists."""

Expand Down Expand Up @@ -175,6 +191,11 @@ def parse_coord(s):
if new_inhibited != self._inhibited:
self._inhibited = new_inhibited
self.emit('inhibit-changed', new_inhibited)
elif key == 'Fullscreen bypass':
new_fs_bypass_inhibited = value != 'Enabled'
if new_fs_bypass_inhibited != self._fs_bypass_inhibited:
self._fs_bypass_inhibited = new_fs_bypass_inhibited
self.emit('fs_bypass_inhibit-changed', new_fs_bypass_inhibited)
elif key == 'Color temperature':
new_temperature = int(value.rstrip('K'), 10)
if new_temperature != self._temperature:
Expand Down
32 changes: 32 additions & 0 deletions src/redshift-gtk/statusicon.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ def __init__(self, controller):
suspend_menu_item.set_submenu(suspend_menu)
self.status_menu.append(suspend_menu_item)

# Add fullscreen bypass toggle
self.fs_bypass_toggle_item = Gtk.CheckMenuItem.new_with_label(
_('Fullscreen bypass'))
self.fs_bypass_toggle_item.connect(
'activate', self.fs_bypass_toggle_item_cb)
self.status_menu.append(self.fs_bypass_toggle_item)

# Add autostart option
if utils.supports_autostart():
autostart_item = Gtk.CheckMenuItem.new_with_label(_('Autostart'))
Expand Down Expand Up @@ -157,6 +164,8 @@ def __init__(self, controller):

# Setup signals to property changes
self._controller.connect('inhibit-changed', self.inhibit_change_cb)
self._controller.connect(
'fs_bypass_inhibit-changed', self.fs_bypass_inhibit_change_cb)
self._controller.connect('period-changed', self.period_change_cb)
self._controller.connect(
'temperature-changed', self.temperature_change_cb)
Expand All @@ -167,6 +176,7 @@ def __init__(self, controller):

# Set info box text
self.change_inhibited(self._controller.inhibited)
self.change_fs_bypass_inhibited(self._controller.fs_bypass_inhibited)
self.change_period(self._controller.period)
self.change_temperature(self._controller.temperature)
self.change_location(self._controller.location)
Expand Down Expand Up @@ -235,6 +245,17 @@ def toggle_item_cb(self, widget, data=None):
self.remove_suspend_timer()
self._controller.set_inhibit(not self._controller.inhibited)

def fs_bypass_toggle_item_cb(self, widget, data=None):
"""Callback when a request to toggle fullscreen bypass was made.

This ensures that the state of redshift is synchronised with
the toggle state of the widget (e.g. Gtk.CheckMenuItem).
"""
active = not self._controller.fs_bypass_inhibited
if active != widget.get_active():
self._controller.set_fs_bypass_inhibit(
not self._controller.fs_bypass_inhibited)

# Info dialog callbacks
def show_info_cb(self, widget, data=None):
"""Callback when the info dialog should be presented."""
Expand Down Expand Up @@ -276,6 +297,10 @@ def inhibit_change_cb(self, controller, inhibit):
"""Callback when controller changes inhibition status."""
self.change_inhibited(inhibit)

def fs_bypass_inhibit_change_cb(self, controller, fs_bypass_inhibit):
"""Callback when controller changes inhibition status."""
self.change_fs_bypass_inhibited(fs_bypass_inhibit)

def period_change_cb(self, controller, period):
"""Callback when controller changes period."""
self.change_period(period)
Expand Down Expand Up @@ -313,6 +338,13 @@ def change_inhibited(self, inhibited):
_('<b>Status:</b> {}').format(
_('Disabled') if inhibited else _('Enabled')))

def change_fs_bypass_inhibited(self, fs_bypass_inhibited):
"""Change interface to new fullscreen bypass inhibition status."""
self.fs_bypass_toggle_item.set_active(not fs_bypass_inhibited)
self.status_label.set_markup(
_('<b>Fullscreen Bypass:</b> {}').format(
_('Disabled') if fs_bypass_inhibited else _('Enabled')))

def change_temperature(self, temperature):
"""Change interface to new temperature."""
self.temperature_label.set_markup(
Expand Down
Loading