backup
commit
28db16e977
|
@ -0,0 +1,3 @@
|
|||
*.o
|
||||
*.swp
|
||||
xmousepasteblock
|
|
@ -0,0 +1,42 @@
|
|||
TARGET = xmousepasteblock
|
||||
|
||||
INSTALL = install
|
||||
PREFIX = /usr
|
||||
BINDIR = $(PREFIX)/bin
|
||||
|
||||
CC = gcc
|
||||
CFLAGS += -std=gnu99
|
||||
CFLAGS += -Wall -Wundef -Wshadow -Wformat-security
|
||||
|
||||
LD = $(CC)
|
||||
LDFLAGS += $(shell pkg-config --libs x11 xi)
|
||||
LDFLAGS += -lev
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
||||
.PHONY: all
|
||||
all: clean $(TARGET)
|
||||
|
||||
.PHONY: debug
|
||||
debug: clean
|
||||
debug: CFLAGS += -g -DDEBUG
|
||||
debug: $(TARGET)
|
||||
|
||||
.PHONY: $(TARGET)
|
||||
$(TARGET): $(TARGET).o
|
||||
$(LD) "$<" $(LDFLAGS) -o "$(TARGET)"
|
||||
|
||||
$(TARGET).o: $(TARGET).c
|
||||
$(CC) $(CFLAGS) -o "$@" -c "$<"
|
||||
|
||||
.PHONY: install
|
||||
install: $(TARGET)
|
||||
$(INSTALL) -Dm 0755 "$(TARGET)" "$(DESTDIR)$(BINDIR)/$(TARGET)"
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall:
|
||||
$(RM) "$(DESTDIR)$(BINDIR)/$(TARGET)"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(RM) $(TARGET) $(TARGET).o
|
|
@ -0,0 +1,27 @@
|
|||
# XMousePasteBlock
|
||||
|
||||
Listens for middle mouse click events and clears the primary X selection/clipboard on detection to avoid accidentially pasting stuff all over the place.
|
||||
|
||||
## About
|
||||
|
||||
No need to disable your precious middle mouse button bindings, no clearing of visual selections nor performance losses because of emptying the primary X clipboard periodically.
|
||||
With the utilization of XInput and Xlibs this has _no_ measurable impact on performance whatsoever.
|
||||
No elevated privileges required. Just run within your regular users' X session.
|
||||
|
||||
## Building
|
||||
````
|
||||
make
|
||||
sudo make install
|
||||
````
|
||||
|
||||
## Running
|
||||
Just add `xmousepasteblock` to your startup script/config.
|
||||
|
||||
## Known issues
|
||||
In case of devices which are configured with middle mouse button hold-to-scroll (e.g. Trackpoints), it may happen that the primary selection clear action gets fired too late on older and slower machines.
|
||||
You can observe the behavior by building with the DEBUG flag set (`make debug`), running `xmousepasteblock` in a shell and watching the debug output as you long press and hold the mouse buttons.
|
||||
|
||||
This is due to the fact that the XI_RawButtonPress event only gets fired _after_ releasing the middle mouse button (in case the user wanted to execute a scroll action).
|
||||
The only option to work around this is to disable the middle mouse button hold-to-scroll functionality on Trackpoint devices (which is often not desirable).
|
||||
To do so (using _libinput_):
|
||||
`xinput set-prop <device id> 'libinput Button Scrolling Button' 0`
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Micha LaQua <micha.laqua@gmail.com>
|
||||
*
|
||||
* Special thanks to Ingo Buerk (Airblader) for his work on the
|
||||
* awesome unclutter-xfixes project, upon which the XInput eventcode
|
||||
* is based on.
|
||||
*
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ev.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
|
||||
static Display *display;
|
||||
static struct ev_io *x_watcher;
|
||||
static struct ev_check *x_check;
|
||||
static int xi_opcode = -1;
|
||||
|
||||
void errormsg(char *msg) {
|
||||
printf("ERROR: %s\n", msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void init_xinput(void) {
|
||||
int event, error;
|
||||
if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error)) {
|
||||
errormsg("XInput extension not available");
|
||||
}
|
||||
|
||||
int major_op = 2, minor_op = 2;
|
||||
int result = XIQueryVersion(display, &major_op, &minor_op);
|
||||
if (result == BadRequest) {
|
||||
errormsg("XI2 is not supported in a sufficient version (>=2.2 required).");
|
||||
} else if (result != Success) {
|
||||
errormsg("Failed to query XI2");
|
||||
}
|
||||
}
|
||||
|
||||
void init_eventmask(void) {
|
||||
XIEventMask masks[1];
|
||||
unsigned char mask[(XI_LASTEVENT + 7)/8];
|
||||
|
||||
memset(mask, 0, sizeof(mask));
|
||||
masks[0].deviceid = XIAllMasterDevices;
|
||||
masks[0].mask_len = sizeof(mask);
|
||||
masks[0].mask = mask;
|
||||
|
||||
XISetMask(mask, XI_RawButtonPress);
|
||||
|
||||
XISelectEvents(display, DefaultRootWindow(display), masks, 1);
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
void clear_primary(void) {
|
||||
XSetSelectionOwner(display, XA_PRIMARY, None, CurrentTime);
|
||||
XSync(display, False);
|
||||
#ifdef DEBUG
|
||||
printf("primary selection cleared\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void stub_cb(EV_P_ ev_io *w, int revents) {
|
||||
/* STUB */
|
||||
}
|
||||
|
||||
void check_cb(EV_P_ ev_check *w, int revents) {
|
||||
XEvent ev;
|
||||
while (XPending(display) > 0) {
|
||||
XNextEvent(display, &ev);
|
||||
XGenericEventCookie *cookie = &ev.xcookie;
|
||||
if (cookie->type != GenericEvent || cookie->extension != xi_opcode || !XGetEventData(display, cookie)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const XIRawEvent *data = (const XIRawEvent *) cookie->data;
|
||||
#ifdef DEBUG
|
||||
printf("button %i pressed\n", data->detail);
|
||||
#endif
|
||||
if (data->detail == 2) {
|
||||
clear_primary();
|
||||
}
|
||||
|
||||
XFreeEventData(display, cookie);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
struct ev_loop *evloop;
|
||||
|
||||
display = XOpenDisplay(NULL);
|
||||
if (display == NULL) {
|
||||
errormsg("Failed to connect to the X server");
|
||||
return 1;
|
||||
}
|
||||
|
||||
init_xinput();
|
||||
init_eventmask();
|
||||
|
||||
evloop = EV_DEFAULT;
|
||||
|
||||
x_watcher = calloc(sizeof(struct ev_io), 1);
|
||||
ev_io_init(x_watcher, stub_cb, XConnectionNumber(display), EV_READ);
|
||||
ev_io_start(evloop, x_watcher);
|
||||
|
||||
x_check = calloc(sizeof(struct ev_check), 1);
|
||||
ev_check_init(x_check, check_cb);
|
||||
ev_check_start(evloop, x_check);
|
||||
|
||||
ev_run(evloop, 0);
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue