1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-19 12:28:22 +01:00
Files
wmaker/WPrefs.app/KeyboardShortcuts.c
2004-10-12 21:28:27 +00:00

655 lines
20 KiB
C

/* KeyboardShortcuts.c- keyboard shortcut bindings
*
* WPrefs - Window Maker Preferences Program
*
* Copyright (c) 1998-2003 Alfredo K. Kojima
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#include "config.h" /* for HAVE_XCONVERTCASE */
#include "WPrefs.h"
#include <ctype.h>
#include <X11/keysym.h>
typedef struct _Panel {
WMBox *box;
char *sectionName;
char *description;
CallbackRec callbacks;
WMWidget *parent;
WMLabel *actL;
WMList *actLs;
WMFrame *shoF;
WMTextField *shoT;
WMButton *cleB;
WMButton *defB;
WMLabel *instructionsL;
WMColor *white;
WMColor *black;
WMColor *gray;
WMFont *font;
/**/
char capturing;
char **shortcuts;
int actionCount;
} _Panel;
#define ICON_FILE "keyshortcuts"
/* must be in the same order as the corresponding items in actions list */
static char *keyOptions[] = {
"RootMenuKey",
"WindowListKey",
"WindowMenuKey",
"HideKey",
"HideOthersKey",
"MiniaturizeKey",
"CloseKey",
"MaximizeKey",
"VMaximizeKey",
"HMaximizeKey",
"RaiseKey",
"LowerKey",
"RaiseLowerKey",
"ShadeKey",
"MoveResizeKey",
"SelectKey",
"FocusNextKey",
"FocusPrevKey",
"NextWorkspaceKey",
"PrevWorkspaceKey",
"NextWorkspaceLayerKey",
"PrevWorkspaceLayerKey",
"Workspace1Key",
"Workspace2Key",
"Workspace3Key",
"Workspace4Key",
"Workspace5Key",
"Workspace6Key",
"Workspace7Key",
"Workspace8Key",
"Workspace9Key",
"Workspace10Key",
"WindowShortcut1Key",
"WindowShortcut2Key",
"WindowShortcut3Key",
"WindowShortcut4Key",
"WindowShortcut5Key",
"WindowShortcut6Key",
"WindowShortcut7Key",
"WindowShortcut8Key",
"WindowShortcut9Key",
"WindowShortcut10Key",
"ScreenSwitchKey",
#ifdef VIRTUAL_DESKTOP
"VirtualEdgeLeftKey",
"VirtualEdgeRightKey",
"VirtualEdgeUpKey",
"VirtualEdgeDownKey",
#endif
"ClipRaiseKey",
"ClipLowerKey",
#ifndef XKB_MODELOCK
"ClipRaiseLowerKey"
#else
"ClipRaiseLowerKey",
"ToggleKbdModeKey"
#endif /* XKB_MODELOCK */
};
#ifndef HAVE_XCONVERTCASE
/* from Xlib */
static void
XConvertCase(register KeySym sym, KeySym *lower, KeySym *upper)
{
*lower = sym;
*upper = sym;
switch(sym >> 8) {
case 0: /* Latin 1 */
if ((sym >= XK_A) && (sym <= XK_Z))
*lower += (XK_a - XK_A);
else if ((sym >= XK_a) && (sym <= XK_z))
*upper -= (XK_a - XK_A);
else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
*lower += (XK_agrave - XK_Agrave);
else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
*upper -= (XK_agrave - XK_Agrave);
else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
*lower += (XK_oslash - XK_Ooblique);
else if ((sym >= XK_oslash) && (sym <= XK_thorn))
*upper -= (XK_oslash - XK_Ooblique);
break;
case 1: /* Latin 2 */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym == XK_Aogonek)
*lower = XK_aogonek;
else if (sym >= XK_Lstroke && sym <= XK_Sacute)
*lower += (XK_lstroke - XK_Lstroke);
else if (sym >= XK_Scaron && sym <= XK_Zacute)
*lower += (XK_scaron - XK_Scaron);
else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
*lower += (XK_zcaron - XK_Zcaron);
else if (sym == XK_aogonek)
*upper = XK_Aogonek;
else if (sym >= XK_lstroke && sym <= XK_sacute)
*upper -= (XK_lstroke - XK_Lstroke);
else if (sym >= XK_scaron && sym <= XK_zacute)
*upper -= (XK_scaron - XK_Scaron);
else if (sym >= XK_zcaron && sym <= XK_zabovedot)
*upper -= (XK_zcaron - XK_Zcaron);
else if (sym >= XK_Racute && sym <= XK_Tcedilla)
*lower += (XK_racute - XK_Racute);
else if (sym >= XK_racute && sym <= XK_tcedilla)
*upper -= (XK_racute - XK_Racute);
break;
case 2: /* Latin 3 */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
*lower += (XK_hstroke - XK_Hstroke);
else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
*lower += (XK_gbreve - XK_Gbreve);
else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
*upper -= (XK_hstroke - XK_Hstroke);
else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
*upper -= (XK_gbreve - XK_Gbreve);
else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
*lower += (XK_cabovedot - XK_Cabovedot);
else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
*upper -= (XK_cabovedot - XK_Cabovedot);
break;
case 3: /* Latin 4 */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym >= XK_Rcedilla && sym <= XK_Tslash)
*lower += (XK_rcedilla - XK_Rcedilla);
else if (sym >= XK_rcedilla && sym <= XK_tslash)
*upper -= (XK_rcedilla - XK_Rcedilla);
else if (sym == XK_ENG)
*lower = XK_eng;
else if (sym == XK_eng)
*upper = XK_ENG;
else if (sym >= XK_Amacron && sym <= XK_Umacron)
*lower += (XK_amacron - XK_Amacron);
else if (sym >= XK_amacron && sym <= XK_umacron)
*upper -= (XK_amacron - XK_Amacron);
break;
case 6: /* Cyrillic */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
*lower -= (XK_Serbian_DJE - XK_Serbian_dje);
else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
*upper += (XK_Serbian_DJE - XK_Serbian_dje);
else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
*lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
*upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
break;
case 7: /* Greek */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
*lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
sym != XK_Greek_iotaaccentdieresis &&
sym != XK_Greek_upsilonaccentdieresis)
*upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
*lower += (XK_Greek_alpha - XK_Greek_ALPHA);
else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
sym != XK_Greek_finalsmallsigma)
*upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
break;
case 0x14: /* Armenian */
if (sym >= XK_Armenian_AYB && sym <= XK_Armenian_fe) {
*lower = sym | 1;
*upper = sym & ~1;
}
break;
}
}
#endif
static char*
captureShortcut(Display *dpy, _Panel *panel)
{
XEvent ev;
KeySym ksym, lksym, uksym;
char buffer[64];
char *key = NULL;
while (panel->capturing) {
XAllowEvents(dpy, AsyncKeyboard, CurrentTime);
WMNextEvent(dpy, &ev);
if (ev.type==KeyPress && ev.xkey.keycode!=0) {
ksym = XKeycodeToKeysym(dpy, ev.xkey.keycode, 0);
if (!IsModifierKey(ksym)) {
XConvertCase(ksym, &lksym, &uksym);
key=XKeysymToString(uksym);
panel->capturing = 0;
break;
}
}
WMHandleEvent(&ev);
}
if (!key)
return NULL;
buffer[0] = 0;
if (ev.xkey.state & ControlMask) {
strcat(buffer, "Control+");
}
if (ev.xkey.state & ShiftMask) {
strcat(buffer, "Shift+");
}
if (ev.xkey.state & Mod1Mask) {
strcat(buffer, "Mod1+");
}
if (ev.xkey.state & Mod2Mask) {
strcat(buffer, "Mod2+");
}
if (ev.xkey.state & Mod3Mask) {
strcat(buffer, "Mod3+");
}
if (ev.xkey.state & Mod4Mask) {
strcat(buffer, "Mod4+");
}
if (ev.xkey.state & Mod5Mask) {
strcat(buffer, "Mod5+");
}
strcat(buffer, key);
return wstrdup(buffer);
}
static void
captureClick(WMWidget *w, void *data)
{
_Panel *panel = (_Panel*)data;
Display *dpy = WMScreenDisplay(WMWidgetScreen(panel->parent));
char *shortcut;
if (!panel->capturing) {
panel->capturing = 1;
WMSetButtonText(w, _("Cancel"));
WMSetLabelText(panel->instructionsL, _("Press the desired shortcut key(s) or click Cancel to stop capturing."));
XGrabKeyboard(dpy, WMWidgetXID(panel->parent), True, GrabModeAsync,
GrabModeAsync, CurrentTime);
shortcut = captureShortcut(dpy, panel);
if (shortcut) {
int row = WMGetListSelectedItemRow(panel->actLs);
WMSetTextFieldText(panel->shoT, shortcut);
if (row>=0) {
if (panel->shortcuts[row])
wfree(panel->shortcuts[row]);
panel->shortcuts[row] = shortcut;
WMRedisplayWidget(panel->actLs);
} else {
wfree(shortcut);
}
}
}
panel->capturing = 0;
WMSetButtonText(w, _("Capture"));
WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key."));
XUngrabKeyboard(dpy, CurrentTime);
}
static void
clearShortcut(WMWidget *w, void *data)
{
_Panel *panel = (_Panel*)data;
int row = WMGetListSelectedItemRow(panel->actLs);
WMSetTextFieldText(panel->shoT, NULL);
if (row>=0) {
if (panel->shortcuts[row])
wfree(panel->shortcuts[row]);
panel->shortcuts[row]=NULL;
WMRedisplayWidget(panel->actLs);
}
}
static void
typedKeys(void *observerData, WMNotification *notification)
{
_Panel *panel = (_Panel*)observerData;
int row = WMGetListSelectedItemRow(panel->actLs);
if (row<0)
return;
if (panel->shortcuts[row])
wfree(panel->shortcuts[row]);
panel->shortcuts[row] = WMGetTextFieldText(panel->shoT);
if (strlen(panel->shortcuts[row])==0) {
wfree(panel->shortcuts[row]);
panel->shortcuts[row] = NULL;
}
WMRedisplayWidget(panel->actLs);
}
static void
listClick(WMWidget *w, void *data)
{
_Panel *panel = (_Panel*)data;
int row = WMGetListSelectedItemRow(w);
WMSetTextFieldText(panel->shoT, panel->shortcuts[row]);
}
static char*
trimstr(char *str)
{
char *p = str;
int i;
while (isspace(*p)) p++;
p = wstrdup(p);
i = strlen(p);
while (isspace(p[i]) && i>0) {
p[i]=0;
i--;
}
return p;
}
static void
showData(_Panel *panel)
{
char *str;
int i;
for (i=0; i<panel->actionCount; i++) {
str = GetStringForKey(keyOptions[i]);
if (panel->shortcuts[i])
wfree(panel->shortcuts[i]);
if (str)
panel->shortcuts[i] = trimstr(str);
else
panel->shortcuts[i] = NULL;
if (panel->shortcuts[i] &&
(strcasecmp(panel->shortcuts[i], "none")==0
|| strlen(panel->shortcuts[i])==0)) {
wfree(panel->shortcuts[i]);
panel->shortcuts[i] = NULL;
}
}
WMRedisplayWidget(panel->actLs);
}
static void
paintItem(WMList *lPtr, int index, Drawable d, char *text, int state,
WMRect *rect)
{
int width, height, x, y;
_Panel *panel = (_Panel*)WMGetHangedData(lPtr);
WMScreen *scr = WMWidgetScreen(lPtr);
Display *dpy = WMScreenDisplay(scr);
WMColor *backColor = (state & WLDSSelected) ? panel->white : panel->gray;
width = rect->size.width;
height = rect->size.height;
x = rect->pos.x;
y = rect->pos.y;
XFillRectangle(dpy, d, WMColorGC(backColor), x, y, width, height);
if (panel->shortcuts[index]) {
WMPixmap *pix = WMGetSystemPixmap(scr, WSICheckMark);
WMSize size = WMGetPixmapSize(pix);
WMDrawPixmap(pix, d, x+(20-size.width)/2, (height-size.height)/2+y);
WMReleasePixmap(pix);
}
WMDrawString(scr, d, panel->black, panel->font, x+20, y, text, strlen(text));
}
static void
createPanel(Panel *p)
{
_Panel *panel = (_Panel*)p;
WMScreen *scr = WMWidgetScreen(panel->parent);
WMColor *color;
WMFont *boldFont;
panel->capturing = 0;
panel->white = WMWhiteColor(scr);
panel->black = WMBlackColor(scr);
panel->gray = WMGrayColor(scr);
panel->font = WMSystemFontOfSize(scr, 12);
panel->box = WMCreateBox(panel->parent);
WMSetViewExpandsToParent(WMWidgetView(panel->box), 2, 2, 2, 2);
boldFont = WMBoldSystemFontOfSize(scr, 12);
/* **************** Actions **************** */
panel->actL = WMCreateLabel(panel->box);
WMResizeWidget(panel->actL, 280, 20);
WMMoveWidget(panel->actL, 20, 10);
WMSetLabelFont(panel->actL, boldFont);
WMSetLabelText(panel->actL, _("Actions"));
WMSetLabelRelief(panel->actL, WRSunken);
WMSetLabelTextAlignment(panel->actL, WACenter);
color = WMDarkGrayColor(scr);
WMSetWidgetBackgroundColor(panel->actL, color);
WMReleaseColor(color);
WMSetLabelTextColor(panel->actL, panel->white);
panel->actLs = WMCreateList(panel->box);
WMResizeWidget(panel->actLs, 280, 190);
WMMoveWidget(panel->actLs, 20, 32);
WMSetListUserDrawProc(panel->actLs, paintItem);
WMHangData(panel->actLs, panel);
WMAddListItem(panel->actLs, _("Open applications menu"));
WMAddListItem(panel->actLs, _("Open window list menu"));
WMAddListItem(panel->actLs, _("Open window commands menu"));
WMAddListItem(panel->actLs, _("Hide active application"));
WMAddListItem(panel->actLs, _("Hide other applications"));
WMAddListItem(panel->actLs, _("Miniaturize active window"));
WMAddListItem(panel->actLs, _("Close active window"));
WMAddListItem(panel->actLs, _("Maximize active window"));
WMAddListItem(panel->actLs, _("Maximize active window vertically"));
WMAddListItem(panel->actLs, _("Maximize active window horizontally"));
WMAddListItem(panel->actLs, _("Raise active window"));
WMAddListItem(panel->actLs, _("Lower active window"));
WMAddListItem(panel->actLs, _("Raise/Lower window under mouse pointer"));
WMAddListItem(panel->actLs, _("Shade active window"));
WMAddListItem(panel->actLs, _("Move/Resize active window"));
WMAddListItem(panel->actLs, _("Select active window"));
WMAddListItem(panel->actLs, _("Focus next window"));
WMAddListItem(panel->actLs, _("Focus previous window"));
WMAddListItem(panel->actLs, _("Switch to next workspace"));
WMAddListItem(panel->actLs, _("Switch to previous workspace"));
WMAddListItem(panel->actLs, _("Switch to next ten workspaces"));
WMAddListItem(panel->actLs, _("Switch to previous ten workspaces"));
WMAddListItem(panel->actLs, _("Switch to workspace 1"));
WMAddListItem(panel->actLs, _("Switch to workspace 2"));
WMAddListItem(panel->actLs, _("Switch to workspace 3"));
WMAddListItem(panel->actLs, _("Switch to workspace 4"));
WMAddListItem(panel->actLs, _("Switch to workspace 5"));
WMAddListItem(panel->actLs, _("Switch to workspace 6"));
WMAddListItem(panel->actLs, _("Switch to workspace 7"));
WMAddListItem(panel->actLs, _("Switch to workspace 8"));
WMAddListItem(panel->actLs, _("Switch to workspace 9"));
WMAddListItem(panel->actLs, _("Switch to workspace 10"));
WMAddListItem(panel->actLs, _("Shortcut for window 1"));
WMAddListItem(panel->actLs, _("Shortcut for window 2"));
WMAddListItem(panel->actLs, _("Shortcut for window 3"));
WMAddListItem(panel->actLs, _("Shortcut for window 4"));
WMAddListItem(panel->actLs, _("Shortcut for window 5"));
WMAddListItem(panel->actLs, _("Shortcut for window 6"));
WMAddListItem(panel->actLs, _("Shortcut for window 7"));
WMAddListItem(panel->actLs, _("Shortcut for window 8"));
WMAddListItem(panel->actLs, _("Shortcut for window 9"));
WMAddListItem(panel->actLs, _("Shortcut for window 10"));
WMAddListItem(panel->actLs, _("Switch to Next Screen/Monitor"));
#ifdef VIRTUAL_DESKTOP
WMAddListItem(panel->actLs, _("Move VirtualDesktop to next left edge"));
WMAddListItem(panel->actLs, _("Move VirtualDesktop to next right edge"));
WMAddListItem(panel->actLs, _("Move VirtualDesktop to next top edge"));
WMAddListItem(panel->actLs, _("Move VirtualDesktop to next bottom edge"));
#endif
WMAddListItem(panel->actLs, _("Raise Clip"));
WMAddListItem(panel->actLs, _("Lower Clip"));
WMAddListItem(panel->actLs, _("Raise/Lower Clip"));
#ifdef XKB_MODELOCK
WMAddListItem(panel->actLs, _("Toggle keyboard language"));
#endif /* XKB_MODELOCK */
WMSetListAction(panel->actLs, listClick, panel);
panel->actionCount = WMGetListNumberOfRows(panel->actLs);
panel->shortcuts = wmalloc(sizeof(char*)*panel->actionCount);
memset(panel->shortcuts, 0, sizeof(char*)*panel->actionCount);
/***************** Shortcut ****************/
panel->shoF = WMCreateFrame(panel->box);
WMResizeWidget(panel->shoF, 190, 210);
WMMoveWidget(panel->shoF, 315, 10);
WMSetFrameTitle(panel->shoF, _("Shortcut"));
panel->shoT = WMCreateTextField(panel->shoF);
WMResizeWidget(panel->shoT, 160, 20);
WMMoveWidget(panel->shoT, 15, 65);
WMAddNotificationObserver(typedKeys, panel,
WMTextDidChangeNotification, panel->shoT);
panel->cleB = WMCreateCommandButton(panel->shoF);
WMResizeWidget(panel->cleB, 75, 24);
WMMoveWidget(panel->cleB, 15, 95);
WMSetButtonText(panel->cleB, _("Clear"));
WMSetButtonAction(panel->cleB, clearShortcut, panel);
panel->defB = WMCreateCommandButton(panel->shoF);
WMResizeWidget(panel->defB, 75, 24);
WMMoveWidget(panel->defB, 100, 95);
WMSetButtonText(panel->defB, _("Capture"));
WMSetButtonAction(panel->defB, captureClick, panel);
panel->instructionsL = WMCreateLabel(panel->shoF);
WMResizeWidget(panel->instructionsL, 160, 55);
WMMoveWidget(panel->instructionsL, 15, 140);
WMSetLabelTextAlignment(panel->instructionsL, WACenter);
WMSetLabelWraps(panel->instructionsL, True);
WMSetLabelText(panel->instructionsL, _("Click on Capture to interactively define the shortcut key."));
WMMapSubwidgets(panel->shoF);
WMReleaseFont(boldFont);
WMRealizeWidget(panel->box);
WMMapSubwidgets(panel->box);
showData(panel);
}
static void
storeData(_Panel *panel)
{
int i;
char *str;
for (i=0; i<panel->actionCount; i++) {
str = NULL;
if (panel->shortcuts[i]) {
str = trimstr(panel->shortcuts[i]);
if (strlen(str)==0) {
wfree(str);
str = NULL;
}
}
if (str) {
SetStringForKey(str, keyOptions[i]);
wfree(str);
} else {
SetStringForKey("None", keyOptions[i]);
}
}
}
Panel*
InitKeyboardShortcuts(WMScreen *scr, WMWidget *parent)
{
_Panel *panel;
panel = wmalloc(sizeof(_Panel));
memset(panel, 0, sizeof(_Panel));
panel->sectionName = _("Keyboard Shortcut Preferences");
panel->description = _("Change the keyboard shortcuts for actions such\n"
"as changing workspaces and opening menus.");
panel->parent = parent;
panel->callbacks.createWidgets = createPanel;
panel->callbacks.updateDomain = storeData;
AddSection(panel, ICON_FILE);
return panel;
}