| |
| /* Copyright (c) Mark J. Kilgard, 1995, 1998. */ |
| |
| /* This program is freely distributable without licensing fees |
| and is provided without guarantee or warrantee expressed or |
| implied. This program is -not- in the public domain. */ |
| |
| #include "glutint.h" |
| |
| #if !defined(_WIN32) |
| #include <X11/Xatom.h> /* For XA_CURSOR */ |
| #include <X11/cursorfont.h> |
| #endif |
| |
| typedef struct _CursorTable { |
| #if defined(_WIN32) |
| char* glyph; |
| #else |
| int glyph; |
| #endif |
| Cursor cursor; |
| } CursorTable; |
| /* *INDENT-OFF* */ |
| |
| static CursorTable cursorTable[] = { |
| {XC_arrow, None}, /* GLUT_CURSOR_RIGHT_ARROW */ |
| {XC_top_left_arrow, None}, /* GLUT_CURSOR_LEFT_ARROW */ |
| {XC_hand1, None}, /* GLUT_CURSOR_INFO */ |
| {XC_pirate, None}, /* GLUT_CURSOR_DESTROY */ |
| {XC_question_arrow, None}, /* GLUT_CURSOR_HELP */ |
| {XC_exchange, None}, /* GLUT_CURSOR_CYCLE */ |
| {XC_spraycan, None}, /* GLUT_CURSOR_SPRAY */ |
| {XC_watch, None}, /* GLUT_CURSOR_WAIT */ |
| {XC_xterm, None}, /* GLUT_CURSOR_TEXT */ |
| {XC_crosshair, None}, /* GLUT_CURSOR_CROSSHAIR */ |
| {XC_sb_v_double_arrow, None}, /* GLUT_CURSOR_UP_DOWN */ |
| {XC_sb_h_double_arrow, None}, /* GLUT_CURSOR_LEFT_RIGHT */ |
| {XC_top_side, None}, /* GLUT_CURSOR_TOP_SIDE */ |
| {XC_bottom_side, None}, /* GLUT_CURSOR_BOTTOM_SIDE */ |
| {XC_left_side, None}, /* GLUT_CURSOR_LEFT_SIDE */ |
| {XC_right_side, None}, /* GLUT_CURSOR_RIGHT_SIDE */ |
| {XC_top_left_corner, None}, /* GLUT_CURSOR_TOP_LEFT_CORNER */ |
| {XC_top_right_corner, None}, /* GLUT_CURSOR_TOP_RIGHT_CORNER */ |
| {XC_bottom_right_corner, None}, /* GLUT_CURSOR_BOTTOM_RIGHT_CORNER */ |
| {XC_bottom_left_corner, None}, /* GLUT_CURSOR_BOTTOM_LEFT_CORNER */ |
| }; |
| /* *INDENT-ON* */ |
| |
| #if !defined(_WIN32) |
| static Cursor blankCursor = None; |
| static Cursor fullCrosshairCusor = None; |
| |
| /* SGI X server's support a special property called the |
| _SGI_CROSSHAIR_CURSOR that when installed as a window's |
| cursor, becomes a full screen crosshair cursor. SGI |
| has special cursor generation hardware for this case. */ |
| static Cursor |
| getFullCrosshairCursor(void) |
| { |
| Cursor cursor; |
| Atom crosshairAtom, actualType; |
| int rc, actualFormat; |
| unsigned long n, left; |
| unsigned char *value; |
| |
| if (fullCrosshairCusor == None) { |
| crosshairAtom = XInternAtom(__glutDisplay, |
| "_SGI_CROSSHAIR_CURSOR", True); |
| if (crosshairAtom != None) { |
| value = 0; /* Make compiler happy. */ |
| rc = XGetWindowProperty(__glutDisplay, __glutRoot, |
| crosshairAtom, 0, 1, False, XA_CURSOR, &actualType, |
| &actualFormat, &n, &left, &value); |
| if (rc == Success && actualFormat == 32 && n >= 1) { |
| cursor = ((unsigned long *)value)[0]; |
| XFree(value); |
| return cursor; |
| } |
| } |
| } |
| return XCreateFontCursor(__glutDisplay, XC_crosshair); |
| } |
| |
| /* X11 forces you to create a blank cursor if you want |
| to disable the cursor. */ |
| static Cursor |
| makeBlankCursor(void) |
| { |
| static char data[1] = |
| {0}; |
| Cursor cursor; |
| Pixmap blank; |
| XColor dummy; |
| |
| blank = XCreateBitmapFromData(__glutDisplay, __glutRoot, |
| data, 1, 1); |
| if (blank == None) |
| __glutFatalError("out of memory."); |
| cursor = XCreatePixmapCursor(__glutDisplay, blank, blank, |
| &dummy, &dummy, 0, 0); |
| XFreePixmap(__glutDisplay, blank); |
| |
| return cursor; |
| } |
| #endif /* !_WIN32 */ |
| |
| /* Win32 and X11 use this same function to accomplish |
| fairly different tasks. X11 lets you just define the |
| cursor for a window and the window system takes care |
| of making sure that the window's cursor is installed |
| when the mouse is in the window. Win32 requires the |
| application to handle a WM_SETCURSOR message to install |
| the right cursor when windows are entered. Think of |
| the Win32 __glutSetCursor (called from __glutWindowProc) |
| as "install cursor". Think of the X11 __glutSetCursor |
| (called from glutSetCursor) as "define cursor". */ |
| void |
| __glutSetCursor(GLUTwindow *window) |
| { |
| int cursor = window->cursor; |
| Cursor xcursor = 0; |
| |
| if (cursor >= 0 && |
| cursor < sizeof(cursorTable) / sizeof(cursorTable[0])) { |
| if (cursorTable[cursor].cursor == None) { |
| cursorTable[cursor].cursor = XCreateFontCursor(__glutDisplay, |
| cursorTable[cursor].glyph); |
| } |
| xcursor = cursorTable[cursor].cursor; |
| } else { |
| /* Special cases. */ |
| switch (cursor) { |
| case GLUT_CURSOR_INHERIT: |
| #if defined(_WIN32) |
| while (window->parent) { |
| window = window->parent; |
| if (window->cursor != GLUT_CURSOR_INHERIT) { |
| __glutSetCursor(window); |
| return; |
| } |
| } |
| /* XXX Default to an arrow cursor. Is this |
| right or should we be letting the default |
| window proc be installing some system cursor? */ |
| xcursor = cursorTable[0].cursor; |
| if (xcursor == NULL) { |
| xcursor = |
| cursorTable[0].cursor = |
| LoadCursor(NULL, cursorTable[0].glyph); |
| } |
| #else |
| xcursor = None; |
| #endif |
| break; |
| case GLUT_CURSOR_NONE: |
| #if defined(_WIN32) |
| xcursor = NULL; |
| #else |
| if (blankCursor == None) { |
| blankCursor = makeBlankCursor(); |
| } |
| xcursor = blankCursor; |
| #endif |
| break; |
| case GLUT_CURSOR_FULL_CROSSHAIR: |
| #if defined(_WIN32) |
| xcursor = (HICON) IDC_CROSS; |
| #else |
| if (fullCrosshairCusor == None) { |
| fullCrosshairCusor = getFullCrosshairCursor(); |
| } |
| xcursor = fullCrosshairCusor; |
| #endif |
| break; |
| } |
| } |
| XDefineCursor(__glutDisplay, |
| window->win, xcursor); |
| XFlush(__glutDisplay); |
| } |
| |
| /* CENTRY */ |
| void GLUTAPIENTRY |
| glutSetCursor(int cursor) |
| { |
| #ifdef _WIN32 |
| POINT point; |
| |
| __glutCurrentWindow->cursor = cursor; |
| /* Are we in the window right now? If so, |
| install the cursor. */ |
| GetCursorPos(&point); |
| if (__glutCurrentWindow->win == WindowFromPoint(point)) { |
| __glutSetCursor(__glutCurrentWindow); |
| } |
| #else |
| __glutCurrentWindow->cursor = cursor; |
| __glutSetCursor(__glutCurrentWindow); |
| #endif |
| } |
| /* ENDCENTRY */ |