all repos — openbox @ c90da6da781932c2d178bfb7e39ec1d5003543b7

openbox fork - make it a bit more like ryudo

move the keyboard and mouse plugins into the kernel for mucho sexiness.
make workspace changing a grabbed/interactive process like focus cycling is, with the popup and all.
this is some hot shit.
Dana Jansens danakj@orodu.net
commit

c90da6da781932c2d178bfb7e39ec1d5003543b7

parent

cb49f853c9b62c4403eb562d39f52c51da292c4f

M ChangeLogChangeLog

@@ -1,3 +1,64 @@

+2003-08-12 xor@zed.orodu.net <xor@zed> + + * kernel/event.c: + keep event_lasttime at the last time an event has come in so far, don't regress when events come out of order. props to shrimpx for this patch. + +2003-08-11 woodblock <woodblock@zed> + + * kernel/menu.c, kernel/menu.h, kernel/menu_render.c, plugins/menu/fifo_menu.c, plugins/menu/timed_menu.c, render/theme.c, render/theme.h: + Some fixes and new bugs. Someone else can do the menus because it is + clear no one gives a fuck what I think and no one else wants a window + manager that doesn't suck the same balls as every other window manager. + +2003-08-10 xor@zed.orodu.net <xor@zed> + + * kernel/client.c: + save the frame decorations in client_configure_full before causing the fake frame adjust, since that loses its old value. + +2003-08-10 xor@zed.orodu.net <xor@zed> + + * framerender.c: + clear the window after setting the background color, this isnt implicit + +2003-08-09 xor@zed.orodu.net <xor@zed> + + * focus.c, popup.c, popup.h, screen.c, timer.c, timer.h: + changes to the timer api, pass the timer to the callback function. + add a desktop-switch popup with the desktop's name + +2003-08-07 woodblock <woodblock@zed> + + * event.c: + Fix lock up when not using a session manager and doing fd management. + +2003-08-05 xor@zed.orodu.net <xor@zed> + + * screen.c: dont ignore topleft layouts + + * frame.c: + dont map the tl/tr invisible grips when the grip decors are turned off + + * client.c, frame.c, frame.h, framerender.c: + a couple frame layout bugfixes hidden inside all this.. wee + fixes for maximizing windows: + - when you toggledecor, it will reconfigure once, but the new constraints from the decor changes would not be in effect when the window was resized to the contranits. fixed by calling frame_adjust_area first thing ni client_configure_fulll with fake=TRUE which will recalc all the frame geometry without resizing/redrawing anything in the frame. this way the decor can take effect in the geometries. + - when maxed horizontally, make the client fill the screen, but dont do this by just making it wider than the screen, fit it to the screen and adjust the titlebar/handle as appropriate to keep it all on the screen. + - when maxed horizontally and vertically, remove the handle from the decorations + + * client.c: + when setting up decor on a window, it needs to reconfigure twice if the decor changes, cuz the constraints need the new frame sizes to work right + + * moveresize.c: + make the position dislpayed in the moving popup offset by the top/left struts so that 0,0 is inside teh struts not neccessarily at the screen edge + +2003-08-03 xor@zed.orodu.net <xor@zed> + + * client.c, config.c, config.h, moveresize.c: + kill non-opaque move/resize + add an option for redrawing/resizing the client window while resizing, when disabled the client is not touched until the resize is complete. + + * framerender.c: give the plate the same background color as its border + 2003-08-03 xor@zed.orodu.net <xor@zed> * data/rc3, kernel/client.c, kernel/config.c, kernel/config.h, kernel/moveresize.c:
M Makefile.amMakefile.am

@@ -28,8 +28,6 @@

plugin_LTLIBRARIES = \ plugins/resistance/resistance.la \ plugins/placement/placement.la \ - plugins/mouse/mouse.la \ - plugins/keyboard/keyboard.la \ plugins/menu/timed_menu.la \ plugins/menu/fifo_menu.la \ plugins/menu/client_menu.la \

@@ -157,10 +155,16 @@ kernel/grab.c \

kernel/grab.h \ kernel/group.c \ kernel/group.h \ + kernel/keyboard.c \ + kernel/keyboard.h \ + kernel/keytree.c \ + kernel/keytree.h \ kernel/menu.c \ kernel/menu.h \ kernel/menu_render.c \ kernel/misc.h \ + kernel/mouse.c \ + kernel/mouse.h \ kernel/moveresize.c \ kernel/moveresize.h \ kernel/mwm.h \

@@ -182,6 +186,8 @@ kernel/startup.c \

kernel/startup.h \ kernel/timer.c \ kernel/timer.h \ + kernel/translate.c \ + kernel/translate.h \ kernel/window.c \ kernel/window.h \ kernel/xerror.c \

@@ -237,44 +243,6 @@ plugins_placement_placement_la_SOURCES = \

plugins/placement/placement.c \ plugins/placement/history.c \ plugins/placement/history.h - -## plugins/mouse ## - -plugins_mouse_mouse_la_CPPFLAGS = \ - $(XFT_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(LIBSN_CFLAGS) \ - $(XML_CFLAGS) \ - -DPLUGINDIR=\"$(plugindir)\" \ - -DG_LOG_DOMAIN=\"Plugin-Mouse\" -plugins_mouse_mouse_la_LDFLAGS = \ - -module \ - -avoid-version -plugins_mouse_mouse_la_SOURCES = \ - plugins/mouse/mouse.c \ - plugins/mouse/mouse.h \ - plugins/mouse/translate.c \ - plugins/mouse/translate.h - -## plugins/mouse ## - -plugins_keyboard_keyboard_la_CPPFLAGS = \ - $(XFT_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(LIBSN_CFLAGS) \ - $(XML_CFLAGS) \ - -DPLUGINDIR=\"$(plugindir)\" \ - -DG_LOG_DOMAIN=\"Plugin-Keyboard\" -plugins_keyboard_keyboard_la_LDFLAGS = \ - -module \ - -avoid-version -plugins_keyboard_keyboard_la_SOURCES = \ - plugins/keyboard/keyboard.c \ - plugins/keyboard/keyboard.h \ - plugins/keyboard/tree.c \ - plugins/keyboard/tree.h \ - plugins/keyboard/translate.c \ - plugins/keyboard/translate.h ## plugins/menu ##
M openbox/.cvsignoreopenbox/.cvsignore

@@ -29,3 +29,6 @@ xerror.lo

.deps openbox .dirstamp +keyboard.lo +mouse.lo +keytree.lo
M openbox/action.copenbox/action.c

@@ -16,18 +16,18 @@

typedef struct ActionString { char *name; void (*func)(union ActionData *); - void (*setup)(Action *); + void (*setup)(ObAction *); } ActionString; -Action *action_new(void (*func)(union ActionData *data)) +ObAction *action_new(void (*func)(union ActionData *data)) { - Action *a = g_new0(Action, 1); + ObAction *a = g_new0(ObAction, 1); a->func = func; return a; } -void action_free(Action *a) +void action_free(ObAction *a) { if (a == NULL) return;

@@ -40,137 +40,209 @@

g_free(a); } -void setup_action_directional_focus_north(Action *a) +void setup_action_directional_focus_north(ObAction *a) { a->data.diraction.direction = OB_DIRECTION_NORTH; } -void setup_action_directional_focus_east(Action *a) +void setup_action_directional_focus_east(ObAction *a) { a->data.diraction.direction = OB_DIRECTION_EAST; } -void setup_action_directional_focus_south(Action *a) +void setup_action_directional_focus_south(ObAction *a) { a->data.diraction.direction = OB_DIRECTION_SOUTH; } -void setup_action_directional_focus_west(Action *a) +void setup_action_directional_focus_west(ObAction *a) { a->data.diraction.direction = OB_DIRECTION_WEST; } -void setup_action_directional_focus_northeast(Action *a) +void setup_action_directional_focus_northeast(ObAction *a) { a->data.diraction.direction = OB_DIRECTION_NORTHEAST; } -void setup_action_directional_focus_southeast(Action *a) +void setup_action_directional_focus_southeast(ObAction *a) { a->data.diraction.direction = OB_DIRECTION_SOUTHEAST; } -void setup_action_directional_focus_southwest(Action *a) +void setup_action_directional_focus_southwest(ObAction *a) { a->data.diraction.direction = OB_DIRECTION_SOUTHWEST; } -void setup_action_directional_focus_northwest(Action *a) +void setup_action_directional_focus_northwest(ObAction *a) { a->data.diraction.direction = OB_DIRECTION_NORTHWEST; } -void setup_action_send_to_desktop(Action *a) +void setup_action_send_to_desktop(ObAction *a) +{ +} + +void setup_action_send_to_desktop_prev(ObAction *a) +{ + a->data.sendtodir.dir = OB_DIRECTION_WEST; + a->data.sendtodir.linear = TRUE; + a->data.sendtodir.wrap = TRUE; +} + +void setup_action_send_to_desktop_next(ObAction *a) { - a->data.sendto.follow = TRUE; + a->data.sendtodir.dir = OB_DIRECTION_EAST; + a->data.sendtodir.linear = TRUE; + a->data.sendtodir.wrap = TRUE; } -void setup_action_send_to_desktop_direction(Action *a) +void setup_action_send_to_desktop_left(ObAction *a) { + a->data.sendtodir.dir = OB_DIRECTION_WEST; + a->data.sendtodir.linear = FALSE; a->data.sendtodir.wrap = TRUE; - a->data.sendtodir.follow = TRUE; +} + +void setup_action_send_to_desktop_right(ObAction *a) +{ + a->data.sendtodir.dir = OB_DIRECTION_EAST; + a->data.sendtodir.linear = FALSE; + a->data.sendtodir.wrap = TRUE; +} + +void setup_action_send_to_desktop_up(ObAction *a) +{ + a->data.sendtodir.dir = OB_DIRECTION_NORTH; + a->data.sendtodir.linear = FALSE; + a->data.sendtodir.wrap = TRUE; +} + +void setup_action_send_to_desktop_down(ObAction *a) +{ + a->data.sendtodir.dir = OB_DIRECTION_SOUTH; + a->data.sendtodir.linear = FALSE; + a->data.sendtodir.wrap = TRUE; +} + +void setup_action_desktop_prev(ObAction *a) +{ + a->data.desktopdir.dir = OB_DIRECTION_WEST; + a->data.desktopdir.linear = TRUE; + a->data.desktopdir.wrap = TRUE; +} + +void setup_action_desktop_next(ObAction *a) +{ + a->data.desktopdir.dir = OB_DIRECTION_EAST; + a->data.desktopdir.linear = TRUE; + a->data.desktopdir.wrap = TRUE; +} + +void setup_action_desktop_left(ObAction *a) +{ + a->data.desktopdir.dir = OB_DIRECTION_WEST; + a->data.desktopdir.linear = FALSE; + a->data.desktopdir.wrap = TRUE; +} + +void setup_action_desktop_right(ObAction *a) +{ + a->data.desktopdir.dir = OB_DIRECTION_EAST; + a->data.desktopdir.linear = FALSE; + a->data.desktopdir.wrap = TRUE; } -void setup_action_desktop_direction(Action *a) +void setup_action_desktop_up(ObAction *a) { + a->data.desktopdir.dir = OB_DIRECTION_NORTH; + a->data.desktopdir.linear = FALSE; a->data.desktopdir.wrap = TRUE; } -void setup_action_move_keyboard(Action *a) +void setup_action_desktop_down(ObAction *a) +{ + a->data.desktopdir.dir = OB_DIRECTION_SOUTH; + a->data.desktopdir.linear = FALSE; + a->data.desktopdir.wrap = TRUE; +} + +void setup_action_move_keyboard(ObAction *a) { a->data.moveresize.corner = prop_atoms.net_wm_moveresize_move_keyboard; } -void setup_action_move(Action *a) +void setup_action_move(ObAction *a) { a->data.moveresize.corner = prop_atoms.net_wm_moveresize_move; } -void setup_action_resize(Action *a) +void setup_action_resize(ObAction *a) { a->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_topleft; } -void setup_action_resize_keyboard(Action *a) +void setup_action_resize_keyboard(ObAction *a) { a->data.moveresize.corner = prop_atoms.net_wm_moveresize_size_keyboard; } -void setup_action_cycle_windows_linear_next(Action *a) +void setup_action_cycle_windows_linear_next(ObAction *a) { a->data.cycle.linear = TRUE; a->data.cycle.forward = TRUE; } -void setup_action_cycle_windows_linear_previous(Action *a) +void setup_action_cycle_windows_linear_previous(ObAction *a) { a->data.cycle.linear = TRUE; a->data.cycle.forward = FALSE; } -void setup_action_cycle_windows_next(Action *a) +void setup_action_cycle_windows_next(ObAction *a) { a->data.cycle.linear = FALSE; a->data.cycle.forward = TRUE; } -void setup_action_cycle_windows_previous(Action *a) +void setup_action_cycle_windows_previous(ObAction *a) { a->data.cycle.linear = FALSE; a->data.cycle.forward = FALSE; } -void setup_action_movetoedge_north(Action *a) +void setup_action_movetoedge_north(ObAction *a) { a->data.diraction.direction = OB_DIRECTION_NORTH; } -void setup_action_movetoedge_south(Action *a) +void setup_action_movetoedge_south(ObAction *a) { a->data.diraction.direction = OB_DIRECTION_SOUTH; } -void setup_action_movetoedge_east(Action *a) +void setup_action_movetoedge_east(ObAction *a) { a->data.diraction.direction = OB_DIRECTION_EAST; } -void setup_action_movetoedge_west(Action *a) +void setup_action_movetoedge_west(ObAction *a) { a->data.diraction.direction = OB_DIRECTION_WEST; } -void setup_action_top_layer(Action *a) +void setup_action_top_layer(ObAction *a) { a->data.layer.layer = 1; } -void setup_action_normal_layer(Action *a) +void setup_action_normal_layer(ObAction *a) { a->data.layer.layer = 0; } -void setup_action_bottom_layer(Action *a) +void setup_action_bottom_layer(ObAction *a) { a->data.layer.layer = -1; }

@@ -358,49 +430,69 @@ action_send_to_desktop,

setup_action_send_to_desktop }, { + "sendtodesktopnext", + action_send_to_desktop_dir, + setup_action_send_to_desktop_next + }, + { + "sendtodesktopprevious", + action_send_to_desktop_dir, + setup_action_send_to_desktop_prev + }, + { "sendtodesktopright", - action_send_to_desktop_right, - setup_action_send_to_desktop_direction + action_send_to_desktop_dir, + setup_action_send_to_desktop_right }, { "sendtodesktopleft", - action_send_to_desktop_left, - setup_action_send_to_desktop_direction + action_send_to_desktop_dir, + setup_action_send_to_desktop_left }, { "sendtodesktopup", - action_send_to_desktop_up, - setup_action_send_to_desktop_direction + action_send_to_desktop_dir, + setup_action_send_to_desktop_up }, { "sendtodesktopdown", - action_send_to_desktop_down, - setup_action_send_to_desktop_direction + action_send_to_desktop_dir, + setup_action_send_to_desktop_down }, { "desktop", action_desktop, NULL + }, + { + "desktopnext", + action_desktop_dir, + setup_action_desktop_next + }, + { + "desktopprevious", + action_desktop_dir, + setup_action_desktop_prev }, { "desktopright", - action_desktop_right, - setup_action_desktop_direction + action_desktop_dir, + setup_action_desktop_right }, { "desktopleft", - action_desktop_left, - setup_action_desktop_direction + action_desktop_dir, + setup_action_desktop_left }, { "desktopup", - action_desktop_up, - setup_action_desktop_direction + action_desktop_dir, + setup_action_desktop_up }, { "desktopdown", - action_desktop_down, - setup_action_desktop_direction + action_desktop_dir, + setup_action_desktop_down }, { "toggledecorations",

@@ -529,9 +621,9 @@ NULL

} }; -Action *action_from_string(char *name) +ObAction *action_from_string(char *name) { - Action *a = NULL; + ObAction *a = NULL; int i; for (i = 0; actionstrings[i].name; i++)

@@ -544,10 +636,10 @@ }

return a; } -Action *action_parse(xmlDocPtr doc, xmlNodePtr node) +ObAction *action_parse(xmlDocPtr doc, xmlNodePtr node) { char *actname; - Action *act = NULL; + ObAction *act = NULL; xmlNodePtr n; if (parse_attr_string("name", node, &actname)) {

@@ -572,21 +664,13 @@ act->func == action_resize_relative_horz ||

act->func == action_resize_relative_vert) { if ((n = parse_find_node("delta", node->xmlChildrenNode))) act->data.relative.delta = parse_int(doc, n); - } else if (act->func == action_desktop_right || - act->func == action_desktop_left || - act->func == action_desktop_up || - act->func == action_desktop_down) { + } else if (act->func == action_desktop_dir) { if ((n = parse_find_node("wrap", node->xmlChildrenNode))) { act->data.desktopdir.wrap = parse_bool(doc, n); } - } else if (act->func == action_send_to_desktop_right || - act->func == action_send_to_desktop_left || - act->func == action_send_to_desktop_up || - act->func == action_send_to_desktop_down) { + } else if (act->func == action_send_to_desktop_dir) { if ((n = parse_find_node("wrap", node->xmlChildrenNode))) act->data.sendtodir.wrap = parse_bool(doc, n); - if ((n = parse_find_node("follow", node->xmlChildrenNode))) - act->data.sendtodir.follow = parse_bool(doc, n); } } g_free(actname);

@@ -802,8 +886,8 @@ if (!c || !client_normal(c)) return;

if (data->sendto.desk < screen_num_desktops || data->sendto.desk == DESKTOP_ALL) { - client_set_desktop(c, data->sendto.desk, data->sendto.follow); - if (data->sendto.follow) screen_set_desktop(data->sendto.desk); + client_set_desktop(c, data->sendto.desk, TRUE); + screen_set_desktop(data->sendto.desk); } }

@@ -814,114 +898,34 @@ data->desktop.desk == DESKTOP_ALL)

screen_set_desktop(data->desktop.desk); } -static void cur_row_col(guint *r, guint *c) +void action_desktop_dir(union ActionData *data) { - switch (screen_desktop_layout.orientation) { - case OB_ORIENTATION_HORZ: - switch (screen_desktop_layout.start_corner) { - case OB_CORNER_TOPLEFT: - *r = screen_desktop / screen_desktop_layout.columns; - *c = screen_desktop % screen_desktop_layout.columns; - break; - case OB_CORNER_BOTTOMLEFT: - *r = screen_desktop_layout.rows - 1 - - screen_desktop / screen_desktop_layout.columns; - *c = screen_desktop % screen_desktop_layout.columns; - break; - case OB_CORNER_TOPRIGHT: - *r = screen_desktop / screen_desktop_layout.columns; - *c = screen_desktop_layout.columns - 1 - - screen_desktop % screen_desktop_layout.columns; - break; - case OB_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 OB_ORIENTATION_VERT: - switch (screen_desktop_layout.start_corner) { - case OB_CORNER_TOPLEFT: - *r = screen_desktop % screen_desktop_layout.rows; - *c = screen_desktop / screen_desktop_layout.rows; - break; - case OB_CORNER_BOTTOMLEFT: - *r = screen_desktop_layout.rows - 1 - - screen_desktop % screen_desktop_layout.rows; - *c = screen_desktop / screen_desktop_layout.rows; - break; - case OB_CORNER_TOPRIGHT: - *r = screen_desktop % screen_desktop_layout.rows; - *c = screen_desktop_layout.columns - 1 - - screen_desktop / screen_desktop_layout.rows; - break; - case OB_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; - } + guint d; + + d = screen_cycle_desktop(data->desktopdir.dir, data->desktopdir.wrap, + data->sendtodir.linear, + data->desktopdir.final, data->desktopdir.cancel); + screen_set_desktop(d); } -static guint translate_row_col(guint r, guint c) +void action_send_to_desktop_dir(union ActionData *data) { - switch (screen_desktop_layout.orientation) { - case OB_ORIENTATION_HORZ: - switch (screen_desktop_layout.start_corner) { - case OB_CORNER_TOPLEFT: - return r % screen_desktop_layout.rows * - screen_desktop_layout.columns + - c % screen_desktop_layout.columns; - case OB_CORNER_BOTTOMLEFT: - return (screen_desktop_layout.rows - 1 - - r % screen_desktop_layout.rows) * - screen_desktop_layout.columns + - c % screen_desktop_layout.columns; - case OB_CORNER_TOPRIGHT: - return r % screen_desktop_layout.rows * - screen_desktop_layout.columns + - (screen_desktop_layout.columns - 1 - - c % screen_desktop_layout.columns); - case OB_CORNER_BOTTOMRIGHT: - return (screen_desktop_layout.rows - 1 - - r % screen_desktop_layout.rows) * - screen_desktop_layout.columns + - (screen_desktop_layout.columns - 1 - - c % screen_desktop_layout.columns); - } - case OB_ORIENTATION_VERT: - switch (screen_desktop_layout.start_corner) { - case OB_CORNER_TOPLEFT: - return c % screen_desktop_layout.columns * - screen_desktop_layout.rows + - r % screen_desktop_layout.rows; - case OB_CORNER_BOTTOMLEFT: - return c % screen_desktop_layout.columns * - screen_desktop_layout.rows + - (screen_desktop_layout.rows - 1 - - r % screen_desktop_layout.rows); - case OB_CORNER_TOPRIGHT: - return (screen_desktop_layout.columns - 1 - - c % screen_desktop_layout.columns) * - screen_desktop_layout.rows + - r % screen_desktop_layout.rows; - case OB_CORNER_BOTTOMRIGHT: - return (screen_desktop_layout.columns - 1 - - c % screen_desktop_layout.columns) * - screen_desktop_layout.rows + - (screen_desktop_layout.rows - 1 - - r % screen_desktop_layout.rows); - } - } - g_assert_not_reached(); - return 0; + ObClient *c = data->sendtodir.c; + guint d; + + if (!c || !client_normal(c)) return; + + d = screen_cycle_desktop(data->sendtodir.dir, data->sendtodir.wrap, + data->sendtodir.linear, + data->sendtodir.final, data->sendtodir.cancel); + + g_message("sendto %d", d); + + client_set_desktop(c, d, TRUE); + screen_set_desktop(d); } +#if 0 void action_desktop_right(union ActionData *data) { guint r, c, d;

@@ -939,7 +943,8 @@ ++c;

} d = translate_row_col(r, c); if (d < screen_num_desktops) - screen_set_desktop(d); + screen_cycle_desktop(d, data->desktopdir.final, + data->desktopdir.cancel); } void action_send_to_desktop_right(union ActionData *data)

@@ -963,7 +968,9 @@ }

d = translate_row_col(r, c); if (d < screen_num_desktops) { client_set_desktop(cl, d, data->sendtodir.follow); - if (data->sendtodir.follow) screen_set_desktop(d); + if (data->sendtodir.follow) + screen_cycle_desktop(d, data->desktopdir.final, + data->desktopdir.cancel); } }

@@ -984,7 +991,8 @@ --c;

} d = translate_row_col(r, c); if (d < screen_num_desktops) - screen_set_desktop(d); + screen_cycle_desktop(d, data->desktopdir.final, + data->desktopdir.cancel); } void action_send_to_desktop_left(union ActionData *data)

@@ -1008,7 +1016,9 @@ }

d = translate_row_col(r, c); if (d < screen_num_desktops) { client_set_desktop(cl, d, data->sendtodir.follow); - if (data->sendtodir.follow) screen_set_desktop(d); + if (data->sendtodir.follow) + screen_cycle_desktop(d, data->desktopdir.final, + data->desktopdir.cancel); } }

@@ -1029,7 +1039,8 @@ ++r;

} d = translate_row_col(r, c); if (d < screen_num_desktops) - screen_set_desktop(d); + screen_cycle_desktop(d, data->desktopdir.final, + data->desktopdir.cancel); } void action_send_to_desktop_down(union ActionData *data)

@@ -1051,7 +1062,9 @@ }

d = translate_row_col(r, c); if (d < screen_num_desktops) { client_set_desktop(data->sendtodir.c, d, data->sendtodir.follow); - if (data->sendtodir.follow) screen_set_desktop(d); + if (data->sendtodir.follow) + screen_cycle_desktop(d, data->desktopdir.final, + data->desktopdir.cancel); } } }

@@ -1073,7 +1086,8 @@ --r;

} d = translate_row_col(r, c); if (d < screen_num_desktops) - screen_set_desktop(d); + screen_cycle_desktop(d, data->desktopdir.final, + data->desktopdir.cancel); } void action_send_to_desktop_up(union ActionData *data)

@@ -1095,10 +1109,13 @@ }

d = translate_row_col(r, c); if (d < screen_num_desktops) { client_set_desktop(data->sendtodir.c, d, data->sendtodir.follow); - if (data->sendtodir.follow) screen_set_desktop(d); + if (data->sendtodir.follow) + screen_cycle_desktop(d, data->desktopdir.final, + data->desktopdir.cancel); } } } +#endif void action_toggle_decorations(union ActionData *data) {
M openbox/action.hopenbox/action.h

@@ -4,6 +4,8 @@

#include "misc.h" #include "parser/parse.h" +typedef struct _ObAction ObAction; + /* These have to all have a Client* at the top even if they don't use it, so that I can set it blindly later on. So every function will have a Client* available (possibly NULL though) if it wants it.

@@ -40,8 +42,11 @@ };

struct SendToDesktopDirection { struct _ObClient *c; + ObDirection dir; gboolean wrap; - gboolean follow; + gboolean linear; + gboolean final; + gboolean cancel; }; struct Desktop {

@@ -56,7 +61,11 @@ };

struct DesktopDirection { struct _ObClient *c; + ObDirection dir; gboolean wrap; + gboolean linear; + gboolean final; + gboolean cancel; }; struct MoveResize {

@@ -98,15 +107,15 @@ struct CycleWindows cycle;

struct Layer layer; }; -typedef struct { +struct _ObAction { /* The func member acts like an enum to tell which one of the structs in the data union are valid. */ void (*func)(union ActionData *data); union ActionData data; -} Action; +}; -Action *action_new(void (*func)(union ActionData *data)); +ObAction *action_new(void (*func)(union ActionData *data)); /* Creates a new Action from the name of the action A few action types need data set after making this call still. Check if

@@ -120,9 +129,9 @@ action_resize_relative_horz - the delta

action_resize_relative_vert - the delta */ -Action *action_from_string(char *name); -Action *action_parse(xmlDocPtr doc, xmlNodePtr node); -void action_free(Action *a); +ObAction *action_from_string(char *name); +ObAction *action_parse(xmlDocPtr doc, xmlNodePtr node); +void action_free(ObAction *a); /* Execute */ void action_execute(union ActionData *data);

@@ -181,23 +190,11 @@ void action_toggle_maximize_vert(union ActionData *data);

/* SendToDesktop */ void action_send_to_desktop(union ActionData *data); /* SendToDesktopDirection */ -void action_send_to_desktop_right(union ActionData *data); -/* SendToDesktopDirection */ -void action_send_to_desktop_left(union ActionData *data); -/* SendToDesktopDirection */ -void action_send_to_desktop_up(union ActionData *data); -/* SendToDesktopDirection */ -void action_send_to_desktop_down(union ActionData *data); +void action_send_to_desktop_dir(union ActionData *data); /* Desktop */ void action_desktop(union ActionData *data); /* DesktopDirection */ -void action_desktop_right(union ActionData *data); -/* DesktopDirection */ -void action_desktop_left(union ActionData *data); -/* DesktopDirection */ -void action_desktop_up(union ActionData *data); -/* DesktopDirection */ -void action_desktop_down(union ActionData *data); +void action_desktop_dir(union ActionData *data); /* ClientAction */ void action_toggle_decorations(union ActionData *data); /* MoveResize */
M openbox/client.copenbox/client.c

@@ -18,6 +18,8 @@ #include "openbox.h"

#include "group.h" #include "config.h" #include "menu.h" +#include "keyboard.h" +#include "mouse.h" #include "render/render.h" #include <glib.h>

@@ -327,6 +329,9 @@

/* update the list hints */ client_set_list(); + keyboard_grab_for_client(self, TRUE); + mouse_grab_for_client(self, TRUE); + dispatch_client(Event_Client_Mapped, self, 0, 0); ob_debug("Managed window 0x%lx (%s)\n", window, self->class);

@@ -355,6 +360,9 @@

dispatch_client(Event_Client_Destroy, self, 0, 0); g_assert(self != NULL); + keyboard_grab_for_client(self, FALSE); + mouse_grab_for_client(self, FALSE); + /* remove the window from our save set */ XChangeSaveSet(ob_display, self->window, SetModeDelete);

@@ -1097,7 +1105,7 @@

/* finally, the user can have requested no decorations, which overrides everything */ if (!self->decorate) - self->decorations = 0; + self->decorations = OB_FRAME_DECOR_BORDER; /* if we don't have a titlebar, then we cannot shade! */ if (!(self->decorations & OB_FRAME_DECOR_TITLEBAR))

@@ -1705,7 +1713,7 @@ gboolean user, gboolean final,

gboolean force_reply) { gboolean moved = FALSE, resized = FALSE; - gint fdecor = self->frame->decorations; + guint fdecor = self->frame->decorations; /* make the frame recalculate its dimentions n shit without changing anything visible for real, this way the constraints below can work with
M openbox/config.copenbox/config.c

@@ -1,4 +1,7 @@

#include "config.h" +#include "keyboard.h" +#include "mouse.h" +#include "prop.h" #include "parser/parse.h" gboolean config_focus_new;

@@ -25,6 +28,151 @@ ObOrientation config_dock_orient;

gboolean config_dock_hide; guint config_dock_hide_timeout; +gint config_mouse_threshold; +gint config_mouse_dclicktime; + +/* + +<keybind key="C-x"> + <action name="ChangeDesktop"> + <desktop>3</desktop> + </action> +</keybind> + +*/ + +static void parse_key(xmlDocPtr doc, xmlNodePtr node, GList *keylist) +{ + char *key; + ObAction *action; + xmlNodePtr n, nact; + GList *it; + + n = parse_find_node("keybind", node); + while (n) { + if (parse_attr_string("key", n, &key)) { + keylist = g_list_append(keylist, key); + + parse_key(doc, n->xmlChildrenNode, keylist); + + it = g_list_last(keylist); + g_free(it->data); + keylist = g_list_delete_link(keylist, it); + } + n = parse_find_node("keybind", n->next); + } + if (keylist) { + nact = parse_find_node("action", node); + while (nact) { + if ((action = action_parse(doc, nact))) { + /* validate that its okay for a key binding */ + if (action->func == action_moveresize && + action->data.moveresize.corner != + prop_atoms.net_wm_moveresize_move_keyboard && + action->data.moveresize.corner != + prop_atoms.net_wm_moveresize_size_keyboard) { + action_free(action); + action = NULL; + } + + if (action) + keyboard_bind(keylist, action); + } + nact = parse_find_node("action", nact->next); + } + } +} + +static void parse_keyboard(xmlDocPtr doc, xmlNodePtr node, void *d) +{ + parse_key(doc, node->xmlChildrenNode, NULL); +} + +static int threshold; +static int dclicktime; +/* + +<context name="Titlebar"> + <mousebind button="Left" action="Press"> + <action name="Raise"></action> + </mousebind> +</context> + +*/ + +static void parse_mouse(xmlDocPtr doc, xmlNodePtr node, void *d) +{ + xmlNodePtr n, nbut, nact; + char *buttonstr; + char *contextstr; + ObMouseAction mact; + ObAction *action; + + node = node->xmlChildrenNode; + + if ((n = parse_find_node("dragThreshold", node))) + threshold = parse_int(doc, n); + if ((n = parse_find_node("doubleClickTime", node))) + dclicktime = parse_int(doc, n); + + n = parse_find_node("context", node); + while (n) { + if (!parse_attr_string("name", n, &contextstr)) + goto next_n; + nbut = parse_find_node("mousebind", n->xmlChildrenNode); + while (nbut) { + if (!parse_attr_string("button", nbut, &buttonstr)) + goto next_nbut; + if (parse_attr_contains("press", nbut, "action")) + mact = MouseAction_Press; + else if (parse_attr_contains("release", nbut, "action")) + mact = MouseAction_Release; + else if (parse_attr_contains("click", nbut, "action")) + mact = MouseAction_Click; + else if (parse_attr_contains("doubleclick", nbut,"action")) + mact = MouseAction_DClick; + else if (parse_attr_contains("drag", nbut, "action")) + mact = MouseAction_Motion; + else + goto next_nbut; + nact = parse_find_node("action", nbut->xmlChildrenNode); + while (nact) { + if ((action = action_parse(doc, nact))) { + /* validate that its okay for a mouse binding*/ + if (mact == MouseAction_Motion) { + if (action->func != action_moveresize || + action->data.moveresize.corner == + prop_atoms.net_wm_moveresize_move_keyboard || + action->data.moveresize.corner == + prop_atoms.net_wm_moveresize_size_keyboard) { + action_free(action); + action = NULL; + } + } else { + if (action->func == action_moveresize && + action->data.moveresize.corner != + prop_atoms.net_wm_moveresize_move_keyboard && + action->data.moveresize.corner != + prop_atoms.net_wm_moveresize_size_keyboard) { + action_free(action); + action = NULL; + } + } + if (action) + mouse_bind(buttonstr, contextstr, mact, action); + } + nact = parse_find_node("action", nact->next); + } + g_free(buttonstr); + next_nbut: + nbut = parse_find_node("mousebind", nbut->next); + } + g_free(contextstr); + next_n: + n = parse_find_node("context", n->next); + } +} + static void parse_focus(xmlDocPtr doc, xmlNodePtr node, void *d) { xmlNodePtr n;

@@ -190,6 +338,13 @@ config_dock_hide = FALSE;

config_dock_hide_timeout = 3000; parse_register("dock", parse_dock, NULL); + + parse_register("keyboard", parse_keyboard, NULL); + + config_mouse_threshold = 3; + config_mouse_dclicktime = 200; + + parse_register("mouse", parse_mouse, NULL); } void config_shutdown()
M openbox/config.hopenbox/config.h

@@ -52,6 +52,11 @@ extern int config_desktops_num;

/*! Names for the desktops */ extern GSList *config_desktops_names; +/*! Number of pixels a drag must go before being considered a drag */ +extern gint config_mouse_threshold; +/*! Number of milliseconds within which 2 clicks must occur to be a + double-click */ +extern gint config_mouse_dclicktime; void config_startup(); void config_shutdown();
M openbox/event.copenbox/event.c

@@ -8,6 +8,8 @@ #include "config.h"

#include "screen.h" #include "frame.h" #include "menu.h" +#include "keyboard.h" +#include "mouse.h" #include "framerender.h" #include "focus.h" #include "moveresize.h"

@@ -541,13 +543,23 @@

} /* user input (action-bound) events */ - /* if (e->type == ButtonPress || e->type == ButtonRelease || - e->type == MotionNotify) - mouse_event(e, client); - else if (e->type == KeyPress || e->type == KeyRelease) - ; - */ + e->type == MotionNotify || e->type == KeyPress || + e->type == KeyRelease) + { + ObFrameContext context; + + context = frame_context(client, e->xany.window); + + if (!keyboard_process_interactive_grab(e, &client, &context)) { + + if (e->type == ButtonPress || e->type == ButtonRelease || + e->type == MotionNotify) + mouse_event(client, context, e); + else if (e->type == KeyPress) + keyboard_event(client, e); + } + } /* dispatch the event to registered handlers */ dispatch_x(e, client);
M openbox/focus.copenbox/focus.c

@@ -262,7 +262,7 @@ }

} ObClient *focus_cycle(gboolean forward, gboolean linear, gboolean done, - gboolean cancel) + gboolean cancel) { static ObClient *first = NULL; static ObClient *t = NULL;

@@ -281,8 +281,6 @@ if (focus_cycle_target)

client_activate(focus_cycle_target); goto done_cycle; } - if (!first) - grab_pointer(TRUE, None); if (!first) first = focus_client; if (!focus_cycle_target) focus_cycle_target = focus_client;

@@ -331,7 +329,6 @@ g_list_free(order);

order = NULL; popup_cycle(ft, FALSE); - grab_pointer(FALSE, None); return NULL; }
A openbox/keyboard.c

@@ -0,0 +1,265 @@

+#include "focus.h" +#include "screen.h" +#include "frame.h" +#include "openbox.h" +#include "event.h" +#include "grab.h" +#include "client.h" +#include "action.h" +#include "prop.h" +#include "timer.h" +#include "keytree.h" +#include "keyboard.h" +#include "translate.h" + +#include <glib.h> + +KeyBindingTree *keyboard_firstnode; + +static KeyBindingTree *curpos; +static ObTimer *chain_timer; +static gboolean interactive_grab; +static guint grabbed_state; +static ObClient *grabbed_client; +static ObAction *grabbed_action; +static ObFrameContext grabbed_context; + +static void grab_for_window(Window win, gboolean grab) +{ + KeyBindingTree *p; + + ungrab_all_keys(win); + + if (grab) { + p = curpos ? curpos->first_child : keyboard_firstnode; + while (p) { + grab_key(p->key, p->state, win, GrabModeAsync); + p = p->next_sibling; + } + } +} + +void keyboard_grab_for_client(ObClient *c, gboolean grab) +{ + grab_for_window(c->window, grab); +} + +static void grab_keys(gboolean grab) +{ + GList *it; + + grab_for_window(screen_support_win, grab); + for (it = client_list; it; it = g_list_next(it)) + grab_for_window(((ObClient*)it->data)->frame->window, grab); +} + +void keyboard_reset_chains() +{ + if (chain_timer) { + timer_stop(chain_timer); + chain_timer = NULL; + } + if (curpos) { + curpos = NULL; + grab_keys(TRUE); + } +} + +static void chain_timeout(ObTimer *t, void *data) +{ + keyboard_reset_chains(); +} + +gboolean keyboard_bind(GList *keylist, ObAction *action) +{ + KeyBindingTree *tree, *t; + gboolean conflict; + + g_assert(keylist != NULL); + g_assert(action != NULL); + + if (!(tree = tree_build(keylist))) + return FALSE; + + if ((t = tree_find(tree, &conflict)) != NULL) { + /* already bound to something, use the existing tree */ + tree_destroy(tree); + tree = NULL; + } else + t = tree; + while (t->first_child) t = t->first_child; + + if (conflict) { + g_warning("conflict with binding"); + tree_destroy(tree); + return FALSE; + } + + /* set the action */ + t->actions = g_slist_append(t->actions, action); + /* assimilate this built tree into the main tree. assimilation + destroys/uses the tree */ + if (tree) tree_assimilate(tree); + + return TRUE; +} + +void keyboard_interactive_grab(guint state, ObClient *client, + ObFrameContext context, ObAction *action) +{ + if (!interactive_grab && grab_keyboard(TRUE)) { + interactive_grab = TRUE; + grabbed_state = state; + grabbed_client = client; + grabbed_action = action; + grabbed_context = context; + grab_pointer(TRUE, None); + } +} + +gboolean keyboard_process_interactive_grab(const XEvent *e, + ObClient **client, + ObFrameContext *context) +{ + gboolean handled = FALSE; + gboolean done = FALSE; + + if (interactive_grab) { + *client = grabbed_client; + *context = grabbed_context; + } + + if ((e->type == KeyRelease && + !(grabbed_state & e->xkey.state))) + done = TRUE; + else if (e->type == KeyPress) { + if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN)) + done = TRUE; + else if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) { + if (grabbed_action->func == action_cycle_windows) { + grabbed_action->data.cycle.cancel = TRUE; + } + if (grabbed_action->func == action_desktop_dir) { + grabbed_action->data.desktopdir.cancel = TRUE; + } + if (grabbed_action->func == action_send_to_desktop_dir) + { + grabbed_action->data.sendtodir.cancel = TRUE; + } + done = TRUE; + } + } + if (done) { + if (grabbed_action->func == action_cycle_windows) { + grabbed_action->data.cycle.final = TRUE; + } + if (grabbed_action->func == action_desktop_dir) { + grabbed_action->data.desktopdir.final = TRUE; + } + if (grabbed_action->func == action_send_to_desktop_dir) { + grabbed_action->data.sendtodir.final = TRUE; + } + + grabbed_action->func(&grabbed_action->data); + + interactive_grab = FALSE; + grab_keyboard(FALSE); + grab_pointer(FALSE, None); + keyboard_reset_chains(); + + handled = TRUE; + } + + return handled; +} + +void keyboard_event(ObClient *client, const XEvent *e) +{ + KeyBindingTree *p; + + g_assert(e->type == KeyPress); + + if (curpos == NULL) + p = keyboard_firstnode; + else + p = curpos->first_child; + while (p) { + if (p->key == e->xkey.keycode && + p->state == e->xkey.state) { + if (p->first_child != NULL) { /* part of a chain */ + if (chain_timer) timer_stop(chain_timer); + /* 5 second timeout for chains */ + chain_timer = timer_start(5000*1000, chain_timeout, + NULL); + curpos = p; + grab_keys(TRUE); + } else { + GSList *it; + for (it = p->actions; it; it = it->next) { + ObAction *act = it->data; + if (act->func != NULL) { + act->data.any.c = client; + + if (act->func == action_cycle_windows) + { + act->data.cycle.final = FALSE; + act->data.cycle.cancel = FALSE; + } + if (act->func == action_desktop_dir) + { + act->data.desktopdir.final = FALSE; + act->data.desktopdir.cancel = FALSE; + } + if (act->func == action_send_to_desktop_dir) + { + act->data.sendtodir.final = FALSE; + act->data.sendtodir.cancel = FALSE; + } + + if (act->func == action_moveresize) + { + screen_pointer_pos(&act->data.moveresize.x, + &act->data.moveresize.y); + } + + if ((act->func == action_cycle_windows || + act->func == action_desktop_dir || + act->func == action_send_to_desktop_dir)) + { + keyboard_interactive_grab(e->xkey.state, client, + 0, act); + } + + if (act->func == action_showmenu) + { + act->data.showmenu.x = + e->xkey.x_root; + act->data.showmenu.y = + e->xkey.y_root; + } + + act->data.any.c = client; + act->func(&act->data); + } + } + + keyboard_reset_chains(); + } + break; + } + p = p->next_sibling; + } +} + +void keyboard_startup() +{ + grab_keys(TRUE); +} + +void keyboard_shutdown() +{ + tree_destroy(keyboard_firstnode); + keyboard_firstnode = NULL; + grab_keys(FALSE); +} +
A openbox/keyboard.h

@@ -0,0 +1,32 @@

+#ifndef ob__keybaord_h +#define ob__keybaord_h + +#include "keytree.h" +#include "frame.h" + +#include <glib.h> +#include <X11/Xlib.h> + +struct _ObClient; +struct _ObAction; + +extern KeyBindingTree *keyboard_firstnode; + +void keyboard_startup(); +void keyboard_shutdown(); + +gboolean keyboard_bind(GList *keylist, ObAction *action); + +void keyboard_event(struct _ObClient *client, const XEvent *e); +void keyboard_reset_chains(); + +void keyboard_interactive_grab(guint state, struct _ObClient *client, + ObFrameContext context, + struct _ObAction *action); +gboolean keyboard_process_interactive_grab(const XEvent *e, + struct _ObClient **client, + ObFrameContext *context); + +void keyboard_grab_for_client(struct _ObClient *c, gboolean grab); + +#endif
A openbox/keytree.c

@@ -0,0 +1,112 @@

+#include "keyboard.h" +#include "translate.h" +#include <glib.h> + +void tree_destroy(KeyBindingTree *tree) +{ + KeyBindingTree *c; + + while (tree) { + tree_destroy(tree->next_sibling); + c = tree->first_child; + if (c == NULL) { + GList *it; + GSList *sit; + for (it = tree->keylist; it != NULL; it = it->next) + g_free(it->data); + g_list_free(tree->keylist); + for (sit = tree->actions; sit != NULL; sit = sit->next) + action_free(sit->data); + g_slist_free(tree->actions); + } + g_free(tree); + tree = c; + } +} + +KeyBindingTree *tree_build(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_new0(KeyBindingTree, 1); + 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_key(it->data, &ret->state, &ret->key)) { + tree_destroy(ret); + return NULL; + } + } + return ret; +} + +void tree_assimilate(KeyBindingTree *node) +{ + KeyBindingTree *a, *b, *tmp, *last; + + if (keyboard_firstnode == NULL) { + /* there are no nodes at this level yet */ + keyboard_firstnode = node; + } else { + a = keyboard_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); + } + } +} + +KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict) +{ + KeyBindingTree *a, *b; + + *conflict = FALSE; + + a = keyboard_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 */ +}
A openbox/keytree.h

@@ -0,0 +1,25 @@

+#ifndef __plugin_keyboard_tree_h +#define __plugin_keyboard_tree_h + +#include "action.h" + +#include <glib.h> + +typedef struct KeyBindingTree { + guint state; + guint key; + GList *keylist; + GSList *actions; /* list of Action pointers */ + + /* the next binding in the tree at the same level */ + struct KeyBindingTree *next_sibling; + /* the first child of this binding (next binding in a chained sequence).*/ + struct KeyBindingTree *first_child; +} KeyBindingTree; + +void tree_destroy(KeyBindingTree *tree); +KeyBindingTree *tree_build(GList *keylist); +void tree_assimilate(KeyBindingTree *node); +KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict); + +#endif
M openbox/menu.copenbox/menu.c

@@ -27,7 +27,7 @@

void parse_menu_full(xmlDocPtr doc, xmlNodePtr node, void *data, gboolean newmenu) { - Action *act; + ObAction *act; xmlNodePtr nact; gchar *id = NULL, *title = NULL, *label = NULL, *plugin;

@@ -233,7 +233,7 @@ {

g_hash_table_remove(menu_hash, name); } -ObMenuEntry *menu_entry_new_full(char *label, Action *action, +ObMenuEntry *menu_entry_new_full(char *label, ObAction *action, ObMenuEntryRenderType render_type, gpointer submenu) {
M openbox/menu.hopenbox/menu.h

@@ -103,7 +103,7 @@ {

char *label; ObMenu *parent; - Action *action; + ObAction *action; ObMenuEntryRenderType render_type; gboolean hilite;

@@ -155,7 +155,7 @@ void menu_hide(ObMenu *self);

void menu_clear(ObMenu *self); -ObMenuEntry *menu_entry_new_full(char *label, Action *action, +ObMenuEntry *menu_entry_new_full(char *label, ObAction *action, ObMenuEntryRenderType render_type, gpointer submenu);
A openbox/mouse.c

@@ -0,0 +1,372 @@

+#include "openbox.h" +#include "config.h" +#include "action.h" +#include "event.h" +#include "client.h" +#include "prop.h" +#include "grab.h" +#include "frame.h" +#include "translate.h" +#include "mouse.h" +#include "keyboard.h" +#include <glib.h> + +typedef struct { + guint state; + guint button; + GSList *actions[NUM_MOUSEACTION]; /* lists of Action pointers */ +} ObMouseBinding; + +/* Array of GSList*s of PointerBinding*s. */ +static GSList *bound_contexts[OB_FRAME_NUM_CONTEXTS]; + +void mouse_grab_for_client(ObClient *client, gboolean grab) +{ + int i; + GSList *it; + + for (i = 0; i < OB_FRAME_NUM_CONTEXTS; ++i) + for (it = bound_contexts[i]; it != NULL; it = it->next) { + /* grab/ungrab the button */ + ObMouseBinding *b = it->data; + Window win; + int mode; + unsigned int mask; + + if (i == OB_FRAME_CONTEXT_FRAME) { + win = client->frame->window; + mode = GrabModeAsync; + mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask; + } else if (i == OB_FRAME_CONTEXT_CLIENT) { + win = client->frame->plate; + mode = GrabModeSync; /* this is handled in event */ + mask = ButtonPressMask; /* can't catch more than this with Sync + mode the release event is + manufactured in event() */ + } else continue; + + if (grab) + grab_button_full(b->button, b->state, win, mask, mode, None); + else + ungrab_button(b->button, b->state, win); + } +} + +static void grab_all_clients(gboolean grab) +{ + GList *it; + + for (it = client_list; it != NULL; it = it->next) + mouse_grab_for_client(it->data, grab); +} + +static void clearall() +{ + int i; + GSList *it; + + for(i = 0; i < OB_FRAME_NUM_CONTEXTS; ++i) { + for (it = bound_contexts[i]; it != NULL; it = it->next) { + int j; + + ObMouseBinding *b = it->data; + for (j = 0; j < NUM_MOUSEACTION; ++j) { + GSList *it; + for (it = b->actions[j]; it; it = it->next) { + action_free(it->data); + } + g_slist_free(b->actions[j]); + } + g_free(b); + } + g_slist_free(bound_contexts[i]); + } +} + +static void fire_button(ObMouseAction a, ObFrameContext context, + ObClient *c, guint state, + guint button, int x, int y) +{ + GSList *it; + ObMouseBinding *b; + + g_message("%d %d %d", context, state, button); + + for (it = bound_contexts[context]; it != NULL; it = it->next) { + b = it->data; + if (b->state == state && b->button == button) + break; + } + /* if not bound, then nothing to do! */ + if (it == NULL) return; + + for (it = b->actions[a]; it; it = it->next) { + ObAction *act = it->data; + if (act->func != NULL) { + act->data.any.c = c; + + g_assert(act->func != action_moveresize); + + if (act->func == action_showmenu) { + act->data.showmenu.x = x; + act->data.showmenu.y = y; + } + + if (act->func == action_desktop_dir) + { + act->data.desktopdir.final = FALSE; + act->data.desktopdir.cancel = FALSE; + } + if (act->func == action_send_to_desktop_dir) + { + act->data.sendtodir.final = FALSE; + act->data.sendtodir.cancel = FALSE; + } + + if ((act->func == action_desktop_dir || + act->func == action_send_to_desktop_dir)) { + keyboard_interactive_grab(state, c, context, act); + } + + g_message("acting"); + + act->func(&act->data); + } + } +} + +static void fire_motion(ObMouseAction a, ObFrameContext context, ObClient *c, + guint state, guint button, int x_root, int y_root, + guint32 corner) +{ + GSList *it; + ObMouseBinding *b; + + for (it = bound_contexts[context]; it != NULL; it = it->next) { + b = it->data; + if (b->state == state && b->button == button) + break; + } + /* if not bound, then nothing to do! */ + if (it == NULL) return; + + for (it = b->actions[a]; it; it = it->next) { + ObAction *act = it->data; + if (act->func != NULL) { + act->data.any.c = c; + + if (act->func == action_moveresize) { + act->data.moveresize.x = x_root; + act->data.moveresize.y = y_root; + act->data.moveresize.button = button; + if (!(act->data.moveresize.corner == + prop_atoms.net_wm_moveresize_move || + act->data.moveresize.corner == + prop_atoms.net_wm_moveresize_move_keyboard || + act->data.moveresize.corner == + prop_atoms.net_wm_moveresize_size_keyboard)) + act->data.moveresize.corner = corner; + } else + g_assert_not_reached(); + + act->func(&act->data); + } + } +} + +static guint32 pick_corner(int x, int y, int cx, int cy, int cw, int ch) +{ + if (x - cx < cw / 2) { + if (y - cy < ch / 2) + return prop_atoms.net_wm_moveresize_size_topleft; + else + return prop_atoms.net_wm_moveresize_size_bottomleft; + } else { + if (y - cy < ch / 2) + return prop_atoms.net_wm_moveresize_size_topright; + else + return prop_atoms.net_wm_moveresize_size_bottomright; + } +} + +void mouse_event(ObClient *client, ObFrameContext context, XEvent *e) +{ + static Time ltime; + static guint button = 0, state = 0, lbutton = 0; + + static Window lwindow = None; + static int px, py; + gboolean click = FALSE; + gboolean dclick = FALSE; + + switch (e->type) { + case ButtonPress: + px = e->xbutton.x_root; + py = e->xbutton.y_root; + button = e->xbutton.button; + state = e->xbutton.state; + + fire_button(MouseAction_Press, context, + client, e->xbutton.state, + e->xbutton.button, + e->xbutton.x_root, e->xbutton.y_root); + + if (context == OB_FRAME_CONTEXT_CLIENT) { + /* Replay the event, so it goes to the client*/ + XAllowEvents(ob_display, ReplayPointer, event_lasttime); + /* Fall through to the release case! */ + } else + break; + + case ButtonRelease: + if (e->xbutton.button == button) { + /* clicks are only valid if its released over the window */ + int junk1, junk2; + Window wjunk; + guint ujunk, b, w, h; + XGetGeometry(ob_display, e->xbutton.window, + &wjunk, &junk1, &junk2, &w, &h, &b, &ujunk); + if (e->xbutton.x >= (signed)-b && + e->xbutton.y >= (signed)-b && + e->xbutton.x < (signed)(w+b) && + e->xbutton.y < (signed)(h+b)) { + click = TRUE; + /* double clicks happen if there were 2 in a row! */ + if (lbutton == button && + lwindow == e->xbutton.window && + e->xbutton.time - config_mouse_dclicktime <= + ltime) { + dclick = TRUE; + lbutton = 0; + } else { + lbutton = button; + lwindow = e->xbutton.window; + } + } else { + lbutton = 0; + lwindow = None; + } + + button = 0; + state = 0; + ltime = e->xbutton.time; + } + fire_button(MouseAction_Release, context, + client, e->xbutton.state, + e->xbutton.button, + e->xbutton.x_root, e->xbutton.y_root); + if (click) + fire_button(MouseAction_Click, context, + client, e->xbutton.state, + e->xbutton.button, + e->xbutton.x_root, + e->xbutton.y_root); + if (dclick) + fire_button(MouseAction_DClick, context, + client, e->xbutton.state, + e->xbutton.button, + e->xbutton.x_root, + e->xbutton.y_root); + break; + + case MotionNotify: + if (button) { + if (ABS(e->xmotion.x_root - px) >= + config_mouse_threshold || + ABS(e->xmotion.y_root - py) >= + config_mouse_threshold) { + guint32 corner; + + /* You can't drag on buttons */ + if (context == OB_FRAME_CONTEXT_MAXIMIZE || + context == OB_FRAME_CONTEXT_ALLDESKTOPS || + context == OB_FRAME_CONTEXT_SHADE || + context == OB_FRAME_CONTEXT_ICONIFY || + context == OB_FRAME_CONTEXT_ICON || + context == OB_FRAME_CONTEXT_CLOSE) + break; + + if (!client) + corner = prop_atoms.net_wm_moveresize_size_bottomright; + else + corner = + pick_corner(e->xmotion.x_root, + e->xmotion.y_root, + client->frame->area.x, + client->frame->area.y, + /* use the client size because the frame + can be differently sized (shaded + windows) and we want this based on the + clients size */ + client->area.width + + client->frame->size.left + + client->frame->size.right, + client->area.height + + client->frame->size.top + + client->frame->size.bottom); + fire_motion(MouseAction_Motion, context, + client, state, button, px, py, corner); + button = 0; + state = 0; + } + } + break; + + default: + g_assert_not_reached(); + } +} + +gboolean mouse_bind(char *buttonstr, char *contextstr, ObMouseAction mact, + ObAction *action) +{ + guint state, button; + ObFrameContext context; + ObMouseBinding *b; + GSList *it; + + if (!translate_button(buttonstr, &state, &button)) { + g_warning("invalid button '%s'", buttonstr); + return FALSE; + } + + contextstr = g_ascii_strdown(contextstr, -1); + context = frame_context_from_string(contextstr); + if (!context) { + g_warning("invalid context '%s'", contextstr); + g_free(contextstr); + return FALSE; + } + g_free(contextstr); + + for (it = bound_contexts[context]; it != NULL; it = it->next){ + b = it->data; + if (b->state == state && b->button == button) { + b->actions[mact] = g_slist_append(b->actions[mact], action); + return TRUE; + } + } + + grab_all_clients(FALSE); + + /* add the binding */ + b = g_new0(ObMouseBinding, 1); + b->state = state; + b->button = button; + b->actions[mact] = g_slist_append(NULL, action); + bound_contexts[context] = g_slist_append(bound_contexts[context], b); + + grab_all_clients(TRUE); + + return TRUE; +} + +void mouse_startup() +{ +} + +void mouse_shutdown() +{ + grab_all_clients(FALSE); + clearall(); +}
A openbox/mouse.h

@@ -0,0 +1,28 @@

+#ifndef ob__mouse_h +#define ob__mouse_h + +#include "action.h" +#include "frame.h" + +#include <X11/Xlib.h> + +typedef enum { + MouseAction_Press, + MouseAction_Release, + MouseAction_Click, + MouseAction_DClick, + MouseAction_Motion, + NUM_MOUSEACTION +} ObMouseAction; + +void mouse_startup(); +void mouse_shutdown(); + +gboolean mouse_bind(char *buttonstr, char *contextstr, ObMouseAction mact, + ObAction *action); + +void mouse_event(struct _ObClient *client, ObFrameContext context, XEvent *e); + +void mouse_grab_for_client(struct _ObClient *client, gboolean grab); + +#endif
M openbox/openbox.copenbox/openbox.c

@@ -13,6 +13,8 @@ #include "screen.h"

#include "focus.h" #include "moveresize.h" #include "frame.h" +#include "keyboard.h" +#include "mouse.h" #include "extensions.h" #include "grab.h" #include "plugin.h"

@@ -243,6 +245,8 @@ screen_startup();

group_startup(); client_startup(); dock_startup(); + keyboard_startup(); + mouse_startup(); /* call startup for all the plugins */ plugin_startall();

@@ -259,6 +263,8 @@ dock_remove_all();

client_unmanage_all(); plugin_shutdown(); /* calls all the plugins' shutdown functions */ + mouse_shutdown(); + keyboard_shutdown(); dock_shutdown(); client_shutdown(); group_shutdown();
M openbox/plugin.copenbox/plugin.c

@@ -156,8 +156,6 @@ }

if (io == NULL) { /* load the default plugins */ - plugin_open("keyboard"); - plugin_open("mouse"); plugin_open("placement"); plugin_open("resistance");
M openbox/screen.copenbox/screen.c

@@ -4,6 +4,7 @@ #include "dock.h"

#include "xerror.h" #include "prop.h" #include "startup.h" +#include "grab.h" #include "timer.h" #include "config.h" #include "screen.h"

@@ -25,6 +26,7 @@ #ifdef HAVE_UNISTD_H

# include <sys/types.h> # include <unistd.h> #endif +#include <assert.h> /*! The event mask to grab on the root window */ #define ROOT_EVENTMASK (StructureNotifyMask | PropertyChangeMask | \

@@ -45,7 +47,6 @@ static Rect **area; /* array of desktop holding array of xinerama areas */

static Rect *monitor_area; static Popup *desktop_cycle_popup; -static ObTimer *popup_timer = NULL; #ifdef USE_LIBSN static SnMonitorContext *sn_context;

@@ -420,36 +421,6 @@ if (screen_desktop >= screen_num_desktops)

screen_set_desktop(num - 1); } -static void popup_cycle_hide(ObTimer *t, void *d) -{ - timer_stop(t); - popup_timer = NULL; - - popup_hide(desktop_cycle_popup); -} - -static void popup_cycle_show() -{ - Rect *a; - - a = screen_physical_area_monitor(0); - popup_position(desktop_cycle_popup, CenterGravity, - a->x + a->width / 2, a->y + a->height / 2); - /* XXX the size and the font extents need to be related on some level - */ - popup_size(desktop_cycle_popup, POPUP_WIDTH, POPUP_HEIGHT); - - popup_set_text_align(desktop_cycle_popup, RR_JUSTIFY_CENTER); - - popup_show(desktop_cycle_popup, - screen_desktop_names[screen_desktop], NULL); - - g_message("%s", screen_desktop_names[screen_desktop]); - - if (popup_timer) timer_stop(popup_timer); - popup_timer = timer_start(G_USEC_PER_SEC / 2, popup_cycle_hide, NULL); -} - void screen_set_desktop(guint num) { GList *it;

@@ -498,10 +469,248 @@ #ifdef DEBUG_FOCUS

ob_debug("/switch fallback\n"); #endif - if (ob_state() == OB_STATE_RUNNING) - popup_cycle_show(); + dispatch_ob(Event_Ob_Desktop, num, old); +} + +static void get_row_col(guint d, guint *r, guint *c) +{ + switch (screen_desktop_layout.orientation) { + case OB_ORIENTATION_HORZ: + switch (screen_desktop_layout.start_corner) { + case OB_CORNER_TOPLEFT: + *r = d / screen_desktop_layout.columns; + *c = d % screen_desktop_layout.columns; + break; + case OB_CORNER_BOTTOMLEFT: + *r = screen_desktop_layout.rows - 1 - + d / screen_desktop_layout.columns; + *c = d % screen_desktop_layout.columns; + break; + case OB_CORNER_TOPRIGHT: + *r = d / screen_desktop_layout.columns; + *c = screen_desktop_layout.columns - 1 - + d % screen_desktop_layout.columns; + break; + case OB_CORNER_BOTTOMRIGHT: + *r = screen_desktop_layout.rows - 1 - + d / screen_desktop_layout.columns; + *c = screen_desktop_layout.columns - 1 - + d % screen_desktop_layout.columns; + break; + } + break; + case OB_ORIENTATION_VERT: + switch (screen_desktop_layout.start_corner) { + case OB_CORNER_TOPLEFT: + *r = d % screen_desktop_layout.rows; + *c = d / screen_desktop_layout.rows; + break; + case OB_CORNER_BOTTOMLEFT: + *r = screen_desktop_layout.rows - 1 - + d % screen_desktop_layout.rows; + *c = d / screen_desktop_layout.rows; + break; + case OB_CORNER_TOPRIGHT: + *r = d % screen_desktop_layout.rows; + *c = screen_desktop_layout.columns - 1 - + d / screen_desktop_layout.rows; + break; + case OB_CORNER_BOTTOMRIGHT: + *r = screen_desktop_layout.rows - 1 - + d % screen_desktop_layout.rows; + *c = screen_desktop_layout.columns - 1 - + d / screen_desktop_layout.rows; + break; + } + break; + } +} - dispatch_ob(Event_Ob_Desktop, num, old); +static guint translate_row_col(guint r, guint c) +{ + switch (screen_desktop_layout.orientation) { + case OB_ORIENTATION_HORZ: + switch (screen_desktop_layout.start_corner) { + case OB_CORNER_TOPLEFT: + return r % screen_desktop_layout.rows * + screen_desktop_layout.columns + + c % screen_desktop_layout.columns; + case OB_CORNER_BOTTOMLEFT: + return (screen_desktop_layout.rows - 1 - + r % screen_desktop_layout.rows) * + screen_desktop_layout.columns + + c % screen_desktop_layout.columns; + case OB_CORNER_TOPRIGHT: + return r % screen_desktop_layout.rows * + screen_desktop_layout.columns + + (screen_desktop_layout.columns - 1 - + c % screen_desktop_layout.columns); + case OB_CORNER_BOTTOMRIGHT: + return (screen_desktop_layout.rows - 1 - + r % screen_desktop_layout.rows) * + screen_desktop_layout.columns + + (screen_desktop_layout.columns - 1 - + c % screen_desktop_layout.columns); + } + case OB_ORIENTATION_VERT: + switch (screen_desktop_layout.start_corner) { + case OB_CORNER_TOPLEFT: + return c % screen_desktop_layout.columns * + screen_desktop_layout.rows + + r % screen_desktop_layout.rows; + case OB_CORNER_BOTTOMLEFT: + return c % screen_desktop_layout.columns * + screen_desktop_layout.rows + + (screen_desktop_layout.rows - 1 - + r % screen_desktop_layout.rows); + case OB_CORNER_TOPRIGHT: + return (screen_desktop_layout.columns - 1 - + c % screen_desktop_layout.columns) * + screen_desktop_layout.rows + + r % screen_desktop_layout.rows; + case OB_CORNER_BOTTOMRIGHT: + return (screen_desktop_layout.columns - 1 - + c % screen_desktop_layout.columns) * + screen_desktop_layout.rows + + (screen_desktop_layout.rows - 1 - + r % screen_desktop_layout.rows); + } + } + g_assert_not_reached(); + return 0; +} + +static void popup_cycle(guint d, gboolean show) +{ + Rect *a; + + if (!show) { + popup_hide(desktop_cycle_popup); + } else { + a = screen_physical_area_monitor(0); + popup_position(desktop_cycle_popup, CenterGravity, + a->x + a->width / 2, a->y + a->height / 2); + /* XXX the size and the font extents need to be related on some level + */ + popup_size(desktop_cycle_popup, POPUP_WIDTH, POPUP_HEIGHT); + + popup_set_text_align(desktop_cycle_popup, RR_JUSTIFY_CENTER); + + popup_show(desktop_cycle_popup, + screen_desktop_names[d], NULL); + } +} + +guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear, + gboolean done, gboolean cancel) +{ + static gboolean first = TRUE; + static gboolean lin; + static guint origd, d; + guint r, c; + + if (cancel) { + d = origd; + goto done_cycle; + } else if (done) { + screen_set_desktop(d); + goto done_cycle; + } + if (first) { + first = FALSE; + lin = linear; + d = origd = screen_desktop; + } + + get_row_col(d, &r, &c); + + if (lin) { + g_message("linear %d", d); + switch (dir) { + case OB_DIRECTION_EAST: + if (d < screen_num_desktops - 1) + ++d; + else if (wrap) + d = 0; + break; + case OB_DIRECTION_WEST: + if (d > 0) + --d; + else if (wrap) + d = screen_num_desktops - 1; + break; + default: + assert(0); + return screen_desktop; + } + g_message("linear %d done", d); + } else { + switch (dir) { + case OB_DIRECTION_EAST: + ++c; + if (c >= screen_desktop_layout.columns) { + if (!wrap) return d = screen_desktop; + c = 0; + } + d = translate_row_col(r, c); + if (d >= screen_num_desktops) { + if (!wrap) return d = screen_desktop; + ++c; + } + break; + case OB_DIRECTION_WEST: + --c; + if (c >= screen_desktop_layout.columns) { + if (!wrap) return d = screen_desktop; + c = screen_desktop_layout.columns - 1; + } + d = translate_row_col(r, c); + if (d >= screen_num_desktops) { + if (!wrap) return d = screen_desktop; + --c; + } + break; + case OB_DIRECTION_SOUTH: + ++r; + if (r >= screen_desktop_layout.rows) { + if (!wrap) return d = screen_desktop; + r = 0; + } + d = translate_row_col(r, c); + if (d >= screen_num_desktops) { + if (!wrap) return d = screen_desktop; + ++r; + } + break; + case OB_DIRECTION_NORTH: + --r; + if (r >= screen_desktop_layout.rows) { + if (!wrap) return d = screen_desktop; + r = screen_desktop_layout.rows - 1; + } + d = translate_row_col(r, c); + if (d >= screen_num_desktops) { + if (!wrap) return d = screen_desktop; + --r; + } + break; + default: + assert(0); + return d = screen_desktop; + } + + d = translate_row_col(r, c); + } + + popup_cycle(d, TRUE); + return d; + +done_cycle: + first = TRUE; + + popup_cycle(0, FALSE); + + return d = screen_desktop; } void screen_update_layout()
M openbox/screen.hopenbox/screen.h

@@ -45,6 +45,9 @@ /*! Change the number of available desktops */

void screen_set_num_desktops(guint num); /*! Change the current desktop */ void screen_set_desktop(guint num); +/*! Interactively change desktops */ +guint screen_cycle_desktop(ObDirection dir, gboolean wrap, gboolean linear, + gboolean done, gboolean cancel); /*! Shows and focuses the desktop and hides all the client windows, or returns to the normal state, showing client windows. */
A openbox/translate.h

@@ -0,0 +1,9 @@

+#ifndef ob__translate_h +#define ob__translate_h + +#include <glib.h> + +gboolean translate_button(gchar *str, guint *state, guint *keycode); +gboolean translate_key(gchar *str, guint *state, guint *keycode); + +#endif
M plugins/menu/client_menu.cplugins/menu/client_menu.c

@@ -52,7 +52,7 @@ menu_clear(self);

ob_debug("update\n"); for (i = 0; i < screen_num_desktops; ++i) { ObMenuEntry *e; - Action *a = action_from_string("sendtodesktop"); + ObAction *a = action_from_string("sendtodesktop"); a->data.sendto.desk = i; a->data.sendto.follow = FALSE; e = menu_entry_new(screen_desktop_names[i], a);
D plugins/mouse/.cvsignore

@@ -1,6 +0,0 @@

-mouse.la -.libs -.deps -.dirstamp -plugins_mouse_mouse_la-mouse.lo -plugins_mouse_mouse_la-translate.lo
D plugins/mouse/Makefile

@@ -1,4 +0,0 @@

-all clean install: - $(MAKE) -C ../.. -$(MAKEFLAGS) $@ - -.PHONY: all clean install
D plugins/mouse/mouse.c

@@ -1,456 +0,0 @@

-#include "kernel/openbox.h" -#include "kernel/dispatch.h" -#include "kernel/action.h" -#include "kernel/event.h" -#include "kernel/client.h" -#include "kernel/prop.h" -#include "kernel/grab.h" -#include "kernel/frame.h" -#include "parser/parse.h" -#include "translate.h" -#include "mouse.h" -#include <glib.h> - -static int threshold; -static int dclicktime; -/* - -<context name="Titlebar"> - <mousebind button="Left" action="Press"> - <action name="Raise"></action> - </mousebind> -</context> - -*/ - -static void parse_xml(xmlDocPtr doc, xmlNodePtr node, void *d) -{ - xmlNodePtr n, nbut, nact; - char *buttonstr; - char *contextstr; - MouseAction mact; - Action *action; - - node = node->xmlChildrenNode; - - if ((n = parse_find_node("dragThreshold", node))) - threshold = parse_int(doc, n); - if ((n = parse_find_node("doubleClickTime", node))) - dclicktime = parse_int(doc, n); - - n = parse_find_node("context", node); - while (n) { - if (!parse_attr_string("name", n, &contextstr)) - goto next_n; - nbut = parse_find_node("mousebind", n->xmlChildrenNode); - while (nbut) { - if (!parse_attr_string("button", nbut, &buttonstr)) - goto next_nbut; - if (parse_attr_contains("press", nbut, "action")) - mact = MouseAction_Press; - else if (parse_attr_contains("release", nbut, "action")) - mact = MouseAction_Release; - else if (parse_attr_contains("click", nbut, "action")) - mact = MouseAction_Click; - else if (parse_attr_contains("doubleclick", nbut,"action")) - mact = MouseAction_DClick; - else if (parse_attr_contains("drag", nbut, "action")) - mact = MouseAction_Motion; - else - goto next_nbut; - nact = parse_find_node("action", nbut->xmlChildrenNode); - while (nact) { - if ((action = action_parse(doc, nact))) { - /* validate that its okay for a mouse binding*/ - if (mact == MouseAction_Motion) { - if (action->func != action_moveresize || - action->data.moveresize.corner == - prop_atoms.net_wm_moveresize_move_keyboard || - action->data.moveresize.corner == - prop_atoms.net_wm_moveresize_size_keyboard) { - action_free(action); - action = NULL; - } - } else { - if (action->func == action_moveresize && - action->data.moveresize.corner != - prop_atoms.net_wm_moveresize_move_keyboard && - action->data.moveresize.corner != - prop_atoms.net_wm_moveresize_size_keyboard) { - action_free(action); - action = NULL; - } - } - if (action) - mbind(buttonstr, contextstr, mact, action); - } - nact = parse_find_node("action", nact->next); - } - g_free(buttonstr); - next_nbut: - nbut = parse_find_node("mousebind", nbut->next); - } - g_free(contextstr); - next_n: - n = parse_find_node("context", n->next); - } -} - -void plugin_setup_config() -{ - threshold = 3; - dclicktime = 200; - parse_register("mouse", parse_xml, NULL); -} - -/* Array of GSList*s of PointerBinding*s. */ -static GSList *bound_contexts[OB_FRAME_NUM_CONTEXTS]; - -static void grab_for_client(ObClient *client, gboolean grab) -{ - int i; - GSList *it; - - for (i = 0; i < OB_FRAME_NUM_CONTEXTS; ++i) - for (it = bound_contexts[i]; it != NULL; it = it->next) { - /* grab/ungrab the button */ - MouseBinding *b = it->data; - Window win; - int mode; - unsigned int mask; - - if (i == OB_FRAME_CONTEXT_FRAME) { - win = client->frame->window; - mode = GrabModeAsync; - mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask; - } else if (i == OB_FRAME_CONTEXT_CLIENT) { - win = client->frame->plate; - mode = GrabModeSync; /* this is handled in event */ - mask = ButtonPressMask; /* can't catch more than this with Sync - mode the release event is - manufactured in event() */ - } else continue; - - if (grab) - grab_button_full(b->button, b->state, win, mask, mode, None); - else - ungrab_button(b->button, b->state, win); - } -} - -static void grab_all_clients(gboolean grab) -{ - GList *it; - - for (it = client_list; it != NULL; it = it->next) - grab_for_client(it->data, grab); -} - -static void clearall() -{ - int i; - GSList *it; - - for(i = 0; i < OB_FRAME_NUM_CONTEXTS; ++i) { - for (it = bound_contexts[i]; it != NULL; it = it->next) { - int j; - - MouseBinding *b = it->data; - for (j = 0; j < NUM_MOUSEACTION; ++j) { - GSList *it; - for (it = b->actions[j]; it; it = it->next) { - action_free(it->data); - } - g_slist_free(b->actions[j]); - } - g_free(b); - } - g_slist_free(bound_contexts[i]); - } -} - -static void fire_button(MouseAction a, ObFrameContext context, - ObClient *c, guint state, - guint button, int x, int y) -{ - GSList *it; - MouseBinding *b; - - for (it = bound_contexts[context]; it != NULL; it = it->next) { - b = it->data; - if (b->state == state && b->button == button) - break; - } - /* if not bound, then nothing to do! */ - if (it == NULL) return; - - for (it = b->actions[a]; it; it = it->next) { - Action *act = it->data; - if (act->func != NULL) { - act->data.any.c = c; - - g_assert(act->func != action_moveresize); - - if (act->func == action_showmenu) { - act->data.showmenu.x = x; - act->data.showmenu.y = y; - } - - act->func(&act->data); - } - } -} - -static void fire_motion(MouseAction a, ObFrameContext context, ObClient *c, - guint state, guint button, int x_root, int y_root, - guint32 corner) -{ - GSList *it; - MouseBinding *b; - - for (it = bound_contexts[context]; it != NULL; it = it->next) { - b = it->data; - if (b->state == state && b->button == button) - break; - } - /* if not bound, then nothing to do! */ - if (it == NULL) return; - - for (it = b->actions[a]; it; it = it->next) { - Action *act = it->data; - if (act->func != NULL) { - act->data.any.c = c; - - if (act->func == action_moveresize) { - act->data.moveresize.x = x_root; - act->data.moveresize.y = y_root; - act->data.moveresize.button = button; - if (!(act->data.moveresize.corner == - prop_atoms.net_wm_moveresize_move || - act->data.moveresize.corner == - prop_atoms.net_wm_moveresize_move_keyboard || - act->data.moveresize.corner == - prop_atoms.net_wm_moveresize_size_keyboard)) - act->data.moveresize.corner = corner; - } else - g_assert_not_reached(); - - act->func(&act->data); - } - } -} - -static guint32 pick_corner(int x, int y, int cx, int cy, int cw, int ch) -{ - if (x - cx < cw / 2) { - if (y - cy < ch / 2) - return prop_atoms.net_wm_moveresize_size_topleft; - else - return prop_atoms.net_wm_moveresize_size_bottomleft; - } else { - if (y - cy < ch / 2) - return prop_atoms.net_wm_moveresize_size_topright; - else - return prop_atoms.net_wm_moveresize_size_bottomright; - } -} - -static void event(ObEvent *e, void *foo) -{ - static Time ltime; - static guint button = 0, state = 0, lbutton = 0; - static Window lwindow = None; - static int px, py; - gboolean click = FALSE; - gboolean dclick = FALSE; - ObFrameContext context; - - switch (e->type) { - case Event_Client_Mapped: - grab_for_client(e->data.c.client, TRUE); - break; - - case Event_Client_Destroy: - grab_for_client(e->data.c.client, FALSE); - break; - - case Event_X_ButtonPress: - context = frame_context(e->data.x.client, - e->data.x.e->xbutton.window); - - px = e->data.x.e->xbutton.x_root; - py = e->data.x.e->xbutton.y_root; - button = e->data.x.e->xbutton.button; - state = e->data.x.e->xbutton.state; - - fire_button(MouseAction_Press, context, - e->data.x.client, e->data.x.e->xbutton.state, - e->data.x.e->xbutton.button, - e->data.x.e->xbutton.x_root, e->data.x.e->xbutton.y_root); - - if (context == OB_FRAME_CONTEXT_CLIENT) { - /* Replay the event, so it goes to the client*/ - XAllowEvents(ob_display, ReplayPointer, event_lasttime); - /* Fall through to the release case! */ - } else - break; - - case Event_X_ButtonRelease: - context = frame_context(e->data.x.client, - e->data.x.e->xbutton.window); - if (e->data.x.e->xbutton.button == button) { - /* clicks are only valid if its released over the window */ - int junk1, junk2; - Window wjunk; - guint ujunk, b, w, h; - XGetGeometry(ob_display, e->data.x.e->xbutton.window, - &wjunk, &junk1, &junk2, &w, &h, &b, &ujunk); - if (e->data.x.e->xbutton.x >= (signed)-b && - e->data.x.e->xbutton.y >= (signed)-b && - e->data.x.e->xbutton.x < (signed)(w+b) && - e->data.x.e->xbutton.y < (signed)(h+b)) { - click = TRUE; - /* double clicks happen if there were 2 in a row! */ - if (lbutton == button && - lwindow == e->data.x.e->xbutton.window && - e->data.x.e->xbutton.time - dclicktime <= ltime) { - dclick = TRUE; - lbutton = 0; - } else { - lbutton = button; - lwindow = e->data.x.e->xbutton.window; - } - } else { - lbutton = 0; - lwindow = None; - } - - button = 0; - state = 0; - ltime = e->data.x.e->xbutton.time; - } - fire_button(MouseAction_Release, context, - e->data.x.client, e->data.x.e->xbutton.state, - e->data.x.e->xbutton.button, - e->data.x.e->xbutton.x_root, e->data.x.e->xbutton.y_root); - if (click) - fire_button(MouseAction_Click, context, - e->data.x.client, e->data.x.e->xbutton.state, - e->data.x.e->xbutton.button, - e->data.x.e->xbutton.x_root, - e->data.x.e->xbutton.y_root); - if (dclick) - fire_button(MouseAction_DClick, context, - e->data.x.client, e->data.x.e->xbutton.state, - e->data.x.e->xbutton.button, - e->data.x.e->xbutton.x_root, - e->data.x.e->xbutton.y_root); - break; - - case Event_X_MotionNotify: - if (button) { - if (ABS(e->data.x.e->xmotion.x_root - px) >= threshold || - ABS(e->data.x.e->xmotion.y_root - py) >= threshold) { - guint32 corner; - - context = frame_context(e->data.x.client, - e->data.x.e->xmotion.window); - - /* You can't drag on buttons */ - if (context == OB_FRAME_CONTEXT_MAXIMIZE || - context == OB_FRAME_CONTEXT_ALLDESKTOPS || - context == OB_FRAME_CONTEXT_SHADE || - context == OB_FRAME_CONTEXT_ICONIFY || - context == OB_FRAME_CONTEXT_ICON || - context == OB_FRAME_CONTEXT_CLOSE) - break; - - if (!e->data.x.client) - corner = prop_atoms.net_wm_moveresize_size_bottomright; - else - corner = - pick_corner(e->data.x.e->xmotion.x_root, - e->data.x.e->xmotion.y_root, - e->data.x.client->frame->area.x, - e->data.x.client->frame->area.y, - /* use the client size because the frame - can be differently sized (shaded - windows) and we want this based on the - clients size */ - e->data.x.client->area.width + - e->data.x.client->frame->size.left + - e->data.x.client->frame->size.right, - e->data.x.client->area.height + - e->data.x.client->frame->size.top + - e->data.x.client->frame->size.bottom); - fire_motion(MouseAction_Motion, context, - e->data.x.client, state, button, px, py, corner); - button = 0; - state = 0; - } - } - break; - - default: - g_assert_not_reached(); - } -} - -gboolean mbind(char *buttonstr, char *contextstr, MouseAction mact, - Action *action) -{ - guint state, button; - ObFrameContext context; - MouseBinding *b; - GSList *it; - - if (!translate_button(buttonstr, &state, &button)) { - g_warning("invalid button '%s'", buttonstr); - return FALSE; - } - - contextstr = g_ascii_strdown(contextstr, -1); - context = frame_context_from_string(contextstr); - if (!context) { - g_warning("invalid context '%s'", contextstr); - g_free(contextstr); - return FALSE; - } - g_free(contextstr); - - for (it = bound_contexts[context]; it != NULL; it = it->next){ - b = it->data; - if (b->state == state && b->button == button) { - b->actions[mact] = g_slist_append(b->actions[mact], action); - return TRUE; - } - } - - grab_all_clients(FALSE); - - /* add the binding */ - b = g_new0(MouseBinding, 1); - b->state = state; - b->button = button; - b->actions[mact] = g_slist_append(NULL, action); - bound_contexts[context] = g_slist_append(bound_contexts[context], b); - - grab_all_clients(TRUE); - - return TRUE; -} - -void plugin_startup() -{ - dispatch_register(Event_Client_Mapped | Event_Client_Destroy | - Event_X_ButtonPress | Event_X_ButtonRelease | - Event_X_MotionNotify, (EventHandler)event, NULL); -} - -void plugin_shutdown() -{ - dispatch_register(0, (EventHandler)event, NULL); - - grab_all_clients(FALSE); - clearall(); -}
D plugins/mouse/mouse.h

@@ -1,24 +0,0 @@

-#ifndef __plugin_mouse_mouse_h -#define __plugin_mouse_mouse_h - -#include "../../kernel/action.h" - -typedef enum { - MouseAction_Press, - MouseAction_Release, - MouseAction_Click, - MouseAction_DClick, - MouseAction_Motion, - NUM_MOUSEACTION -} MouseAction; - -typedef struct { - guint state; - guint button; - GSList *actions[NUM_MOUSEACTION]; /* lists of Action pointers */ -} MouseBinding; - -gboolean mbind(char *buttonstr, char *contextstr, MouseAction mact, - Action *action); - -#endif
M plugins/mouse/translate.copenbox/translate.c

@@ -63,3 +63,47 @@ translation_fail:

g_strfreev(parsed); return ret; } + +gboolean translate_key(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 = 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; +}
D plugins/mouse/translate.h

@@ -1,8 +0,0 @@

-#ifndef __plugin_mouse_translate_h -#define __plugin_mouse_translate_h - -#include <glib.h> - -gboolean translate_button(char *str, guint *state, guint *keycode); - -#endif