1c041511dScube
2c041511dScube/* Copyright (c) Mark J. Kilgard, 1995, 1998. */
3c041511dScube
4c041511dScube/* This program is freely distributable without licensing fees
5c041511dScube   and is provided without guarantee or warrantee expressed or
6c041511dScube   implied. This program is -not- in the public domain. */
7c041511dScube
8c041511dScube#include "glutint.h"
9c041511dScube
10c041511dScube#if !defined(_WIN32)
11c041511dScube#include <X11/Xatom.h>  /* For XA_CURSOR */
12c041511dScube#include <X11/cursorfont.h>
13c041511dScube#endif
14c041511dScube
15c041511dScubetypedef struct _CursorTable {
16c041511dScube#if defined(_WIN32)
17c041511dScube  char* glyph;
18c041511dScube#else
19c041511dScube  int glyph;
20c041511dScube#endif
21c041511dScube  Cursor cursor;
22c041511dScube} CursorTable;
23c041511dScube/* *INDENT-OFF* */
24c041511dScube
25c041511dScubestatic CursorTable cursorTable[] = {
26c041511dScube  {XC_arrow, None},		  /* GLUT_CURSOR_RIGHT_ARROW */
27c041511dScube  {XC_top_left_arrow, None},	  /* GLUT_CURSOR_LEFT_ARROW */
28c041511dScube  {XC_hand1, None},		  /* GLUT_CURSOR_INFO */
29c041511dScube  {XC_pirate, None},		  /* GLUT_CURSOR_DESTROY */
30c041511dScube  {XC_question_arrow, None},	  /* GLUT_CURSOR_HELP */
31c041511dScube  {XC_exchange, None},		  /* GLUT_CURSOR_CYCLE */
32c041511dScube  {XC_spraycan, None},		  /* GLUT_CURSOR_SPRAY */
33c041511dScube  {XC_watch, None},		  /* GLUT_CURSOR_WAIT */
34c041511dScube  {XC_xterm, None},		  /* GLUT_CURSOR_TEXT */
35c041511dScube  {XC_crosshair, None},		  /* GLUT_CURSOR_CROSSHAIR */
36c041511dScube  {XC_sb_v_double_arrow, None},	  /* GLUT_CURSOR_UP_DOWN */
37c041511dScube  {XC_sb_h_double_arrow, None},	  /* GLUT_CURSOR_LEFT_RIGHT */
38c041511dScube  {XC_top_side, None},		  /* GLUT_CURSOR_TOP_SIDE */
39c041511dScube  {XC_bottom_side, None},	  /* GLUT_CURSOR_BOTTOM_SIDE */
40c041511dScube  {XC_left_side, None},		  /* GLUT_CURSOR_LEFT_SIDE */
41c041511dScube  {XC_right_side, None},	  /* GLUT_CURSOR_RIGHT_SIDE */
42c041511dScube  {XC_top_left_corner, None},	  /* GLUT_CURSOR_TOP_LEFT_CORNER */
43c041511dScube  {XC_top_right_corner, None},	  /* GLUT_CURSOR_TOP_RIGHT_CORNER */
44c041511dScube  {XC_bottom_right_corner, None}, /* GLUT_CURSOR_BOTTOM_RIGHT_CORNER */
45c041511dScube  {XC_bottom_left_corner, None},  /* GLUT_CURSOR_BOTTOM_LEFT_CORNER */
46c041511dScube};
47c041511dScube/* *INDENT-ON* */
48c041511dScube
49c041511dScube#if !defined(_WIN32)
50c041511dScubestatic Cursor blankCursor = None;
51c041511dScubestatic Cursor fullCrosshairCusor = None;
52c041511dScube
53c041511dScube/* SGI X server's support a special property called the
54c041511dScube   _SGI_CROSSHAIR_CURSOR that when installed as a window's
55c041511dScube   cursor, becomes a full screen crosshair cursor.  SGI
56c041511dScube   has special cursor generation hardware for this case. */
57c041511dScubestatic Cursor
58c041511dScubegetFullCrosshairCursor(void)
59c041511dScube{
60c041511dScube  Cursor cursor;
61c041511dScube  Atom crosshairAtom, actualType;
62c041511dScube  int rc, actualFormat;
63c041511dScube  unsigned long n, left;
64c041511dScube  unsigned char *value;
65c041511dScube
66c041511dScube  if (fullCrosshairCusor == None) {
67c041511dScube    crosshairAtom = XInternAtom(__glutDisplay,
68c041511dScube      "_SGI_CROSSHAIR_CURSOR", True);
69c041511dScube    if (crosshairAtom != None) {
70c041511dScube      value = 0;        /* Make compiler happy. */
71c041511dScube      rc = XGetWindowProperty(__glutDisplay, __glutRoot,
72c041511dScube        crosshairAtom, 0, 1, False, XA_CURSOR, &actualType,
73c041511dScube        &actualFormat, &n, &left, &value);
74c041511dScube      if (rc == Success && actualFormat == 32 && n >= 1) {
75c041511dScube        cursor = ((unsigned long *)value)[0];
76c041511dScube        XFree(value);
77c041511dScube        return cursor;
78c041511dScube      }
79c041511dScube    }
80c041511dScube  }
81c041511dScube  return XCreateFontCursor(__glutDisplay, XC_crosshair);
82c041511dScube}
83c041511dScube
84c041511dScube/* X11 forces you to create a blank cursor if you want
85c041511dScube   to disable the cursor. */
86c041511dScubestatic Cursor
87c041511dScubemakeBlankCursor(void)
88c041511dScube{
89c041511dScube  static char data[1] =
90c041511dScube  {0};
91c041511dScube  Cursor cursor;
92c041511dScube  Pixmap blank;
93c041511dScube  XColor dummy;
94c041511dScube
95c041511dScube  blank = XCreateBitmapFromData(__glutDisplay, __glutRoot,
96c041511dScube    data, 1, 1);
97c041511dScube  if (blank == None)
98c041511dScube    __glutFatalError("out of memory.");
99c041511dScube  cursor = XCreatePixmapCursor(__glutDisplay, blank, blank,
100c041511dScube    &dummy, &dummy, 0, 0);
101c041511dScube  XFreePixmap(__glutDisplay, blank);
102c041511dScube
103c041511dScube  return cursor;
104c041511dScube}
105c041511dScube#endif /* !_WIN32 */
106c041511dScube
107c041511dScube/* Win32 and X11 use this same function to accomplish
108c041511dScube   fairly different tasks.  X11 lets you just define the
109c041511dScube   cursor for a window and the window system takes care
110c041511dScube   of making sure that the window's cursor is installed
111c041511dScube   when the mouse is in the window.  Win32 requires the
112c041511dScube   application to handle a WM_SETCURSOR message to install
113c041511dScube   the right cursor when windows are entered.  Think of
114c041511dScube   the Win32 __glutSetCursor (called from __glutWindowProc)
115c041511dScube   as "install cursor".  Think of the X11 __glutSetCursor
116c041511dScube   (called from glutSetCursor) as "define cursor". */
117c041511dScubevoid
118c041511dScube__glutSetCursor(GLUTwindow *window)
119c041511dScube{
120c041511dScube  int cursor = window->cursor;
121c041511dScube  Cursor xcursor = 0;
122c041511dScube
123c041511dScube  if (cursor >= 0 &&
124c041511dScube    cursor < sizeof(cursorTable) / sizeof(cursorTable[0])) {
125c041511dScube    if (cursorTable[cursor].cursor == None) {
126c041511dScube      cursorTable[cursor].cursor = XCreateFontCursor(__glutDisplay,
127c041511dScube        cursorTable[cursor].glyph);
128c041511dScube    }
129c041511dScube    xcursor = cursorTable[cursor].cursor;
130c041511dScube  } else {
131c041511dScube    /* Special cases. */
132c041511dScube    switch (cursor) {
133c041511dScube    case GLUT_CURSOR_INHERIT:
134c041511dScube#if defined(_WIN32)
135c041511dScube      while (window->parent) {
136c041511dScube        window = window->parent;
137c041511dScube        if (window->cursor != GLUT_CURSOR_INHERIT) {
138c041511dScube          __glutSetCursor(window);
139c041511dScube          return;
140c041511dScube        }
141c041511dScube      }
142c041511dScube      /* XXX Default to an arrow cursor.  Is this
143c041511dScube         right or should we be letting the default
144c041511dScube         window proc be installing some system cursor? */
145c041511dScube      xcursor = cursorTable[0].cursor;
146c041511dScube      if (xcursor == NULL) {
147c041511dScube        xcursor =
148c041511dScube          cursorTable[0].cursor =
149c041511dScube          LoadCursor(NULL, cursorTable[0].glyph);
150c041511dScube      }
151c041511dScube#else
152c041511dScube      xcursor = None;
153c041511dScube#endif
154c041511dScube      break;
155c041511dScube    case GLUT_CURSOR_NONE:
156c041511dScube#if defined(_WIN32)
157c041511dScube      xcursor = NULL;
158c041511dScube#else
159c041511dScube      if (blankCursor == None) {
160c041511dScube        blankCursor = makeBlankCursor();
161c041511dScube      }
162c041511dScube      xcursor = blankCursor;
163c041511dScube#endif
164c041511dScube      break;
165c041511dScube    case GLUT_CURSOR_FULL_CROSSHAIR:
166c041511dScube#if defined(_WIN32)
167c041511dScube      xcursor = (HICON) IDC_CROSS;
168c041511dScube#else
169c041511dScube      if (fullCrosshairCusor == None) {
170c041511dScube        fullCrosshairCusor = getFullCrosshairCursor();
171c041511dScube      }
172c041511dScube      xcursor = fullCrosshairCusor;
173c041511dScube#endif
174c041511dScube      break;
175c041511dScube    }
176c041511dScube  }
177c041511dScube  XDefineCursor(__glutDisplay,
178c041511dScube    window->win, xcursor);
179c041511dScube  XFlush(__glutDisplay);
180c041511dScube}
181c041511dScube
182c041511dScube/* CENTRY */
183c041511dScubevoid GLUTAPIENTRY
184c041511dScubeglutSetCursor(int cursor)
185c041511dScube{
186c041511dScube#ifdef _WIN32
187c041511dScube  POINT point;
188c041511dScube
189c041511dScube  __glutCurrentWindow->cursor = cursor;
190c041511dScube  /* Are we in the window right now?  If so,
191c041511dScube     install the cursor. */
192c041511dScube  GetCursorPos(&point);
193c041511dScube  if (__glutCurrentWindow->win == WindowFromPoint(point)) {
194c041511dScube    __glutSetCursor(__glutCurrentWindow);
195c041511dScube  }
196c041511dScube#else
197c041511dScube  __glutCurrentWindow->cursor = cursor;
198c041511dScube  __glutSetCursor(__glutCurrentWindow);
199c041511dScube#endif
200c041511dScube}
201c041511dScube/* ENDCENTRY */
202