aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Makefile.am7
-rw-r--r--src/colorramp.c2
-rw-r--r--src/config-ini.c237
-rw-r--r--src/config-ini.h49
-rw-r--r--src/gamma-randr.c7
-rw-r--r--src/gamma-vidmode.c5
-rw-r--r--src/gtk-redshift/Makefile.am29
-rw-r--r--src/gtk-redshift/__init__.py1
-rw-r--r--src/gtk-redshift/defs.py.in1
-rw-r--r--src/gtk-redshift/gtk-redshift (renamed from src/gtk-redshift/gtk-redshift.in)2
-rw-r--r--src/gtk-redshift/rsappindicator.py99
-rw-r--r--src/gtk-redshift/statusicon.py77
-rw-r--r--src/gtk-redshift/utils.py66
-rw-r--r--src/location-gnome-clock.c109
-rw-r--r--src/redshift.c310
15 files changed, 745 insertions, 256 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index c07aea3..3680f4a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,11 +9,12 @@ INCLUDES = -DLOCALEDIR=\"$(localedir)\"
bin_PROGRAMS = redshift
redshift_SOURCES = \
- redshift.c \
+ redshift.c redshift.h \
colorramp.c colorramp.h \
+ config-ini.c config-ini.h \
+ location-manual.c location-manual.h \
solar.c solar.h \
- systemtime.c systemtime.h \
- location-manual.c location-manual.h
+ systemtime.c systemtime.h
EXTRA_redshift_SOURCES = \
gamma-randr.c gamma-randr.h \
diff --git a/src/colorramp.c b/src/colorramp.c
index a154a9e..7241a8d 100644
--- a/src/colorramp.c
+++ b/src/colorramp.c
@@ -130,7 +130,7 @@ void
colorramp_fill(uint16_t *gamma_r, uint16_t *gamma_g, uint16_t *gamma_b,
int size, int temp, float gamma[3])
{
- /* Calculate white point */
+ /* Approximate white point */
float white_point[3];
float alpha = (temp % 100) / 100.0;
int temp_index = ((temp - 1000) / 100)*3;
diff --git a/src/config-ini.c b/src/config-ini.c
new file mode 100644
index 0000000..5231ba5
--- /dev/null
+++ b/src/config-ini.c
@@ -0,0 +1,237 @@
+/* config-ini.c -- INI config file parser
+ 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) 2010 Jon Lund Steffensen <jonlst@gmail.com>
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "config-ini.h"
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# define _(s) gettext(s)
+#else
+# define _(s) s
+#endif
+
+#define MAX_CONFIG_PATH 4096
+#define MAX_LINE_LENGTH 512
+
+
+static FILE *
+open_config_file(const char *filepath)
+{
+ FILE *f = NULL;
+
+ if (filepath == NULL) {
+ char cp[MAX_CONFIG_PATH];
+ char *env;
+
+ if ((env = getenv("XDG_CONFIG_HOME")) != NULL &&
+ env[0] != '\0') {
+ snprintf(cp, sizeof(cp), "%s/redshift.conf", env);
+ filepath = cp;
+ } else if ((env = getenv("HOME")) != NULL && env[0] != '\0') {
+ snprintf(cp, sizeof(cp),
+ "%s/.config/redshift.conf", env);
+ filepath = cp;
+ }
+
+ if (filepath != NULL) {
+ f = fopen(filepath, "r");
+ if (f != NULL) return f;
+ else if (f == NULL && errno != ENOENT) return NULL;
+ }
+
+ /* TODO look in getenv("XDG_CONFIG_DIRS") */
+ } else {
+ f = fopen(filepath, "r");
+ if (f == NULL) {
+ perror("fopen");
+ return NULL;
+ }
+ }
+
+ return f;
+}
+
+int
+config_ini_init(config_ini_state_t *state, const char *filepath)
+{
+ config_ini_section_t *section = NULL;
+ state->sections = NULL;
+
+ FILE *f = open_config_file(filepath);
+ if (f == NULL) {
+ /* Only a serious error if a file was explicitly requested. */
+ if (filepath != NULL) return -1;
+ return 0;
+ }
+
+ char line[MAX_LINE_LENGTH];
+ char *s;
+
+ while (1) {
+ /* Handle the file input linewise. */
+ char *r = fgets(line, sizeof(line), f);
+ if (r == NULL) break;
+
+ /* Strip leading blanks and trailing newline. */
+ s = line + strspn(line, " \t");
+ s[strcspn(s, "\r\n")] = '\0';
+
+ /* Skip comments and empty lines. */
+ if (s[0] == ';' || s[0] == '\0') continue;
+
+ if (s[0] == '[') {
+ /* Read name of section. */
+ const char *name = s+1;
+ char *end = strchr(s, ']');
+ if (end == NULL || end[1] != '\0' || end == name) {
+ fputs(_("Malformed section header in config"
+ " file.\n"), stderr);
+ fclose(f);
+ config_ini_free(state);
+ return -1;
+ }
+
+ *end = '\0';
+
+ /* Create section. */
+ section = malloc(sizeof(config_ini_section_t));
+ if (section == NULL) {
+ fclose(f);
+ config_ini_free(state);
+ return -1;
+ }
+
+ /* Insert into section list. */
+ section->name = NULL;
+ section->settings = NULL;
+ section->next = state->sections;
+ state->sections = section;
+
+ /* Copy section name. */
+ section->name = malloc(end - name + 1);
+ if (section->name == NULL) {
+ fclose(f);
+ config_ini_free(state);
+ return -1;
+ }
+
+ memcpy(section->name, name, end - name + 1);
+ } else {
+ /* Split assignment at equals character. */
+ char *end = strchr(s, '=');
+ if (end == NULL || end == s) {
+ fputs(_("Malformed assignment in config"
+ " file.\n"), stderr);
+ fclose(f);
+ config_ini_free(state);
+ return -1;
+ }
+
+ *end = '\0';
+ char *value = end + 1;
+
+ if (section == NULL) {
+ fputs(_("Assignment outside section in config"
+ " file.\n"), stderr);
+ fclose(f);
+ config_ini_free(state);
+ return -1;
+ }
+
+ /* Create section. */
+ config_ini_setting_t *setting =
+ malloc(sizeof(config_ini_setting_t));
+ if (setting == NULL) {
+ fclose(f);
+ config_ini_free(state);
+ return -1;
+ }
+
+ /* Insert into section list. */
+ setting->name = NULL;
+ setting->value = NULL;
+ setting->next = section->settings;
+ section->settings = setting;
+
+ /* Copy name of setting. */
+ setting->name = malloc(end - s + 1);
+ if (setting->name == NULL) {
+ fclose(f);
+ config_ini_free(state);
+ return -1;
+ }
+
+ memcpy(setting->name, s, end - s + 1);
+
+ /* Copy setting value. */
+ size_t value_len = strlen(value) + 1;
+ setting->value = malloc(value_len);
+ if (setting->value == NULL) {
+ fclose(f);
+ config_ini_free(state);
+ return -1;
+ }
+
+ memcpy(setting->value, value, value_len);
+ }
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+void
+config_ini_free(config_ini_state_t *state)
+{
+ config_ini_section_t *section = state->sections;
+
+ while (section != NULL) {
+ config_ini_setting_t *setting = section->settings;
+
+ while (setting != NULL) {
+ free(setting->name);
+ free(setting->value);
+ setting = setting->next;
+ }
+
+ free(section->name);
+ section = section->next;
+ }
+}
+
+config_ini_section_t *
+config_ini_get_section(config_ini_state_t *state, const char *name)
+{
+ config_ini_section_t *section = state->sections;
+ while (section != NULL) {
+ if (strcasecmp(section->name, name) == 0) {
+ return section;
+ }
+ section = section->next;
+ }
+
+ return NULL;
+}
diff --git a/src/config-ini.h b/src/config-ini.h
new file mode 100644
index 0000000..e1bff73
--- /dev/null
+++ b/src/config-ini.h
@@ -0,0 +1,49 @@
+/* config-ini.h -- INI config file parser 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) 2010 Jon Lund Steffensen <jonlst@gmail.com>
+*/
+
+#ifndef _REDSHIFT_CONFIG_INI_H
+#define _REDSHIFT_CONFIG_INI_H
+
+typedef struct _config_ini_section config_ini_section_t;
+typedef struct _config_ini_setting config_ini_setting_t;
+
+struct _config_ini_setting {
+ config_ini_setting_t *next;
+ char *name;
+ char *value;
+};
+
+struct _config_ini_section {
+ config_ini_section_t *next;
+ char *name;
+ config_ini_setting_t *settings;
+};
+
+typedef struct {
+ config_ini_section_t *sections;
+} config_ini_state_t;
+
+
+int config_ini_init(config_ini_state_t *state, const char *filepath);
+void config_ini_free(config_ini_state_t *state);
+
+config_ini_section_t *config_ini_get_section(config_ini_state_t *state,
+ const char *name);
+
+#endif /* ! _REDSHIFT_CONFIG_INI_H */
diff --git a/src/gamma-randr.c b/src/gamma-randr.c
index 66d5c48..be8bdd9 100644
--- a/src/gamma-randr.c
+++ b/src/gamma-randr.c
@@ -62,9 +62,12 @@ randr_init(randr_state_t *state)
xcb_randr_query_version_reply_t *ver_reply =
xcb_randr_query_version_reply(state->conn, ver_cookie, &error);
- if (error) {
+ /* TODO What does it mean when both error and ver_reply is NULL?
+ Apparently, we have to check both to avoid seg faults. */
+ if (error || ver_reply == NULL) {
+ int ec = (error != 0) ? error->error_code : -1;
fprintf(stderr, _("`%s' returned error %d\n"),
- "RANDR Query Version", error->error_code);
+ "RANDR Query Version", ec);
xcb_disconnect(state->conn);
return -1;
}
diff --git a/src/gamma-vidmode.c b/src/gamma-vidmode.c
index e6b9412..7b891d8 100644
--- a/src/gamma-vidmode.c
+++ b/src/gamma-vidmode.c
@@ -68,7 +68,6 @@ vidmode_start(vidmode_state_t *state)
if (!r) {
fprintf(stderr, _("X request failed: %s\n"),
"XF86VidModeQueryVersion");
- XCloseDisplay(state->display);
return -1;
}
@@ -78,14 +77,12 @@ vidmode_start(vidmode_state_t *state)
if (!r) {
fprintf(stderr, _("X request failed: %s\n"),
"XF86VidModeGetGammaRampSize");
- XCloseDisplay(state->display);
return -1;
}
if (state->ramp_size == 0) {
fprintf(stderr, _("Gamma ramp size too small: %i\n"),
state->ramp_size);
- XCloseDisplay(state->display);
return -1;
}
@@ -93,7 +90,6 @@ vidmode_start(vidmode_state_t *state)
state->saved_ramps = malloc(3*state->ramp_size*sizeof(uint16_t));
if (state->saved_ramps == NULL) {
perror("malloc");
- XCloseDisplay(state->display);
return -1;
}
@@ -108,7 +104,6 @@ vidmode_start(vidmode_state_t *state)
if (!r) {
fprintf(stderr, _("X request failed: %s\n"),
"XF86VidModeGetGammaRamp");
- XCloseDisplay(state->display);
return -1;
}
diff --git a/src/gtk-redshift/Makefile.am b/src/gtk-redshift/Makefile.am
index ddeafd6..bb69459 100644
--- a/src/gtk-redshift/Makefile.am
+++ b/src/gtk-redshift/Makefile.am
@@ -1,38 +1,19 @@
-if ENABLE_STATUSICON
-gui_module=statusicon
+if ENABLE_GUI
gtk_redshift_PYTHON = \
__init__.py \
+ utils.py \
statusicon.py
nodist_gtk_redshift_PYTHON = \
defs.py
gtk_redshiftdir = $(pythondir)/gtk_redshift
-bin_SCRIPTS = gtk-redshift
+dist_bin_SCRIPTS = gtk-redshift
endif
-if ENABLE_APPINDICATOR
-gui_module=rsappindicator
-gtk_redshift_PYTHON = \
- __init__.py \
- rsappindicator.py
-nodist_gtk_redshift_PYTHON = \
- defs.py
-gtk_redshiftdir = $(pythondir)/gtk_redshift
-
-bin_SCRIPTS = gtk-redshift
-endif
-
-EXTRA_DIST = gtk-redshift.in \
- defs.py.in
-
-CLEANFILES = defs.py \
- gtk-redshift
-
+EXTRA_DIST = defs.py.in
+CLEANFILES = defs.py
-# Main GUI script
-gtk-redshift: gtk-redshift.in
- sed -e "s|\@gui_module\@|$(gui_module)|g" $< > $@
# Local python definitions
defs.py: defs.py.in
diff --git a/src/gtk-redshift/__init__.py b/src/gtk-redshift/__init__.py
index 51ab2ef..0e4f254 100644
--- a/src/gtk-redshift/__init__.py
+++ b/src/gtk-redshift/__init__.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# __init__.py -- gtk-redshift package __init__ file
# This file is part of Redshift.
diff --git a/src/gtk-redshift/defs.py.in b/src/gtk-redshift/defs.py.in
index d3ca5ed..026fefd 100644
--- a/src/gtk-redshift/defs.py.in
+++ b/src/gtk-redshift/defs.py.in
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# defs.py -- GTK+ redshift local definitions
# This file is part of Redshift.
diff --git a/src/gtk-redshift/gtk-redshift.in b/src/gtk-redshift/gtk-redshift
index 120e05c..56d940e 100644
--- a/src/gtk-redshift/gtk-redshift.in
+++ b/src/gtk-redshift/gtk-redshift
@@ -19,5 +19,5 @@
if __name__ == '__main__':
- from gtk_redshift.@gui_module@ import run
+ from gtk_redshift.statusicon import run
run()
diff --git a/src/gtk-redshift/rsappindicator.py b/src/gtk-redshift/rsappindicator.py
deleted file mode 100644
index 59fa725..0000000
--- a/src/gtk-redshift/rsappindicator.py
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/usr/bin/env python
-# rsappindicator.py -- Application Panel Indicator source
-# 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) 2010 Jon Lund Steffensen <jonlst@gmail.com>
-
-
-import sys, os
-import subprocess, signal
-import gettext
-
-import pygtk
-pygtk.require("2.0")
-
-import gtk, glib
-try:
- import appindicator
-except ImportError as ie:
- # No module named appindicator
- sys.exit(str(ie))
-
-import defs
-
-
-def run():
- # Internationalisation
- gettext.bindtextdomain('redshift', defs.LOCALEDIR)
- gettext.textdomain('redshift')
- _ = gettext.gettext
-
- # Start redshift with arguments from the command line
- args = sys.argv[1:]
- args.insert(0, os.path.join(defs.BINDIR, 'redshift'))
- process = subprocess.Popen(args)
-
- try:
- # Create status icon
- indicator = appindicator.Indicator ("redshift",
- "redshift",
- appindicator.CATEGORY_APPLICATION_STATUS)
- indicator.set_status (appindicator.STATUS_ACTIVE)
-
- def toggle_cb(widget, data=None):
- if indicator.get_icon() == 'redshift':
- indicator.set_icon('redshift-idle')
- else:
- indicator.set_icon('redshift')
- process.send_signal(signal.SIGUSR1)
-
- def destroy_cb(widget, data=None):
- gtk.main_quit()
- return False
-
- # Create popup menu
- status_menu = gtk.Menu()
-
- toggle_item = gtk.ImageMenuItem(_('Toggle'))
- toggle_item.connect('activate', toggle_cb)
- status_menu.append(toggle_item)
-
- quit_item = gtk.ImageMenuItem(gtk.STOCK_QUIT)
- quit_item.connect('activate', destroy_cb)
- status_menu.append(quit_item)
-
- status_menu.show_all()
-
- # Set the menu
- indicator.set_menu(status_menu)
-
- def child_cb(pid, cond, data=None):
- sys.exit(-1)
-
- # Add watch on child process
- glib.child_watch_add(process.pid, child_cb)
-
- # Run main loop
- gtk.main()
-
- except KeyboardInterrupt:
- # Ignore user interruption
- pass
-
- finally:
- # Always terminate redshift
- process.terminate()
- process.wait()
diff --git a/src/gtk-redshift/statusicon.py b/src/gtk-redshift/statusicon.py
index 2295963..29801e8 100644
--- a/src/gtk-redshift/statusicon.py
+++ b/src/gtk-redshift/statusicon.py
@@ -1,5 +1,4 @@
-#!/usr/bin/env python
-# statusicon.py -- GTK+ status icon source
+# statusicon.py -- GUI status icon source
# This file is part of Redshift.
# Redshift is free software: you can redistribute it and/or modify
@@ -18,6 +17,12 @@
# Copyright (c) 2010 Jon Lund Steffensen <jonlst@gmail.com>
+'''GUI status icon for Redshift.
+
+The run method will try to start an appindicator for Redshift. If the
+appindicator module isn't present it will fall back to a GTK status icon.
+'''
+
import sys, os
import subprocess, signal
import gettext
@@ -26,8 +31,13 @@ import pygtk
pygtk.require("2.0")
import gtk, glib
+try:
+ import appindicator
+except ImportError:
+ appindicator = None
import defs
+import utils
def run():
@@ -42,39 +52,76 @@ def run():
process = subprocess.Popen(args)
try:
- # Create status icon
- status_icon = gtk.StatusIcon()
- status_icon.set_from_icon_name('redshift')
- status_icon.set_tooltip('Redshift')
+ if appindicator:
+ # Create indicator
+ indicator = appindicator.Indicator('redshift', 'redshift',
+ appindicator.CATEGORY_APPLICATION_STATUS)
+ indicator.set_status(appindicator.STATUS_ACTIVE)
+ else:
+ # Create status icon
+ status_icon = gtk.StatusIcon()
+ status_icon.set_from_icon_name('redshift-status-on')
+ status_icon.set_tooltip('Redshift')
def toggle_cb(widget, data=None):
process.send_signal(signal.SIGUSR1)
+ if appindicator:
+ if indicator.get_icon() == 'redshift':
+ indicator.set_icon('redshift-status-off')
+ else:
+ indicator.set_icon('redshift-status-on')
+ else:
+ if status_icon.get_icon_name() == 'redshift':
+ status_icon.set_from_icon_name('redshift-status-off')
+ else:
+ status_icon.set_from_icon_name('redshift-status-on')
+
+ def autostart_cb(widget, data=None):
+ utils.set_autostart(widget.get_active())
def destroy_cb(widget, data=None):
- status_icon.set_visible(False)
+ if not appindicator:
+ status_icon.set_visible(False)
gtk.main_quit()
return False
# Create popup menu
status_menu = gtk.Menu()
- toggle_item = gtk.ImageMenuItem(_('Toggle'))
+ toggle_item = gtk.MenuItem(_('Toggle'))
toggle_item.connect('activate', toggle_cb)
status_menu.append(toggle_item)
+ autostart_item = gtk.CheckMenuItem(_('Autostart'))
+ try:
+ autostart_item.set_active(utils.get_autostart())
+ except IOError as strerror:
+ print strerror
+ autostart_item.set_property('sensitive', False)
+ else:
+ autostart_item.connect('activate', autostart_cb)
+ finally:
+ status_menu.append(autostart_item)
+
quit_item = gtk.ImageMenuItem(gtk.STOCK_QUIT)
quit_item.connect('activate', destroy_cb)
status_menu.append(quit_item)
- def popup_menu_cb(widget, button, time, data=None):
+ if appindicator:
status_menu.show_all()
- status_menu.popup(None, None, gtk.status_icon_position_menu,
- button, time, status_icon)
- # Connect signals for status icon and show
- status_icon.connect('activate', toggle_cb)
- status_icon.connect('popup-menu', popup_menu_cb)
- status_icon.set_visible(True)
+ # Set the menu
+ indicator.set_menu(status_menu)
+ else:
+ def popup_menu_cb(widget, button, time, data=None):
+ status_menu.show_all()
+ status_menu.popup(None, None, gtk.status_icon_position_menu,
+ button, time, status_icon)
+
+ # Connect signals for status icon and show
+ status_icon.connect('activate', toggle_cb)
+ status_icon.connect('popup-menu', popup_menu_cb)
+ status_icon.set_visible(True)
def child_cb(pid, cond, data=None):
sys.exit(-1)
diff --git a/src/gtk-redshift/utils.py b/src/gtk-redshift/utils.py
new file mode 100644
index 0000000..93e0195
--- /dev/null
+++ b/src/gtk-redshift/utils.py
@@ -0,0 +1,66 @@
+# utils.py -- utility functions source
+# 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) 2010 Francesco Marella <francesco.marella@gmail.com>
+
+import os
+from xdg import BaseDirectory as base
+from xdg import DesktopEntry as desktop
+
+REDSHIFT_DESKTOP = 'gtk-redshift.desktop'
+
+
+def get_autostart():
+ AUTOSTART_KEY = "X-GNOME-Autostart-enabled"
+ autostart_dir = base.save_config_path("autostart")
+ autostart_file = os.path.join(autostart_dir, REDSHIFT_DESKTOP)
+ if not os.path.exists(autostart_file):
+ desktop_files = list(base.load_data_paths("applications",
+ REDSHIFT_DESKTOP))
+ if not desktop_files:
+ raise IOError("Installed redshift desktop file not found!")
+ desktop_file_path = desktop_files[0]
+ # Read installed file and modify it
+ dfile = desktop.DesktopEntry(desktop_file_path)
+ dfile.set(AUTOSTART_KEY, "false")
+ dfile.write(filename=autostart_file)
+ return False
+ else:
+ dfile = desktop.DesktopEntry(autostart_file)
+ if dfile.get(AUTOSTART_KEY) == 'false':
+ return False
+ else:
+ return True
+
+def set_autostart(active):
+ AUTOSTART_KEY = "X-GNOME-Autostart-enabled"
+ autostart_dir = base.save_config_path("autostart")
+ autostart_file = os.path.join(autostart_dir, REDSHIFT_DESKTOP)
+ if not os.path.exists(autostart_file):
+ desktop_files = list(base.load_data_paths("applications",
+ REDSHIFT_DESKTOP))
+ if not desktop_files:
+ raise IOError("Installed redshift desktop file not found!")
+ return
+ desktop_file_path = desktop_files[0]
+ # Read installed file and modify it
+ dfile = desktop.DesktopEntry(desktop_file_path)
+ else:
+ dfile = desktop.DesktopEntry(autostart_file)
+ activestr = str(bool(active)).lower()
+ # print "Setting autostart to %s" % activestr
+ dfile.set(AUTOSTART_KEY, activestr)
+ dfile.write(filename=autostart_file)
diff --git a/src/location-gnome-clock.c b/src/location-gnome-clock.c
index 10b95eb..8c317ed 100644
--- a/src/location-gnome-clock.c
+++ b/src/location-gnome-clock.c
@@ -32,6 +32,41 @@
#endif
+/* Find current selected city for the clock applet with the specified id.
+ Returns NULL if not found. */
+static char *
+find_current_city(GConfClient *client, const char *id)
+{
+ GError *error = NULL;
+
+ char *current_city = NULL;
+ char *cities_key = g_strdup_printf("/apps/panel/applets/%s"
+ "/prefs/cities", id);
+ GSList *cities = gconf_client_get_list(client,
+ cities_key,
+ GCONF_VALUE_STRING, &error);
+
+ if (error) {
+ fprintf(stderr, _("Error reading city list: `%s'.\n"),
+ cities_key);
+ g_free(cities_key);
+ return NULL;
+ }
+
+ g_free(cities_key);
+
+ for (GSList *city = cities; city != NULL;
+ city = g_slist_next(city)) {
+ char *city_spec = city->data;
+ char *c = strstr(city_spec, "current=\"true\"");
+ if (c) current_city = g_strdup(city_spec);
+ g_free(city->data);
+ }
+ g_slist_free(cities);
+
+ return current_city;
+}
+
int
location_gnome_clock_init(location_gnome_clock_state_t *state)
{
@@ -40,80 +75,74 @@ location_gnome_clock_init(location_gnome_clock_state_t *state)
GError *error = NULL;
GConfClient *client = gconf_client_get_default();
- GSList *applets = gconf_client_all_dirs(client, "/apps/panel/applets",
- &error);
+ /* Get a list of active applets in the panel. */
+ GSList *applets = gconf_client_get_list(client,
+ "/apps/panel/general/applet_id_list",
+ GCONF_VALUE_STRING, &error);
if (error) {
- fputs(_("Cannot list dirs in `/apps/panel/applets'.\n"),
- stderr);
+ fputs(_("Cannot list GNOME panel applets.\n"), stderr);
g_object_unref(client);
+ g_slist_free(applets);
return -1;
}
- char *cities_key = NULL;
+ /* Go through each applet and check if it is a clock applet.
+ When a clock applet is found, check whether there is a
+ city selected as the current city. */
+ char *current_city = NULL;
+
+ /* Keep track of the number of clock applets found to be able to give
+ better error output if something fails. */
+ int clock_applet_count = 0;
+
for (GSList *applet = applets; applet != NULL;
applet = g_slist_next(applet)) {
- char *path = applet->data;
- if (cities_key == NULL) {
- char *key = g_strdup_printf("%s/bonobo_iid", path);
+ char *id = applet->data;
+ if (current_city == NULL) {
+ char *key = g_strdup_printf("/apps/panel/applets/%s"
+ "/bonobo_iid", id);
char *bonobo_iid = gconf_client_get_string(client, key,
&error);
- if (!error && bonobo_iid != NULL) {
- if (!strcmp(bonobo_iid,
- "OAFIID:GNOME_ClockApplet")) {
- cities_key = g_strdup_printf(
- "%s/prefs/cities", path);
- }
- g_free(bonobo_iid);
+ if (!error && bonobo_iid != NULL &&
+ !strcmp(bonobo_iid, "OAFIID:GNOME_ClockApplet")) {
+ clock_applet_count += 1;
+ current_city = find_current_city(client, id);
}
+ g_free(bonobo_iid);
g_free(key);
}
- g_free(path);
+ g_free(id);
}
g_slist_free(applets);
+ g_object_unref(client);
- if (cities_key == NULL) {
- fputs(_("No clock applet was found.\n"), stderr);
- g_object_unref(client);
- return -1;
- }
+ /* Check whether an applet and a current city was found. */
- GSList *cities = gconf_client_get_list(client, cities_key,
- GCONF_VALUE_STRING, &error);
- if (error) {
- fprintf(stderr, _("Error reading city list: `%s'.\n"),
- cities_key);
- g_free(cities_key);
- g_object_unref(client);
+ if (clock_applet_count == 0) {
+ fputs(_("No clock applet was found.\n"), stderr);
return -1;
}
- g_free(cities_key);
-
- char *current_city = NULL;
- for (GSList *city = cities; city != NULL;
- city = g_slist_next(city)) {
- char *city_spec = city->data;
- char *c = strstr(city_spec, "current=\"true\"");
- if (c) current_city = g_strdup(city_spec);
- g_free(city->data);
- }
- g_slist_free(cities);
-
if (current_city == NULL) {
fputs(_("No city selected as current city.\n"), stderr);
return -1;
}
+ /* Find coords for selected city and parse as number. */
+
char *lat_str = strstr(current_city, "latitude=\"");
char *lon_str = strstr(current_city, "longitude=\"");
if (lat_str == NULL || lon_str == NULL) {
fputs(_("Location not specified for city.\n"), stderr);
+ g_free(current_city);
return -1;
}
+ g_free(current_city);
+
char *lat_num_str = lat_str + strlen("latitude=\"");
char *lon_num_str = lon_str + strlen("longitude=\"");
diff --git a/src/redshift.c b/src/redshift.c
index 18cc2c5..f5a7762 100644
--- a/src/redshift.c
+++ b/src/redshift.c
@@ -42,6 +42,7 @@
#endif
#include "redshift.h"
+#include "config-ini.h"
#include "solar.h"
#include "systemtime.h"
@@ -285,7 +286,8 @@ print_help(const char *program_name)
/* TRANSLATORS: help output 4
`list' must not be translated
no-wrap */
- fputs(_(" -g R:G:B\tAdditional gamma correction to apply\n"
+ fputs(_(" -c FILE\tLoad settings from specified configuration file\n"
+ " -g R:G:B\tAdditional gamma correction to apply\n"
" -l LAT:LON\tYour current location\n"
" -l PROVIDER\tSelect provider for automatic"
" location updates\n"
@@ -301,6 +303,16 @@ print_help(const char *program_name)
fputs("\n", stdout);
/* TRANSLATORS: help output 5 */
+ printf(_("The neutral temperature is %uK. Using this value will not\n"
+ "change the color temperature of the display. Setting the\n"
+ "color temperature to a value higher than this results in\n"
+ "more blue light, and setting a lower value will result in\n"
+ "more red light.\n"),
+ NEUTRAL_TEMP);
+
+ fputs("\n", stdout);
+
+ /* TRANSLATORS: help output 6 */
printf(_("Default values:\n\n"
" Daytime temperature: %uK\n"
" Night temperature: %uK\n"),
@@ -308,7 +320,7 @@ print_help(const char *program_name)
fputs("\n", stdout);
- /* TRANSLATORS: help output 6 */
+ /* TRANSLATORS: help output 7 */
printf(_("Please report bugs to <%s>\n"), PACKAGE_BUGREPORT);
}
@@ -345,7 +357,8 @@ print_provider_list()
static int
provider_try_start(const location_provider_t *provider,
- location_state_t *state, char *args)
+ location_state_t *state,
+ config_ini_state_t *config, char *args)
{
int r;
@@ -356,7 +369,31 @@ provider_try_start(const location_provider_t *provider,
return -1;
}
- /* Set provider options. */
+ /* Set provider options from config file. */
+ config_ini_section_t *section =
+ config_ini_get_section(config, provider->name);
+ if (section != NULL) {
+ config_ini_setting_t *setting = section->settings;
+ while (setting != NULL) {
+ r = provider->set_option(state, setting->name,
+ setting->value);
+ if (r < 0) {
+ provider->free(state);
+ fprintf(stderr, _("Failed to set %s"
+ " option.\n"),
+ provider->name);
+ /* TRANSLATORS: `help' must not be
+ translated. */
+ fprintf(stderr, _("Try `-l %s:help' for more"
+ " information.\n"),
+ provider->name);
+ return -1;
+ }
+ setting = setting->next;
+ }
+ }
+
+ /* Set provider options from command line. */
while (args != NULL) {
char *next_arg = strchr(args, ':');
if (next_arg != NULL) *(next_arg++) = '\0';
@@ -398,7 +435,8 @@ provider_try_start(const location_provider_t *provider,
static int
method_try_start(const gamma_method_t *method,
- gamma_state_t *state, char *args)
+ gamma_state_t *state,
+ config_ini_state_t *config, char *args)
{
int r;
@@ -409,7 +447,31 @@ method_try_start(const gamma_method_t *method,
return -1;
}
- /* Set method options. */
+ /* Set method options from config file. */
+ config_ini_section_t *section =
+ config_ini_get_section(config, method->name);
+ if (section != NULL) {
+ config_ini_setting_t *setting = section->settings;
+ while (setting != NULL) {
+ r = method->set_option(state, setting->name,
+ setting->value);
+ if (r < 0) {
+ method->free(state);
+ fprintf(stderr, _("Failed to set %s"
+ " option.\n"),
+ method->name);
+ /* TRANSLATORS: `help' must not be
+ translated. */
+ fprintf(stderr, _("Try `-m %s:help' for more"
+ " information.\n"),
+ method->name);
+ return -1;
+ }
+ setting = setting->next;
+ }
+ }
+
+ /* Set method options from command line. */
while (args != NULL) {
char *next_arg = strchr(args, ':');
if (next_arg != NULL) *(next_arg++) = '\0';
@@ -449,6 +511,60 @@ method_try_start(const gamma_method_t *method,
return 0;
}
+/* A gamma string contains either one floating point value,
+ or three values separated by colon. */
+static int
+parse_gamma_string(const char *str, float gamma[])
+{
+ char *s = strchr(str, ':');
+ if (s == NULL) {
+ /* Use value for all channels */
+ float g = atof(str);
+ gamma[0] = gamma[1] = gamma[2] = g;
+ } else {
+ /* Parse separate value for each channel */
+ *(s++) = '\0';
+ char *g_s = s;
+ s = strchr(s, ':');
+ if (s == NULL) return -1;
+
+ *(s++) = '\0';
+ gamma[0] = atof(str); /* Red */
+ gamma[1] = atof(g_s); /* Blue */
+ gamma[2] = atof(s); /* Green */
+ }
+}
+
+static const gamma_method_t *
+find_gamma_method(const char *name)
+{
+ const gamma_method_t *method = NULL;
+ for (int i = 0; gamma_methods[i].name != NULL; i++) {
+ const gamma_method_t *m = &gamma_methods[i];
+ if (strcasecmp(name, m->name) == 0) {
+ method = m;
+ break;
+ }
+ }
+
+ return method;
+}
+
+static const location_provider_t *
+find_location_provider(const char *name)
+{
+ const location_provider_t *provider = NULL;
+ for (int i = 0; location_providers[i].name != NULL; i++) {
+ const location_provider_t *p = &location_providers[i];
+ if (strcasecmp(name, p->name) == 0) {
+ provider = p;
+ break;
+ }
+ }
+
+ return provider;
+}
+
int
main(int argc, char *argv[])
@@ -465,10 +581,12 @@ main(int argc, char *argv[])
textdomain(PACKAGE);
#endif
- /* Initialize to defaults */
- int temp_day = DEFAULT_DAY_TEMP;
- int temp_night = DEFAULT_NIGHT_TEMP;
- float gamma[3] = { DEFAULT_GAMMA, DEFAULT_GAMMA, DEFAULT_GAMMA };
+ /* Initialize settings to NULL values. */
+ char *config_filepath = NULL;
+
+ int temp_day = -1;
+ int temp_night = -1;
+ float gamma[3] = { NAN, NAN, NAN };
const gamma_method_t *method = NULL;
char *method_args = NULL;
@@ -476,38 +594,27 @@ main(int argc, char *argv[])
const location_provider_t *provider = NULL;
char *provider_args = NULL;
- int transition = 1;
+ int transition = -1;
program_mode_t mode = PROGRAM_MODE_CONTINUAL;
int verbose = 0;
char *s;
- /* Parse arguments. */
+ /* Parse command line arguments. */
int opt;
- while ((opt = getopt(argc, argv, "g:hl:m:ort:vx")) != -1) {
+ while ((opt = getopt(argc, argv, "c:g:hl:m:ort:vx")) != -1) {
switch (opt) {
+ case 'c':
+ if (config_filepath != NULL) free(config_filepath);
+ config_filepath = strdup(optarg);
+ break;
case 'g':
- s = strchr(optarg, ':');
- if (s == NULL) {
- /* Use value for all channels */
- float g = atof(optarg);
- gamma[0] = gamma[1] = gamma[2] = g;
- } else {
- /* Parse separate value for each channel */
- *(s++) = '\0';
- gamma[0] = atof(optarg); /* Red */
- char *g_s = s;
- s = strchr(s, ':');
- if (s == NULL) {
- fputs(_("Malformed gamma argument.\n"),
- stderr);
- fputs(_("Try `-h' for more"
- " information.\n"), stderr);
- exit(EXIT_FAILURE);
- }
-
- *(s++) = '\0';
- gamma[1] = atof(g_s); /* Blue */
- gamma[2] = atof(s); /* Green */
+ r = parse_gamma_string(optarg, gamma);
+ if (r < 0) {
+ fputs(_("Malformed gamma argument.\n"),
+ stderr);
+ fputs(_("Try `-h' for more"
+ " information.\n"), stderr);
+ exit(EXIT_FAILURE);
}
break;
case 'h':
@@ -543,16 +650,8 @@ main(int argc, char *argv[])
provider_name = optarg;
}
- /* Lookup argument in location provider table */
- for (int i = 0; location_providers[i].name != NULL;
- i++) {
- const location_provider_t *p =
- &location_providers[i];
- if (strcasecmp(provider_name, p->name) == 0) {
- provider = p;
- }
- }
-
+ /* Lookup provider from name. */
+ provider = find_location_provider(provider_name);
if (provider == NULL) {
fprintf(stderr, _("Unknown location provider"
" `%s'.\n"), provider_name);
@@ -563,7 +662,7 @@ main(int argc, char *argv[])
if (provider_args != NULL &&
strcasecmp(provider_args, "help") == 0) {
provider->print_help(stdout);
- exit(EXIT_FAILURE);
+ exit(EXIT_SUCCESS);
}
break;
case 'm':
@@ -580,20 +679,13 @@ main(int argc, char *argv[])
method_args = s;
}
- /* Lookup argument in gamma methods table */
- for (int i = 0; gamma_methods[i].name != NULL; i++) {
- const gamma_method_t *m =
- &gamma_methods[i];
- if (strcasecmp(optarg, m->name) == 0) {
- method = m;
- }
- }
-
+ /* Find adjustment method by name. */
+ method = find_gamma_method(optarg);
if (method == NULL) {
/* TRANSLATORS: This refers to the method
used to adjust colors e.g VidMode */
- fprintf(stderr, _("Unknown method `%s'.\n"),
- optarg);
+ fprintf(stderr, _("Unknown adjustment method"
+ " `%s'.\n"), optarg);
exit(EXIT_FAILURE);
}
@@ -601,7 +693,7 @@ main(int argc, char *argv[])
if (method_args != NULL &&
strcasecmp(method_args, "help") == 0) {
method->print_help(stdout);
- exit(EXIT_FAILURE);
+ exit(EXIT_SUCCESS);
}
break;
case 'o':
@@ -636,6 +728,91 @@ main(int argc, char *argv[])
}
}
+ /* Load settings from config file. */
+ config_ini_state_t config_state;
+ r = config_ini_init(&config_state, config_filepath);
+ if (r < 0) {
+ fputs("Unable to load config file.\n", stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ if (config_filepath != NULL) free(config_filepath);
+
+ /* Read global config settings. */
+ config_ini_section_t *section = config_ini_get_section(&config_state,
+ "redshift");
+ if (section != NULL) {
+ config_ini_setting_t *setting = section->settings;
+ while (setting != NULL) {
+ if (strcasecmp(setting->name, "temp-day") == 0) {
+ if (temp_day < 0) {
+ temp_day = atoi(setting->value);
+ }
+ } else if (strcasecmp(setting->name,
+ "temp-night") == 0) {
+ if (temp_night < 0) {
+ temp_night = atoi(setting->value);
+ }
+ } else if (strcasecmp(setting->name,
+ "transition") == 0) {
+ if (transition < 0) {
+ transition = !!atoi(setting->value);
+ }
+ } else if (strcasecmp(setting->name, "gamma") == 0) {
+ if (isnan(gamma[0])) {
+ r = parse_gamma_string(setting->value,
+ gamma);
+ if (r < 0) {
+ fputs(_("Malformed gamma"
+ " setting.\n"),
+ stderr);
+ exit(EXIT_FAILURE);
+ }
+ }
+ } else if (strcasecmp(setting->name,
+ "adjustment-method") == 0) {
+ if (method == NULL) {
+ method = find_gamma_method(
+ setting->value);
+ if (method == NULL) {
+ fprintf(stderr, _("Unknown"
+ " adjustment"
+ " method"
+ " `%s'.\n"),
+ setting->value);
+ exit(EXIT_FAILURE);
+ }
+ }
+ } else if (strcasecmp(setting->name,
+ "location-provider") == 0) {
+ if (provider == NULL) {
+ provider = find_location_provider(
+ setting->value);
+ if (provider == NULL) {
+ fprintf(stderr, _("Unknown"
+ " location"
+ " provider"
+ " `%s'.\n"),
+ setting->value);
+ exit(EXIT_FAILURE);
+ }
+ }
+ } else {
+ fprintf(stderr, _("Unknown configuration"
+ " setting `%s'.\n"),
+ setting->name);
+ }
+ setting = setting->next;
+ }
+ }
+
+ /* Use default values for settings that were neither defined in
+ the config file nor on the command line. */
+ if (temp_day < 0) temp_day = DEFAULT_DAY_TEMP;
+ if (temp_night < 0) temp_night = DEFAULT_NIGHT_TEMP;
+ if (isnan(gamma[0])) gamma[0] = gamma[1] = gamma[2] = DEFAULT_GAMMA;
+ if (transition < 0) transition = 1;
+
/* Initialize location provider. If provider is NULL
try all providers until one that works is found. */
location_state_t location_state;
@@ -645,7 +822,7 @@ main(int argc, char *argv[])
if (provider != NULL) {
/* Use provider specified on command line. */
r = provider_try_start(provider, &location_state,
- provider_args);
+ &config_state, provider_args);
if (r < 0) exit(EXIT_FAILURE);
} else {
/* Try all providers, use the first that works. */
@@ -654,13 +831,15 @@ main(int argc, char *argv[])
const location_provider_t *p =
&location_providers[i];
r = provider_try_start(p, &location_state,
- NULL);
+ &config_state, NULL);
if (r < 0) {
- fputs(_("Trying other provider...\n"),
+ fputs(_("Trying next provider...\n"),
stderr);
continue;
}
+ /* Found provider that works. */
+ printf(_("Using provider `%s'.\n"), p->name);
provider = p;
break;
}
@@ -750,18 +929,21 @@ main(int argc, char *argv[])
if (method != NULL) {
/* Use method specified on command line. */
- r = method_try_start(method, &state, method_args);
+ r = method_try_start(method, &state, &config_state,
+ method_args);
if (r < 0) exit(EXIT_FAILURE);
} else {
/* Try all methods, use the first that works. */
for (int i = 0; gamma_methods[i].name != NULL; i++) {
const gamma_method_t *m = &gamma_methods[i];
- r = method_try_start(m, &state, NULL);
+ r = method_try_start(m, &state, &config_state, NULL);
if (r < 0) {
- fputs(_("Trying other method...\n"), stderr);
+ fputs(_("Trying next method...\n"), stderr);
continue;
}
+ /* Found method that works. */
+ printf(_("Using method `%s'.\n"), m->name);
method = m;
break;
}