view xia-inhibitor.c @ 3:957d697d27d3

Minimize interference with menus Fake keypresses of the left Alt key interfere with the menus of several toolkits, use the left Shift key instead.
author Guido Berhoerster <guido+xinhibit-applet@berhoerster.name>
date Sat, 27 Jul 2013 19:21:07 +0200
parents 9a16bf50daba
children 14f31e92372f
line wrap: on
line source

/*
 * Copyright (C) 2013 Guido Berhoerster <guido+xinhibit-applet@berhoerster.name>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/extensions/Xext.h>
#ifdef HAVE_LIBXTST
#include <X11/extensions/XTest.h>
#endif /* HAVE_LIBXTST */
#include <glib.h>
#include <glib/gi18n.h>
#include <gdk/gdkx.h>
#include "xia-inhibitor.h"

#define	FAKE_EVENT_TIMEOUT	20

G_DEFINE_TYPE(XiaInhibitor, xia_inhibitor, G_TYPE_OBJECT)

#define	XIA_INHIBITOR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
	XIA_TYPE_INHIBITOR, XiaInhibitorPrivate))

struct _XiaInhibitorPrivate
{
	XiaInhibitor	*inhibitor;
	gboolean	inhibited;
	gboolean	have_xtest;
	guint		generate_fake_event_id;
};

enum { PROP_0, PROP_INHIBITED };

static gboolean
generate_fake_event(gpointer data)
{
#ifdef HAVE_LIBXTST
	XiaInhibitor *self = XIA_INHIBITOR(data);
	static KeyCode keycode = 0;

	if (!self->priv->have_xtest) {
		return (TRUE);
	}

	if (keycode == 0) {
		keycode = XKeysymToKeycode(gdk_x11_get_default_xdisplay(),
		    XK_Shift_L);
		if (keycode == 0) {
			return (TRUE);
		}
	}

	XTestFakeKeyEvent(gdk_x11_get_default_xdisplay(), keycode, True, 0);
	XTestFakeKeyEvent(gdk_x11_get_default_xdisplay(), keycode, False, 0);

	g_debug("Generated fake key event using XTEST");
#endif /* HAVE_LIBXTST */

	return (TRUE);
}

static void
xia_inhibitor_set_property(GObject *object, guint property_id,
    const GValue *value, GParamSpec *pspec)
{
	XiaInhibitor	*self = XIA_INHIBITOR(object);

	switch (property_id) {
	case PROP_INHIBITED: {
		gboolean inhibited = g_value_get_boolean(value);
		if (self->priv->inhibited == inhibited) {
			return;
		}

		if (inhibited) {
			self->priv->generate_fake_event_id = \
			    g_timeout_add_seconds(FAKE_EVENT_TIMEOUT,
			    (GSourceFunc)generate_fake_event, self);
		} else {
			g_source_remove(self->priv->generate_fake_event_id);
			self->priv->generate_fake_event_id = 0;
		}

		self->priv->inhibited = inhibited;

		g_debug("Automatic power management is %s", (inhibited) ?
		    "inhibited" : "enabled");
		break;
	}
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
		break;
	}
}

static void
xia_inhibitor_get_property(GObject *object, guint property_id, GValue *value,
    GParamSpec *pspec)
{
	XiaInhibitor	*self = XIA_INHIBITOR(object);

	switch (property_id) {
		case PROP_INHIBITED:
			g_value_set_boolean(value, self->priv->inhibited);
			break;
		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id,
			    pspec);
			break;
	}
}

static void
xia_inhibitor_finalize(GObject *gobject)
{
	XiaInhibitor	*self = XIA_INHIBITOR(gobject);

	if (self->priv->generate_fake_event_id != 0) {
		g_source_remove(self->priv->generate_fake_event_id);
		self->priv->generate_fake_event_id = 0;
	}

	G_OBJECT_CLASS(xia_inhibitor_parent_class)->finalize(gobject);
}

static void
xia_inhibitor_class_init(XiaInhibitorClass *klass)
{
	GObjectClass	*gobject_class = G_OBJECT_CLASS(klass);
	GParamSpec	*pspec;

	gobject_class->set_property = xia_inhibitor_set_property;
	gobject_class->get_property = xia_inhibitor_get_property;
	gobject_class->finalize = xia_inhibitor_finalize;

	pspec = g_param_spec_boolean("inhibited", "Inhibited",
	    "Whether automatic power management is inhibited", FALSE,
	    G_PARAM_READWRITE);
	g_object_class_install_property(gobject_class, PROP_INHIBITED, pspec);

	g_type_class_add_private(klass, sizeof (XiaInhibitorPrivate));
}

static void
xia_inhibitor_init(XiaInhibitor *self)
{
#ifdef HAVE_LIBXTST
	int	event_base;
	int	error_base;
	int	xtest_major;
	int	xtest_minor;
#endif /* HAVE_LIBXTST */

	self->priv = XIA_INHIBITOR_GET_PRIVATE(self);

	self->priv->inhibited = FALSE;
	self->priv->generate_fake_event_id = 0;

#ifdef HAVE_LIBXTST
	self->priv->have_xtest = ((gboolean)XTestQueryExtension(
	    gdk_x11_get_default_xdisplay(), &event_base, &error_base,
	    &xtest_major, &xtest_minor));
#endif /* HAVE_LIBXTST */
}

void
xia_inhibitor_set_inhibited(XiaInhibitor *self, gboolean inhibited)
{
	g_return_if_fail(XIA_IS_INHIBITOR(self));

	g_object_set(G_OBJECT(self), "inhibited", inhibited, NULL);
}

gboolean
xia_inhibitor_get_inhibited(XiaInhibitor *self)
{
	gboolean inhibited;

	g_return_val_if_fail(XIA_IS_INHIBITOR(self), FALSE);

	g_object_get(G_OBJECT(self), "inhibited", &inhibited, NULL);

	return (inhibited);
}

XiaInhibitor *
xia_inhibitor_new(void)
{
	return (g_object_new(XIA_TYPE_INHIBITOR, NULL));
}