Building custom x11 cursors for Linux

Table of Contents

img

I wanted to use the sort of Starcraft game cursors I enjoyed on my windows machine as a teenager, and this was my first thought of custom cursors in Linux. Note that I use EXWM as a low-level window manager, so these instructions should work for most any Linux system. Spoiler: I got it working, but it took a good deal of time that I hope you might be saved. Here is my story.

1. Acquire the Windows cursor theme

If you already have png of your cursors you can skip this, but I found a windows theme with cursors I want here: http://www.rw-designer.com/cursor-set/starcraft-original

Unpacking, I ended up with a collection of .cur and .ani files, which represent static and animated cursors for Windows.

2. Acquire the convert-script and its dependencies

There’s a simple shell script made by paddygord here on git. Grab that file and make sure you have the dependencies of imagemagick and xcursorgen (both should be available in your repos).

3. Follow instructions to convert the files with convert.sh

The instructions come with the converter, but basically you put the Windows cursors you acquired in step 1 into your “input” directory of the converter. Note that I had to rename many of the windows files to remove spaces and any other odd characters, which otherwise mess up the naive script in convert.sh.

4. Gather and rename the generated files

Linux cursors have no file extension and so you end up with the output of the script being a folder of folders, where each final folder includes pngs, xcg, ico, and the extensionless x11 cursor file. You need to gather all those latter things into one place. I did it with the following find invocation from my output dir:

find -type f ! -name "*.*" -exec cp {} ~/tmp/cursors/ \;

This takes all extensionless files (ie files without a . in their name) and moves them to my /tmp/cursors/ directory.

5. Make your custom cursor theme

You can locate your custom cursor themes in ~/.icons, where I put mine in ~/.icons/Scraft. Just stick the files from step 4 in whatever directory there.

6. Associate your theme as the system theme

There are two chief actions here:

I) Inherit your theme in the default (maybe optional?)

# ~/.icons/default/index.theme
[Icon Theme]
Inherits=Scraft

That’s the whole file.

II) Change ~/.config/gtk-3.0/settings.ini

This might be is not optional.

# ~/.config/gtk-3.0/settings.ini

[Settings]
gtk-cursor-theme-name=cursor_theme_name

7. Link & rename files

After completing things so far I had inconsistent results – some cursors appeared in some programs, but others did not. Some programs found most of the cursors but others had no luck. It turns out that different programs seek differerent extensionless-file names. I consulted some of the existing themes on my system for reference (e.g. I found /usr/share/icons/DMZ-Black/cursors/) and made sure I had soft-links to my theme files to all of the same names necessary in that theme. I included the long gibberish file names that I could see were linked to sensible names; I’m not sure if this last part was necessary, but I wanted to be complete. In the end my cursor directory looked like this:

/home/userme/.icons/Scraft/cursors:
total used in directory 1.2M available 133405516
drwxr-xr-x 1 userme users 1.6K Mar  8 13:30 .
drwxr-xr-x 1 userme users   14 Feb 26 13:51 ..
lrwxrwxrwx 1 userme users   43 Feb 27 09:43 00000000000000020006000e7e9ffc3f -> /home/userme/.icons/Scraft/cursors/progress
lrwxrwxrwx 1 userme users   44 Feb 27 14:04 640fb0e74195791501fd1ed57b41487f -> /home/userme/.icons/Scraft/cursors/progress2
lrwxrwxrwx 1 userme users   39 Feb 27 13:58 9081237383d90e509aa00f00170e968f -> /home/userme/.icons/Scraft/cursors/grab
lrwxrwxrwx 1 userme users   39 Feb 27 13:56 9d800788f1b08800ae810202380a0822 -> /home/userme/.icons/Scraft/cursors/hand
-rw-r--r-- 1 userme users  16K Oct 30 07:55 bd_double_arrow
-rw-r--r-- 1 userme users  16K Oct 30 07:55 bottom_left_corner
lrwxrwxrwx 1 userme users   44 Feb 27 14:11 bottom_right_corner -> /home/userme/.icons/Scraft/cursors/se-resize
-rw-r--r-- 1 userme users  16K Oct 30 07:55 bottom_side
-rw-r--r-- 1 userme users  16K Oct 30 07:55 bottom_tee
-rw-r--r-- 1 userme users  16K Oct 30 07:55 circle
-rw-r--r-- 1 userme users  16K Oct 30 07:55 color-picker
lrwxrwxrwx 1 userme users   44 Feb 27 14:07 col-resize -> /home/userme/.icons/Scraft/cursors/ew-resize
-rw-r--r-- 1 userme users  16K Oct 30 07:55 copy
-rw-r--r-- 1 userme users  16K Oct 30 07:55 cross
lrwxrwxrwx 1 userme users   46 Feb 27 14:01 cross-circle -> /home/userme/.icons/Scraft/cursors/not-allowed
lrwxrwxrwx 1 userme users   46 Feb 27 14:05 crossed_circle -> /home/userme/.icons/Scraft/cursors/not-allowed
-rw-r--r-- 1 userme users  16K Oct 30 07:55 crosshair
lrwxrwxrwx 1 userme users   39 Feb 27 14:08 d9ce0ab605698f320427677b458ad60b -> /home/userme/.icons/Scraft/cursors/help
lrwxrwxrwx 1 userme users   43 Feb 27 14:08 default -> /home/userme/.icons/Scraft/cursors/left_ptr
-rw-r--r-- 1 userme users  16K Oct 30 07:55 dnd-ask
-rw-r--r-- 1 userme users  16K Oct 30 07:55 dnd-copy
-rw-r--r-- 1 userme users  16K Oct 30 07:55 dnd-link
-rw-r--r-- 1 userme users  16K Oct 30 07:55 dnd-move
-rw-r--r-- 1 userme users  16K Oct 30 07:55 dnd-none
-rw-r--r-- 1 userme users  16K Oct 30 07:55 dotbox
-rw-r--r-- 1 userme users  21K Feb 26 14:24 ew-resize
-rw-r--r-- 1 userme users  16K Oct 30 07:55 fd_double_arrow
lrwxrwxrwx 1 userme users   46 Feb 27 14:09 forbidden -> /home/userme/.icons/Scraft/cursors/not-allowed
-rw-r--r-- 1 userme users  21K Feb 26 14:24 grab
-rw-r--r-- 1 userme users  16K Oct 30 07:55 grabbing
-rw-r--r-- 1 userme users  25K Feb 26 14:24 hand
lrwxrwxrwx 1 userme users   39 Feb 27 09:49 hand1 -> /home/userme/.icons/Scraft/cursors/hand
lrwxrwxrwx 1 userme users   39 Feb 27 09:45 hand2 -> /home/userme/.icons/Scraft/cursors/hand
-rw-r--r-- 1 userme users  21K Feb 26 14:24 help
lrwxrwxrwx 1 userme users   39 Feb 27 09:49 ibeam -> /home/userme/.icons/Scraft/cursors/text
-rw-r--r-- 1 userme users  61K Feb 26 13:14 left_ptr
-rw-r--r-- 1 userme users  33K Feb 26 13:14 left_ptr_watch
-rw-r--r-- 1 userme users  16K Oct 30 07:55 left_side
-rw-r--r-- 1 userme users  16K Oct 30 07:55 left_tee
lrwxrwxrwx 1 userme users   44 Feb 27 14:03 link -> /home/userme/.icons/Scraft/cursors/progress2
-rw-r--r-- 1 userme users  16K Oct 30 07:55 ll_angle
-rw-r--r-- 1 userme users  16K Oct 30 07:55 lr_angle
lrwxrwxrwx 1 userme users   39 Feb 27 13:58 move -> /home/userme/.icons/Scraft/cursors/grab
-rw-r--r-- 1 userme users  21K Feb 26 14:24 not-allowed
-rw-r--r-- 1 userme users  21K Feb 26 14:24 ns-resize
-rw-r--r-- 1 userme users  21K Feb 26 14:24 nw-resize
-rw-r--r-- 1 userme users  16K Oct 30 07:55 pencil
-rw-r--r-- 1 userme users  16K Oct 30 07:55 plus
-rw-r--r-- 1 userme users  17K Feb 26 14:24 pointer
-rw-r--r-- 1 userme users  25K Feb 26 14:24 progress
-rw-r--r-- 1 userme users  21K Feb 26 14:24 progress2
lrwxrwxrwx 1 userme users   39 Feb 27 14:06 question_arrow -> /home/userme/.icons/Scraft/cursors/help
-rw-r--r-- 1 userme users  16K Oct 30 07:55 right_ptr
-rw-r--r-- 1 userme users  16K Oct 30 07:55 right_side
-rw-r--r-- 1 userme users  16K Oct 30 07:55 right_tee
-rw-r--r-- 1 userme users  16K Oct 30 07:55 sb_down_arrow
-rw-r--r-- 1 userme users  16K Oct 30 07:55 sb_h_double_arrow
-rw-r--r-- 1 userme users  16K Oct 30 07:55 sb_left_arrow
-rw-r--r-- 1 userme users  16K Oct 30 07:55 sb_right_arrow
-rw-r--r-- 1 userme users  16K Oct 30 07:55 sb_up_arrow
-rw-r--r-- 1 userme users  16K Oct 30 07:55 sb_v_double_arrow
-rw-r--r-- 1 userme users  21K Feb 26 14:24 se-resize
-rw-r--r-- 1 userme users  16K Oct 30 07:55 tcross
-rw-r--r-- 1 userme users 4.1K Mar  8 13:30 text
-rw-r--r-- 1 userme users 4.1K Feb 26 14:24 text_old
-rw-r--r-- 1 userme users  16K Oct 30 07:55 top_left_corner
-rw-r--r-- 1 userme users  16K Oct 30 07:55 top_right_corner
-rw-r--r-- 1 userme users  16K Oct 30 07:55 top_side
-rw-r--r-- 1 userme users  16K Oct 30 07:55 top_tee
-rw-r--r-- 1 userme users  16K Oct 30 07:55 ul_angle
-rw-r--r-- 1 userme users  16K Oct 30 07:55 ur_angle
-rw-r--r-- 1 userme users  33K Feb 26 13:14 wait
lrwxrwxrwx 1 userme users   39 Feb 27 14:12 watch -> /home/userme/.icons/Scraft/cursors/wait
lrwxrwxrwx 1 userme users   39 Feb 27 14:13 whats_this -> /home/userme/.icons/Scraft/cursors/help
-rw-r--r-- 1 userme users  16K Oct 30 07:55 X_cursor
lrwxrwxrwx 1 userme users   39 Feb 27 13:53 xterm -> /home/userme/.icons/Scraft/cursors/text

8. (optional) fix bad cursors

I had one persisting problem: the text-select cursor, though it looked okay, had its hotspots all wrong: when I tried to move a cursor or select text, I really selected a line upward and a character to the left. This was really annoying, so I needed to fix that individual cursor.

First, I found the PNG that was left-over from step 3 above. I then edited it so that the cursor was in the top-left most of its 32x32 frame instead of in the middle. Alternatively, I could have left the image the same and just changed the hotspot info in the xcg file of the next step. I called this file TextSelect2.png.

Second, make the xcg file what has instructions for the cursor generation, including the reference to my png file:

# text2.xcg
32 1 1 TextSelect2.png

Next, I converted that PNG to a cursor file with a single invocation of what the cursorgen script was doing in bulk.

xcursorgen text2.xcg text2

Finally, replace the original text icon with this new one. Then, after relogging in to my system, my text cursor worked great.

Resources

Tory Anderson avatar
Tory Anderson
Full-time Web App Engineer, Digital Humanist, Researcher, Computer Psychologist