add actions for key/mouse bindings etc
This commit is contained in:
parent
a86421d7d8
commit
ad44e8a708
7 changed files with 427 additions and 408 deletions
|
@ -20,11 +20,11 @@ ob3_LDADD=@LIBINTL@ ../render/librender.a
|
||||||
ob3_LDFLAGS=-export-dynamic
|
ob3_LDFLAGS=-export-dynamic
|
||||||
ob3_SOURCES=client.c event.c extensions.c focus.c frame.c openbox.c prop.c \
|
ob3_SOURCES=client.c event.c extensions.c focus.c frame.c openbox.c prop.c \
|
||||||
screen.c stacking.c xerror.c themerc.c timer.c dispatch.c \
|
screen.c stacking.c xerror.c themerc.c timer.c dispatch.c \
|
||||||
engine.c plugin.c
|
engine.c plugin.c action.c
|
||||||
|
|
||||||
noinst_HEADERS=client.h event.h extensions.h focus.h frame.h geom.h gettext.h \
|
noinst_HEADERS=client.h event.h extensions.h focus.h frame.h geom.h gettext.h \
|
||||||
openbox.h prop.h screen.h stacking.h xerror.h themerc.h dispatch.h \
|
openbox.h prop.h screen.h stacking.h xerror.h themerc.h dispatch.h \
|
||||||
timer.h engine.h plugin.h
|
timer.h engine.h plugin.h action.h
|
||||||
|
|
||||||
MAINTAINERCLEANFILES= Makefile.in
|
MAINTAINERCLEANFILES= Makefile.in
|
||||||
|
|
||||||
|
|
346
openbox/action.c
Normal file
346
openbox/action.c
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
#include "client.h"
|
||||||
|
#include "stacking.h"
|
||||||
|
#include "screen.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
void action_execute(char *path)
|
||||||
|
{
|
||||||
|
GError *e;
|
||||||
|
if (!g_spawn_command_line_async(path, &e)) {
|
||||||
|
g_warning("failed to execute '%s': %s", path, e->message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_iconify(Client *c)
|
||||||
|
{
|
||||||
|
client_iconify(c, TRUE, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_raise(Client *c)
|
||||||
|
{
|
||||||
|
stacking_raise(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_lower(Client *c)
|
||||||
|
{
|
||||||
|
stacking_lower(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_close(Client *c)
|
||||||
|
{
|
||||||
|
client_close(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_shade(Client *c)
|
||||||
|
{
|
||||||
|
client_shade(c, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_unshade(Client *c)
|
||||||
|
{
|
||||||
|
client_shade(c, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_toggle_shade(Client *c)
|
||||||
|
{
|
||||||
|
client_shade(c, !c->shaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_toggle_omnipresent(Client *c)
|
||||||
|
{
|
||||||
|
client_set_desktop(c, c->desktop == DESKTOP_ALL ?
|
||||||
|
screen_desktop : DESKTOP_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_move_relative(Client *c, int dx, int dy)
|
||||||
|
{
|
||||||
|
client_configure(c, Corner_TopLeft, c->area.x + dx, c->area.y + dy,
|
||||||
|
c->area.width, c->area.height, TRUE, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_resize_relative(Client *c, int dx, int dy)
|
||||||
|
{
|
||||||
|
client_configure(c, Corner_TopLeft, c->area.x, c->area.y,
|
||||||
|
c->area.width + dx, c->area.height + dy, TRUE, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_maximize_full(Client *c)
|
||||||
|
{
|
||||||
|
client_maximize(c, TRUE, 0, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_unmaximize_full(Client *c)
|
||||||
|
{
|
||||||
|
client_maximize(c, FALSE, 0, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_toggle_maximize_full(Client *c)
|
||||||
|
{
|
||||||
|
client_maximize(c, !(c->max_horz || c->max_vert), 0, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_maximize_horz(Client *c)
|
||||||
|
{
|
||||||
|
client_maximize(c, TRUE, 1, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_unmaximize_horz(Client *c)
|
||||||
|
{
|
||||||
|
client_maximize(c, FALSE, 1, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_toggle_maximize_horz(Client *c)
|
||||||
|
{
|
||||||
|
client_maximize(c, !c->max_horz, 1, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_maximize_vert(Client *c)
|
||||||
|
{
|
||||||
|
client_maximize(c, TRUE, 2, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_unmaximize_vert(Client *c)
|
||||||
|
{
|
||||||
|
client_maximize(c, FALSE, 2, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_toggle_maximize_vert(Client *c)
|
||||||
|
{
|
||||||
|
client_maximize(c, !c->max_vert, 2, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_send_to_desktop(Client *c, guint desktop)
|
||||||
|
{
|
||||||
|
if (desktop < screen_num_desktops || desktop == DESKTOP_ALL)
|
||||||
|
client_set_desktop(c, desktop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_send_to_next_desktop(Client *c, gboolean wrap, gboolean follow)
|
||||||
|
{
|
||||||
|
guint d;
|
||||||
|
|
||||||
|
d = screen_desktop + 1;
|
||||||
|
if (d >= screen_num_desktops) {
|
||||||
|
if (!wrap) return;
|
||||||
|
d = 0;
|
||||||
|
}
|
||||||
|
client_set_desktop(c, d);
|
||||||
|
if (follow) screen_set_desktop(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_send_to_previous_desktop(Client *c, gboolean wrap, gboolean follow)
|
||||||
|
{
|
||||||
|
guint d;
|
||||||
|
|
||||||
|
d = screen_desktop - 1;
|
||||||
|
if (d >= screen_num_desktops) {
|
||||||
|
if (!wrap) return;
|
||||||
|
d = screen_num_desktops - 1;
|
||||||
|
}
|
||||||
|
client_set_desktop(c, d);
|
||||||
|
if (follow) screen_set_desktop(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_desktop(guint desktop)
|
||||||
|
{
|
||||||
|
if (desktop < screen_num_desktops || desktop == DESKTOP_ALL)
|
||||||
|
screen_set_desktop(desktop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_next_desktop(gboolean wrap)
|
||||||
|
{
|
||||||
|
guint d;
|
||||||
|
|
||||||
|
d = screen_desktop + 1;
|
||||||
|
if (d >= screen_num_desktops) {
|
||||||
|
if (!wrap) return;
|
||||||
|
d = 0;
|
||||||
|
}
|
||||||
|
screen_set_desktop(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_previous_desktop(gboolean wrap)
|
||||||
|
{
|
||||||
|
guint d;
|
||||||
|
|
||||||
|
d = screen_desktop - 1;
|
||||||
|
if (d >= screen_num_desktops) {
|
||||||
|
if (!wrap) return;
|
||||||
|
d = screen_num_desktops - 1;
|
||||||
|
}
|
||||||
|
screen_set_desktop(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cur_row_col(guint *r, guint *c)
|
||||||
|
{
|
||||||
|
switch (screen_desktop_layout.orientation) {
|
||||||
|
case Orientation_Horz:
|
||||||
|
switch (screen_desktop_layout.start_corner) {
|
||||||
|
case Corner_TopLeft:
|
||||||
|
*r = screen_desktop / screen_desktop_layout.columns;
|
||||||
|
*c = screen_desktop % screen_desktop_layout.columns;
|
||||||
|
break;
|
||||||
|
case Corner_BottomLeft:
|
||||||
|
*r = screen_desktop_layout.rows - 1 -
|
||||||
|
screen_desktop / screen_desktop_layout.columns;
|
||||||
|
*c = screen_desktop % screen_desktop_layout.columns;
|
||||||
|
break;
|
||||||
|
break;
|
||||||
|
case Corner_TopRight:
|
||||||
|
*r = screen_desktop / screen_desktop_layout.columns;
|
||||||
|
*c = screen_desktop_layout.columns - 1 -
|
||||||
|
screen_desktop % screen_desktop_layout.columns;
|
||||||
|
break;
|
||||||
|
case Corner_BottomRight:
|
||||||
|
*r = screen_desktop_layout.rows - 1 -
|
||||||
|
screen_desktop / screen_desktop_layout.columns;
|
||||||
|
*c = screen_desktop_layout.columns - 1 -
|
||||||
|
screen_desktop % screen_desktop_layout.columns;
|
||||||
|
break;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Orientation_Vert:
|
||||||
|
switch (screen_desktop_layout.start_corner) {
|
||||||
|
case Corner_TopLeft:
|
||||||
|
*r = screen_desktop % screen_desktop_layout.rows;
|
||||||
|
*c = screen_desktop / screen_desktop_layout.rows;
|
||||||
|
break;
|
||||||
|
case Corner_BottomLeft:
|
||||||
|
*r = screen_desktop_layout.rows - 1 -
|
||||||
|
screen_desktop % screen_desktop_layout.rows;
|
||||||
|
*c = screen_desktop / screen_desktop_layout.rows;
|
||||||
|
break;
|
||||||
|
break;
|
||||||
|
case Corner_TopRight:
|
||||||
|
*r = screen_desktop % screen_desktop_layout.rows;
|
||||||
|
*c = screen_desktop_layout.columns - 1 -
|
||||||
|
screen_desktop / screen_desktop_layout.rows;
|
||||||
|
break;
|
||||||
|
case Corner_BottomRight:
|
||||||
|
*r = screen_desktop_layout.rows - 1 -
|
||||||
|
screen_desktop % screen_desktop_layout.rows;
|
||||||
|
*c = screen_desktop_layout.columns - 1 -
|
||||||
|
screen_desktop / screen_desktop_layout.rows;
|
||||||
|
break;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint translate_row_col(guint r, guint c)
|
||||||
|
{
|
||||||
|
switch (screen_desktop_layout.orientation) {
|
||||||
|
case Orientation_Horz:
|
||||||
|
switch (screen_desktop_layout.start_corner) {
|
||||||
|
case Corner_TopLeft:
|
||||||
|
return r * screen_desktop_layout.columns + c;
|
||||||
|
case Corner_BottomLeft:
|
||||||
|
return (screen_desktop_layout.rows - 1 - r) *
|
||||||
|
screen_desktop_layout.columns + c;
|
||||||
|
case Corner_TopRight:
|
||||||
|
return r * screen_desktop_layout.columns +
|
||||||
|
(screen_desktop_layout.columns - 1 - c);
|
||||||
|
case Corner_BottomRight:
|
||||||
|
return (screen_desktop_layout.rows - 1 - r) *
|
||||||
|
screen_desktop_layout.columns +
|
||||||
|
(screen_desktop_layout.columns - 1 - c);
|
||||||
|
}
|
||||||
|
case Orientation_Vert:
|
||||||
|
switch (screen_desktop_layout.start_corner) {
|
||||||
|
case Corner_TopLeft:
|
||||||
|
return c * screen_desktop_layout.rows + r;
|
||||||
|
case Corner_BottomLeft:
|
||||||
|
return c * screen_desktop_layout.rows +
|
||||||
|
(screen_desktop_layout.rows - 1 - r);
|
||||||
|
case Corner_TopRight:
|
||||||
|
return (screen_desktop_layout.columns - 1 - c) *
|
||||||
|
screen_desktop_layout.rows + r;
|
||||||
|
case Corner_BottomRight:
|
||||||
|
return (screen_desktop_layout.columns - 1 - c) *
|
||||||
|
screen_desktop_layout.rows +
|
||||||
|
(screen_desktop_layout.rows - 1 - r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_assert_not_reached();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_next_desktop_column(gboolean wrap)
|
||||||
|
{
|
||||||
|
guint r, c, d;
|
||||||
|
|
||||||
|
cur_row_col(&r, &c);
|
||||||
|
++c;
|
||||||
|
d = translate_row_col(r, c);
|
||||||
|
if (d >= screen_num_desktops) {
|
||||||
|
if (!wrap) return;
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
if (d >= screen_num_desktops)
|
||||||
|
++c;
|
||||||
|
d = translate_row_col(r, c);
|
||||||
|
if (d < screen_num_desktops)
|
||||||
|
screen_set_desktop(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_previous_desktop_column(gboolean wrap)
|
||||||
|
{
|
||||||
|
guint r, c, d;
|
||||||
|
|
||||||
|
cur_row_col(&r, &c);
|
||||||
|
--c;
|
||||||
|
d = translate_row_col(r, c);
|
||||||
|
if (d >= screen_num_desktops) {
|
||||||
|
if (!wrap) return;
|
||||||
|
c = screen_desktop_layout.columns - 1;
|
||||||
|
}
|
||||||
|
if (d >= screen_num_desktops)
|
||||||
|
--c;
|
||||||
|
d = translate_row_col(r, c);
|
||||||
|
if (d < screen_num_desktops)
|
||||||
|
screen_set_desktop(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_next_desktop_row(gboolean wrap)
|
||||||
|
{
|
||||||
|
guint r, c, d;
|
||||||
|
|
||||||
|
cur_row_col(&r, &c);
|
||||||
|
++r;
|
||||||
|
d = translate_row_col(r, c);
|
||||||
|
if (d >= screen_num_desktops) {
|
||||||
|
if (!wrap) return;
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
if (d >= screen_num_desktops)
|
||||||
|
++r;
|
||||||
|
d = translate_row_col(r, c);
|
||||||
|
if (d < screen_num_desktops)
|
||||||
|
screen_set_desktop(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_previous_desktop_row(gboolean wrap)
|
||||||
|
{
|
||||||
|
guint r, c, d;
|
||||||
|
|
||||||
|
cur_row_col(&r, &c);
|
||||||
|
--r;
|
||||||
|
d = translate_row_col(r, c);
|
||||||
|
if (d >= screen_num_desktops) {
|
||||||
|
if (!wrap) return;
|
||||||
|
c = screen_desktop_layout.rows - 1;
|
||||||
|
}
|
||||||
|
if (d >= screen_num_desktops)
|
||||||
|
--r;
|
||||||
|
d = translate_row_col(r, c);
|
||||||
|
if (d < screen_num_desktops)
|
||||||
|
screen_set_desktop(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_toggle_decorations(Client *c)
|
||||||
|
{
|
||||||
|
c->disabled_decorations = c->disabled_decorations ? 0 : ~0;
|
||||||
|
client_setup_decor_and_functions(c);
|
||||||
|
}
|
72
openbox/action.h
Normal file
72
openbox/action.h
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#ifndef __action_h
|
||||||
|
#define __action_h
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
Action_Execute,
|
||||||
|
Action_Iconify,
|
||||||
|
Action_Raise,
|
||||||
|
Action_Lower,
|
||||||
|
Action_Close,
|
||||||
|
Action_Shade,
|
||||||
|
Action_Unshade,
|
||||||
|
Action_ToggleShade,
|
||||||
|
Action_ToggleOmnipresent,
|
||||||
|
Action_MoveRelative,
|
||||||
|
Action_ResizeRelative,
|
||||||
|
Action_MaximizeFull,
|
||||||
|
Action_UnmaximizeFull,
|
||||||
|
Action_ToggleMaximizeFull,
|
||||||
|
Action_MaximizeHorz,
|
||||||
|
Action_UnmaximizeHorz,
|
||||||
|
Action_ToggleMaximizeHorz,
|
||||||
|
Action_MaximizeVert,
|
||||||
|
Action_UnmaximizeVert,
|
||||||
|
Action_ToggleMaximizeVert,
|
||||||
|
Action_SendToDesktop,
|
||||||
|
Action_SendToNextDesktop,
|
||||||
|
Action_SendToPreviousDesktop,
|
||||||
|
Action_Desktop,
|
||||||
|
Action_NextDesktop,
|
||||||
|
Action_PreviousDesktop,
|
||||||
|
Action_NextDesktopColumn,
|
||||||
|
Action_PreviousDesktopColumn,
|
||||||
|
Action_NextDesktopRow,
|
||||||
|
Action_PreviousDesktopRow,
|
||||||
|
Action_ToggleDecorations
|
||||||
|
} Action;
|
||||||
|
|
||||||
|
void action_execute(char *path);
|
||||||
|
void action_iconify(Client *c);
|
||||||
|
void action_raise(Client *c);
|
||||||
|
void action_lower(Client *c);
|
||||||
|
void action_close(Client *c);
|
||||||
|
void action_shade(Client *c);
|
||||||
|
void action_unshade(Client *c);
|
||||||
|
void action_toggle_shade(Client *c);
|
||||||
|
void action_toggle_omnipresent(Client *c);
|
||||||
|
void action_move_relative(Client *c, int dx, int dy);
|
||||||
|
void action_resize_relative(Client *c, int dx, int dy);
|
||||||
|
void action_maximize_full(Client *c);
|
||||||
|
void action_unmaximize_full(Client *c);
|
||||||
|
void action_toggle_maximize_full(Client *c);
|
||||||
|
void action_maximize_horz(Client *c);
|
||||||
|
void action_unmaximize_horz(Client *c);
|
||||||
|
void action_toggle_maximize_horz(Client *c);
|
||||||
|
void action_maximize_vert(Client *c);
|
||||||
|
void action_unmaximize_vert(Client *c);
|
||||||
|
void action_toggle_maximize_vert(Client *c);
|
||||||
|
void action_send_to_desktop(Client *c, guint desktop);
|
||||||
|
void action_send_to_next_desktop(Client *c, gboolean wrap, gboolean follow);
|
||||||
|
void action_send_to_previous_desktop(Client *c, gboolean wrap,gboolean follow);
|
||||||
|
void action_desktop(guint desktop);
|
||||||
|
void action_next_desktop(gboolean wrap);
|
||||||
|
void action_previous_desktop(gboolean wrap);
|
||||||
|
void action_next_desktop_column(gboolean wrap);
|
||||||
|
void action_previous_desktop_column(gboolean wrap);
|
||||||
|
void action_next_desktop_row(gboolean wrap);
|
||||||
|
void action_previous_desktop_row(gboolean wrap);
|
||||||
|
void action_toggle_decorations(Client *c);
|
||||||
|
|
||||||
|
#endif
|
|
@ -1632,9 +1632,7 @@ void client_set_desktop(Client *self, guint target)
|
||||||
|
|
||||||
g_message("Setting desktop %u\n", target);
|
g_message("Setting desktop %u\n", target);
|
||||||
|
|
||||||
if (!(target < screen_num_desktops ||
|
g_assert(target < screen_num_desktops || target == DESKTOP_ALL);
|
||||||
target == DESKTOP_ALL))
|
|
||||||
return;
|
|
||||||
|
|
||||||
old = self->desktop;
|
old = self->desktop;
|
||||||
self->desktop = target;
|
self->desktop = target;
|
||||||
|
|
|
@ -103,319 +103,7 @@ static PyTypeObject KeyboardDataType = {
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
guint keyboard_translate_modifier(char *str)
|
|
||||||
{
|
|
||||||
if (!strcmp("Mod1", str)) return Mod1Mask;
|
|
||||||
else if (!strcmp("Mod2", str)) return Mod2Mask;
|
|
||||||
else if (!strcmp("Mod3", str)) return Mod3Mask;
|
|
||||||
else if (!strcmp("Mod4", str)) return Mod4Mask;
|
|
||||||
else if (!strcmp("Mod5", str)) return Mod5Mask;
|
|
||||||
else if (!strcmp("C", str)) return ControlMask;
|
|
||||||
else if (!strcmp("S", str)) return ShiftMask;
|
|
||||||
g_warning("Invalid modifier '%s' in binding.", str);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean translate(char *str, guint *state, guint *keycode)
|
|
||||||
{
|
|
||||||
char **parsed;
|
|
||||||
char *l;
|
|
||||||
int i;
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
KeySym sym;
|
|
||||||
|
|
||||||
parsed = g_strsplit(str, "-", -1);
|
|
||||||
|
|
||||||
/* first, find the key (last token) */
|
|
||||||
l = NULL;
|
|
||||||
for (i = 0; parsed[i] != NULL; ++i)
|
|
||||||
l = parsed[i];
|
|
||||||
if (l == NULL)
|
|
||||||
goto translation_fail;
|
|
||||||
|
|
||||||
/* figure out the mod mask */
|
|
||||||
*state = 0;
|
|
||||||
for (i = 0; parsed[i] != l; ++i) {
|
|
||||||
guint m = keyboard_translate_modifier(parsed[i]);
|
|
||||||
if (!m) goto translation_fail;
|
|
||||||
*state |= m;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* figure out the keycode */
|
|
||||||
sym = XStringToKeysym(l);
|
|
||||||
if (sym == NoSymbol) {
|
|
||||||
g_warning("Invalid key name '%s' in key binding.", l);
|
|
||||||
goto translation_fail;
|
|
||||||
}
|
|
||||||
*keycode = XKeysymToKeycode(ob_display, sym);
|
|
||||||
if (!keycode) {
|
|
||||||
g_warning("Key '%s' does not exist on the display.", l);
|
|
||||||
goto translation_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
|
|
||||||
translation_fail:
|
|
||||||
g_strfreev(parsed);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void destroytree(KeyBindingTree *tree)
|
|
||||||
{
|
|
||||||
KeyBindingTree *c;
|
|
||||||
|
|
||||||
while (tree) {
|
|
||||||
destroytree(tree->next_sibling);
|
|
||||||
c = tree->first_child;
|
|
||||||
if (c == NULL) {
|
|
||||||
GList *it;
|
|
||||||
for (it = tree->keylist; it != NULL; it = it->next)
|
|
||||||
g_free(it->data);
|
|
||||||
g_list_free(tree->keylist);
|
|
||||||
Py_XDECREF(tree->func);
|
|
||||||
}
|
|
||||||
g_free(tree);
|
|
||||||
tree = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static KeyBindingTree *buildtree(GList *keylist)
|
|
||||||
{
|
|
||||||
GList *it;
|
|
||||||
KeyBindingTree *ret = NULL, *p;
|
|
||||||
|
|
||||||
if (g_list_length(keylist) <= 0)
|
|
||||||
return NULL; /* nothing in the list.. */
|
|
||||||
|
|
||||||
for (it = g_list_last(keylist); it != NULL; it = it->prev) {
|
|
||||||
p = ret;
|
|
||||||
ret = g_new(KeyBindingTree, 1);
|
|
||||||
ret->next_sibling = NULL;
|
|
||||||
ret->func = NULL;
|
|
||||||
if (p == NULL) {
|
|
||||||
GList *it;
|
|
||||||
|
|
||||||
/* this is the first built node, the bottom node of the tree */
|
|
||||||
ret->keylist = g_list_copy(keylist); /* shallow copy */
|
|
||||||
for (it = ret->keylist; it != NULL; it = it->next) /* deep copy */
|
|
||||||
it->data = g_strdup(it->data);
|
|
||||||
}
|
|
||||||
ret->first_child = p;
|
|
||||||
if (!translate(it->data, &ret->state, &ret->key)) {
|
|
||||||
destroytree(ret);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void assimilate(KeyBindingTree *node)
|
|
||||||
{
|
|
||||||
KeyBindingTree *a, *b, *tmp, *last;
|
|
||||||
|
|
||||||
if (firstnode == NULL) {
|
|
||||||
/* there are no nodes at this level yet */
|
|
||||||
firstnode = node;
|
|
||||||
} else {
|
|
||||||
a = firstnode;
|
|
||||||
last = a;
|
|
||||||
b = node;
|
|
||||||
while (a) {
|
|
||||||
last = a;
|
|
||||||
if (!(a->state == b->state && a->key == b->key)) {
|
|
||||||
a = a->next_sibling;
|
|
||||||
} else {
|
|
||||||
tmp = b;
|
|
||||||
b = b->first_child;
|
|
||||||
g_free(tmp);
|
|
||||||
a = a->first_child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!(last->state == b->state && last->key == b->key))
|
|
||||||
last->next_sibling = b;
|
|
||||||
else {
|
|
||||||
last->first_child = b->first_child;
|
|
||||||
g_free(b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static KeyBindingTree *find(KeyBindingTree *search, gboolean *conflict)
|
|
||||||
{
|
|
||||||
KeyBindingTree *a, *b;
|
|
||||||
|
|
||||||
*conflict = FALSE;
|
|
||||||
|
|
||||||
a = firstnode;
|
|
||||||
b = search;
|
|
||||||
while (a && b) {
|
|
||||||
if (!(a->state == b->state && a->key == b->key)) {
|
|
||||||
a = a->next_sibling;
|
|
||||||
} else {
|
|
||||||
if ((a->first_child == NULL) == (b->first_child == NULL)) {
|
|
||||||
if (a->first_child == NULL) {
|
|
||||||
/* found it! (return the actual node, not the search's) */
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*conflict = TRUE;
|
|
||||||
return NULL; /* the chain status' don't match (conflict!) */
|
|
||||||
}
|
|
||||||
b = b->first_child;
|
|
||||||
a = a->first_child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL; // it just isn't in here
|
|
||||||
}
|
|
||||||
|
|
||||||
static void grab_keys(gboolean grab)
|
|
||||||
{
|
|
||||||
if (!grab) {
|
|
||||||
XUngrabKey(ob_display, AnyKey, AnyModifier, ob_root);
|
|
||||||
} else {
|
|
||||||
KeyBindingTree *p = firstnode;
|
|
||||||
while (p) {
|
|
||||||
XGrabKey(ob_display, p->key, p->state, ob_root, FALSE,
|
|
||||||
GrabModeAsync, GrabModeSync);
|
|
||||||
p = p->next_sibling;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reset_chains()
|
|
||||||
{
|
|
||||||
/* XXX kill timer */
|
|
||||||
curpos = NULL;
|
|
||||||
if (grabbed) {
|
|
||||||
grabbed = FALSE;
|
|
||||||
g_message("reset chains. user_grabbed: %d", user_grabbed);
|
|
||||||
if (!user_grabbed)
|
|
||||||
XUngrabKeyboard(ob_display, CurrentTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void keyboard_event(XKeyEvent *e)
|
|
||||||
{
|
|
||||||
PyObject *chain, *client, *args, *keybdata, *ret;
|
|
||||||
gboolean press = e->type == KeyPress;
|
|
||||||
|
|
||||||
if (focus_client) client = clientwrap_new(focus_client);
|
|
||||||
else client = Py_None;
|
|
||||||
|
|
||||||
if (user_grabbed) {
|
|
||||||
GString *str = g_string_sized_new(0);
|
|
||||||
KeySym sym;
|
|
||||||
|
|
||||||
/* build the 'chain' */
|
|
||||||
if (e->state & ControlMask)
|
|
||||||
g_string_append(str, "C-");
|
|
||||||
if (e->state & ShiftMask)
|
|
||||||
g_string_append(str, "S-");
|
|
||||||
if (e->state & Mod1Mask)
|
|
||||||
g_string_append(str, "Mod1-");
|
|
||||||
if (e->state & Mod2Mask)
|
|
||||||
g_string_append(str, "Mod2-");
|
|
||||||
if (e->state & Mod3Mask)
|
|
||||||
g_string_append(str, "Mod3-");
|
|
||||||
if (e->state & Mod4Mask)
|
|
||||||
g_string_append(str, "Mod4-");
|
|
||||||
if (e->state & Mod5Mask)
|
|
||||||
g_string_append(str, "Mod5-");
|
|
||||||
|
|
||||||
sym = XKeycodeToKeysym(ob_display, e->keycode, 0);
|
|
||||||
if (sym == NoSymbol)
|
|
||||||
g_string_append(str, "NoSymbol");
|
|
||||||
else {
|
|
||||||
char *name = XKeysymToString(sym);
|
|
||||||
if (name == NULL)
|
|
||||||
name = "Undefined";
|
|
||||||
g_string_append(str, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
chain = PyTuple_New(1);
|
|
||||||
PyTuple_SET_ITEM(chain, 0, PyString_FromString(str->str));
|
|
||||||
g_string_free(str, TRUE);
|
|
||||||
|
|
||||||
keybdata = keybdata_new(chain, e->state, e->keycode, press);
|
|
||||||
|
|
||||||
args = Py_BuildValue("OO", keybdata, client);
|
|
||||||
|
|
||||||
ret = PyObject_CallObject(grab_func, args);
|
|
||||||
if (ret == NULL) PyErr_Print();
|
|
||||||
Py_XDECREF(ret);
|
|
||||||
|
|
||||||
Py_DECREF(args);
|
|
||||||
Py_DECREF(keybdata);
|
|
||||||
Py_DECREF(chain);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (press) {
|
|
||||||
if (e->keycode == reset_key && e->state == reset_state) {
|
|
||||||
reset_chains();
|
|
||||||
XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
|
|
||||||
} else {
|
|
||||||
KeyBindingTree *p;
|
|
||||||
if (curpos == NULL)
|
|
||||||
p = firstnode;
|
|
||||||
else
|
|
||||||
p = curpos->first_child;
|
|
||||||
while (p) {
|
|
||||||
if (p->key == e->keycode && p->state == e->state) {
|
|
||||||
if (p->first_child != NULL) { /* part of a chain */
|
|
||||||
/* XXX TIMER */
|
|
||||||
if (!grabbed && !user_grabbed) {
|
|
||||||
/*grab should never fail because we should have a
|
|
||||||
sync grab at this point */
|
|
||||||
XGrabKeyboard(ob_display, ob_root, 0,
|
|
||||||
GrabModeAsync, GrabModeSync,
|
|
||||||
CurrentTime);
|
|
||||||
}
|
|
||||||
grabbed = TRUE;
|
|
||||||
curpos = p;
|
|
||||||
XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
|
|
||||||
} else {
|
|
||||||
GList *it;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
chain = PyTuple_New(g_list_length(p->keylist));
|
|
||||||
for (i = 0, it = p->keylist; it != NULL;
|
|
||||||
it = it->next, ++i)
|
|
||||||
PyTuple_SET_ITEM(chain, i,
|
|
||||||
PyString_FromString(it->data));
|
|
||||||
|
|
||||||
keybdata = keybdata_new(chain, e->state, e->keycode,
|
|
||||||
press);
|
|
||||||
|
|
||||||
args = Py_BuildValue("OO", keybdata, client);
|
|
||||||
|
|
||||||
ret = PyObject_CallObject(p->func, args);
|
|
||||||
if (ret == NULL) PyErr_Print();
|
|
||||||
Py_XDECREF(ret);
|
|
||||||
|
|
||||||
Py_DECREF(args);
|
|
||||||
Py_DECREF(keybdata);
|
|
||||||
Py_DECREF(chain);
|
|
||||||
|
|
||||||
XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
|
|
||||||
reset_chains();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
p = p->next_sibling;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client != Py_None) { Py_DECREF(client); }
|
|
||||||
}
|
|
||||||
|
|
||||||
static void clearall()
|
|
||||||
{
|
|
||||||
grab_keys(FALSE);
|
|
||||||
destroytree(firstnode);
|
|
||||||
firstnode = NULL;
|
|
||||||
grab_keys(TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean grab_keyboard(gboolean grab)
|
static gboolean grab_keyboard(gboolean grab)
|
||||||
{
|
{
|
||||||
|
@ -456,93 +144,6 @@ typedef struct Keyboard {
|
||||||
|
|
||||||
staticforward PyTypeObject KeyboardType;
|
staticforward PyTypeObject KeyboardType;
|
||||||
|
|
||||||
static PyObject *keyb_bind(Keyboard *self, PyObject *args)
|
|
||||||
{
|
|
||||||
KeyBindingTree *tree = NULL, *t;
|
|
||||||
gboolean conflict;
|
|
||||||
PyObject *item, *tuple, *func;
|
|
||||||
GList *keylist = NULL, *it;
|
|
||||||
int i, s;
|
|
||||||
|
|
||||||
CHECK_KEYBOARD(self, "grab");
|
|
||||||
if (!PyArg_ParseTuple(args, "OO:grab", &tuple, &func))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!PyTuple_Check(tuple)) {
|
|
||||||
PyErr_SetString(PyExc_ValueError, "expected a tuple of strings");
|
|
||||||
goto binderror;
|
|
||||||
}
|
|
||||||
if (!PyCallable_Check(func)) {
|
|
||||||
PyErr_SetString(PyExc_ValueError, "expected a callable object");
|
|
||||||
goto binderror;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = PyTuple_GET_SIZE(tuple);
|
|
||||||
if (s <= 0) {
|
|
||||||
PyErr_SetString(PyExc_ValueError, "expected a tuple of strings");
|
|
||||||
goto binderror;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < s; ++i) {
|
|
||||||
item = PyTuple_GET_ITEM(tuple, i);
|
|
||||||
if (!PyString_Check(item)) {
|
|
||||||
PyErr_SetString(PyExc_ValueError, "expected a tuple of strings");
|
|
||||||
goto binderror;
|
|
||||||
}
|
|
||||||
keylist = g_list_append(keylist,
|
|
||||||
g_strdup(PyString_AsString(item)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(tree = buildtree(keylist))) {
|
|
||||||
PyErr_SetString(PyExc_ValueError, "invalid binding");
|
|
||||||
goto binderror;
|
|
||||||
}
|
|
||||||
|
|
||||||
t = find(tree, &conflict);
|
|
||||||
if (conflict) {
|
|
||||||
PyErr_SetString(PyExc_ValueError, "conflict with binding");
|
|
||||||
goto binderror;
|
|
||||||
}
|
|
||||||
if (t != NULL) {
|
|
||||||
/* already bound to something */
|
|
||||||
PyErr_SetString(PyExc_ValueError, "keychain is already bound");
|
|
||||||
goto binderror;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* grab the server here to make sure no key pressed go missed */
|
|
||||||
XGrabServer(ob_display);
|
|
||||||
XSync(ob_display, FALSE);
|
|
||||||
|
|
||||||
grab_keys(FALSE);
|
|
||||||
|
|
||||||
/* set the function */
|
|
||||||
t = tree;
|
|
||||||
while (t->first_child) t = t->first_child;
|
|
||||||
t->func = func;
|
|
||||||
Py_INCREF(func);
|
|
||||||
|
|
||||||
/* assimilate this built tree into the main tree */
|
|
||||||
assimilate(tree); // assimilation destroys/uses the tree
|
|
||||||
|
|
||||||
grab_keys(TRUE);
|
|
||||||
|
|
||||||
XUngrabServer(ob_display);
|
|
||||||
XFlush(ob_display);
|
|
||||||
|
|
||||||
for (it = keylist; it != NULL; it = it->next)
|
|
||||||
g_free(it->data);
|
|
||||||
g_list_free(it);
|
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
return Py_None;
|
|
||||||
|
|
||||||
binderror:
|
|
||||||
if (tree != NULL) destroytree(tree);
|
|
||||||
for (it = keylist; it != NULL; it = it->next)
|
|
||||||
g_free(it->data);
|
|
||||||
g_list_free(it);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *keyb_clearBinds(Keyboard *self, PyObject *args)
|
static PyObject *keyb_clearBinds(Keyboard *self, PyObject *args)
|
||||||
{
|
{
|
||||||
|
|
|
@ -141,6 +141,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
/* XXX load all plugins!! */
|
/* XXX load all plugins!! */
|
||||||
plugin_open("focus");
|
plugin_open("focus");
|
||||||
|
plugin_open("keyboard");
|
||||||
|
|
||||||
/* get all the existing windows */
|
/* get all the existing windows */
|
||||||
client_manage_all();
|
client_manage_all();
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define __screen_h
|
#define __screen_h
|
||||||
|
|
||||||
#include "geom.h"
|
#include "geom.h"
|
||||||
|
#include "client.h"
|
||||||
|
|
||||||
struct Client;
|
struct Client;
|
||||||
|
|
||||||
|
@ -18,13 +19,13 @@ extern gboolean screen_showing_desktop;
|
||||||
|
|
||||||
/*! Orientation of the desktops */
|
/*! Orientation of the desktops */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Orientation_Horz,
|
Orientation_Horz = 0,
|
||||||
Orientation_Vert
|
Orientation_Vert = 1
|
||||||
} Orientation;
|
} Orientation;
|
||||||
|
|
||||||
typedef struct DesktopLayout {
|
typedef struct DesktopLayout {
|
||||||
guint orientation;
|
Orientation orientation;
|
||||||
guint start_corner;
|
Corner start_corner;
|
||||||
guint rows;
|
guint rows;
|
||||||
guint columns;
|
guint columns;
|
||||||
} DesktopLayout;
|
} DesktopLayout;
|
||||||
|
|
Loading…
Reference in a new issue