From 4ff4da0eb60b13f7fc3d5348af31d5715916c656 Mon Sep 17 00:00:00 2001 From: Tudor Roman Date: Thu, 10 Aug 2017 20:56:11 +0300 Subject: [PATCH] Mouse support! Move, focus, and resize windows with the mouse! --- client.c | 91 ++++++++++++++++++++++++++++++++++++------- config.h | 5 ++- examples/windowchefrc | 4 ++ ipc.h | 3 ++ man/waitron.1 | 29 +++++++++++++- man/waitron.1.html | 14 +++++-- man/waitron.1.md | 19 +++++++++ man/windowchef.1 | 2 +- man/windowchef.1.html | 2 +- wm.c | 55 ++++++++++++++++++++++---- 10 files changed, 196 insertions(+), 28 deletions(-) diff --git a/client.c b/client.c index 19e5879..49d03c3 100644 --- a/client.c +++ b/client.c @@ -29,6 +29,9 @@ static bool fn_hex(uint32_t *, int, char **); static bool fn_position(uint32_t *, int, char **); static bool fn_gap(uint32_t *, int, char **); static bool fn_direction(uint32_t *, int, char **); +static bool fn_pac(uint32_t *, int, char **); +static bool fn_mod(uint32_t *, int, char **); +static bool fn_button(uint32_t *, int, char **); static void usage(char *, int); static void version(void); @@ -43,6 +46,7 @@ struct Command { struct ConfigEntry { char *key; enum IPCConfig config; + int argc; bool (*handler)(uint32_t *, int, char **); }; @@ -79,19 +83,22 @@ static struct Command c[] = { }; static struct ConfigEntry configs[] = { - { "border_width" , IPCConfigBorderWidth , fn_naturals }, - { "color_focused" , IPCConfigColorFocused , fn_hex }, - { "color_unfocused" , IPCConfigColorUnfocused , fn_hex }, - { "gap_width" , IPCConfigGapWidth , fn_gap }, - { "grid_gap_width" , IPCConfigGridGapWidth , fn_naturals }, - { "cursor_position" , IPCConfigCursorPosition , fn_position }, - { "groups_nr" , IPCConfigGroupsNr , fn_naturals }, - { "enable_sloppy_focus" , IPCConfigEnableSloppyFocus , fn_bool }, - { "enable_resize_hints" , IPCConfigEnableResizeHints , fn_bool }, - { "sticky_windows" , IPCConfigStickyWindows , fn_bool }, - { "enable_borders" , IPCConfigEnableBorders , fn_bool }, - { "enable_last_window_focusing", IPCConfigEnableLastWindowFocusing, fn_bool }, - { "apply_settings" , IPCConfigApplySettings , fn_bool }, + { "border_width" , IPCConfigBorderWidth , 1 , fn_naturals }, + { "color_focused" , IPCConfigColorFocused , 1 , fn_hex }, + { "color_unfocused" , IPCConfigColorUnfocused , 1 , fn_hex }, + { "gap_width" , IPCConfigGapWidth , 2 , fn_gap }, + { "grid_gap_width" , IPCConfigGridGapWidth , 1 , fn_naturals }, + { "cursor_position" , IPCConfigCursorPosition , 1 , fn_position }, + { "groups_nr" , IPCConfigGroupsNr , 1 , fn_naturals }, + { "enable_sloppy_focus" , IPCConfigEnableSloppyFocus , 1 , fn_bool }, + { "enable_resize_hints" , IPCConfigEnableResizeHints , 1 , fn_bool }, + { "sticky_windows" , IPCConfigStickyWindows , 1 , fn_bool }, + { "enable_borders" , IPCConfigEnableBorders , 1 , fn_bool }, + { "enable_last_window_focusing", IPCConfigEnableLastWindowFocusing, 1 , fn_bool }, + { "apply_settings" , IPCConfigApplySettings , 1 , fn_bool }, + { "pointer_actions" , IPCConfigPointerActions , 3 , fn_pac }, + { "pointer_modifier" , IPCConfigPointerModifier , 1 , fn_mod }, + { "click_to_focus" , IPCConfigClickToFocus , 1 , fn_button }, }; /* @@ -171,6 +178,8 @@ fn_config(uint32_t *data, int argc, char **argv) { i++; if (i < NR_IPC_CONFIGS) { + if (configs[i].argc != argc - 1) + errx(EXIT_FAILURE, "too many or not enough arguments. Want: %d", configs[i].argc); data[0] = configs[i].config; status = (configs[i].handler)(data + 1, argc - 1, argv + 1); @@ -221,6 +230,62 @@ fn_direction(uint32_t *data, int argc, char **argv) return true; } +static bool +fn_pac(uint32_t *data, int argc, char **argv) +{ + for (int i = 0; i < argc; i++) { + char *pac = argv[i]; + if (strcasecmp(pac, "nothing") == 0) + data[i] = POINTER_ACTION_NOTHING; + else if (strcasecmp(pac, "focus") == 0) + data[i] = POINTER_ACTION_FOCUS; + else if (strcasecmp(pac, "move") == 0) + data[i] = POINTER_ACTION_MOVE; + else if (strcasecmp(pac, "resize_corner") == 0) + data[i] = POINTER_ACTION_RESIZE_CORNER; + else if (strcasecmp(pac, "resize_side") == 0) + data[i] = POINTER_ACTION_RESIZE_SIDE; + else + return false; + } + + return true; +} +static bool +fn_mod(uint32_t *data, int argc, char **argv) +{ + (void)(argc); + if (strcasecmp(argv[0], "alt") == 0) + data[0] = XCB_MOD_MASK_1; + else if (strcasecmp(argv[0], "super") == 0) + data[0] = XCB_MOD_MASK_4; + else + return false; + + return true; +} +static bool +fn_button(uint32_t *data, int argc, char **argv) +{ + char *btn = argv[0]; + (void)(argc); + + if (strcasecmp(btn, "left") == 0) + data[0] = 1; + else if (strcasecmp(btn, "middle") == 0) + data[0] = 2; + else if (strcasecmp(btn, "right") == 0) + data[0] = 3; + else if (strcasecmp(btn, "none") == 0) + data[0] = UINT32_MAX; + else if (strcasecmp(btn, "any") == 0) + data[0] = 0; + else + return false; + + return true; +} + static bool fn_position(uint32_t *data, int argc, char **argv) { diff --git a/config.h b/config.h index 0925e51..66d7d98 100644 --- a/config.h +++ b/config.h @@ -45,10 +45,11 @@ #define DEFAULT_MIDDLE_BUTTON_ACTION POINTER_ACTION_RESIZE_SIDE #define DEFAULT_RIGHT_BUTTON_ACTION POINTER_ACTION_RESIZE_CORNER -/* default pointer modifier (super key) */ +/* default pointer modifier (super key). Set to XCB_MOD_MASK_1 for alt */ #define POINTER_MODIFIER XCB_MOD_MASK_4 -/* default mouse button for click to focus. -1 for none */ +/* default mouse button for click to focus. -1 for none, 0 for any + 1, 2, 3 for left-click, middle-click, right-click */ #define CLICK_TO_FOCUS_BUTTON 0 #endif diff --git a/examples/windowchefrc b/examples/windowchefrc index 8c674d9..3e4bd79 100755 --- a/examples/windowchefrc +++ b/examples/windowchefrc @@ -12,3 +12,7 @@ waitron wm_config enable_sloppy_focus true waitron wm_config sticky_windows false waitron wm_config enable_borders true waitron wm_config enable_last_window_focusing true +waitron wm_config apply_settings true +waitron wm_config pointer_actions move resize_side resize_corner +waitron wm_config pointer_modifier super +waitron wm_config click_to_focus any diff --git a/ipc.h b/ipc.h index 88003f8..21eea12 100644 --- a/ipc.h +++ b/ipc.h @@ -55,6 +55,9 @@ enum IPCConfig { IPCConfigEnableBorders, IPCConfigEnableLastWindowFocusing, IPCConfigApplySettings, + IPCConfigPointerActions, + IPCConfigPointerModifier, + IPCConfigClickToFocus, NR_IPC_CONFIGS }; diff --git a/man/waitron.1 b/man/waitron.1 index d5d69e0..b651657 100644 --- a/man/waitron.1 +++ b/man/waitron.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WAITRON" "1" "July 2017" "Windowchef" "Windowchef Manual" +.TH "WAITRON" "1" "August 2017" "Windowchef" "Windowchef Manual" . .SH "NAME" \fBwaitron\fR \- A client for windowchef(1) @@ -39,6 +39,18 @@ false values: \fBfalse\fR | \fBf\fR | \fBno\fR | \fBn\fR | \fB0\fR \fBDIRECTION\fR \fBup\fR | \fBdown\fR | \fBleft\fR | \fBright\fR | \fBnorth\fR | \fBsouth\fR | \fBwest\fR | \fBeast\fR . +.TP +\fBPOINTER_ACTION\fR +\fBnothing\fR | \fBfocus\fR | \fBmove\fR | \fBresize_corner\fR | \fBresize_side\fR +. +.TP +\fBPOINTER_MODIFIER\fR +\fBalt\fR | \fBsuper\fR +. +.TP +\fBMOUSE_BUTTON\fR +\fBany\fR | \fBnone\fR | \fBleft\fR | \fBmiddle\fR | \fBright\fR +. .SH "COMMANDS" . .TP @@ -234,7 +246,22 @@ If true, when the currently focused window is unmapped or closed, \fBwindowchef\ \fBapply_settings\fR \fIBOOL\fR If true, then some settings will be applied on all windows instead of newly created windows\. True by default\. . +.TP +\fBpointer_actions\fR \fIPOINTER_ACTION\fR \fIPOINTER_ACTION\fR \fIPOINTER_ACTION\fR +Sets the action that should be done whenever the modifier key and the corresponding button are clicked at the same time on the window\. There are 3 actions for three mouse buttons: left, middle and right\. +. +.TP +\fBpointer_modifier\fR \fIPOINTER_MODIFIER\fR +Set the modifier for pointer actions\. +. +.TP +\fBclick_to_focus\fR \fIMOUSE_BUTTON\fR +Set the mouse button that focuses the hovered window when clicked\. +. .SH "SEE ALSO" + +. +.P windowchef(1), sxhkd(1), wmutils(1), pfw(1), lsw(1), chwb2(1), lemonbar(1) . .SH "REPORTING BUGS" diff --git a/man/waitron.1.html b/man/waitron.1.html index 4745b98..ccf941c 100644 --- a/man/waitron.1.html +++ b/man/waitron.1.html @@ -103,6 +103,9 @@

COMMON DEFINITIONS

false values: false | f | no | n | 0

DIRECTION

up | down | left | right | north | south | west | east

+
POINTER_ACTION

nothing | focus | move | resize_corner | resize_side

+
POINTER_MODIFIER

alt | super

+
MOUSE_BUTTON

any | none | left | middle | right

@@ -204,10 +207,15 @@

CONFIGURING

previously focused window. See the window_focus_last command.

apply_settings BOOL

If true, then some settings will be applied on all windows instead of newly created windows. True by default.

- +
pointer_actions POINTER_ACTION POINTER_ACTION POINTER_ACTION

Sets the action that should be done whenever the modifier key and the corresponding button + are clicked at the same time on the window. There are 3 actions for three mouse buttons: + left, middle and right.

+
pointer_modifier POINTER_MODIFIER

Set the modifier for pointer actions.

+
click_to_focus MOUSE_BUTTON

Set the mouse button that focuses the hovered window when clicked.

+

SEE ALSO

+ -

SEE ALSO

windowchef(1), sxhkd(1), wmutils(1), pfw(1), lsw(1), chwb2(1), lemonbar(1)

@@ -222,7 +230,7 @@

AUTHOR

  1. Windowchef
  2. -
  3. July 2017
  4. +
  5. August 2017
  6. waitron(1)
diff --git a/man/waitron.1.md b/man/waitron.1.md index 4537a8b..0fb3c88 100644 --- a/man/waitron.1.md +++ b/man/waitron.1.md @@ -32,6 +32,15 @@ anything on `stdout`. * `DIRECTION`: `up` | `down` | `left` | `right` | `north` | `south` | `west` | `east` +* `POINTER_ACTION`: + `nothing` | `focus` | `move` | `resize_corner` | `resize_side` + +* `POINTER_MODIFIER`: + `alt` | `super` + +* `MOUSE_BUTTON`: + `any` | `none` | `left` | `middle` | `right` + ## COMMANDS * `window_move` : @@ -206,6 +215,16 @@ are: If true, then some settings will be applied on all windows instead of newly created windows. True by default. +* `pointer_actions` : + Sets the action that should be done whenever the modifier key and the corresponding button + are clicked at the same time on the window. There are 3 actions for three mouse buttons: + left, middle and right. + +* `pointer_modifier` : + Set the modifier for pointer actions. + +* `click_to_focus` : + Set the mouse button that focuses the hovered window when clicked. ## SEE ALSO windowchef(1), sxhkd(1), wmutils(1), pfw(1), lsw(1), chwb2(1), lemonbar(1) diff --git a/man/windowchef.1 b/man/windowchef.1 index a6e6290..c37a85c 100644 --- a/man/windowchef.1 +++ b/man/windowchef.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "WINDOWCHEF" "1" "July 2017" "Windowchef" "Windowchef Manual" +.TH "WINDOWCHEF" "1" "August 2017" "Windowchef" "Windowchef Manual" . .SH "NAME" \fBwindowchef\fR \- A stacking window cooker diff --git a/man/windowchef.1.html b/man/windowchef.1.html index e22b2f1..3d10b5e 100644 --- a/man/windowchef.1.html +++ b/man/windowchef.1.html @@ -114,7 +114,7 @@

AUTHOR

  1. Windowchef
  2. -
  3. July 2017
  4. +
  5. August 2017
  6. windowchef(1)
diff --git a/wm.c b/wm.c index 4252dc7..d8487d9 100644 --- a/wm.c +++ b/wm.c @@ -199,6 +199,8 @@ static void window_grab_button(xcb_window_t, uint8_t, uint16_t); static bool pointer_grab(enum pointer_action); static enum resize_handle get_handle(struct client *, xcb_point_t, enum pointer_action); static void track_pointer(struct client *, enum pointer_action, xcb_point_t); +static void grab_buttons(void); +static void ungrab_buttons(void); static void usage(char *); static void version(void); @@ -214,6 +216,7 @@ cleanup(void) { xcb_set_input_focus(conn, XCB_NONE, XCB_INPUT_FOCUS_POINTER_ROOT, XCB_CURRENT_TIME); + ungrab_buttons(); if (ewmh != NULL) xcb_ewmh_connection_wipe(ewmh); if (win_list != NULL) @@ -2993,6 +2996,26 @@ ipc_wm_config(uint32_t *d) case IPCConfigApplySettings: conf.apply_settings = d[1]; break; + case IPCConfigPointerActions: + for (int i = 0; i < NR_BUTTONS; i++) { + conf.pointer_actions[i] = d[i + 1]; + } + ungrab_buttons(); + grab_buttons(); + break; + case IPCConfigPointerModifier: + conf.pointer_modifier = d[1]; + ungrab_buttons(); + grab_buttons(); + break; + case IPCConfigClickToFocus: + if (d[1] == UINT32_MAX) + conf.click_to_focus = -1; + else + conf.click_to_focus = d[1]; + ungrab_buttons(); + grab_buttons(); + break; default: DMSG("!!! unhandled config key %d\n", key); break; @@ -3110,13 +3133,13 @@ pointer_grab(enum pointer_action pac) if (client == NULL) return true; + raise_window(client->window); if (pac == POINTER_ACTION_FOCUS) { DMSG("grabbing pointer to focus on 0x%08x\n", client->window); if (client != focused_win) { set_focused(client); return true; } - raise_window(client->window); return false; } @@ -3183,12 +3206,6 @@ get_handle(struct client *client, xcb_point_t pos, enum pointer_action pac) else handle = HANDLE_BOTTOM_RIGHT; } - switch (handle) { - case HANDLE_TOP_LEFT: DMSG("top left\n"); break; - case HANDLE_TOP_RIGHT: DMSG("top right\n"); break; - case HANDLE_BOTTOM_LEFT: DMSG("bottom left\n"); break; - case HANDLE_BOTTOM_RIGHT: DMSG("bottom right\n"); break; - } } else { handle = HANDLE_TOP_LEFT; } @@ -3283,6 +3300,30 @@ track_pointer(struct client *client, enum pointer_action pac, xcb_point_t pos) xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); } +static void +grab_buttons(void) +{ + struct list_item *item; + struct client *client; + + for (item = win_list; item != NULL; item = item->next) { + client = item->data; + window_grab_buttons(client->window); + } +} + +static void +ungrab_buttons(void) +{ + struct list_item *item; + struct client *client; + + for (item = win_list; item != NULL; item = item->next) { + client = item->data; + xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, client->window, XCB_MOD_MASK_ANY); + } +} + static void usage(char *name) {