Compare commits

..

No commits in common. "master" and "v1.0" have entirely different histories.
master ... v1.0

8 changed files with 185 additions and 307 deletions

1
.github/FUNDING.yml vendored
View File

@ -1 +0,0 @@
github: arp242

2
.gitignore vendored
View File

@ -1 +1 @@
/find-cursor find-cursor

8
.travis.yml Normal file
View File

@ -0,0 +1,8 @@
language: c
install: make
script: make
compiler:
- clang
- gcc
notifications:
email: false

View File

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright © Martin Tournoij Copyright © 2015-2017 Martin Tournoij
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to of this software and associated documentation files (the "Software"), to

View File

@ -1,21 +1,8 @@
CC?=cc CC?=cc
PREFIX ?= /usr/local CFLAGS?=-std=c99 -pedantic -Wall -Os
NAME ?= find-cursor
CFLAGS += -std=c99 -pedantic -Wall -Wextra -Wpedantic -Os
LDFLAGS += -L/usr/lib
LIBS += -lX11 -lXext -lXfixes
.PHONY: all clean install uninstall
all: all:
${CC} ${CFLAGS} ${LDFLAGS} -o ${NAME} *.c ${LIBS} ${CC} ${CFLAGS} -o find-cursor find-cursor.c -lX11 -lXext -lXfixes
clean:
rm -f ${NAME}
install: install:
install -Dm755 ${NAME} ${DESTDIR}${PREFIX}/bin/${NAME} install --strip -o root -g root find-cursor /bin/
uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/${NAME}

42
README.markdown Normal file
View File

@ -0,0 +1,42 @@
[![This project is considered stable](https://img.shields.io/badge/Status-stable-green.svg)](https://arp242.net/status/stable)
[![Build Status](https://travis-ci.org/Carpetsmoker/find-cursor.svg?branch=master)](https://travis-ci.org/Carpetsmoker/find-cursor)
Simple XLib program to highlight the cursor position. This is similar to the
feature found in Windows XP (and possibly later?)
![screenshot.gif](https://raw.githubusercontent.com/Carpetsmoker/find-cursor/master/screenshot.gif)
Using it
========
Compile it by typing `make`. Run `find-cursor -h to see some options for
controlling the appearance.
- The author runs it with [`xcape`][xcape]:
xcape -e 'Control_L=Escape;Shift_L=KP_Add'
When Left shift is tapped, a Keypad Add is sent I don't have a numpad on my
keyboard which we can then use to launch the program.
- I configured my window manager (PekWM) to pick up Numpad Add and launch this:
KeyPress = "KP_Add" { Actions = "Exec find-cursor" }
I'm not going to include instructions for every window manager out there.
I'm sure you can figure out how to use it with your WM ;-) You can also use
[`xbindkeys`](xbindkeys), which should work with `$any` window manager.
- You may want to disable shadows if you use compton or some other composite
manager; for example for compton start it with:
compton --shadow-exclude "class_g = 'find-cursor'"
Or, perhaps even better, disable it for all shaped windows:
compton --shadow-exclude 'bounding_shaped'
You can also put that in the compton config file. Other managers might have
different options/flags.
[xcape]: https://github.com/alols/xcape
[xbindkeys]: http://www.nongnu.org/xbindkeys/xbindkeys.html

View File

@ -1,70 +0,0 @@
Simple XLib program to highlight the cursor position. This is similar to the
feature found in Windows XP (and possibly later?)
![screenshot.gif](https://raw.githubusercontent.com/arp242/find-cursor/master/screenshot.gif)
Installation
------------
Compile it by typing `make`, install it with `make install`. There
[packages][pkg] for some platforms as well.
You'll need to install some X11 header files on some systems; e.g. on
Ubuntu/Debian: `libx11-dev`, `libxcomposite-dev`, `libxdamage-dev`, and
`libxrender-dev`. For Fedora 36 you might need to install following:
`libXext-devel`, `libXdamage-devel`, `libXrender-devel`, `libXext-devel`.
There is also a Docker container at [klo2k/find-cursor][d] if you want it. Note
this is NOT maintained (or supported) by me. See #19.
[d]: https://hub.docker.com/r/klo2k/find-cursor
[pkg]: https://repology.org/project/find-cursor/versions
Usage
-----
See `find-cursor -h` to see some options for controlling the appearance.
Launching
---------
You will want to map a key in your window manager to run `find-cursor`. You can
also use [`xbindkeys`](xbindkeys), which should work with `$any` window manager.
I run it with [`xcape`][xcape]:
xcape -e 'Control_L=Escape;Shift_L=KP_Add'
When `Left Shift` is tapped a `Keypad Add` is sent; I configured my window
manager to launch `find-cursor` with that.
I don't have a numpad on my keyboard; you can also use `F13` or some other
unused key.
You can use a little wrapper script if you want a "toggle" switch for when
repeating forever:
#!/bin/sh
if pgrep find-cursor; then
pkill find-cursor
else
find-cursor -r0 &
fi
Compton
-------
You may want to disable shadows if you use compton or some other composite
manager; for example for compton start it with:
compton --shadow-exclude "class_g = 'find-cursor'"
Or, perhaps even better, disable it for all shaped windows:
compton --shadow-exclude 'bounding_shaped'
You can also put that in the compton config file. Other managers might have
different options/flags.
[xcape]: https://github.com/alols/xcape
[xbindkeys]: http://www.nongnu.org/xbindkeys/xbindkeys.html

View File

@ -1,10 +1,10 @@
/* /*
* http://code.arp242.net/find-cursor * http://code.arp242.net/find-cursor
* Copyright © Martin Tournoij <martin@arp242.net> * Copyright © 2015-2017 Martin Tournoij <martin@arp242.net>
* See below for full copyright * See below for full copyright
*/ */
#define _DEFAULT_SOURCE #define _XOPEN_SOURCE 500
#include <getopt.h> #include <getopt.h>
#include <stdint.h> #include <stdint.h>
@ -22,10 +22,10 @@
void usage(char *name); void usage(char *name);
int parse_num(int ch, char *opt, char *name); int parse_num(int ch, char *opt, char *name);
int pointer_screen(char *name, Display *display); void draw(
void draw(char *name, Display *display, int screen, char *name,
int size, int distance, int wait, int line_width, char *color_name, int size, int distance, int wait, int line_width, char *color_name,
int follow, int transparent, int grow, int outline, char *ocolor_name); int follow, int transparent, int grow, int outline);
static struct option longopts[] = { static struct option longopts[] = {
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
@ -37,77 +37,53 @@ static struct option longopts[] = {
{"follow", no_argument, NULL, 'f'}, {"follow", no_argument, NULL, 'f'},
{"transparent", no_argument, NULL, 't'}, {"transparent", no_argument, NULL, 't'},
{"grow", no_argument, NULL, 'g'}, {"grow", no_argument, NULL, 'g'},
{"outline", optional_argument, NULL, 'o'}, // Optional for compat, as previously it was hard-coded to 2px. {"outline", no_argument, NULL, 'o'},
{"repeat", required_argument, NULL, 'r'},
{"outline-color", required_argument, NULL, 'O'},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
void usage(char *name) { void usage(char *name) {
printf("" printf("Usage: %s [-stplcftg]\n\n", name);
"find-cursor highlights the cursor position by drawing circles around it.\n" printf(" -h, --help Show this help.\n");
"https://github.com/arp242/find-cursor\n" printf("\n");
"\n" printf("Shape options:\n");
"Flags:\n" printf(" -s, --size Maximum size the circle will grow to in pixels.\n");
" -h, --help Show this help.\n" printf(" -d, --distance Distance between the circles in pixels.\n");
"\n" printf(" -l, --line-width Width of the lines in pixels.\n");
"Shape options:\n" printf(" -w, --wait Time to wait before drawing the next circle in\n");
" -s, --size Maximum size the circle will grow to in pixels.\n" printf(" microseconds.\n");
" -d, --distance Distance between the circles in pixels.\n" printf(" -c, --color Color; can either be an X11 color name or RGB as hex.\n");
" -l, --line-width Width of the lines in pixels.\n" printf(" -g, --grow Grow the animation in size, rather than shrinking it.\n");
" -w, --wait Time to wait before drawing the next circle in\n" printf("\n");
" tenths of milliseconds.\n" printf("Extra options:\n");
" -c, --color Color as X11 color name or RGB (e.g. #ff0000)\n" printf(" -f, --follow Follow the cursor position as the cursor is moving.\n");
" -g, --grow Grow the animation in size, rather than shrinking it.\n" printf(" -t, --transparent Make the window truly 'transparent'. This helps with\n");
"\n" printf(" some display issues when following the cursor position,\n");
"Extra options:\n" printf(" but it doesn't work well with all WMs, which is why\n");
" -f, --follow Follow the cursor position as the cursor is moving.\n" printf(" it's disabled by default.\n");
" -t, --transparent Make the window truly 'transparent'. This helps with\n" printf(" -o, --outline Draw an outline in the opposite color as well. Helps\n");
" some display issues when following the cursor position,\n" printf(" visibility on all backgrounds.\n");
" but it doesn't work well with all WMs, which is why\n" printf("\n");
" it's disabled by default.\n" printf("Examples:\n");
" -o, --outline Width in pixels of outline; uses 2px if no value is given.\n" printf(" The defaults:\n");
" Helps visibility on all backgrounds.\n" printf(" %s --size 320 --distance 40 --wait 400 --line-width 4 --color black\n\n", name);
" -O, --outline-color Color of outline; if omitted it will automatically use\n" printf(" Draw a solid circle:\n");
" the opposite color. No effect if -o isn't set.\n" printf(" %s --size 100 --distance 1 --wait 20 --line-width 1\n", name);
" -r, --repeat Number of times to repeat the animation; use 0 to repeat\n" printf("\n");
" indefinitely.\n"
"\n"
"Examples:\n"
" The defaults:\n"
" %s --size 320 --distance 40 --wait 400 --line-width 4 --color black\n\n"
" Draw a solid circle:\n"
" %s --size 100 --distance 1 --wait 20 --line-width 1\n\n"
" Always draw a full circle on top of the cursor:\n"
" %s --repeat 0 --follow --distance 1 --wait 1 --line-width 16 --size 16\n"
"\n"
"Launching:\n"
" You will want to map a key in your window manager to run find-cursor.\n"
" You can also use xbindkeys, which should work with any window manager.\n"
"\n"
" I run it with xcape:\n"
" xcape -e 'Control_L=Escape;Shift_L=KP_Add'\n"
"\n"
" When Left Shift is tapped a Keypad Add is sent; I configured my window\n"
" manager to launch find-cursor with that.\n"
"\n"
" I don't have a numpad on my keyboard; you can also use F13 or some\n"
" other unused key.\n",
name, name, name);
} }
// Parse number from commandline, or show error and exit if it's not a number. // Parse number from commandline, or show error and exit if it's not a number.
int parse_num(int ch, char *opt, char *name) { int parse_num(int ch, char *opt, char *name) {
char *end; char *end;
long result = strtol(opt, &end, 10); long result = strtol(optarg, &end, 10);
if (*end) { if (*end) {
fprintf(stderr, "%s: value for -%c must be a number\n\n", name, ch); fprintf(stderr, "%s: %d must be a number\n", name, ch);
usage(name); usage(name);
exit(1); exit(1);
} }
return result; return result;
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
// Parse options // Parse options
int size = 320; int size = 320;
@ -115,16 +91,13 @@ int main(int argc, char* argv[]) {
int wait = 400; int wait = 400;
int line_width = 4; int line_width = 4;
char color_name[64] = "black"; char color_name[64] = "black";
char ocolor_name[64];
int follow = 0; int follow = 0;
int transparent = 0; int transparent = 0;
int grow = 0; int grow = 0;
int outline = 0; int outline = 0;
int repeat = 0;
extern int optopt;
int ch; int ch;
while ((ch = getopt_long(argc, argv, ":hs:d:w:l:c:r:ftgo:O:", longopts, NULL)) != -1) while ((ch = getopt_long(argc, argv, "hs:d:w:l:c:r:ftgo", longopts, NULL)) != -1)
switch (ch) { switch (ch) {
case 's': case 's':
size = parse_num(ch, optarg, argv[0]); size = parse_num(ch, optarg, argv[0]);
@ -154,140 +127,82 @@ int main(int argc, char* argv[]) {
grow = 1; grow = 1;
break; break;
case 'o': case 'o':
outline = parse_num(ch, optarg, argv[0]); outline = 1;
break;
case 'O':
strncpy(ocolor_name, optarg, sizeof(ocolor_name));
break;
case 'r':
repeat = parse_num(ch, optarg, argv[0]);
if (repeat == 0)
repeat = -1;
break;
case ':':
switch (optopt) {
case 'o':
outline = 2;
break; break;
default: default:
fprintf(stderr, "%s: missing required argument for -%c\n\n", argv[0], optopt);
usage(argv[0]); usage(argv[0]);
exit(1); exit(1);
} }
break; argc -= optind;
case '?': argv += optind;
fprintf(stderr, "%s: invalid option: -%c\n\n", argv[0], ch);
// fallthrough draw(argv[0],
default: size, distance, wait, line_width, color_name,
usage(argv[0]); follow, transparent, grow, outline);
exit(1);
} }
void draw(
char *name,
int size, int distance, int wait, int line_width, char *color_name,
int follow, int transparent, int grow, int outline
) {
// Setup display and such // Setup display and such
char *display_name = getenv("DISPLAY"); char *display_name = getenv("DISPLAY");
if (!display_name) { if (!display_name) {
fprintf(stderr, "%s: DISPLAY not set\n\n", argv[0]); fprintf(stderr, "%s: cannot connect to X server '%s'\n", name, display_name);
exit(1); exit(1);
} }
Display *display = XOpenDisplay(display_name); Display *display = XOpenDisplay(display_name);
if (!display) { int screen = DefaultScreen(display);
fprintf(stderr, "%s: cannot open display '%s'\n\n", argv[0], display_name);
exit(1);
}
int shape_event_base, shape_error_base; int shape_event_base, shape_error_base;
if (!XShapeQueryExtension(display, &shape_event_base, &shape_error_base)) { if (!XShapeQueryExtension(display, &shape_event_base, &shape_error_base)) {
fprintf(stderr, "%s: no XShape extension for display '%s'\n\n", argv[0], display_name); fprintf(stderr, "%s: no XShape extension for display '%s'\n", name, display_name);
exit(1); exit(1);
} }
// Actually draw. // Get the mouse cursor position
do int win_x, win_y, root_x, root_y = 0;
draw(argv[0], display, pointer_screen(argv[0], display), unsigned int mask = 0;
size, distance, wait, line_width, color_name, Window child_win, root_win;
follow, transparent, grow, outline, ocolor_name); XQueryPointer(display, XRootWindow(display, screen),
while (repeat == -1 || repeat--); &child_win, &root_win,
&root_x, &root_y, &win_x, &win_y, &mask);
XCloseDisplay(display);
}
// Identify which screen the cursor is on.
int pointer_screen(char *name, Display *display) {
int screencount = ScreenCount(display);
// The traditional case
if (screencount == 1)
return DefaultScreen(display);
// Multihead
for (int s=0; s < screencount; s++) {
Window root, win;
int unused = 0;
unsigned int unusedu = 0;
Screen *screen = ScreenOfDisplay(display, s);
int found = XQueryPointer(display, RootWindowOfScreen(screen),
&root, &win, &unused, &unused, &unused, &unused, &unusedu);
if (found)
return s;
}
// Fall through (should never happen)
fprintf(stderr, "%s: Unable to identify pointer screen, using Default\n", name);
return DefaultScreen(display);
}
// Try to get the centre of the cursor.
void cursor_center(Display *display, int size, int *x, int *y) {
XFixesCursorImage *c = XFixesGetCursorImage(display);
*x = c->x - size/2 - c->width/2 + c->xhot;
*y = c->y - size/2 - c->height/2 + c->yhot;
XFree(c);
}
void draw(char *name, Display *display, int screen,
int size, int distance, int wait, int line_width, char *color_name,
int follow, int transparent, int grow, int outline, char *ocolor_name
) {
// Get the mouse cursor position and size.
int center_x, center_y;
cursor_center(display, size, &center_x, &center_y);
// Create a window at the mouse position // Create a window at the mouse position
Window window; Window window;
XSetWindowAttributes window_attr; XSetWindowAttributes window_attr;
window_attr.override_redirect = 1; window_attr.override_redirect = 1;
Colormap colormap = DefaultColormap(display, screen);
if (transparent) { if (transparent) {
XVisualInfo vinfo; XVisualInfo vinfo;
XMatchVisualInfo(display, screen, 32, TrueColor, &vinfo); XMatchVisualInfo(display, DefaultScreen(display), 32, TrueColor, &vinfo);
window_attr.colormap = XCreateColormap(display, DefaultRootWindow(display), vinfo.visual, AllocNone); window_attr.colormap = XCreateColormap(display, DefaultRootWindow(display), vinfo.visual, AllocNone);
colormap = window_attr.colormap;
window_attr.background_pixel = 0; window_attr.background_pixel = 0;
window = XCreateWindow(display, XRootWindow(display, screen), window = XCreateWindow(display, XRootWindow(display, screen),
center_x, // x position root_x - size/2, root_y - size/2, // x, y position
center_y, // y position
size, size, // width, height size, size, // width, height
4, // border width 4, // border width
vinfo.depth, // depth vinfo.depth, // depth
CopyFromParent, // class CopyFromParent, // class
vinfo.visual, // visual vinfo.visual, // visual
CWColormap | CWBorderPixel | CWBackPixel | CWOverrideRedirect, // valuemask CWColormap | CWBorderPixel | CWBackPixel | CWOverrideRedirect, // valuemask
&window_attr); // attributes &window_attr // attributes
);
} }
else else {
window = XCreateWindow(display, XRootWindow(display, screen), window = XCreateWindow(display, XRootWindow(display, screen),
center_x, // x position root_x - size/2, root_y - size/2, // x, y position
center_y, // y position
size, size, // width, height size, size, // width, height
4, // border width 4, // border width
DefaultDepth(display, screen), // depth DefaultDepth(display, screen), // depth
CopyFromParent, // class CopyFromParent, // class
DefaultVisual(display, screen), // visual DefaultVisual(display, screen), // visual
CWOverrideRedirect, // valuemask CWOverrideRedirect, // valuemask
&window_attr); // attributes &window_attr // attributes
);
}
// Make round shaped window. // Make round shaped window.
XGCValues xgcv; XGCValues xgcv;
@ -300,7 +215,6 @@ void draw(char *name, Display *display, int screen,
0, 0, // x, y position 0, 0, // x, y position
size, size, // Size size, size, // Size
0, 360 * 64); // Make it a full circle 0, 360 * 64); // Make it a full circle
XFreeGC(display, part_shape);
XShapeCombineMask(display, window, ShapeBounding, 0,0, shape_mask, ShapeSet); XShapeCombineMask(display, window, ShapeBounding, 0,0, shape_mask, ShapeSet);
XShapeCombineMask(display, window, ShapeClip, 0,0, shape_mask, ShapeSet); XShapeCombineMask(display, window, ShapeClip, 0,0, shape_mask, ShapeSet);
@ -350,31 +264,20 @@ void draw(char *name, Display *display, int screen,
unsigned long valuemask = 0; unsigned long valuemask = 0;
GC gc = XCreateGC(display, window, valuemask, &values); GC gc = XCreateGC(display, window, valuemask, &values);
// Get colours. Colormap colormap = DefaultColormap(display, screen);
XColor color; XColor color;
int err = XAllocNamedColor(display, colormap, color_name, &color, &color); XAllocNamedColor(display, colormap, color_name, &color, &color);
if (err == 0) {
fprintf(stderr, "%s: invalid color value for -c/--color: '%s'\n\n", name, color_name);
usage(name);
exit(1);
}
XColor color2; XColor color2;
if (outline > 0) { char color2_name[14]; // hash + 3x4-digit hex
if (ocolor_name[0] == 0) { // Use opposite colour. if (outline) {
// Insert and convert to XColor.
color2.red = 65535 - color.red; color2.red = 65535 - color.red;
color2.green = 65535 - color.green; color2.green = 65535 - color.green;
color2.blue = 65535 - color.blue; color2.blue = 65535 - color.blue;
sprintf(ocolor_name, "#%04X%04X%04X", color2.red, color2.green, color2.blue); sprintf(color2_name,"#%04X%04X%04X", color2.red,color2.green, color2.blue);
} XAllocNamedColor(display, colormap, color2_name, &color2, &color2);
int err = XAllocNamedColor(display, colormap, ocolor_name, &color2, &color2); } else {
if (err == 0) {
fprintf(stderr, "%s: invalid color value for -O/--outline-color: '%s'\n\n", name, ocolor_name);
usage(name);
exit(1);
}
}
else {
// Set colour only once if not outline. // Set colour only once if not outline.
XSetLineAttributes(display, gc, line_width, LineSolid, CapButt, JoinBevel); XSetLineAttributes(display, gc, line_width, LineSolid, CapButt, JoinBevel);
XSetForeground(display, gc, color.pixel); XSetForeground(display, gc, color.pixel);
@ -383,13 +286,18 @@ void draw(char *name, Display *display, int screen,
// Draw the circles // Draw the circles
int i = 1; int i = 1;
for (i=1; i<=size; i+=distance) { for (i=1; i<=size; i+=distance) {
if (follow) if (follow) {
XClearWindow(display, window); XClearWindow(display, window);
}
int cs = grow ? i : size - i; int cs;
if (grow)
cs = i;
else
cs = size - i;
if (outline > 0) { if (outline) {
XSetLineAttributes(display, gc, line_width+outline, LineSolid, CapButt, JoinBevel); XSetLineAttributes(display, gc, line_width+2, LineSolid, CapButt, JoinBevel);
XSetForeground(display, gc, color2.pixel); XSetForeground(display, gc, color2.pixel);
XDrawArc(display, window, gc, XDrawArc(display, window, gc,
size/2 - cs/2, size/2 - cs/2, // x, y position size/2 - cs/2, size/2 - cs/2, // x, y position
@ -407,8 +315,10 @@ void draw(char *name, Display *display, int screen,
0, 360 * 64); // Make it a full circle 0, 360 * 64); // Make it a full circle
if (follow) { if (follow) {
cursor_center(display, size, &center_x, &center_y); XQueryPointer(display, XRootWindow(display, screen),
XMoveWindow(display, window, center_x, center_y); &child_win, &root_win,
&root_x, &root_y, &win_x, &win_y, &mask);
XMoveWindow(display, window, root_x - size/2, root_y - size/2);
} }
XSync(display, False); XSync(display, False);
@ -416,13 +326,14 @@ void draw(char *name, Display *display, int screen,
} }
XFreeGC(display, gc); XFreeGC(display, gc);
XDestroyWindow(display, window); XCloseDisplay(display);
} }
/* The MIT License (MIT) /*
* The MIT License (MIT)
* *
* Copyright © Martin Tournoij * Copyright © 2015-2017 Martin Tournoij
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to * of this software and associated documentation files (the "Software"), to
@ -440,4 +351,5 @@ void draw(char *name, Display *display, int screen,
* authors or copyright holders be liable for any claim, damages or other * authors or copyright holders be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising * liability, whether in an action of contract, tort or otherwise, arising
* from, out of or in connection with the software or the use or other dealings * from, out of or in connection with the software or the use or other dealings
* in the software. */ * in the software.
*/