[comp.windows.x] Questions about cursors

price@Sun.COM (Chuck Price) (12/06/90)

You are not guaranteed that a particular X server will support arbitrary
cursor sizes. (And I bet those that do support cursors the size of your  window
are not likely to move them around as quickly as you would hope).

You will get quite reasonable performance on most systems by simulating
a crosshair cursor on the client side. First, set an invisible cursor (makes
any lag less noticable...). Next, be sure you are getting motion hints, not
every mouse motion the server generates. Then listen for motion events,
drawing and undrawing the lines with the appropriate graphics functions.

This conference and the sources contain many examples of each step described
above (check out most any window manager source). Also, using zero width lines
frequently speeds things up quite a bit.

-chuck

mouse@LIGHTNING.MCRCIM.MCGILL.EDU (12/06/90)

> I have the need for a very large crosshair cursor.  By "very large" I
> mean a crosshair cursor whose crosshairs always extend to the edge of
> the window no matter how large the window is.  This crosshair cursor
> must also be clipped at the window boundaries so that the crosshairs
> never extend outside the window.

You cannot get these semantics by setting the cursor in the
XDefineCursor sense; the X cursor mechanisms are incompatible with the
goals you state.  In particular, cursors are never clipped by window
boundaries (the root window boundaries might be an exception).

I fear you'll have to do your own crosshair drawing....

That said, let's try to see why your code doesn't work.  I added a
little code to turn it into a whole program, and here's what I'd say is
going wrong:

> 				/* how to tell if Create fails? */
>     pix_curs = XCreatePixmap(disp, window, width, width, 1);
>     pix_curs_mask = XCreatePixmap(disp, window, width, width, 1);
>     tmp_gc = XCreateGC(disp, pix_curs, 0, NULL);

If XCreatePixmap fails, you will get an error event (probably BadAlloc)
from the server.  If you don't arrange otherwise, this will print a
message and kill your program.

I notice that you don't clear pix_curs and pix_curs_mask.  The initial
contents of pixmaps are unspecified, and most servers use whatever junk
happens to be lying around in the newly-allocated memory.  Let's clear
them first:

	XSetForeground(disp,tmp_gc,0L);
	XFillRectangle(disp,pix_curs,tmp_gc,0,0,width,width);
	XFillRectangle(disp,pix_curs_mask,tmp_gc,0,0,width,width);

Ah.  That got rid of the garbage.  Now we just have a solid rectangle
of the background color as the cursor.

> [...set crosshair_lines[]...]
>     XDrawSegments (disp, pix_curs, tmp_gc, crosshair_lines, 2);

Ah yes, the XSetForeground above changed the GC's foreground from the
default of 1.  Let's set it back (insert this before the XDrawSegments
call):

	XSetForeground(disp,tmp_gc,1L);

Now we have a solid rectangle of background with a vertical slit in it
through which we see whatever's behind the cursor.

>     XSetFunction(disp, tmp_gc, GXcopyInverted);
>     XCopyArea(disp, pix_curs, pix_curs_mask, tmp_gc, 0, 0, width, width,
> 	      0, 0);

You've got this backwards.  You want the mask to have 1 where the
picture is to be visible and 0 where it is supposed to let the
window(s) underneath it show through.  Let's change the XSetFunction to
set it to GXcopy, or, since that's the default and we haven't changed
it yet, just delete the XSetFunction altogether.

Ah.  Now we have a T cross.  Presumably what you were after is more
like a + sign.  To get that, change

>     crosshair_lines[0].y1 = crosshair_lines[0].y2 = 0;

into

    crosshair_lines[0].y1 = crosshair_lines[0].y2 = width / 2;

This produces a very nice crosshair.  However, as I indicated above, it
will ignore window boundaries.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

mouse@LARRY.MCRCIM.MCGILL.EDU (12/06/90)

> Well, first of all, you are not initializing your pixmap.

This is true.

> Also, you are not initializing your foreground in tmp_gc.  This must
> be set to 1 [...].

Also true.

> Also, is it not an error to free the cursor before the window that is
> using it is destroyed?  I don't know but I am just wondering.

It is not an error.

From the Xlib document:

	3.2.  Window Attributes
...
	3.2.10.  Cursor Attribute
	
	The cursor attribute specifies which cursor is to be used
	when the pointer is in the InputOutput or InputOnly window.
	You can set the cursor to a cursor or None (default).
	
	If you set the cursor to None, the parent's cursor is used
	when the pointer is in the InputOutput or InputOnly window,
	and any change in the parent's cursor will cause an immedi-
	ate change in the displayed cursor.  By calling XFreeCursor,
	the cursor can be freed immediately as long as no further
	explicit reference to it is made.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu