Merged Ryan's SDL-gui-backend branch.
Adds three APIs, and implements them on X11, Cocoa, and Windows: - SDL_CaptureMouse() - SDL_GetGlobalMouseState() - SDL_SetWindowHitTest()
This commit is contained in:
commit
b273873297
28 changed files with 901 additions and 59 deletions
|
@ -84,6 +84,7 @@ test/testgesture
|
|||
test/testgl2
|
||||
test/testgles
|
||||
test/testhaptic
|
||||
test/testhittesting
|
||||
test/testiconv
|
||||
test/testime
|
||||
test/testintersections
|
||||
|
|
|
@ -77,6 +77,31 @@ extern DECLSPEC SDL_Window * SDLCALL SDL_GetMouseFocus(void);
|
|||
*/
|
||||
extern DECLSPEC Uint32 SDLCALL SDL_GetMouseState(int *x, int *y);
|
||||
|
||||
/**
|
||||
* \brief Get the current state of the mouse, in relation to the desktop
|
||||
*
|
||||
* This works just like SDL_GetMouseState(), but the coordinates will be
|
||||
* reported relative to the top-left of the desktop. This can be useful if
|
||||
* you need to track the mouse outside of a specific window and
|
||||
* SDL_CaptureMouse() doesn't fit your needs. For example, it could be
|
||||
* useful if you need to track the mouse while dragging a window, where
|
||||
* coordinates relative to a window might not be in sync at all times.
|
||||
*
|
||||
* \note SDL_GetMouseState() returns the mouse position as SDL understands
|
||||
* it from the last pump of the event queue. This function, however,
|
||||
* queries the OS for the current mouse position, and as such, might
|
||||
* be a slightly less efficient function. Unless you know what you're
|
||||
* doing and have a good reason to use this function, you probably want
|
||||
* SDL_GetMouseState() instead.
|
||||
*
|
||||
* \param x Returns the current X coord, relative to the desktop. Can be NULL.
|
||||
* \param y Returns the current Y coord, relative to the desktop. Can be NULL.
|
||||
* \return The current button state as a bitmask, which can be tested using the SDL_BUTTON(X) macros.
|
||||
*
|
||||
* \sa SDL_GetMouseState
|
||||
*/
|
||||
extern DECLSPEC Uint32 SDLCALL SDL_GetGlobalMouseState(int *x, int *y);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the relative state of the mouse.
|
||||
*
|
||||
|
@ -126,6 +151,37 @@ extern DECLSPEC void SDLCALL SDL_WarpMouseGlobal(int x, int y);
|
|||
*/
|
||||
extern DECLSPEC int SDLCALL SDL_SetRelativeMouseMode(SDL_bool enabled);
|
||||
|
||||
/**
|
||||
* \brief Capture the mouse, to track input outside an SDL window.
|
||||
*
|
||||
* \param enabled Whether or not to enable capturing
|
||||
*
|
||||
* Capturing enables your app to obtain mouse events globally, instead of
|
||||
* just within your window. Not all video targets support this function.
|
||||
* When capturing is enabled, the current window will get all mouse events,
|
||||
* but unlike relative mode, no change is made to the cursor and it is
|
||||
* not restrained to your window.
|
||||
*
|
||||
* This function may also deny mouse input to other windows--both those in
|
||||
* your application and others on the system--so you should use this
|
||||
* function sparingly, and in small bursts. For example, you might want to
|
||||
* track the mouse while the user is dragging something, until the user
|
||||
* releases a mouse button. It is not recommended that you capture the mouse
|
||||
* for long periods of time, such as the entire time your app is running.
|
||||
*
|
||||
* While captured, mouse events still report coordinates relative to the
|
||||
* current (foreground) window, but those coordinates may be outside the
|
||||
* bounds of the window (including negative values). Capturing is only
|
||||
* allowed for the foreground window. If the window loses focus while
|
||||
* capturing, the capture will be disabled automatically.
|
||||
*
|
||||
* While capturing is enabled, the current window will have the
|
||||
* SDL_WINDOW_MOUSE_CAPTURE flag set.
|
||||
*
|
||||
* \return 0 on success, or -1 if not supported.
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL SDL_CaptureMouse(SDL_bool enabled);
|
||||
|
||||
/**
|
||||
* \brief Query whether relative mouse mode is enabled.
|
||||
*
|
||||
|
|
|
@ -43,6 +43,7 @@ extern "C" {
|
|||
* \brief The structure that defines a point
|
||||
*
|
||||
* \sa SDL_EnclosePoints
|
||||
* \sa SDL_PointInRect
|
||||
*/
|
||||
typedef struct SDL_Point
|
||||
{
|
||||
|
@ -66,6 +67,15 @@ typedef struct SDL_Rect
|
|||
int w, h;
|
||||
} SDL_Rect;
|
||||
|
||||
/**
|
||||
* \brief Returns true if point resides inside a rectangle.
|
||||
*/
|
||||
SDL_FORCE_INLINE SDL_bool SDL_PointInRect(const SDL_Point *p, const SDL_Rect *r)
|
||||
{
|
||||
return ( (p->x >= r->x) && (p->x < (r->x + r->w)) &&
|
||||
(p->y >= r->y) && (p->y < (r->y + r->h)) ) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns true if the rectangle has no area.
|
||||
*/
|
||||
|
|
|
@ -108,7 +108,8 @@ typedef enum
|
|||
SDL_WINDOW_MOUSE_FOCUS = 0x00000400, /**< window has mouse focus */
|
||||
SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ),
|
||||
SDL_WINDOW_FOREIGN = 0x00000800, /**< window not created by SDL */
|
||||
SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000 /**< window should be created in high-DPI mode if supported */
|
||||
SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000, /**< window should be created in high-DPI mode if supported */
|
||||
SDL_WINDOW_MOUSE_CAPTURE = 0x00004000 /**< window has mouse captured (unrelated to INPUT_GRABBED) */
|
||||
} SDL_WindowFlags;
|
||||
|
||||
/**
|
||||
|
@ -790,6 +791,75 @@ extern DECLSPEC int SDLCALL SDL_GetWindowGammaRamp(SDL_Window * window,
|
|||
Uint16 * green,
|
||||
Uint16 * blue);
|
||||
|
||||
/**
|
||||
* \brief Possible return values from the SDL_HitTest callback.
|
||||
*
|
||||
* \sa SDL_HitTest
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
SDL_HITTEST_NORMAL, /**< Region is normal. No special properties. */
|
||||
SDL_HITTEST_DRAGGABLE, /**< Region can drag entire window. */
|
||||
SDL_HITTEST_RESIZE_TOPLEFT,
|
||||
SDL_HITTEST_RESIZE_TOP,
|
||||
SDL_HITTEST_RESIZE_TOPRIGHT,
|
||||
SDL_HITTEST_RESIZE_RIGHT,
|
||||
SDL_HITTEST_RESIZE_BOTTOMRIGHT,
|
||||
SDL_HITTEST_RESIZE_BOTTOM,
|
||||
SDL_HITTEST_RESIZE_BOTTOMLEFT,
|
||||
SDL_HITTEST_RESIZE_LEFT
|
||||
} SDL_HitTestResult;
|
||||
|
||||
/**
|
||||
* \brief Callback used for hit-testing.
|
||||
*
|
||||
* \sa SDL_SetWindowHitTest
|
||||
*/
|
||||
typedef SDL_HitTestResult (SDLCALL *SDL_HitTest)(SDL_Window *win,
|
||||
const SDL_Point *area,
|
||||
void *data);
|
||||
|
||||
/**
|
||||
* \brief Provide a callback that decides if a window region has special properties.
|
||||
*
|
||||
* Normally windows are dragged and resized by decorations provided by the
|
||||
* system window manager (a title bar, borders, etc), but for some apps, it
|
||||
* makes sense to drag them from somewhere else inside the window itself; for
|
||||
* example, one might have a borderless window that wants to be draggable
|
||||
* from any part, or simulate its own title bar, etc.
|
||||
*
|
||||
* This function lets the app provide a callback that designates pieces of
|
||||
* a given window as special. This callback is run during event processing
|
||||
* if we need to tell the OS to treat a region of the window specially; the
|
||||
* use of this callback is known as "hit testing."
|
||||
*
|
||||
* Mouse input may not be delivered to your application if it is within
|
||||
* a special area; the OS will often apply that input to moving the window or
|
||||
* resizing the window and not deliver it to the application.
|
||||
*
|
||||
* Specifying NULL for a callback disables hit-testing. Hit-testing is
|
||||
* disabled by default.
|
||||
*
|
||||
* Platforms that don't support this functionality will return -1
|
||||
* unconditionally, even if you're attempting to disable hit-testing.
|
||||
*
|
||||
* Your callback may fire at any time, and its firing does not indicate any
|
||||
* specific behavior (for example, on Windows, this certainly might fire
|
||||
* when the OS is deciding whether to drag your window, but it fires for lots
|
||||
* of other reasons, too, some unrelated to anything you probably care about
|
||||
* _and when the mouse isn't actually at the location it is testing_).
|
||||
* Since this can fire at any time, you should try to keep your callback
|
||||
* efficient, devoid of allocations, etc.
|
||||
*
|
||||
* \param window The window to set hit-testing on.
|
||||
* \param callback The callback to call when doing a hit-test.
|
||||
* \param callback_data An app-defined void pointer passed to the callback.
|
||||
* \return 0 on success, -1 on error (including unsupported).
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL SDL_SetWindowHitTest(SDL_Window * window,
|
||||
SDL_HitTest callback,
|
||||
void *callback_data);
|
||||
|
||||
/**
|
||||
* \brief Destroy a window.
|
||||
*/
|
||||
|
|
|
@ -584,3 +584,6 @@
|
|||
#define SDL_sqrtf SDL_sqrtf_REAL
|
||||
#define SDL_tan SDL_tan_REAL
|
||||
#define SDL_tanf SDL_tanf_REAL
|
||||
#define SDL_CaptureMouse SDL_CaptureMouse_REAL
|
||||
#define SDL_SetWindowHitTest SDL_SetWindowHitTest_REAL
|
||||
#define SDL_GetGlobalMouseState SDL_GetGlobalMouseState_REAL
|
||||
|
|
|
@ -616,3 +616,6 @@ SDL_DYNAPI_PROC(void,SDL_WarpMouseGlobal,(int a, int b),(a,b),)
|
|||
SDL_DYNAPI_PROC(float,SDL_sqrtf,(float a),(a),return)
|
||||
SDL_DYNAPI_PROC(double,SDL_tan,(double a),(a),return)
|
||||
SDL_DYNAPI_PROC(float,SDL_tanf,(float a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_CaptureMouse,(SDL_bool a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_SetWindowHitTest,(SDL_Window *a, SDL_HitTest b, void *c),(a,b,c),return)
|
||||
SDL_DYNAPI_PROC(Uint32,SDL_GetGlobalMouseState,(int *a, int *b),(a,b),return)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "SDL_timer.h"
|
||||
#include "SDL_events.h"
|
||||
#include "SDL_events_c.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "../video/SDL_sysvideo.h"
|
||||
|
||||
|
||||
|
@ -619,6 +620,16 @@ SDL_SetKeyboardFocus(SDL_Window * window)
|
|||
|
||||
/* See if the current window has lost focus */
|
||||
if (keyboard->focus && keyboard->focus != window) {
|
||||
|
||||
/* new window shouldn't think it has mouse captured. */
|
||||
SDL_assert(!window || !(window->flags & SDL_WINDOW_MOUSE_CAPTURE));
|
||||
|
||||
/* old window must lose an existing mouse capture. */
|
||||
if (keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE) {
|
||||
SDL_CaptureMouse(SDL_FALSE); /* drop the capture. */
|
||||
SDL_assert(!(keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE));
|
||||
}
|
||||
|
||||
SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_LOST,
|
||||
0, 0);
|
||||
|
||||
|
|
|
@ -140,14 +140,14 @@ static SDL_bool
|
|||
SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
|
||||
{
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
int w, h;
|
||||
SDL_bool inWindow;
|
||||
SDL_bool inWindow = SDL_TRUE;
|
||||
|
||||
if ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0) {
|
||||
int w, h;
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
if (x < 0 || y < 0 || x >= w || y >= h) {
|
||||
inWindow = SDL_FALSE;
|
||||
} else {
|
||||
inWindow = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Linux doesn't give you mouse events outside your window unless you grab
|
||||
|
@ -246,12 +246,16 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
|
|||
mouse->y += yrel;
|
||||
}
|
||||
|
||||
/* !!! FIXME: shouldn't this be (window) instead of (mouse->focus)? */
|
||||
/* make sure that the pointers find themselves inside the windows,
|
||||
unless we have the mouse captured. */
|
||||
if ((window->flags & SDL_WINDOW_MOUSE_CAPTURE) == 0) {
|
||||
int x_max = 0, y_max = 0;
|
||||
|
||||
// !!! FIXME: shouldn't this be (window) instead of (mouse->focus)?
|
||||
SDL_GetWindowSize(mouse->focus, &x_max, &y_max);
|
||||
--x_max;
|
||||
--y_max;
|
||||
|
||||
/* make sure that the pointers find themselves inside the windows */
|
||||
if (mouse->x > x_max) {
|
||||
mouse->x = x_max;
|
||||
}
|
||||
|
@ -265,6 +269,7 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
|
|||
if (mouse->y < 0) {
|
||||
mouse->y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
mouse->xdelta += xrel;
|
||||
mouse->ydelta += yrel;
|
||||
|
@ -426,6 +431,7 @@ SDL_MouseQuit(void)
|
|||
SDL_Cursor *cursor, *next;
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
|
||||
SDL_CaptureMouse(SDL_FALSE);
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
SDL_ShowCursor(1);
|
||||
|
||||
|
@ -477,16 +483,42 @@ SDL_GetRelativeMouseState(int *x, int *y)
|
|||
return mouse->buttonstate;
|
||||
}
|
||||
|
||||
Uint32
|
||||
SDL_GetGlobalMouseState(int *x, int *y)
|
||||
{
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
int tmpx, tmpy;
|
||||
|
||||
/* make sure these are never NULL for the backend implementations... */
|
||||
if (!x) {
|
||||
x = &tmpx;
|
||||
}
|
||||
if (!y) {
|
||||
y = &tmpy;
|
||||
}
|
||||
|
||||
*x = *y = 0;
|
||||
|
||||
if (!mouse->GetGlobalMouseState) {
|
||||
SDL_assert(0 && "This should really be implemented for every target.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mouse->GetGlobalMouseState(x, y);
|
||||
}
|
||||
|
||||
void
|
||||
SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
|
||||
{
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
|
||||
if (window == NULL)
|
||||
if (window == NULL) {
|
||||
window = mouse->focus;
|
||||
}
|
||||
|
||||
if (window == NULL)
|
||||
if (window == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouse->WarpMouse) {
|
||||
mouse->WarpMouse(window, x, y);
|
||||
|
|
|
@ -66,6 +66,12 @@ typedef struct
|
|||
/* Set relative mode */
|
||||
int (*SetRelativeMouseMode) (SDL_bool enabled);
|
||||
|
||||
/* Set mouse capture */
|
||||
int (*CaptureMouse) (SDL_Window * window);
|
||||
|
||||
/* Get absolute mouse coordinates. (x) and (y) are never NULL and set to zero before call. */
|
||||
Uint32 (*GetGlobalMouseState) (int *x, int *y);
|
||||
|
||||
/* Data common to all mice */
|
||||
SDL_MouseID mouseID;
|
||||
SDL_Window *focus;
|
||||
|
|
|
@ -1379,6 +1379,14 @@ SDLTest_CommonEvent(SDLTest_CommonState * state, SDL_Event * event, int *done)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (withShift) {
|
||||
SDL_Window *current_win = SDL_GetKeyboardFocus();
|
||||
if (current_win) {
|
||||
const SDL_bool shouldCapture = (SDL_GetWindowFlags(current_win) & SDL_WINDOW_MOUSE_CAPTURE) == 0;
|
||||
const int rc = SDL_CaptureMouse(shouldCapture);
|
||||
SDL_Log("%sapturing mouse %s!\n", shouldCapture ? "C" : "Unc", (rc == 0) ? "succeeded" : "failed");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDLK_v:
|
||||
if (withControl) {
|
||||
|
@ -1478,6 +1486,19 @@ SDLTest_CommonEvent(SDLTest_CommonState * state, SDL_Event * event, int *done)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case SDLK_a:
|
||||
if (withControl) {
|
||||
/* Ctrl-A reports absolute mouse position. */
|
||||
int x, y;
|
||||
const Uint32 mask = SDL_GetGlobalMouseState(&x, &y);
|
||||
SDL_Log("ABSOLUTE MOUSE: (%d, %d)%s%s%s%s%s\n", x, y,
|
||||
(mask & SDL_BUTTON_LMASK) ? " [LBUTTON]" : "",
|
||||
(mask & SDL_BUTTON_MMASK) ? " [MBUTTON]" : "",
|
||||
(mask & SDL_BUTTON_RMASK) ? " [RBUTTON]" : "",
|
||||
(mask & SDL_BUTTON_X1MASK) ? " [X2BUTTON]" : "",
|
||||
(mask & SDL_BUTTON_X2MASK) ? " [X2BUTTON]" : "");
|
||||
}
|
||||
break;
|
||||
case SDLK_0:
|
||||
if (withControl) {
|
||||
SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
|
||||
|
|
|
@ -97,6 +97,9 @@ struct SDL_Window
|
|||
|
||||
SDL_WindowShaper *shaper;
|
||||
|
||||
SDL_HitTest hit_test;
|
||||
void *hit_test_data;
|
||||
|
||||
SDL_WindowUserData *data;
|
||||
|
||||
void *driverdata;
|
||||
|
@ -261,6 +264,9 @@ struct SDL_VideoDevice
|
|||
/* MessageBox */
|
||||
int (*ShowMessageBox) (_THIS, const SDL_MessageBoxData *messageboxdata, int *buttonid);
|
||||
|
||||
/* Hit-testing */
|
||||
int (*SetWindowHitTest)(SDL_Window * window, SDL_bool enabled);
|
||||
|
||||
/* * * */
|
||||
/* Data common to all drivers */
|
||||
SDL_bool suspend_screensaver;
|
||||
|
|
|
@ -1428,6 +1428,11 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags)
|
|||
SDL_SetWindowIcon(window, icon);
|
||||
SDL_FreeSurface(icon);
|
||||
}
|
||||
|
||||
if (window->hit_test) {
|
||||
_this->SetWindowHitTest(window, SDL_TRUE);
|
||||
}
|
||||
|
||||
SDL_FinishWindowCreation(window, flags);
|
||||
|
||||
return 0;
|
||||
|
@ -3292,12 +3297,17 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
|
|||
int retval = -1;
|
||||
SDL_bool relative_mode;
|
||||
int show_cursor_prev;
|
||||
SDL_bool mouse_captured;
|
||||
SDL_Window *current_window;
|
||||
|
||||
if (!messageboxdata) {
|
||||
return SDL_InvalidParamError("messageboxdata");
|
||||
}
|
||||
|
||||
current_window = SDL_GetKeyboardFocus();
|
||||
mouse_captured = current_window && ((SDL_GetWindowFlags(current_window) & SDL_WINDOW_MOUSE_CAPTURE) != 0);
|
||||
relative_mode = SDL_GetRelativeMouseMode();
|
||||
SDL_CaptureMouse(SDL_FALSE);
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
show_cursor_prev = SDL_ShowCursor(1);
|
||||
|
||||
|
@ -3349,6 +3359,13 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
|
|||
SDL_SetError("No message system available");
|
||||
}
|
||||
|
||||
if (current_window) {
|
||||
SDL_RaiseWindow(current_window);
|
||||
if (mouse_captured) {
|
||||
SDL_CaptureMouse(SDL_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_ShowCursor(show_cursor_prev);
|
||||
SDL_SetRelativeMouseMode(relative_mode);
|
||||
|
||||
|
@ -3391,4 +3408,21 @@ SDL_ShouldAllowTopmost(void)
|
|||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SetWindowHitTest(SDL_Window * window, SDL_HitTest callback, void *userdata)
|
||||
{
|
||||
CHECK_WINDOW_MAGIC(window, -1);
|
||||
|
||||
if (!_this->SetWindowHitTest) {
|
||||
return SDL_Unsupported();
|
||||
} else if (_this->SetWindowHitTest(window, callback != NULL) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
window->hit_test = callback;
|
||||
window->hit_test_data = userdata;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -307,6 +307,39 @@ Cocoa_SetRelativeMouseMode(SDL_bool enabled)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
Cocoa_CaptureMouse(SDL_Window *window)
|
||||
{
|
||||
/* our Cocoa event code already tracks the mouse outside the window,
|
||||
so all we have to do here is say "okay" and do what we always do. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint32
|
||||
Cocoa_GetGlobalMouseState(int *x, int *y)
|
||||
{
|
||||
const NSUInteger cocoaButtons = [NSEvent pressedMouseButtons];
|
||||
const NSPoint cocoaLocation = [NSEvent mouseLocation];
|
||||
Uint32 retval = 0;
|
||||
|
||||
for (NSScreen *screen in [NSScreen screens]) {
|
||||
NSRect frame = [screen frame];
|
||||
if (NSPointInRect(cocoaLocation, frame)) {
|
||||
*x = (int) cocoaLocation.x;
|
||||
*y = (int) ((frame.origin.y + frame.size.height) - cocoaLocation.y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
retval |= (cocoaButtons & (1 << 0)) ? SDL_BUTTON_LMASK : 0;
|
||||
retval |= (cocoaButtons & (1 << 1)) ? SDL_BUTTON_RMASK : 0;
|
||||
retval |= (cocoaButtons & (1 << 2)) ? SDL_BUTTON_MMASK : 0;
|
||||
retval |= (cocoaButtons & (1 << 3)) ? SDL_BUTTON_X1MASK : 0;
|
||||
retval |= (cocoaButtons & (1 << 4)) ? SDL_BUTTON_X2MASK : 0;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
Cocoa_InitMouse(_THIS)
|
||||
{
|
||||
|
@ -321,6 +354,8 @@ Cocoa_InitMouse(_THIS)
|
|||
mouse->WarpMouse = Cocoa_WarpMouse;
|
||||
mouse->WarpMouseGlobal = Cocoa_WarpMouseGlobal;
|
||||
mouse->SetRelativeMouseMode = Cocoa_SetRelativeMouseMode;
|
||||
mouse->CaptureMouse = Cocoa_CaptureMouse;
|
||||
mouse->GetGlobalMouseState = Cocoa_GetGlobalMouseState;
|
||||
|
||||
SDL_SetDefaultCursor(Cocoa_CreateDefaultCursor());
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ Cocoa_CreateDevice(int devindex)
|
|||
device->SetWindowGrab = Cocoa_SetWindowGrab;
|
||||
device->DestroyWindow = Cocoa_DestroyWindow;
|
||||
device->GetWindowWMInfo = Cocoa_GetWindowWMInfo;
|
||||
device->SetWindowHitTest = Cocoa_SetWindowHitTest;
|
||||
|
||||
device->shape_driver.CreateShaper = Cocoa_CreateShaper;
|
||||
device->shape_driver.SetWindowShape = Cocoa_SetWindowShape;
|
||||
|
|
|
@ -45,6 +45,7 @@ typedef enum
|
|||
PendingWindowOperation pendingWindowOperation;
|
||||
BOOL isMoving;
|
||||
int pendingWindowWarpX, pendingWindowWarpY;
|
||||
BOOL isDragAreaRunning;
|
||||
}
|
||||
|
||||
-(void) listen:(SDL_WindowData *) data;
|
||||
|
@ -75,6 +76,9 @@ typedef enum
|
|||
-(void) windowDidExitFullScreen:(NSNotification *) aNotification;
|
||||
-(NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions;
|
||||
|
||||
/* See if event is in a drag area, toggle on window dragging. */
|
||||
-(BOOL) processHitTest:(NSEvent *)theEvent;
|
||||
|
||||
/* Window event handling */
|
||||
-(void) mouseDown:(NSEvent *) theEvent;
|
||||
-(void) rightMouseDown:(NSEvent *) theEvent;
|
||||
|
@ -138,8 +142,8 @@ extern int Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * r
|
|||
extern int Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp);
|
||||
extern void Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
|
||||
extern void Cocoa_DestroyWindow(_THIS, SDL_Window * window);
|
||||
extern SDL_bool Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window,
|
||||
struct SDL_SysWMinfo *info);
|
||||
extern SDL_bool Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info);
|
||||
extern int Cocoa_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
|
||||
|
||||
#endif /* _SDL_cocoawindow_h */
|
||||
|
||||
|
|
|
@ -192,6 +192,7 @@ SetWindowStyle(SDL_Window * window, unsigned int style)
|
|||
inFullscreenTransition = NO;
|
||||
pendingWindowOperation = PENDING_OPERATION_NONE;
|
||||
isMoving = NO;
|
||||
isDragAreaRunning = NO;
|
||||
|
||||
center = [NSNotificationCenter defaultCenter];
|
||||
|
||||
|
@ -663,10 +664,48 @@ SetWindowStyle(SDL_Window * window, unsigned int style)
|
|||
/*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
|
||||
}
|
||||
|
||||
/* We'll respond to selectors by doing nothing so we don't beep.
|
||||
* The escape key gets converted to a "cancel" selector, etc.
|
||||
*/
|
||||
- (void)doCommandBySelector:(SEL)aSelector
|
||||
{
|
||||
/*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/
|
||||
}
|
||||
|
||||
- (BOOL)processHitTest:(NSEvent *)theEvent
|
||||
{
|
||||
SDL_assert(isDragAreaRunning == [_data->nswindow isMovableByWindowBackground]);
|
||||
|
||||
if (_data->window->hit_test) { /* if no hit-test, skip this. */
|
||||
const NSPoint location = [theEvent locationInWindow];
|
||||
const SDL_Point point = { (int) location.x, _data->window->h - (((int) location.y)-1) };
|
||||
const SDL_HitTestResult rc = _data->window->hit_test(_data->window, &point, _data->window->hit_test_data);
|
||||
if (rc == SDL_HITTEST_DRAGGABLE) {
|
||||
if (!isDragAreaRunning) {
|
||||
isDragAreaRunning = YES;
|
||||
[_data->nswindow setMovableByWindowBackground:YES];
|
||||
}
|
||||
return YES; /* dragging! */
|
||||
}
|
||||
}
|
||||
|
||||
if (isDragAreaRunning) {
|
||||
isDragAreaRunning = NO;
|
||||
[_data->nswindow setMovableByWindowBackground:NO];
|
||||
return YES; /* was dragging, drop event. */
|
||||
}
|
||||
|
||||
return NO; /* not a special area, carry on. */
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)theEvent
|
||||
{
|
||||
int button;
|
||||
|
||||
if ([self processHitTest:theEvent]) {
|
||||
return; /* dragging, drop event. */
|
||||
}
|
||||
|
||||
switch ([theEvent buttonNumber]) {
|
||||
case 0:
|
||||
if (([theEvent modifierFlags] & NSControlKeyMask) &&
|
||||
|
@ -705,6 +744,10 @@ SetWindowStyle(SDL_Window * window, unsigned int style)
|
|||
{
|
||||
int button;
|
||||
|
||||
if ([self processHitTest:theEvent]) {
|
||||
return; /* stopped dragging, drop event. */
|
||||
}
|
||||
|
||||
switch ([theEvent buttonNumber]) {
|
||||
case 0:
|
||||
if (wasCtrlLeft) {
|
||||
|
@ -744,6 +787,10 @@ SetWindowStyle(SDL_Window * window, unsigned int style)
|
|||
NSPoint point;
|
||||
int x, y;
|
||||
|
||||
if ([self processHitTest:theEvent]) {
|
||||
return; /* dragging, drop event. */
|
||||
}
|
||||
|
||||
if (mouse->relative_mode) {
|
||||
return;
|
||||
}
|
||||
|
@ -752,8 +799,8 @@ SetWindowStyle(SDL_Window * window, unsigned int style)
|
|||
x = (int)point.x;
|
||||
y = (int)(window->h - point.y);
|
||||
|
||||
if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
|
||||
if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
|
||||
if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
} else if (x >= window->w) {
|
||||
|
@ -890,6 +937,7 @@ SetWindowStyle(SDL_Window * window, unsigned int style)
|
|||
|
||||
/* The default implementation doesn't pass rightMouseDown to responder chain */
|
||||
- (void)rightMouseDown:(NSEvent *)theEvent;
|
||||
- (BOOL)mouseDownCanMoveWindow;
|
||||
@end
|
||||
|
||||
@implementation SDLView
|
||||
|
@ -898,6 +946,14 @@ SetWindowStyle(SDL_Window * window, unsigned int style)
|
|||
[[self nextResponder] rightMouseDown:theEvent];
|
||||
}
|
||||
|
||||
- (BOOL)mouseDownCanMoveWindow
|
||||
{
|
||||
/* Always say YES, but this doesn't do anything until we call
|
||||
-[NSWindow setMovableByWindowBackground:YES], which we ninja-toggle
|
||||
during mouse events when we're using a drag area. */
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)resetCursorRects
|
||||
{
|
||||
[super resetCursorRects];
|
||||
|
@ -995,6 +1051,7 @@ SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created
|
|||
|
||||
/* All done! */
|
||||
[pool release];
|
||||
window->driverdata = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1566,6 +1623,12 @@ Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state)
|
|||
return succeeded;
|
||||
}
|
||||
|
||||
int
|
||||
Cocoa_SetWindowHitTest(SDL_Window * window, SDL_bool enabled)
|
||||
{
|
||||
return 0; /* just succeed, the real work is done elsewhere. */
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_COCOA */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "../../events/SDL_events_c.h"
|
||||
#include "../../events/SDL_touch_c.h"
|
||||
#include "../../events/scancodes_windows.h"
|
||||
#include "SDL_assert.h"
|
||||
|
||||
/* Dropfile support */
|
||||
#include <shellapi.h>
|
||||
|
@ -438,15 +439,20 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
HRAWINPUT hRawInput = (HRAWINPUT)lParam;
|
||||
RAWINPUT inp;
|
||||
UINT size = sizeof(inp);
|
||||
const SDL_bool isRelative = mouse->relative_mode || mouse->relative_mode_warp;
|
||||
const SDL_bool isCapture = ((data->window->flags & SDL_WINDOW_MOUSE_CAPTURE) != 0);
|
||||
|
||||
if (!mouse->relative_mode || mouse->relative_mode_warp || mouse->focus != data->window) {
|
||||
if (!isRelative || mouse->focus != data->window) {
|
||||
if (!isCapture) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
|
||||
|
||||
/* Mouse data */
|
||||
if (inp.header.dwType == RIM_TYPEMOUSE) {
|
||||
if (isRelative) {
|
||||
RAWMOUSE* mouse = &inp.data.mouse;
|
||||
|
||||
if ((mouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) {
|
||||
|
@ -465,6 +471,23 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
initialMousePoint.y = mouse->lLastY;
|
||||
}
|
||||
WIN_CheckRawMouseButtons( mouse->usButtonFlags, data );
|
||||
} else if (isCapture) {
|
||||
/* we check for where Windows thinks the system cursor lives in this case, so we don't really lose mouse accel, etc. */
|
||||
POINT pt;
|
||||
HWND hwnd = data->hwnd;
|
||||
GetCursorPos(&pt);
|
||||
if (WindowFromPoint(pt) != hwnd) { /* if in the window, WM_MOUSEMOVE, etc, will cover it. */
|
||||
ScreenToClient(data->hwnd, &pt);
|
||||
SDL_SendMouseMotion(data->window, 0, 0, (int) pt.x, (int) pt.y);
|
||||
SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_LEFT);
|
||||
SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_RIGHT);
|
||||
SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE);
|
||||
SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1);
|
||||
SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2);
|
||||
}
|
||||
} else {
|
||||
SDL_assert(0 && "Shouldn't happen");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -509,7 +532,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
#ifdef WM_MOUSELEAVE
|
||||
case WM_MOUSELEAVE:
|
||||
if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode) {
|
||||
if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
|
||||
if (!IsIconic(hwnd)) {
|
||||
POINT cursorPos;
|
||||
GetCursorPos(&cursorPos);
|
||||
|
@ -863,6 +886,32 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_NCHITTEST:
|
||||
{
|
||||
SDL_Window *window = data->window;
|
||||
if (window->hit_test) {
|
||||
POINT winpoint = { (int) LOWORD(lParam), (int) HIWORD(lParam) };
|
||||
if (ScreenToClient(data->hwnd, &winpoint)) {
|
||||
const SDL_Point point = { (int) winpoint.x, (int) winpoint.y };
|
||||
const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
|
||||
switch (rc) {
|
||||
case SDL_HITTEST_DRAGGABLE: return HTCAPTION;
|
||||
case SDL_HITTEST_RESIZE_TOPLEFT: return HTTOPLEFT;
|
||||
case SDL_HITTEST_RESIZE_TOP: return HTTOP;
|
||||
case SDL_HITTEST_RESIZE_TOPRIGHT: return HTTOPRIGHT;
|
||||
case SDL_HITTEST_RESIZE_RIGHT: return HTRIGHT;
|
||||
case SDL_HITTEST_RESIZE_BOTTOMRIGHT: return HTBOTTOMRIGHT;
|
||||
case SDL_HITTEST_RESIZE_BOTTOM: return HTBOTTOM;
|
||||
case SDL_HITTEST_RESIZE_BOTTOMLEFT: return HTBOTTOMLEFT;
|
||||
case SDL_HITTEST_RESIZE_LEFT: return HTLEFT;
|
||||
}
|
||||
}
|
||||
/* If we didn't return, this will call DefWindowProc below. */
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/* If there's a window proc, assume it's going to handle messages */
|
||||
|
|
|
@ -30,6 +30,44 @@
|
|||
|
||||
HCURSOR SDL_cursor = NULL;
|
||||
|
||||
static int rawInputEnableCount = 0;
|
||||
|
||||
static int
|
||||
ToggleRawInput(SDL_bool enabled)
|
||||
{
|
||||
RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
|
||||
|
||||
if (enabled) {
|
||||
rawInputEnableCount++;
|
||||
if (rawInputEnableCount > 1) {
|
||||
return 0; /* already done. */
|
||||
}
|
||||
} else {
|
||||
if (rawInputEnableCount == 0) {
|
||||
return 0; /* already done. */
|
||||
}
|
||||
rawInputEnableCount--;
|
||||
if (rawInputEnableCount > 0) {
|
||||
return 0; /* not time to disable yet */
|
||||
}
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
rawMouse.dwFlags |= RIDEV_REMOVE;
|
||||
}
|
||||
|
||||
/* (Un)register raw input for mice */
|
||||
if (RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) {
|
||||
|
||||
/* Only return an error when registering. If we unregister and fail,
|
||||
then it's probably that we unregistered twice. That's OK. */
|
||||
if (enabled) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static SDL_Cursor *
|
||||
WIN_CreateDefaultCursor()
|
||||
|
@ -211,22 +249,43 @@ WIN_WarpMouseGlobal(int x, int y)
|
|||
static int
|
||||
WIN_SetRelativeMouseMode(SDL_bool enabled)
|
||||
{
|
||||
RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
|
||||
|
||||
if (!enabled) {
|
||||
rawMouse.dwFlags |= RIDEV_REMOVE;
|
||||
return ToggleRawInput(enabled);
|
||||
}
|
||||
|
||||
/* (Un)register raw input for mice */
|
||||
if (RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) {
|
||||
static int
|
||||
WIN_CaptureMouse(SDL_Window *window)
|
||||
{
|
||||
if (!window) {
|
||||
SDL_Window *focusWin = SDL_GetKeyboardFocus();
|
||||
if (focusWin) {
|
||||
SDL_WindowData *data = (SDL_WindowData *)focusWin->driverdata;
|
||||
WIN_OnWindowEnter(SDL_GetVideoDevice(), focusWin); /* make sure WM_MOUSELEAVE messages are (re)enabled. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Only return an error when registering. If we unregister and fail,
|
||||
then it's probably that we unregistered twice. That's OK. */
|
||||
if (enabled) {
|
||||
return SDL_Unsupported();
|
||||
/* While we were thinking of SetCapture() when designing this API in SDL,
|
||||
we didn't count on the fact that SetCapture() only tracks while the
|
||||
left mouse button is held down! Instead, we listen for raw mouse input
|
||||
and manually query the mouse when it leaves the window. :/ */
|
||||
return ToggleRawInput(window != NULL);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
static Uint32
|
||||
WIN_GetGlobalMouseState(int *x, int *y)
|
||||
{
|
||||
Uint32 retval = 0;
|
||||
POINT pt = { 0, 0 };
|
||||
GetCursorPos(&pt);
|
||||
*x = (int) pt.x;
|
||||
*y = (int) pt.y;
|
||||
|
||||
retval |= GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_BUTTON_LMASK : 0;
|
||||
retval |= GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_BUTTON_RMASK : 0;
|
||||
retval |= GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_BUTTON_MMASK : 0;
|
||||
retval |= GetAsyncKeyState(VK_X1BUTTON) & 0x8000 ? SDL_BUTTON_X1MASK : 0;
|
||||
retval |= GetAsyncKeyState(VK_X2BUTTON) & 0x8000 ? SDL_BUTTON_X2MASK : 0;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -241,6 +300,8 @@ WIN_InitMouse(_THIS)
|
|||
mouse->WarpMouse = WIN_WarpMouse;
|
||||
mouse->WarpMouseGlobal = WIN_WarpMouseGlobal;
|
||||
mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode;
|
||||
mouse->CaptureMouse = WIN_CaptureMouse;
|
||||
mouse->GetGlobalMouseState = WIN_GetGlobalMouseState;
|
||||
|
||||
SDL_SetDefaultCursor(WIN_CreateDefaultCursor());
|
||||
|
||||
|
@ -256,6 +317,11 @@ WIN_QuitMouse(_THIS)
|
|||
mouse->def_cursor = NULL;
|
||||
mouse->cur_cursor = NULL;
|
||||
}
|
||||
|
||||
if (rawInputEnableCount) { /* force RAWINPUT off here. */
|
||||
rawInputEnableCount = 1;
|
||||
ToggleRawInput(SDL_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
|
||||
|
|
|
@ -144,6 +144,7 @@ WIN_CreateDevice(int devindex)
|
|||
device->UpdateWindowFramebuffer = WIN_UpdateWindowFramebuffer;
|
||||
device->DestroyWindowFramebuffer = WIN_DestroyWindowFramebuffer;
|
||||
device->OnWindowEnter = WIN_OnWindowEnter;
|
||||
device->SetWindowHitTest = WIN_SetWindowHitTest;
|
||||
|
||||
device->shape_driver.CreateShaper = Win32_CreateShaper;
|
||||
device->shape_driver.SetWindowShape = Win32_SetWindowShape;
|
||||
|
|
|
@ -785,6 +785,12 @@ WIN_UpdateClipCursor(SDL_Window *window)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
|
||||
{
|
||||
return 0; /* just succeed, the real work is done elsewhere. */
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -69,6 +69,7 @@ extern SDL_bool WIN_GetWindowWMInfo(_THIS, SDL_Window * window,
|
|||
struct SDL_SysWMinfo *info);
|
||||
extern void WIN_OnWindowEnter(_THIS, SDL_Window * window);
|
||||
extern void WIN_UpdateClipCursor(SDL_Window *window);
|
||||
extern int WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
|
||||
|
||||
#endif /* _SDL_windowswindow_h */
|
||||
|
||||
|
|
|
@ -40,6 +40,42 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef _NET_WM_MOVERESIZE_SIZE_TOPLEFT
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
|
||||
#endif
|
||||
|
||||
#ifndef _NET_WM_MOVERESIZE_SIZE_TOP
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOP 1
|
||||
#endif
|
||||
|
||||
#ifndef _NET_WM_MOVERESIZE_SIZE_TOPRIGHT
|
||||
#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
|
||||
#endif
|
||||
|
||||
#ifndef _NET_WM_MOVERESIZE_SIZE_RIGHT
|
||||
#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
|
||||
#endif
|
||||
|
||||
#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
|
||||
#endif
|
||||
|
||||
#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOM
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
|
||||
#endif
|
||||
|
||||
#ifndef _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
|
||||
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
|
||||
#endif
|
||||
|
||||
#ifndef _NET_WM_MOVERESIZE_SIZE_LEFT
|
||||
#define _NET_WM_MOVERESIZE_SIZE_LEFT 7
|
||||
#endif
|
||||
|
||||
#ifndef _NET_WM_MOVERESIZE_MOVE
|
||||
#define _NET_WM_MOVERESIZE_MOVE 8
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
unsigned char *data;
|
||||
int format, count;
|
||||
|
@ -347,6 +383,124 @@ X11_DispatchUnmapNotify(SDL_WindowData *data)
|
|||
SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
InitiateWindowMove(_THIS, const SDL_WindowData *data, const SDL_Point *point)
|
||||
{
|
||||
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
|
||||
SDL_Window* window = data->window;
|
||||
Display *display = viddata->display;
|
||||
|
||||
/* !!! FIXME: we need to regrab this if necessary when the drag is done. */
|
||||
X11_XUngrabPointer(display, 0L);
|
||||
X11_XFlush(display);
|
||||
|
||||
XEvent evt;
|
||||
evt.xclient.type = ClientMessage;
|
||||
evt.xclient.window = data->xwindow;
|
||||
evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True);
|
||||
evt.xclient.format = 32;
|
||||
evt.xclient.data.l[0] = window->x + point->x;
|
||||
evt.xclient.data.l[1] = window->y + point->y;
|
||||
evt.xclient.data.l[2] = _NET_WM_MOVERESIZE_MOVE;
|
||||
evt.xclient.data.l[3] = Button1;
|
||||
evt.xclient.data.l[4] = 0;
|
||||
X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt);
|
||||
|
||||
X11_XSync(display, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
InitiateWindowResize(_THIS, const SDL_WindowData *data, const SDL_Point *point, int direction)
|
||||
{
|
||||
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
|
||||
SDL_Window* window = data->window;
|
||||
Display *display = viddata->display;
|
||||
|
||||
if (direction < _NET_WM_MOVERESIZE_SIZE_TOPLEFT || direction > _NET_WM_MOVERESIZE_SIZE_LEFT)
|
||||
return;
|
||||
|
||||
/* !!! FIXME: we need to regrab this if necessary when the drag is done. */
|
||||
X11_XUngrabPointer(display, 0L);
|
||||
X11_XFlush(display);
|
||||
|
||||
XEvent evt;
|
||||
evt.xclient.type = ClientMessage;
|
||||
evt.xclient.window = data->xwindow;
|
||||
evt.xclient.message_type = X11_XInternAtom(display, "_NET_WM_MOVERESIZE", True);
|
||||
evt.xclient.format = 32;
|
||||
evt.xclient.data.l[0] = window->x + point->x;
|
||||
evt.xclient.data.l[1] = window->y + point->y;
|
||||
evt.xclient.data.l[2] = direction;
|
||||
evt.xclient.data.l[3] = Button1;
|
||||
evt.xclient.data.l[4] = 0;
|
||||
X11_XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &evt);
|
||||
|
||||
X11_XSync(display, 0);
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev)
|
||||
{
|
||||
SDL_Window *window = data->window;
|
||||
SDL_bool ret = SDL_FALSE;
|
||||
|
||||
if (window->hit_test) {
|
||||
const SDL_Point point = { xev->xbutton.x, xev->xbutton.y };
|
||||
const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
|
||||
switch (rc) {
|
||||
case SDL_HITTEST_DRAGGABLE: {
|
||||
InitiateWindowMove(_this, data, &point);
|
||||
ret = SDL_TRUE;
|
||||
}
|
||||
break;
|
||||
case SDL_HITTEST_RESIZE_TOPLEFT: {
|
||||
InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPLEFT);
|
||||
ret = SDL_TRUE;
|
||||
}
|
||||
break;
|
||||
case SDL_HITTEST_RESIZE_TOP: {
|
||||
InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOP);
|
||||
ret = SDL_TRUE;
|
||||
}
|
||||
break;
|
||||
case SDL_HITTEST_RESIZE_TOPRIGHT: {
|
||||
InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPRIGHT);
|
||||
ret = SDL_TRUE;
|
||||
}
|
||||
break;
|
||||
case SDL_HITTEST_RESIZE_RIGHT: {
|
||||
InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_RIGHT);
|
||||
ret = SDL_TRUE;
|
||||
}
|
||||
break;
|
||||
case SDL_HITTEST_RESIZE_BOTTOMRIGHT: {
|
||||
InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT);
|
||||
ret = SDL_TRUE;
|
||||
}
|
||||
break;
|
||||
case SDL_HITTEST_RESIZE_BOTTOM: {
|
||||
InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOM);
|
||||
ret = SDL_TRUE;
|
||||
}
|
||||
break;
|
||||
case SDL_HITTEST_RESIZE_BOTTOMLEFT: {
|
||||
InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT);
|
||||
ret = SDL_TRUE;
|
||||
}
|
||||
break;
|
||||
case SDL_HITTEST_RESIZE_LEFT: {
|
||||
InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_LEFT);
|
||||
ret = SDL_TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
X11_DispatchEvent(_THIS)
|
||||
{
|
||||
|
@ -820,6 +974,11 @@ X11_DispatchEvent(_THIS)
|
|||
if (X11_IsWheelEvent(display,&xevent,&ticks)) {
|
||||
SDL_SendMouseWheel(data->window, 0, 0, ticks);
|
||||
} else {
|
||||
if(xevent.xbutton.button == Button1) {
|
||||
if (ProcessHitTest(_this, data, &xevent)) {
|
||||
break; /* don't pass this event on to app. */
|
||||
}
|
||||
}
|
||||
SDL_SendMouseButton(data->window, 0, SDL_PRESSED, xevent.xbutton.button);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -339,6 +339,62 @@ X11_SetRelativeMouseMode(SDL_bool enabled)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
X11_CaptureMouse(SDL_Window *window)
|
||||
{
|
||||
Display *display = GetDisplay();
|
||||
|
||||
if (window) {
|
||||
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
|
||||
const unsigned int mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask;
|
||||
const int rc = X11_XGrabPointer(display, data->xwindow, False,
|
||||
mask, GrabModeAsync, GrabModeAsync,
|
||||
None, None, CurrentTime);
|
||||
if (rc != GrabSuccess) {
|
||||
return SDL_SetError("X server refused mouse capture");
|
||||
}
|
||||
} else {
|
||||
X11_XUngrabPointer(display, CurrentTime);
|
||||
}
|
||||
|
||||
X11_XSync(display, False);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint32
|
||||
X11_GetGlobalMouseState(int *x, int *y)
|
||||
{
|
||||
Display *display = GetDisplay();
|
||||
const int num_screens = SDL_GetNumVideoDisplays();
|
||||
int i;
|
||||
|
||||
/* !!! FIXME: should we XSync() here first? */
|
||||
|
||||
for (i = 0; i < num_screens; i++) {
|
||||
SDL_DisplayData *data = (SDL_DisplayData *) SDL_GetDisplayDriverData(i);
|
||||
if (data != NULL) {
|
||||
Window root, child;
|
||||
int rootx, rooty, winx, winy;
|
||||
unsigned int mask;
|
||||
if (X11_XQueryPointer(display, RootWindow(display, data->screen), &root, &child, &rootx, &rooty, &winx, &winy, &mask)) {
|
||||
Uint32 retval = 0;
|
||||
retval |= (mask & Button1Mask) ? SDL_BUTTON_LMASK : 0;
|
||||
retval |= (mask & Button2Mask) ? SDL_BUTTON_MMASK : 0;
|
||||
retval |= (mask & Button3Mask) ? SDL_BUTTON_RMASK : 0;
|
||||
*x = data->x + rootx;
|
||||
*y = data->y + rooty;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_assert(0 && "The pointer wasn't on any X11 screen?!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
X11_InitMouse(_THIS)
|
||||
{
|
||||
|
@ -351,6 +407,8 @@ X11_InitMouse(_THIS)
|
|||
mouse->WarpMouse = X11_WarpMouse;
|
||||
mouse->WarpMouseGlobal = X11_WarpMouseGlobal;
|
||||
mouse->SetRelativeMouseMode = X11_SetRelativeMouseMode;
|
||||
mouse->CaptureMouse = X11_CaptureMouse;
|
||||
mouse->GetGlobalMouseState = X11_GetGlobalMouseState;
|
||||
|
||||
SDL_SetDefaultCursor(X11_CreateDefaultCursor());
|
||||
}
|
||||
|
|
|
@ -243,6 +243,7 @@ X11_CreateDevice(int devindex)
|
|||
device->UpdateWindowFramebuffer = X11_UpdateWindowFramebuffer;
|
||||
device->DestroyWindowFramebuffer = X11_DestroyWindowFramebuffer;
|
||||
device->GetWindowWMInfo = X11_GetWindowWMInfo;
|
||||
device->SetWindowHitTest = X11_SetWindowHitTest;
|
||||
|
||||
device->shape_driver.CreateShaper = X11_CreateShaper;
|
||||
device->shape_driver.SetWindowShape = X11_SetWindowShape;
|
||||
|
|
|
@ -1445,6 +1445,12 @@ X11_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
|
||||
{
|
||||
return 0; /* just succeed, the real work is done elsewhere. */
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_X11 */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -93,6 +93,7 @@ extern void X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed);
|
|||
extern void X11_DestroyWindow(_THIS, SDL_Window * window);
|
||||
extern SDL_bool X11_GetWindowWMInfo(_THIS, SDL_Window * window,
|
||||
struct SDL_SysWMinfo *info);
|
||||
extern int X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
|
||||
|
||||
#endif /* _SDL_x11window_h */
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ TARGETS = \
|
|||
testgles$(EXE) \
|
||||
testgles2$(EXE) \
|
||||
testhaptic$(EXE) \
|
||||
testhittesting$(EXE) \
|
||||
testrumble$(EXE) \
|
||||
testhotplug$(EXE) \
|
||||
testthread$(EXE) \
|
||||
|
@ -108,6 +109,9 @@ testintersections$(EXE): $(srcdir)/testintersections.c
|
|||
testrelative$(EXE): $(srcdir)/testrelative.c
|
||||
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
||||
|
||||
testhittesting$(EXE): $(srcdir)/testhittesting.c
|
||||
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
||||
|
||||
testdraw2$(EXE): $(srcdir)/testdraw2.c
|
||||
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
||||
|
||||
|
|
134
test/testhittesting.c
Normal file
134
test/testhittesting.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
#include <stdio.h>
|
||||
#include "SDL.h"
|
||||
|
||||
/* !!! FIXME: rewrite this to be wired in to test framework. */
|
||||
|
||||
#define RESIZE_BORDER 20
|
||||
|
||||
const SDL_Rect drag_areas[] = {
|
||||
{ 20, 20, 100, 100 },
|
||||
{ 200, 70, 100, 100 },
|
||||
{ 400, 90, 100, 100 }
|
||||
};
|
||||
|
||||
static const SDL_Rect *areas = drag_areas;
|
||||
static int numareas = SDL_arraysize(drag_areas);
|
||||
|
||||
static SDL_HitTestResult
|
||||
hitTest(SDL_Window *window, const SDL_Point *pt, void *data)
|
||||
{
|
||||
int i;
|
||||
int w, h;
|
||||
|
||||
for (i = 0; i < numareas; i++) {
|
||||
if (SDL_PointInRect(pt, &areas[i])) {
|
||||
SDL_Log("HIT-TEST: DRAGGABLE\n");
|
||||
return SDL_HITTEST_DRAGGABLE;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
|
||||
#define REPORT_RESIZE_HIT(name) { \
|
||||
SDL_Log("HIT-TEST: RESIZE_" #name "\n"); \
|
||||
return SDL_HITTEST_RESIZE_##name; \
|
||||
}
|
||||
|
||||
if (pt->x < RESIZE_BORDER && pt->y < RESIZE_BORDER) {
|
||||
REPORT_RESIZE_HIT(TOPLEFT);
|
||||
} else if (pt->x > RESIZE_BORDER && pt->x < w - RESIZE_BORDER && pt->y < RESIZE_BORDER) {
|
||||
REPORT_RESIZE_HIT(TOP);
|
||||
} else if (pt->x > w - RESIZE_BORDER && pt->y < RESIZE_BORDER) {
|
||||
REPORT_RESIZE_HIT(TOPRIGHT);
|
||||
} else if (pt->x > w - RESIZE_BORDER && pt->y > RESIZE_BORDER && pt->y < h - RESIZE_BORDER) {
|
||||
REPORT_RESIZE_HIT(RIGHT);
|
||||
} else if (pt->x > w - RESIZE_BORDER && pt->y > h - RESIZE_BORDER) {
|
||||
REPORT_RESIZE_HIT(BOTTOMRIGHT);
|
||||
} else if (pt->x < w - RESIZE_BORDER && pt->x > RESIZE_BORDER && pt->y > h - RESIZE_BORDER) {
|
||||
REPORT_RESIZE_HIT(BOTTOM);
|
||||
} else if (pt->x < RESIZE_BORDER && pt->y > h - RESIZE_BORDER) {
|
||||
REPORT_RESIZE_HIT(BOTTOMLEFT);
|
||||
} else if (pt->x < RESIZE_BORDER && pt->y < h - RESIZE_BORDER && pt->y > RESIZE_BORDER) {
|
||||
REPORT_RESIZE_HIT(LEFT);
|
||||
}
|
||||
|
||||
SDL_Log("HIT-TEST: NORMAL\n");
|
||||
return SDL_HITTEST_NORMAL;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int done = 0;
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
|
||||
/* !!! FIXME: check for errors. */
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
window = SDL_CreateWindow("Drag the red boxes", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE);
|
||||
renderer = SDL_CreateRenderer(window, -1, 0);
|
||||
|
||||
if (SDL_SetWindowHitTest(window, hitTest, NULL) == -1) {
|
||||
SDL_Log("Enabling hit-testing failed!\n");
|
||||
SDL_Quit();
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (!done)
|
||||
{
|
||||
SDL_Event e;
|
||||
int nothing_to_do = 1;
|
||||
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 127, 255);
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
|
||||
SDL_RenderFillRects(renderer, areas, SDL_arraysize(drag_areas));
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
while (SDL_PollEvent(&e)) {
|
||||
nothing_to_do = 0;
|
||||
|
||||
switch (e.type)
|
||||
{
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
SDL_Log("button down!\n");
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
SDL_Log("button up!\n");
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT:
|
||||
if (e.window.event == SDL_WINDOWEVENT_MOVED) {
|
||||
SDL_Log("Window event moved to (%d, %d)!\n", (int) e.window.data1, (int) e.window.data2);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_KEYDOWN:
|
||||
if (e.key.keysym.sym == SDLK_ESCAPE) {
|
||||
done = 1;
|
||||
} else if (e.key.keysym.sym == SDLK_x) {
|
||||
if (!areas) {
|
||||
areas = drag_areas;
|
||||
numareas = SDL_arraysize(drag_areas);
|
||||
} else {
|
||||
areas = NULL;
|
||||
numareas = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nothing_to_do) {
|
||||
SDL_Delay(50);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Quit();
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue