wmstatus: add a sleep timer
Since GNOME Settings Daemon doesn't work.
This commit is contained in:
parent
aed4436ed7
commit
cca674789b
142
wmstatus.c
142
wmstatus.c
|
@ -35,6 +35,7 @@
|
|||
#include <X11/keysym.h>
|
||||
#include <X11/XF86keysym.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/extensions/sync.h>
|
||||
|
||||
#include <pulse/mainloop.h>
|
||||
#include <pulse/context.h>
|
||||
|
@ -1136,7 +1137,7 @@ static struct simple_config_item g_config_table[] =
|
|||
{ "nut_load_power", NULL, "ups.realpower.nominal override" },
|
||||
|
||||
{ "command", NULL, "command to run for more info" },
|
||||
|
||||
{ "sleep_timer", NULL, "idle seconds to suspend after" },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -1148,7 +1149,7 @@ struct app_context
|
|||
struct backend *backend; ///< WM backend
|
||||
|
||||
Display *dpy; ///< X display handle
|
||||
int xkb_base_event_code; ///< Xkb base event code
|
||||
struct poller_fd x_event; ///< X11 event
|
||||
const char *prefix; ///< User-defined prefix
|
||||
|
||||
struct poller poller; ///< Poller
|
||||
|
@ -1156,6 +1157,15 @@ struct app_context
|
|||
struct poller_timer make_context; ///< Start PulseAudio communication
|
||||
struct poller_timer refresh_rest; ///< Refresh unpollable information
|
||||
|
||||
// Sleep timer:
|
||||
|
||||
int xsync_base_event_code; ///< XSync base event code
|
||||
XSyncCounter idle_counter; ///< XSync IDLETIME counter
|
||||
XSyncValue idle_timeout; ///< Sleep timeout
|
||||
|
||||
XSyncAlarm idle_alarm_inactive; ///< User is inactive
|
||||
XSyncAlarm idle_alarm_active; ///< User is active
|
||||
|
||||
// Command:
|
||||
|
||||
struct poller_timer command_start; ///< Start the command
|
||||
|
@ -1167,7 +1177,7 @@ struct app_context
|
|||
|
||||
// Hotkeys:
|
||||
|
||||
struct poller_fd x_event; ///< X11 event
|
||||
int xkb_base_event_code; ///< Xkb base event code
|
||||
char *layout; ///< Keyboard layout
|
||||
|
||||
// Insomnia:
|
||||
|
@ -1215,6 +1225,29 @@ str_map_destroy (void *self)
|
|||
free (self);
|
||||
}
|
||||
|
||||
static void
|
||||
app_context_init_xsync (struct app_context *self)
|
||||
{
|
||||
int n;
|
||||
if (!XSyncQueryExtension (self->dpy, &self->xsync_base_event_code, &n)
|
||||
|| !XSyncInitialize (self->dpy, &n, &n))
|
||||
{
|
||||
print_error ("cannot initialize XSync");
|
||||
return;
|
||||
}
|
||||
|
||||
// The idle counter is not guaranteed to exist, only SERVERTIME is
|
||||
XSyncSystemCounter *counters = XSyncListSystemCounters (self->dpy, &n);
|
||||
while (n--)
|
||||
{
|
||||
if (!strcmp (counters[n].name, "IDLETIME"))
|
||||
self->idle_counter = counters[n].counter;
|
||||
}
|
||||
if (!self->idle_counter)
|
||||
print_error ("idle counter is missing");
|
||||
XSyncFreeSystemCounterList (counters);
|
||||
}
|
||||
|
||||
static void
|
||||
app_context_init (struct app_context *self)
|
||||
{
|
||||
|
@ -1241,6 +1274,8 @@ app_context_init (struct app_context *self)
|
|||
poller_fd_init (&self->x_event, &self->poller,
|
||||
ConnectionNumber (self->dpy));
|
||||
|
||||
app_context_init_xsync (self);
|
||||
|
||||
// So far we don't necessarily need DBus to function,
|
||||
// and we have no desire to process any incoming messages either
|
||||
DBusError err = DBUS_ERROR_INIT;
|
||||
|
@ -1551,6 +1586,77 @@ on_refresh_rest (void *user_data)
|
|||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static void
|
||||
suspend (struct app_context *ctx)
|
||||
{
|
||||
DBusMessage *msg = dbus_message_new_method_call
|
||||
("org.freedesktop.login1", "/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager", "Suspend");
|
||||
hard_assert (msg != NULL);
|
||||
|
||||
dbus_bool_t interactive = false;
|
||||
hard_assert (dbus_message_append_args (msg,
|
||||
DBUS_TYPE_BOOLEAN, &interactive,
|
||||
DBUS_TYPE_INVALID));
|
||||
|
||||
DBusError err = DBUS_ERROR_INIT;
|
||||
DBusMessage *reply = dbus_connection_send_with_reply_and_block
|
||||
(ctx->system_bus, msg, 1000, &err);
|
||||
dbus_message_unref (msg);
|
||||
if (!reply)
|
||||
{
|
||||
print_error ("%s: %s", "suspend", err.message);
|
||||
dbus_error_free (&err);
|
||||
}
|
||||
else
|
||||
dbus_message_unref (reply);
|
||||
}
|
||||
|
||||
static void
|
||||
set_idle_alarm (struct app_context *ctx,
|
||||
XSyncAlarm *alarm, XSyncTestType test, XSyncValue value)
|
||||
{
|
||||
XSyncAlarmAttributes attr;
|
||||
attr.trigger.counter = ctx->idle_counter;
|
||||
attr.trigger.test_type = test;
|
||||
attr.trigger.wait_value = value;
|
||||
XSyncIntToValue (&attr.delta, 0);
|
||||
|
||||
long flags = XSyncCACounter | XSyncCATestType | XSyncCAValue | XSyncCADelta;
|
||||
if (*alarm)
|
||||
XSyncChangeAlarm (ctx->dpy, *alarm, flags, &attr);
|
||||
else
|
||||
*alarm = XSyncCreateAlarm (ctx->dpy, flags, &attr);
|
||||
}
|
||||
|
||||
static void
|
||||
on_x_alarm_notify (struct app_context *ctx, XSyncAlarmNotifyEvent *ev)
|
||||
{
|
||||
if (ev->alarm == ctx->idle_alarm_inactive)
|
||||
{
|
||||
// Our own lock doesn't matter, we have to check it ourselves
|
||||
if (ctx->system_bus && ctx->insomnia_fd == -1)
|
||||
suspend (ctx);
|
||||
|
||||
XSyncValue one, minus_one;
|
||||
XSyncIntToValue (&one, 1);
|
||||
|
||||
Bool overflow;
|
||||
XSyncValueSubtract (&minus_one, ev->counter_value, one, &overflow);
|
||||
|
||||
// Set an alarm for IDLETIME <= current_idletime - 1
|
||||
set_idle_alarm (ctx, &ctx->idle_alarm_active,
|
||||
XSyncNegativeComparison, minus_one);
|
||||
}
|
||||
else if (ev->alarm == ctx->idle_alarm_active)
|
||||
// XXX: even though it doesn't seem to run during the time the system
|
||||
// is suspended, I haven't found any place where it is specified
|
||||
set_idle_alarm (ctx, &ctx->idle_alarm_inactive,
|
||||
XSyncPositiveComparison, ctx->idle_timeout);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static void
|
||||
command_queue_start (struct app_context *ctx)
|
||||
{
|
||||
|
@ -2386,12 +2492,6 @@ go_insomniac (struct app_context *ctx)
|
|||
static const char *why = "";
|
||||
static const char *mode = "block";
|
||||
|
||||
if (!ctx->system_bus)
|
||||
{
|
||||
ctx->insomnia_info = xstrdup_printf ("%s: %s", "Insomnia", "no DBus");
|
||||
return;
|
||||
}
|
||||
|
||||
DBusMessage *msg = dbus_message_new_method_call
|
||||
("org.freedesktop.login1", "/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager", "Inhibit");
|
||||
|
@ -2441,7 +2541,7 @@ on_insomnia (struct app_context *ctx, int arg)
|
|||
xclose (ctx->insomnia_fd);
|
||||
ctx->insomnia_fd = -1;
|
||||
}
|
||||
else
|
||||
else if (ctx->system_bus)
|
||||
go_insomniac (ctx);
|
||||
|
||||
refresh_status (ctx);
|
||||
|
@ -2556,6 +2656,8 @@ on_xkb_event (struct app_context *ctx, XkbEvent *ev)
|
|||
refresh_status (ctx);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
static void
|
||||
on_x_ready (const struct pollfd *pfd, void *user_data)
|
||||
{
|
||||
|
@ -2569,14 +2671,28 @@ on_x_ready (const struct pollfd *pfd, void *user_data)
|
|||
exit_fatal ("XNextEvent returned non-zero");
|
||||
if (ev.type == KeyPress)
|
||||
on_x_keypress (ctx, &ev.core);
|
||||
if (ev.type == ctx->xkb_base_event_code)
|
||||
else if (ev.type == ctx->xkb_base_event_code)
|
||||
on_xkb_event (ctx, &ev);
|
||||
else if (ctx->xsync_base_event_code
|
||||
&& ev.type == ctx->xsync_base_event_code + XSyncAlarmNotify)
|
||||
on_x_alarm_notify (ctx, (XSyncAlarmNotifyEvent *) &ev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
grab_keys (struct app_context *ctx)
|
||||
init_xlib_events (struct app_context *ctx)
|
||||
{
|
||||
unsigned long n;
|
||||
const char *sleep_timer = str_map_find (&ctx->config, "sleep_timer");
|
||||
if (sleep_timer && ctx->idle_counter)
|
||||
{
|
||||
if (!xstrtoul (&n, sleep_timer, 10) || !n || n > INT_MAX / 1000)
|
||||
exit_fatal ("invalid value for the sleep timer");
|
||||
XSyncIntToValue (&ctx->idle_timeout, n * 1000);
|
||||
set_idle_alarm (ctx, &ctx->idle_alarm_inactive,
|
||||
XSyncPositiveComparison, ctx->idle_timeout);
|
||||
}
|
||||
|
||||
unsigned ignored_locks =
|
||||
LockMask | XkbKeysymToModifiers (ctx->dpy, XK_Num_Lock);
|
||||
hard_assert (XkbSetIgnoreLockMods
|
||||
|
@ -2751,7 +2867,7 @@ main (int argc, char *argv[])
|
|||
poller_timer_init_and_set (&ctx.nut_reconnect, &ctx.poller,
|
||||
on_nut_reconnect, &ctx);
|
||||
|
||||
grab_keys (&ctx);
|
||||
init_xlib_events (&ctx);
|
||||
|
||||
if (i3bar)
|
||||
ctx.backend = backend_i3_new ();
|
||||
|
|
Loading…
Reference in New Issue