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
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
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)
{