Mercurial > sdl-ios-xcode
view src/video/x11/SDL_x11mouse.c @ 1700:21184e1d04c3 SDL-1.3
Merged dynamic X11 fix from SDL 1.2
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Fri, 23 Jun 2006 08:40:46 +0000 |
parents | 4da1ee79c9af |
children |
line wrap: on
line source
/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2006 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga slouken@libsdl.org */ #include "SDL_config.h" #include <X11/Xlib.h> #include <X11/Xutil.h> #include "SDL_mouse.h" #include "../../events/SDL_events_c.h" #include "../SDL_cursor_c.h" #include "SDL_x11dga_c.h" #include "SDL_x11mouse_c.h" /* The implementation dependent data for the window manager cursor */ struct WMcursor { Cursor x_cursor; }; void X11_FreeWMCursor(_THIS, WMcursor * cursor) { if (SDL_Display != NULL) { SDL_Lock_EventThread(); XFreeCursor(SDL_Display, cursor->x_cursor); XSync(SDL_Display, False); SDL_Unlock_EventThread(); } SDL_free(cursor); } WMcursor * X11_CreateWMCursor(_THIS, Uint8 * data, Uint8 * mask, int w, int h, int hot_x, int hot_y) { WMcursor *cursor; XGCValues GCvalues; GC GCcursor; XImage *data_image, *mask_image; Pixmap data_pixmap, mask_pixmap; int clen, i; char *x_data, *x_mask; static XColor black = { 0, 0, 0, 0 }; static XColor white = { 0xffff, 0xffff, 0xffff, 0xffff }; /* Allocate the cursor memory */ cursor = (WMcursor *) SDL_malloc(sizeof(WMcursor)); if (cursor == NULL) { SDL_OutOfMemory(); return (NULL); } /* Mix the mask and the data */ clen = (w / 8) * h; x_data = (char *) SDL_malloc(clen); if (x_data == NULL) { SDL_free(cursor); SDL_OutOfMemory(); return (NULL); } x_mask = (char *) SDL_malloc(clen); if (x_mask == NULL) { SDL_free(cursor); SDL_free(x_data); SDL_OutOfMemory(); return (NULL); } for (i = 0; i < clen; ++i) { /* The mask is OR'd with the data to turn inverted color pixels black since inverted color cursors aren't supported under X11. */ x_mask[i] = data[i] | mask[i]; x_data[i] = data[i]; } /* Prevent the event thread from running while we use the X server */ SDL_Lock_EventThread(); /* Create the data image */ data_image = XCreateImage(SDL_Display, DefaultVisual(SDL_Display, SDL_Screen), 1, XYBitmap, 0, x_data, w, h, 8, w / 8); data_image->byte_order = MSBFirst; data_image->bitmap_bit_order = MSBFirst; data_pixmap = XCreatePixmap(SDL_Display, SDL_Root, w, h, 1); /* Create the data mask */ mask_image = XCreateImage(SDL_Display, DefaultVisual(SDL_Display, SDL_Screen), 1, XYBitmap, 0, x_mask, w, h, 8, w / 8); mask_image->byte_order = MSBFirst; mask_image->bitmap_bit_order = MSBFirst; mask_pixmap = XCreatePixmap(SDL_Display, SDL_Root, w, h, 1); /* Create the graphics context */ GCvalues.function = GXcopy; GCvalues.foreground = ~0; GCvalues.background = 0; GCvalues.plane_mask = AllPlanes; GCcursor = XCreateGC(SDL_Display, data_pixmap, (GCFunction | GCForeground | GCBackground | GCPlaneMask), &GCvalues); /* Blit the images to the pixmaps */ XPutImage(SDL_Display, data_pixmap, GCcursor, data_image, 0, 0, 0, 0, w, h); XPutImage(SDL_Display, mask_pixmap, GCcursor, mask_image, 0, 0, 0, 0, w, h); XFreeGC(SDL_Display, GCcursor); /* These free the x_data and x_mask memory pointers */ XDestroyImage(data_image); XDestroyImage(mask_image); /* Create the cursor */ cursor->x_cursor = XCreatePixmapCursor(SDL_Display, data_pixmap, mask_pixmap, &black, &white, hot_x, hot_y); XFreePixmap(SDL_Display, data_pixmap); XFreePixmap(SDL_Display, mask_pixmap); /* Release the event thread */ XSync(SDL_Display, False); SDL_Unlock_EventThread(); return (cursor); } int X11_ShowWMCursor(_THIS, WMcursor * cursor) { /* Don't do anything if the display is gone */ if (SDL_Display == NULL) { return (0); } /* Set the X11 cursor cursor, or blank if cursor is NULL */ if (SDL_Window) { SDL_Lock_EventThread(); if (cursor == NULL) { if (SDL_BlankCursor != NULL) { XDefineCursor(SDL_Display, SDL_Window, SDL_BlankCursor->x_cursor); } } else { XDefineCursor(SDL_Display, SDL_Window, cursor->x_cursor); } XSync(SDL_Display, False); SDL_Unlock_EventThread(); } return (1); } void X11_WarpWMCursor(_THIS, Uint16 x, Uint16 y) { if (using_dga & DGA_MOUSE) { SDL_PrivateMouseMotion(0, 0, x, y); } else if (mouse_relative) { /* RJR: March 28, 2000 leave physical cursor at center of screen if mouse hidden and grabbed */ SDL_PrivateMouseMotion(0, 0, x, y); } else { SDL_Lock_EventThread(); XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0, x, y); XSync(SDL_Display, False); SDL_Unlock_EventThread(); } } /* Sets the mouse acceleration from a string of the form: 2/1/0 The first number is the numerator, followed by the acceleration denumenator and threshold. */ static void SetMouseAccel(_THIS, const char *accel_param) { int i; size_t len; int accel_value[3]; char *mouse_param, *mouse_param_buf, *pin; len = SDL_strlen(accel_param) + 1; mouse_param_buf = SDL_stack_alloc(char, len); if (!mouse_param_buf) { return; } SDL_strlcpy(mouse_param_buf, accel_param, len); mouse_param = mouse_param_buf; for (i = 0; (i < 3) && mouse_param; ++i) { pin = SDL_strchr(mouse_param, '/'); if (pin) { *pin = '\0'; } accel_value[i] = atoi(mouse_param); if (pin) { mouse_param = pin + 1; } else { mouse_param = NULL; } } if (mouse_param_buf) { XChangePointerControl(SDL_Display, True, True, accel_value[0], accel_value[1], accel_value[2]); SDL_free(mouse_param_buf); } } /* Check to see if we need to enter or leave mouse relative mode */ void X11_CheckMouseModeNoLock(_THIS) { const Uint8 full_focus = (SDL_APPACTIVE | SDL_APPINPUTFOCUS | SDL_APPMOUSEFOCUS); char *env_override; int enable_relative = 1; /* Allow the user to override the relative mouse mode. They almost never want to do this, as it seriously affects applications that rely on continuous relative mouse motion. */ env_override = SDL_getenv("SDL_MOUSE_RELATIVE"); if (env_override) { enable_relative = atoi(env_override); } /* If the mouse is hidden and input is grabbed, we use relative mode */ if (enable_relative && !(SDL_cursorstate & CURSOR_VISIBLE) && (SDL_CurrentWindow.input_grab != SDL_GRAB_OFF) && (SDL_GetAppState() & full_focus) == full_focus) { if (!mouse_relative) { X11_EnableDGAMouse(this); if (!(using_dga & DGA_MOUSE)) { char *xmouse_accel; SDL_GetMouseState(&mouse_last.x, &mouse_last.y); /* Use as raw mouse mickeys as possible */ XGetPointerControl(SDL_Display, &mouse_accel.numerator, &mouse_accel.denominator, &mouse_accel.threshold); xmouse_accel = SDL_getenv("SDL_VIDEO_X11_MOUSEACCEL"); if (xmouse_accel) { SetMouseAccel(this, xmouse_accel); } } mouse_relative = 1; } } else { if (mouse_relative) { if (using_dga & DGA_MOUSE) { X11_DisableDGAMouse(this); } else { XChangePointerControl(SDL_Display, True, True, mouse_accel.numerator, mouse_accel.denominator, mouse_accel.threshold); } mouse_relative = 0; } } } void X11_CheckMouseMode(_THIS) { SDL_Lock_EventThread(); X11_CheckMouseModeNoLock(this); SDL_Unlock_EventThread(); } /* vi: set ts=4 sw=4 expandtab: */