wmstatus: add a sleep timer
Since GNOME Settings Daemon doesn't work.
This commit is contained in:
		
							
								
								
									
										142
									
								
								wmstatus.c
									
									
									
									
									
								
							
							
						
						
									
										142
									
								
								wmstatus.c
									
									
									
									
									
								
							@@ -35,6 +35,7 @@
 | 
				
			|||||||
#include <X11/keysym.h>
 | 
					#include <X11/keysym.h>
 | 
				
			||||||
#include <X11/XF86keysym.h>
 | 
					#include <X11/XF86keysym.h>
 | 
				
			||||||
#include <X11/XKBlib.h>
 | 
					#include <X11/XKBlib.h>
 | 
				
			||||||
 | 
					#include <X11/extensions/sync.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pulse/mainloop.h>
 | 
					#include <pulse/mainloop.h>
 | 
				
			||||||
#include <pulse/context.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" },
 | 
						{ "nut_load_power",  NULL,              "ups.realpower.nominal override" },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{ "command",         NULL,              "command to run for more info"   },
 | 
						{ "command",         NULL,              "command to run for more info"   },
 | 
				
			||||||
 | 
						{ "sleep_timer",     NULL,              "idle seconds to suspend after"  },
 | 
				
			||||||
	{ NULL,              NULL,              NULL                             }
 | 
						{ NULL,              NULL,              NULL                             }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1148,7 +1149,7 @@ struct app_context
 | 
				
			|||||||
	struct backend *backend;            ///< WM backend
 | 
						struct backend *backend;            ///< WM backend
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Display *dpy;                       ///< X display handle
 | 
						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
 | 
						const char *prefix;                 ///< User-defined prefix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct poller poller;               ///< Poller
 | 
						struct poller poller;               ///< Poller
 | 
				
			||||||
@@ -1156,6 +1157,15 @@ struct app_context
 | 
				
			|||||||
	struct poller_timer make_context;   ///< Start PulseAudio communication
 | 
						struct poller_timer make_context;   ///< Start PulseAudio communication
 | 
				
			||||||
	struct poller_timer refresh_rest;   ///< Refresh unpollable information
 | 
						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:
 | 
						// Command:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct poller_timer command_start;  ///< Start the command
 | 
						struct poller_timer command_start;  ///< Start the command
 | 
				
			||||||
@@ -1167,7 +1177,7 @@ struct app_context
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Hotkeys:
 | 
						// Hotkeys:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct poller_fd x_event;           ///< X11 event
 | 
						int xkb_base_event_code;            ///< Xkb base event code
 | 
				
			||||||
	char *layout;                       ///< Keyboard layout
 | 
						char *layout;                       ///< Keyboard layout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Insomnia:
 | 
						// Insomnia:
 | 
				
			||||||
@@ -1215,6 +1225,29 @@ str_map_destroy (void *self)
 | 
				
			|||||||
	free (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
 | 
					static void
 | 
				
			||||||
app_context_init (struct app_context *self)
 | 
					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,
 | 
						poller_fd_init (&self->x_event, &self->poller,
 | 
				
			||||||
		ConnectionNumber (self->dpy));
 | 
							ConnectionNumber (self->dpy));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						app_context_init_xsync (self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// So far we don't necessarily need DBus to function,
 | 
						// So far we don't necessarily need DBus to function,
 | 
				
			||||||
	// and we have no desire to process any incoming messages either
 | 
						// and we have no desire to process any incoming messages either
 | 
				
			||||||
	DBusError err = DBUS_ERROR_INIT;
 | 
						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
 | 
					static void
 | 
				
			||||||
command_queue_start (struct app_context *ctx)
 | 
					command_queue_start (struct app_context *ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -2386,12 +2492,6 @@ go_insomniac (struct app_context *ctx)
 | 
				
			|||||||
	static const char *why = "";
 | 
						static const char *why = "";
 | 
				
			||||||
	static const char *mode = "block";
 | 
						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
 | 
						DBusMessage *msg = dbus_message_new_method_call
 | 
				
			||||||
		("org.freedesktop.login1", "/org/freedesktop/login1",
 | 
							("org.freedesktop.login1", "/org/freedesktop/login1",
 | 
				
			||||||
		"org.freedesktop.login1.Manager", "Inhibit");
 | 
							"org.freedesktop.login1.Manager", "Inhibit");
 | 
				
			||||||
@@ -2441,7 +2541,7 @@ on_insomnia (struct app_context *ctx, int arg)
 | 
				
			|||||||
		xclose (ctx->insomnia_fd);
 | 
							xclose (ctx->insomnia_fd);
 | 
				
			||||||
		ctx->insomnia_fd = -1;
 | 
							ctx->insomnia_fd = -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else
 | 
						else if (ctx->system_bus)
 | 
				
			||||||
		go_insomniac (ctx);
 | 
							go_insomniac (ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	refresh_status (ctx);
 | 
						refresh_status (ctx);
 | 
				
			||||||
@@ -2556,6 +2656,8 @@ on_xkb_event (struct app_context *ctx, XkbEvent *ev)
 | 
				
			|||||||
	refresh_status (ctx);
 | 
						refresh_status (ctx);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
on_x_ready (const struct pollfd *pfd, void *user_data)
 | 
					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");
 | 
								exit_fatal ("XNextEvent returned non-zero");
 | 
				
			||||||
		if (ev.type == KeyPress)
 | 
							if (ev.type == KeyPress)
 | 
				
			||||||
			on_x_keypress (ctx, &ev.core);
 | 
								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);
 | 
								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
 | 
					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 =
 | 
						unsigned ignored_locks =
 | 
				
			||||||
		LockMask | XkbKeysymToModifiers (ctx->dpy, XK_Num_Lock);
 | 
							LockMask | XkbKeysymToModifiers (ctx->dpy, XK_Num_Lock);
 | 
				
			||||||
	hard_assert (XkbSetIgnoreLockMods
 | 
						hard_assert (XkbSetIgnoreLockMods
 | 
				
			||||||
@@ -2751,7 +2867,7 @@ main (int argc, char *argv[])
 | 
				
			|||||||
	poller_timer_init_and_set (&ctx.nut_reconnect, &ctx.poller,
 | 
						poller_timer_init_and_set (&ctx.nut_reconnect, &ctx.poller,
 | 
				
			||||||
		on_nut_reconnect, &ctx);
 | 
							on_nut_reconnect, &ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	grab_keys (&ctx);
 | 
						init_xlib_events (&ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (i3bar)
 | 
						if (i3bar)
 | 
				
			||||||
		ctx.backend = backend_i3_new ();
 | 
							ctx.backend = backend_i3_new ();
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user