Skip to content

Commit

Permalink
Works for displays with more than one screen
Browse files Browse the repository at this point in the history
Implements old unclutter root, onescreen and not options.
  • Loading branch information
ileGITimo committed Nov 25, 2018
1 parent fa8df8a commit 57fea4d
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 33 deletions.
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;

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;

13 changes: 9 additions & 4 deletions man/unclutter-xfixes.man
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,19 @@ This argument is ignored.
This argument is ignored.

*--root*::
This argument is ignored as this is the default behavior in unclutter-xfixes.
See *--exclude-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 is ignored.
This argument restricts unclutter to the single screen specified in *--display*
or to the default screen of the display.

*--not*::
This argument is ignored.
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

Expand Down
24 changes: 15 additions & 9 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;
unsigned int mask;
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;
}
}
}
80 changes: 71 additions & 9 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 @@ -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;
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);
}
63 changes: 57 additions & 6 deletions src/unclutter.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"
#include <getopt.h>
#include <unistd.h>
Expand All @@ -17,16 +17,30 @@ static void on_exit_hook(void);
static void parse_args(int argc, char *argv[]);
static void print_usage(char *argv[]);
static void safe_fork(callback child_callback);
static void display_init();

Display *display;

int num_screens;
Window *roots; // root of each screen

// screen and root window the cursor is in, as set in cursor_find
int active_screen;
Window active_root;

// the screen to use with the onescreen option
int default_screen;

Config config = {
.timeout = 5,
.jitter = 0,
.exclude_root = false,
.ignore_scrolling = false,
.fork = false,
.debug = false
.debug = false,
.onescreen = false,
.ignore_matches = false,
.matches = NULL
};

int main(int argc, char *argv[]) {
Expand All @@ -45,6 +59,7 @@ static void run(void) {
if (display == NULL)
bail("Failed to connect to the X server.");

display_init();
extensions_init();
event_init();

Expand All @@ -71,7 +86,7 @@ static void parse_args(int argc, char *argv[]) {
{ "reset", no_argument, 0, 0 },
{ "root", no_argument, 0, 0 },
{ "onescreen", no_argument, 0, 0 },
{ "not", required_argument, 0, 0 },
{ "not", no_argument, 0, 0 },

/* unclutter-xfixes options */
{ "timeout", required_argument, 0, 0 },
Expand Down Expand Up @@ -115,15 +130,22 @@ static void parse_args(int argc, char *argv[]) {
} else if (OPT_NAME_IS("exclude-root")) {
config.exclude_root = true;
break;
} else if (OPT_NAME_IS("root")) {
config.exclude_root = false;
break;
} else if (OPT_NAME_IS("onescreen")) {
config.onescreen = true;
break;
} else if (OPT_NAME_IS("not")) {
config.ignore_matches = true;
break;
} else if (OPT_NAME_IS("ignore-scrolling")) {
config.ignore_scrolling = true;
break;
} else if (OPT_NAME_IS("debug")) {
config.debug = true;
break;
} else if (OPT_NAME_IS("keystroke") || OPT_NAME_IS("grab") ||
OPT_NAME_IS("noevents") || OPT_NAME_IS("reset") || OPT_NAME_IS("root") ||
OPT_NAME_IS("onescreen") || OPT_NAME_IS("not")) {
} else if (OPT_NAME_IS("keystroke") || OPT_NAME_IS("grab") || OPT_NAME_IS("noevents") || OPT_NAME_IS("reset")) {
ELOG("Using unsupported unclutter argument \"%s\", ignoring.", opt_name);
break;
}
Expand All @@ -147,6 +169,17 @@ static void parse_args(int argc, char *argv[]) {
}
}

if (config.ignore_matches) {
config.matches = calloc(sizeof(match_t), argc - optind + 1);
if (config.matches == NULL)
bail("Failed to allocate space for matches");
for (c = 0; optind < argc; c++, optind++) {
char *name = argv[optind];
config.matches[c].name = name;
config.matches[c].len = name ? strlen(name) : 0;
}
}

#undef OPT_NAME_IS

}
Expand All @@ -169,3 +202,21 @@ static void safe_fork(callback child_callback) {
waitpid(pid, NULL, 0);
}
}

static void display_init() {
int screen;
Window child;
int root_x, root_y;

num_screens = ScreenCount(display);
roots = calloc(sizeof(Window), num_screens);
if (roots == NULL)
bail("Failed to allocate root windows.");

for (screen = 0; screen < num_screens; screen++)
roots[screen] = XRootWindow(display, screen);
active_screen = DefaultScreen(display);
active_root = RootWindow(display, active_screen);
default_screen = active_screen;
cursor_find(&child, &root_x, &root_y);
}

0 comments on commit 57fea4d

Please sign in to comment.