/*
* Copyright (c) 2001-2009 Hypertriton, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Application-wide hotkey bindings.
*/
#include
#include
struct ag_global_key {
AG_KeySym keysym;
AG_KeyMod keymod;
void (*fn)(void);
void (*fn_ev)(AG_Event *);
SLIST_ENTRY(ag_global_key) gkeys;
};
static SLIST_HEAD_(ag_global_key) agGlobalKeys;
#ifdef AG_THREADS
static AG_Mutex agGlobalKeysLock;
#endif
/* Initialize the global keys table. */
void
AG_InitGlobalKeys(void)
{
AG_MutexInitRecursive(&agGlobalKeysLock);
SLIST_INIT(&agGlobalKeys);
}
/* Clear the global keys table. */
void
AG_DestroyGlobalKeys(void)
{
AG_ClearGlobalKeys();
AG_MutexDestroy(&agGlobalKeysLock);
}
/* Tie a global hotkey to a callback function. */
void
AG_BindGlobalKey(AG_KeySym keysym, AG_KeyMod keymod, void (*fn)(void))
{
struct ag_global_key *gk;
gk = Malloc(sizeof(struct ag_global_key));
gk->keysym = keysym;
gk->keymod = keymod;
gk->fn = fn;
gk->fn_ev = NULL;
AG_MutexLock(&agGlobalKeysLock);
SLIST_INSERT_HEAD(&agGlobalKeys, gk, gkeys);
AG_MutexUnlock(&agGlobalKeysLock);
}
/*
* Set up some standard, platform-specific hotkey bindings for controlling
* zoom or exiting the application.
*/
void
AG_BindStdGlobalKeys(void)
{
#ifdef __APPLE__
AG_BindGlobalKey(AG_KEY_EQUALS, AG_KEYMOD_META, AG_ZoomIn);
AG_BindGlobalKey(AG_KEY_MINUS, AG_KEYMOD_META, AG_ZoomOut);
AG_BindGlobalKey(AG_KEY_0, AG_KEYMOD_META, AG_ZoomReset);
AG_BindGlobalKey(AG_KEY_Q, AG_KEYMOD_META, AG_QuitGUI);
#else
AG_BindGlobalKey(AG_KEY_EQUALS, AG_KEYMOD_CTRL, AG_ZoomIn);
AG_BindGlobalKey(AG_KEY_MINUS, AG_KEYMOD_CTRL, AG_ZoomOut);
AG_BindGlobalKey(AG_KEY_0, AG_KEYMOD_CTRL, AG_ZoomReset);
AG_BindGlobalKey(AG_KEY_Q, AG_KEYMOD_CTRL, AG_QuitGUI);
#endif
AG_BindGlobalKey(AG_KEY_ESCAPE, AG_KEYMOD_ANY, AG_CloseFocusedWindow);
}
/* Tie a global hotkey to a callback function (AG_Event style). */
void
AG_BindGlobalKeyEv(AG_KeySym keysym, AG_KeyMod keymod,
void (*fn_ev)(AG_Event *))
{
struct ag_global_key *gk;
gk = Malloc(sizeof(struct ag_global_key));
gk->keysym = keysym;
gk->keymod = keymod;
gk->fn = NULL;
gk->fn_ev = fn_ev;
AG_MutexLock(&agGlobalKeysLock);
SLIST_INSERT_HEAD(&agGlobalKeys, gk, gkeys);
AG_MutexUnlock(&agGlobalKeysLock);
}
/* Unregister a hotkey. */
int
AG_UnbindGlobalKey(AG_KeySym keysym, AG_KeyMod keymod)
{
struct ag_global_key *gk;
AG_MutexLock(&agGlobalKeysLock);
SLIST_FOREACH(gk, &agGlobalKeys, gkeys) {
if (gk->keysym == keysym && gk->keymod == keymod) {
SLIST_REMOVE(&agGlobalKeys, gk, ag_global_key, gkeys);
free(gk);
AG_MutexUnlock(&agGlobalKeysLock);
return (0);
}
}
AG_MutexUnlock(&agGlobalKeysLock);
AG_SetError("No such key binding");
return (-1);
}
/* Free the table of hotkeys. */
void
AG_ClearGlobalKeys(void)
{
struct ag_global_key *gk, *gkNext;
AG_MutexLock(&agGlobalKeysLock);
for (gk = SLIST_FIRST(&agGlobalKeys);
gk != SLIST_END(&agGlobalKeys);
gk = gkNext) {
gkNext = SLIST_NEXT(gk, gkeys);
free(gk);
}
SLIST_INIT(&agGlobalKeys);
AG_MutexUnlock(&agGlobalKeysLock);
}
/* Execute any action tied to a hotkey. */
int
AG_ExecGlobalKeys(AG_KeySym sym, AG_KeyMod mod)
{
struct ag_global_key *gk;
int rv = 0;
AG_MutexLock(&agGlobalKeysLock);
SLIST_FOREACH(gk, &agGlobalKeys, gkeys) {
if ((gk->keysym == AG_KEY_ANY || gk->keysym == sym) &&
(gk->keymod == AG_KEYMOD_ANY || gk->keymod & mod)) {
if (gk->fn != NULL) {
gk->fn();
} else if (gk->fn_ev != NULL) {
gk->fn_ev(NULL);
}
rv = 1;
}
}
AG_MutexUnlock(&agGlobalKeysLock);
return (rv);
}