diff options
| author | Dana Jansens <danakj@orodu.net> | 2003-08-12 07:26:16 +0000 |
|---|---|---|
| committer | Dana Jansens <danakj@orodu.net> | 2003-08-12 07:26:16 +0000 |
| commit | c90da6da781932c2d178bfb7e39ec1d5003543b7 (patch) | |
| tree | e9ed8a17f574701880fe73fcfbd872cdb4868c4d /openbox | |
| parent | cb49f853c9b62c4403eb562d39f52c51da292c4f (diff) | |
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.
Diffstat (limited to 'openbox')
| -rw-r--r-- | openbox/.cvsignore | 3 | ||||
| -rw-r--r-- | openbox/action.c | 367 | ||||
| -rw-r--r-- | openbox/action.h | 39 | ||||
| -rw-r--r-- | openbox/client.c | 12 | ||||
| -rw-r--r-- | openbox/config.c | 155 | ||||
| -rw-r--r-- | openbox/config.h | 5 | ||||
| -rw-r--r-- | openbox/event.c | 24 | ||||
| -rw-r--r-- | openbox/focus.c | 5 | ||||
| -rw-r--r-- | openbox/keyboard.c | 265 | ||||
| -rw-r--r-- | openbox/keyboard.h | 32 | ||||
| -rw-r--r-- | openbox/keytree.c | 112 | ||||
| -rw-r--r-- | openbox/keytree.h | 25 | ||||
| -rw-r--r-- | openbox/menu.c | 4 | ||||
| -rw-r--r-- | openbox/menu.h | 4 | ||||
| -rw-r--r-- | openbox/mouse.c | 372 | ||||
| -rw-r--r-- | openbox/mouse.h | 28 | ||||
| -rw-r--r-- | openbox/openbox.c | 6 | ||||
| -rw-r--r-- | openbox/plugin.c | 2 | ||||
| -rw-r--r-- | openbox/screen.c | 277 | ||||
| -rw-r--r-- | openbox/screen.h | 3 | ||||
| -rw-r--r-- | openbox/translate.c | 109 | ||||
| -rw-r--r-- | openbox/translate.h | 9 |
22 files changed, 1610 insertions, 248 deletions
diff --git a/openbox/.cvsignore b/openbox/.cvsignore index e982b462..ab5b29ab 100644 --- a/openbox/.cvsignore +++ b/openbox/.cvsignore @@ -29,3 +29,6 @@ xerror.lo .deps openbox .dirstamp +keyboard.lo +mouse.lo +keytree.lo diff --git a/openbox/action.c b/openbox/action.c index d59c5514..275ba96a 100644 --- a/openbox/action.c +++ b/openbox/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 @@ void action_free(Action *a) 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) { - a->data.sendto.follow = TRUE; } -void setup_action_send_to_desktop_direction(Action *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; - a->data.sendtodir.follow = TRUE; } -void setup_action_desktop_direction(Action *a) +void setup_action_send_to_desktop_next(ObAction *a) { + a->data.sendtodir.dir = OB_DIRECTION_EAST; + a->data.sendtodir.linear = TRUE; + a->data.sendtodir.wrap = TRUE; +} + +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; +} + +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_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,24 +430,34 @@ ActionString actionstrings[] = 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", @@ -383,24 +465,34 @@ ActionString actionstrings[] = 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 @@ ActionString actionstrings[] = } }; -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 @@ Action *action_from_string(char *name) 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 @@ Action *action_parse(xmlDocPtr doc, xmlNodePtr node) 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 @@ void action_send_to_desktop(union ActionData *data) 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 @@ void action_desktop(union ActionData *data) 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) -{ - 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; +void action_send_to_desktop_dir(union ActionData *data) +{ + 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 @@ void action_desktop_right(union ActionData *data) } 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 @@ void action_send_to_desktop_right(union ActionData *data) 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 @@ void action_desktop_left(union ActionData *data) } 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 @@ void action_send_to_desktop_left(union ActionData *data) 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 @@ void action_desktop_down(union ActionData *data) } 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 @@ void action_send_to_desktop_down(union ActionData *data) 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 @@ void action_desktop_up(union ActionData *data) } 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 @@ void action_send_to_desktop_up(union ActionData *data) 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) { diff --git a/openbox/action.h b/openbox/action.h index 3abf7f2b..3ac3ee67 100644 --- a/openbox/action.h +++ b/openbox/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 SendToDesktop { struct SendToDesktopDirection { struct _ObClient *c; + ObDirection dir; gboolean wrap; - gboolean follow; + gboolean linear; + gboolean final; + gboolean cancel; }; struct Desktop { @@ -56,7 +61,11 @@ struct Layer { struct DesktopDirection { struct _ObClient *c; + ObDirection dir; gboolean wrap; + gboolean linear; + gboolean final; + gboolean cancel; }; struct MoveResize { @@ -98,15 +107,15 @@ union ActionData { 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 *action_new(void (*func)(union ActionData *data)); 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 */ diff --git a/openbox/client.c b/openbox/client.c index 191fa994..b5e2a3cf 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -18,6 +18,8 @@ #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 @@ void client_manage(Window window) /* 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 @@ void client_unmanage(ObClient *self) 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 @@ void client_setup_decor_and_functions(ObClient *self) /* 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 @@ void client_configure_full(ObClient *self, ObCorner anchor, 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 diff --git a/openbox/config.c b/openbox/config.c index 1ffc155a..5444e013 100644 --- a/openbox/config.c +++ b/openbox/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 @@ void config_startup() 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() diff --git a/openbox/config.h b/openbox/config.h index d10617d0..413ff184 100644 --- a/openbox/config.h +++ b/openbox/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(); diff --git a/openbox/event.c b/openbox/event.c index b5e15a3c..97f01fb6 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -8,6 +8,8 @@ #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 @@ static void event_process(XEvent *e) } /* 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); diff --git a/openbox/focus.c b/openbox/focus.c index 1642261d..9949dea3 100644 --- a/openbox/focus.c +++ b/openbox/focus.c @@ -262,7 +262,7 @@ static void popup_cycle(ObClient *c, gboolean show) } 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 @@ ObClient *focus_cycle(gboolean forward, gboolean linear, gboolean done, 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 @@ done_cycle: order = NULL; popup_cycle(ft, FALSE); - grab_pointer(FALSE, None); return NULL; } diff --git a/openbox/keyboard.c b/openbox/keyboard.c new file mode 100644 index 00000000..607941dd --- /dev/null +++ b/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); +} + diff --git a/openbox/keyboard.h b/openbox/keyboard.h new file mode 100644 index 00000000..aa171221 --- /dev/null +++ b/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 diff --git a/openbox/keytree.c b/openbox/keytree.c new file mode 100644 index 00000000..9aa2ea95 --- /dev/null +++ b/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 */ +} diff --git a/openbox/keytree.h b/openbox/keytree.h new file mode 100644 index 00000000..0c61e478 --- /dev/null +++ b/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 diff --git a/openbox/menu.c b/openbox/menu.c index 00a2bc2b..0f2eff42 100644 --- a/openbox/menu.c +++ b/openbox/menu.c @@ -27,7 +27,7 @@ static void parse_menu(xmlDocPtr doc, xmlNodePtr node, void *data) 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 @@ void menu_free(char *name) 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) { diff --git a/openbox/menu.h b/openbox/menu.h index 3b7c1c38..2ecbb5cd 100644 --- a/openbox/menu.h +++ b/openbox/menu.h @@ -103,7 +103,7 @@ struct _ObMenuEntry 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); diff --git a/openbox/mouse.c b/openbox/mouse.c new file mode 100644 index 00000000..ac0fb1d2 --- /dev/null +++ b/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(); +} diff --git a/openbox/mouse.h b/openbox/mouse.h new file mode 100644 index 00000000..a5e8f9a8 --- /dev/null +++ b/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 diff --git a/openbox/openbox.c b/openbox/openbox.c index 7f141d6f..631395cc 100644 --- a/openbox/openbox.c +++ b/openbox/openbox.c @@ -13,6 +13,8 @@ #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 @@ int main(int argc, char **argv) group_startup(); client_startup(); dock_startup(); + keyboard_startup(); + mouse_startup(); /* call startup for all the plugins */ plugin_startall(); @@ -259,6 +263,8 @@ int main(int argc, char **argv) client_unmanage_all(); plugin_shutdown(); /* calls all the plugins' shutdown functions */ + mouse_shutdown(); + keyboard_shutdown(); dock_shutdown(); client_shutdown(); group_shutdown(); diff --git a/openbox/plugin.c b/openbox/plugin.c index cd17d215..e95d03e9 100644 --- a/openbox/plugin.c +++ b/openbox/plugin.c @@ -156,8 +156,6 @@ void plugin_loadall() if (io == NULL) { /* load the default plugins */ - plugin_open("keyboard"); - plugin_open("mouse"); plugin_open("placement"); plugin_open("resistance"); diff --git a/openbox/screen.c b/openbox/screen.c index 4f9e6a2c..6c9042a9 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -4,6 +4,7 @@ #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 @@ # 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 @@ void screen_set_num_desktops(guint num) 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,12 +469,250 @@ void screen_set_desktop(guint num) 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; + } +} + +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() { ObOrientation orient; diff --git a/openbox/screen.h b/openbox/screen.h index 1c687036..696423e2 100644 --- a/openbox/screen.h +++ b/openbox/screen.h @@ -45,6 +45,9 @@ void screen_resize(); 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. */ diff --git a/openbox/translate.c b/openbox/translate.c new file mode 100644 index 00000000..9b4c1406 --- /dev/null +++ b/openbox/translate.c @@ -0,0 +1,109 @@ +#include "kernel/openbox.h" +#include "mouse.h" +#include <glib.h> +#include <string.h> +#include <stdlib.h> + +static guint translate_modifier(char *str) +{ + if (!g_ascii_strcasecmp("Mod1", str) || + !g_ascii_strcasecmp("A", str)) return Mod1Mask; + else if (!g_ascii_strcasecmp("Mod2", str)) return Mod2Mask; + else if (!g_ascii_strcasecmp("Mod3", str)) return Mod3Mask; + else if (!g_ascii_strcasecmp("Mod4", str) || + !g_ascii_strcasecmp("W", str)) return Mod4Mask; + else if (!g_ascii_strcasecmp("Mod5", str)) return Mod5Mask; + else if (!g_ascii_strcasecmp("Control", str) || + !g_ascii_strcasecmp("C", str)) return ControlMask; + else if (!g_ascii_strcasecmp("Shift", str) || + !g_ascii_strcasecmp("S", str)) return ShiftMask; + g_warning("Invalid modifier '%s' in binding.", str); + return 0; +} + +gboolean translate_button(char *str, guint *state, guint *button) +{ + char **parsed; + char *l; + int i; + gboolean ret = FALSE; + + parsed = g_strsplit(str, "-", -1); + + /* first, find the button (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 button */ + if (!g_ascii_strcasecmp("Left", l)) *button = 1; + else if (!g_ascii_strcasecmp("Middle", l)) *button = 2; + else if (!g_ascii_strcasecmp("Right", l)) *button = 3; + else if (!g_ascii_strcasecmp("Up", l)) *button = 4; + else if (!g_ascii_strcasecmp("Down", l)) *button = 5; + else if (!g_ascii_strncasecmp("Button", l, 6)) *button = atoi(l+6); + if (!*button) { + g_warning("Invalid button '%s' in pointer binding.", l); + goto translation_fail; + } + + ret = TRUE; + +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; +} diff --git a/openbox/translate.h b/openbox/translate.h new file mode 100644 index 00000000..5afab50f --- /dev/null +++ b/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 |
