view src/hotkey/grab.c @ 2335:6b9d5a8b509e

automated merge
author mf0102 <0102@gmx.at>
date Wed, 23 Jan 2008 14:12:02 +0100
parents 0be42d832217
children ad45d65e9ae7
line wrap: on
line source

/*
 *  This file is part of audacious-hotkey plugin for audacious
 *
 *  Copyright (c) 2007 - 2008  Sascha Hlusiak <contact@saschahlusiak.de>
 *  Name: grab.c
 *  Description: grab.c
 * 
 *  Part of this code is from itouch-ctrl plugin.
 *  Authors of itouch-ctrl are listed below:
 *
 *  Copyright (c) 2006 - 2007 Vladimir Paskov <vlado.paskov@gmail.com>
 *
 *  Part of this code are from xmms-itouch plugin.
 *  Authors of xmms-itouch are listed below:
 *
 *  Copyright (C) 2000-2002 Ville Syrjälä <syrjala@sci.fi>
 *                         Bryn Davies <curious@ihug.com.au>
 *                         Jonathan A. Davis <davis@jdhouse.org>
 *                         Jeremy Tan <nsx@nsx.homeip.net>
 *
 *  audacious-hotkey 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 2 of the License, or
 *  (at your option) any later version.
 *
 *  audacious-hotkey 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 audacious-hotkey; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <config.h>

#include <gtk/gtk.h>
#include <gdk/gdkx.h>

#include "grab.h"
#include "plugin.h"


static gint grabbed = 0;
static unsigned int numlock_mask = 0;
static unsigned int scrolllock_mask = 0;
static unsigned int capslock_mask = 0;


/* Taken from xbindkeys */
static void get_offending_modifiers (Display * dpy)
{
	int i;
	XModifierKeymap *modmap;
	KeyCode nlock, slock;

	static int mask_table[8] = {
		ShiftMask, LockMask, ControlMask, Mod1Mask,
		Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
	};
	
	nlock = XKeysymToKeycode (dpy, XK_Num_Lock);
	slock = XKeysymToKeycode (dpy, XK_Scroll_Lock);
	
	/*
	* Find out the masks for the NumLock and ScrollLock modifiers,
	* so that we can bind the grabs for when they are enabled too.
	*/
	modmap = XGetModifierMapping (dpy);
	
	if (modmap != NULL && modmap->max_keypermod > 0)
	{
		for (i = 0; i < 8 * modmap->max_keypermod; i++)
		{
			if (modmap->modifiermap[i] == nlock && nlock != 0)
				numlock_mask = mask_table[i / modmap->max_keypermod];
			else if (modmap->modifiermap[i] == slock && slock != 0)
				scrolllock_mask = mask_table[i / modmap->max_keypermod];
		}
	}
	
	capslock_mask = LockMask;
	
	if (modmap)
		XFreeModifiermap (modmap);
}


static int x11_error_handler (Display *dpy, XErrorEvent *error)
{
	return 0;
}

/* grab required keys */
static void grab_key(HotkeyConfiguration hotkey, Display *xdisplay, Window x_root_window)
{
	unsigned int modifier = hotkey.mask & ~(numlock_mask | capslock_mask | scrolllock_mask);
	
	if (hotkey.key == 0) return;

	if (hotkey.type == TYPE_KEY)
	{
		XGrabKey (xdisplay, hotkey.key, modifier, x_root_window,
			False, GrabModeAsync, GrabModeAsync);
		
		if (modifier == AnyModifier)
			return;
		
		if (numlock_mask)
			XGrabKey (xdisplay, hotkey.key, modifier | numlock_mask,
				x_root_window,
				False, GrabModeAsync, GrabModeAsync);
		
		if (capslock_mask)
			XGrabKey (xdisplay, hotkey.key, modifier | capslock_mask,
				x_root_window,
				False, GrabModeAsync, GrabModeAsync);
		
		if (scrolllock_mask)
			XGrabKey (xdisplay, hotkey.key, modifier | scrolllock_mask,
				x_root_window,
				False, GrabModeAsync, GrabModeAsync);
		
		if (numlock_mask && capslock_mask)
			XGrabKey (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask,
				x_root_window,
				False, GrabModeAsync, GrabModeAsync);
		
		if (numlock_mask && scrolllock_mask)
			XGrabKey (xdisplay, hotkey.key, modifier | numlock_mask | scrolllock_mask,
				x_root_window,
				False, GrabModeAsync, GrabModeAsync);
		
		if (capslock_mask && scrolllock_mask)
			XGrabKey (xdisplay, hotkey.key, modifier | capslock_mask | scrolllock_mask,
				x_root_window,
				False, GrabModeAsync, GrabModeAsync);
		
		if (numlock_mask && capslock_mask && scrolllock_mask)
			XGrabKey (xdisplay, hotkey.key,
				modifier | numlock_mask | capslock_mask | scrolllock_mask,
				x_root_window, False, GrabModeAsync,
				GrabModeAsync);
	}
	if (hotkey.type == TYPE_MOUSE)
	{
		XGrabButton (xdisplay, hotkey.key, modifier, x_root_window,
			False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
		
		if (modifier == AnyModifier)
			return;
		
		if (numlock_mask)
			XGrabButton (xdisplay, hotkey.key, modifier | numlock_mask,
				x_root_window,
				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
		
		if (capslock_mask)
			XGrabButton (xdisplay, hotkey.key, modifier | capslock_mask,
				x_root_window,
				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
		
		if (scrolllock_mask)
			XGrabButton (xdisplay, hotkey.key, modifier | scrolllock_mask,
				x_root_window,
				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
		
		if (numlock_mask && capslock_mask)
			XGrabButton (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask,
				x_root_window,
				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
		
		if (numlock_mask && scrolllock_mask)
			XGrabButton (xdisplay, hotkey.key, modifier | numlock_mask | scrolllock_mask,
				x_root_window,
				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
		
		if (capslock_mask && scrolllock_mask)
			XGrabButton (xdisplay, hotkey.key, modifier | capslock_mask | scrolllock_mask,
				x_root_window,
				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
		
		if (numlock_mask && capslock_mask && scrolllock_mask)
			XGrabButton (xdisplay, hotkey.key,
				modifier | numlock_mask | capslock_mask | scrolllock_mask,
				x_root_window, False, ButtonPressMask, GrabModeAsync,
				GrabModeAsync, None, None);
	}
}

void grab_keys ( )
{
	Display* xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
	Window x_root_window = GDK_WINDOW_XID(gdk_get_default_root_window());
	PluginConfig* plugin_cfg = get_config();
	XErrorHandler old_handler = 0;

	if (grabbed) return;


	XSync(xdisplay, False);
	old_handler = XSetErrorHandler (x11_error_handler);

	get_offending_modifiers(xdisplay);

	grab_key(plugin_cfg->mute, xdisplay, x_root_window);
	grab_key(plugin_cfg->vol_up, xdisplay, x_root_window);
	grab_key(plugin_cfg->vol_down, xdisplay, x_root_window);
	grab_key(plugin_cfg->play, xdisplay, x_root_window);
	grab_key(plugin_cfg->pause, xdisplay, x_root_window);
	grab_key(plugin_cfg->stop, xdisplay, x_root_window);
	grab_key(plugin_cfg->prev_track, xdisplay, x_root_window);
	grab_key(plugin_cfg->next_track, xdisplay, x_root_window);
	grab_key(plugin_cfg->jump_to_file, xdisplay, x_root_window);
	grab_key(plugin_cfg->forward, xdisplay, x_root_window);
	grab_key(plugin_cfg->backward, xdisplay, x_root_window);
	grab_key(plugin_cfg->toggle_win, xdisplay, x_root_window);
	grab_key(plugin_cfg->show_aosd, xdisplay, x_root_window);
	
	XSync(xdisplay, False);
	XSetErrorHandler (old_handler);

	grabbed = 1;
}



/* grab required keys */
static void ungrab_key(HotkeyConfiguration hotkey, Display* xdisplay, Window x_root_window)
{
	unsigned int modifier = hotkey.mask & ~(numlock_mask | capslock_mask | scrolllock_mask);
	
	if (hotkey.key == 0) return;
	
	if (hotkey.type == TYPE_KEY)
	{
		XUngrabKey (xdisplay, hotkey.key, modifier, x_root_window);
		
		if (modifier == AnyModifier)
			return;
		
		if (numlock_mask)
			XUngrabKey (xdisplay, hotkey.key, modifier | numlock_mask, x_root_window);
	
		if (capslock_mask)
			XUngrabKey (xdisplay, hotkey.key, modifier | capslock_mask, x_root_window);
	
		if (scrolllock_mask)
			XUngrabKey (xdisplay, hotkey.key, modifier | scrolllock_mask, x_root_window);
	
		if (numlock_mask && capslock_mask)
			XUngrabKey (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask, x_root_window);
	
		if (numlock_mask && scrolllock_mask)
			XUngrabKey (xdisplay, hotkey.key, modifier | numlock_mask | scrolllock_mask, x_root_window);
	
		if (capslock_mask && scrolllock_mask)
			XUngrabKey (xdisplay, hotkey.key, modifier | capslock_mask | scrolllock_mask, x_root_window);
	
		if (numlock_mask && capslock_mask && scrolllock_mask)
			XUngrabKey (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask | scrolllock_mask, x_root_window);
	}
	if (hotkey.type == TYPE_MOUSE)
	{
		XUngrabButton (xdisplay, hotkey.key, modifier, x_root_window);
		
		if (modifier == AnyModifier)
			return;
		
		if (numlock_mask)
			XUngrabButton (xdisplay, hotkey.key, modifier | numlock_mask, x_root_window);
	
		if (capslock_mask)
			XUngrabButton (xdisplay, hotkey.key, modifier | capslock_mask, x_root_window);
	
		if (scrolllock_mask)
			XUngrabButton (xdisplay, hotkey.key, modifier | scrolllock_mask, x_root_window);
	
		if (numlock_mask && capslock_mask)
			XUngrabButton (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask, x_root_window);
	
		if (numlock_mask && scrolllock_mask)
			XUngrabButton (xdisplay, hotkey.key, modifier | numlock_mask | scrolllock_mask, x_root_window);
	
		if (capslock_mask && scrolllock_mask)
			XUngrabButton (xdisplay, hotkey.key, modifier | capslock_mask | scrolllock_mask, x_root_window);
	
		if (numlock_mask && capslock_mask && scrolllock_mask)
			XUngrabButton (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask | scrolllock_mask, x_root_window);
	}
}

void ungrab_keys ( )
{
	XErrorHandler old_handler = 0;
	Display* xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
	Window x_root_window = GDK_WINDOW_XID(gdk_get_default_root_window());
	PluginConfig* plugin_cfg = get_config();

	if (!grabbed) return;
	if (!xdisplay) return;

	XSync(xdisplay, False);
	old_handler = XSetErrorHandler (x11_error_handler);

	get_offending_modifiers(xdisplay);

	ungrab_key(plugin_cfg->mute, xdisplay, x_root_window);
	ungrab_key(plugin_cfg->vol_up, xdisplay, x_root_window);
	ungrab_key(plugin_cfg->vol_down, xdisplay, x_root_window);
	ungrab_key(plugin_cfg->play, xdisplay, x_root_window);
	ungrab_key(plugin_cfg->pause, xdisplay, x_root_window);
	ungrab_key(plugin_cfg->stop, xdisplay, x_root_window);
	ungrab_key(plugin_cfg->prev_track, xdisplay, x_root_window);
	ungrab_key(plugin_cfg->next_track, xdisplay, x_root_window);
	ungrab_key(plugin_cfg->jump_to_file, xdisplay, x_root_window);
	ungrab_key(plugin_cfg->forward, xdisplay, x_root_window);
	ungrab_key(plugin_cfg->backward, xdisplay, x_root_window);
	ungrab_key(plugin_cfg->toggle_win, xdisplay, x_root_window);
	ungrab_key(plugin_cfg->show_aosd, xdisplay, x_root_window);
	
	XSync(xdisplay, False);
	XSetErrorHandler (old_handler);

	grabbed = 0;
}


static GdkFilterReturn
gdk_filter(GdkXEvent *xevent,
	   GdkEvent *event,
	   gpointer data)
{
	switch (((XEvent*)xevent)->type)
	{
	case KeyPress:
		{
			XKeyEvent *keyevent = (XKeyEvent*)xevent;
			if (handle_keyevent(keyevent->keycode, keyevent->state & ~(scrolllock_mask | numlock_mask | capslock_mask), TYPE_KEY))
				return GDK_FILTER_REMOVE;
			break;
		}
	case ButtonPress:
		{
			XButtonEvent *buttonevent = (XButtonEvent*)xevent;
			if (handle_keyevent(buttonevent->button, buttonevent->state, TYPE_MOUSE))
				return GDK_FILTER_REMOVE;
			break;
		}
	default:
		return -1;
	}
	
	return GDK_FILTER_CONTINUE;
}

gboolean setup_filter()
{
	gdk_window_add_filter(gdk_get_default_root_window(),
				gdk_filter,
				NULL);

	return TRUE;
}

void release_filter()
{
	gdk_window_remove_filter(gdk_get_default_root_window(),
				gdk_filter,
				NULL);
}