Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature 14 #36

Merged
merged 3 commits into from
Dec 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions include/cursor.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// vim:ts=4:sw=4:expandtab
// vim:ts=4:sw=4:expandtab -*- c-basic-offset:4 tab-width:4 -*-
#pragma once

#include <X11/Xlib.h>

void cursor_show(void);

void cursor_hide(void);

bool cursor_on_root_window(void);
void cursor_find(Window *child, int *root_x, int *root_y);
3 changes: 2 additions & 1 deletion include/externals.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// vim:ts=4:sw=4:expandtab
// vim:ts=4:sw=4:expandtab -*- c-basic-offset:4 tab-width:4 -*-
#pragma once

#include <stdlib.h>
Expand All @@ -9,5 +9,6 @@
#include <ev.h>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XInput2.h>
#include <X11/extensions/Xfixes.h>
10 changes: 9 additions & 1 deletion include/globals.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// vim:ts=4:sw=4:expandtab
// vim:ts=4:sw=4:expandtab -*- c-basic-offset:4 tab-width:4 -*-
#pragma once

#include <X11/Xlib.h>
Expand All @@ -9,3 +9,11 @@ extern Display *display;
extern int xi_ext_opcode;

extern Config config;

extern int num_screens;
extern Window *roots;
ileGITimo marked this conversation as resolved.
Show resolved Hide resolved

extern int active_screen;
extern Window active_root;

extern int default_screen;
11 changes: 10 additions & 1 deletion include/types.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
// vim:ts=4:sw=4:expandtab
// vim:ts=4:sw=4:expandtab -*- c-basic-offset:4 tab-width:4 -*-
#pragma once

typedef struct match_t {
char *name;
int len;
} match_t;

typedef struct Config {
long timeout;
long jitter;
bool exclude_root;
bool ignore_scrolling;
bool fork;
bool debug;
bool onescreen;
bool ignore_matches;
match_t *matches;
} Config;

typedef struct coordinates_t {
int x;
int y;
} coordinates_t;

59 changes: 51 additions & 8 deletions man/unclutter-xfixes.man
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,78 @@ unclutter-xfixes - rewrite of unclutter using the X11-Xfixes extension

== SYNOPSIS

unclutter [--timeout <n>] [--jitter <radius>] [--exclude-root] [--ignore-scrolling] [--fork|-b] [--help|-h] [--version|-v]
unclutter [*--timeout* _seconds_] [*--jitter* _radius_] [*--exclude-root*] [*--ignore-scrolling*] [*--fork*|*-b*] [*--help*|*-h*] [*--version*|*-v*]

Compatibility arguments:

unclutter [*--display*|*-d* _display_] [*--idle* _seconds_] [*--keystroke*] [*--grab*] [*--noevents*] [*--reset*] [*--root*] [*--onescreen*] [*--not*] _name …_

== OPTIONS

--timeout <n>::
*--timeout* _seconds_::
Specifies the number of seconds after which the cursor should be hidden if
it was neither moved nor any button was pressed. (Default: 5)

--jitter <radius>::
*--jitter* _radius_::
Ignore cursor movements if the cursor hasn't moved sufficiently far.

--exclude-root::
*--exclude-root*::
Don't hide the mouse cursor if it is idling over the root window and not an
actual window since in this case it isn't obscuring anything important, but
rather just the desktop background.

--ignore-scrolling::
*--ignore-scrolling*::
Ignore mouse scroll events (buttons 4 and 5) so that scrolling doesn't unhide
the cursor.

--fork|-b::
*--fork*|*-b*::
Fork unclutter to the background.

--help|-h::
*--help|-h*::
Display the usage and exit.

--version|-v::
*--version*|*-v*::
Display the version and exit.

== COMPATIBILITY

In order to be used as a drop-in replacement of unclutter, unclutter-xfixes
accepts all command line arguments of unclutter, but ignores most of them.

*--display*|*-d* _display_::
Specifies the X display to use. The same effect can be achieved by setting the
*DISPLAY* environment variable.

*--idle* _seconds_::
This argument is mapped to *--timeout*.

*--keystroke*::
This argument is ignored.

*--grab*::
This argument is ignored.

*--noevents*::
This argument is ignored.

*--reset*::
This argument is ignored.

*--root*::
This argument does the opposite of *--exclude-root*.
Shouldn't need to be given, as this is the default behavior in unclutter-xfixes.

*--onescreen*::
This argument restricts unclutter to the single screen specified in *--display*
or to the default screen of the display.

*--not*::
This argument will result in all arguments that aren't options or option arguments, to be collected
into a list that specifies windows where the cursor shall not be removed. These will be the windows
where an element of the list matches, in a case insensitive comparison, the starting characters of
either the WM_NAME, or the name or class of the WM_CLASS, properties of the window. (Note that this
argument can be given anywhere on the command line.)

== DESCRIPTION

Hide the mouse cursor if it isn't being used.
Expand Down
22 changes: 14 additions & 8 deletions src/cursor.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// vim:ts=4:sw=4:expandtab
// vim:ts=4:sw=4:expandtab -*- c-basic-offset:4 tab-width:4 -*-
#include "all.h"

static bool hidden = false;
Expand All @@ -8,7 +8,7 @@ void cursor_show(void) {
return;

DLOG("Showing the cursor.");
XFixesShowCursor(display, DefaultRootWindow(display));
XFixesShowCursor(display, active_root);
XFlush(display);
hidden = false;
}
Expand All @@ -18,16 +18,22 @@ void cursor_hide(void) {
return;

DLOG("Hiding the cursor.");
XFixesHideCursor(display, DefaultRootWindow(display));
XFixesHideCursor(display, active_root);
XFlush(display);
hidden = true;
}

bool cursor_on_root_window(void) {
Window root, child;
int root_x, root_y, win_x, win_y;
void cursor_find(Window *child, int *root_x, int *root_y) {
Window root;
int win_x, win_y;
unsigned int mask;
int screen;

XQueryPointer(display, DefaultRootWindow(display), &root, &child, &root_x, &root_y, &win_x, &win_y, &mask);
return child == None;
for (screen = 0; screen < num_screens; screen++) {
if (XQueryPointer(display, roots[screen], &root, child, root_x, root_y, &win_x, &win_y, &mask)) {
active_screen = screen;
active_root = roots[screen];
break;
}
}
}
82 changes: 72 additions & 10 deletions src/event.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// vim:ts=4:sw=4:expandtab
// vim:ts=4:sw=4:expandtab -*- c-basic-offset:4 tab-width:4 -*-
#include "all.h"

static struct ev_loop *loop;
Expand All @@ -7,6 +7,7 @@ static struct ev_io *x_watcher;
static struct ev_check *x_check;

static coordinates_t last_cursor_pos;
static Window last_avoided = None;

/* Forward declarations */
static void event_init_x_loop(void);
Expand Down Expand Up @@ -52,7 +53,7 @@ static void x_check_cb(EV_P_ ev_check *w, int revents) {

XGenericEventCookie *cookie = &ev.xcookie;
if (cookie->type != GenericEvent || cookie->extension != xi_ext_opcode ||
!XGetEventData(display, cookie)) {
!XGetEventData(display, cookie)) {
continue;
}

Expand All @@ -67,12 +68,10 @@ static void x_check_cb(EV_P_ ev_check *w, int revents) {
XFreeEventData(display, cookie);

if (config.jitter > 0 && cookie->evtype == XI_RawMotion) {
Window root, child;
int root_x, root_y, win_x, win_y;
unsigned int mask;

XQueryPointer(display, DefaultRootWindow(display), &root, &child, &root_x, &root_y, &win_x, &win_y, &mask);
Window child;
int root_x, root_y;

cursor_find(&child, &root_x, &root_y);
int dx = last_cursor_pos.x - root_x;
int dy = last_cursor_pos.y - root_y;
if (dx * dx + dy * dy < config.jitter * config.jitter) {
Expand All @@ -89,9 +88,72 @@ static void x_check_cb(EV_P_ ev_check *w, int revents) {
}
}

static bool name_matches(Window win) {
match_t *ignored;
XClassHint hint;
char *name;
bool found = false;

if (XFetchName(display, win, &name)) {
for (ignored = config.matches; ignored->name; ignored++)
if((found = strncasecmp(ignored->name, name, ignored->len)==0))
break;
XFree(name);
if (found) return true;
}
if (XGetClassHint(display, win, &hint)) {
for (ignored = config.matches; ignored->name; ignored++)
if((found =
strncasecmp(ignored->name, hint.res_name, ignored->len) == 0 ||
strncasecmp(ignored->name, hint.res_class, ignored->len) == 0))
break;
XFree(hint.res_name);
XFree(hint.res_class);
if (found) return true;
}

return false;
}

static bool is_on_ignore_list(Window win) {
Window child_in;
Airblader marked this conversation as resolved.
Show resolved Hide resolved
Window win_in;
Window win_dummy;
int root_x, root_y;
int win_x, win_y;
unsigned int mask;

if (win == last_avoided) return true;

last_avoided = None;
child_in = win_in = win;

do {
win_in = child_in;
if (name_matches(win_in)) {
last_avoided = win;
return true;
}
} while (XQueryPointer(display, win_in, &win_dummy, &child_in, &root_x, &root_y, &win_x, &win_y, &mask)
&& child_in != None);

return false;
}

static void idle_cb(EV_P_ ev_timer *w, int revents) {
if (!config.exclude_root || !cursor_on_root_window())
cursor_hide();
Window child;
int root_x, root_y;

cursor_find(&child, &root_x, &root_y);
if (child) { // not on root
if (!config.onescreen || active_screen == default_screen)
if (!config.ignore_matches || !is_on_ignore_list(child))
cursor_hide();
} else { // on root
if (!config.exclude_root)
if (!config.onescreen || active_screen == default_screen)
cursor_hide();
}
}

static void event_select_xi(void) {
Expand All @@ -106,6 +168,6 @@ static void event_select_xi(void) {
masks[0].mask_len = sizeof(mask);
masks[0].mask = mask;

XISelectEvents(display, DefaultRootWindow(display), masks, 1);
XISelectEvents(display, active_root, masks, 1);
XFlush(display);
}
Loading