Improvements to handle the cursor on MS Windows.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@38429 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Germán Arias 2015-03-23 19:32:36 +00:00
parent 042f6f3761
commit 925b52e02e
2 changed files with 180 additions and 6 deletions

View file

@ -1,3 +1,14 @@
2015-03-23 Germán Arias <germanandre@gmx.es>
* Source/win32/WIN32Server.m (-windowEventProc:, -process_mouse_event:):
Add code to handle the case when the mouse leave the window, move over
a nonclient area, update the cursor or when the user open a
contextual menu. Also handle the first mouse movement inside the
window and save the cursor if we should preserve it between different
windows. Sometimes there is a problem with the cursor if the user
open a contextual menu after resize the window. But this seems
other issue.
2015-03-22 Fred Kiefer <FredKiefer@gmx.de> 2015-03-22 Fred Kiefer <FredKiefer@gmx.de>
* Source/x11/XGServerEvent.m (-processEvent:): Reenable Richard's * Source/x11/XGServerEvent.m (-processEvent:): Reenable Richard's

View file

@ -49,6 +49,7 @@
#include <AppKit/NSTextField.h> #include <AppKit/NSTextField.h>
#include <AppKit/DPSOperators.h> #include <AppKit/DPSOperators.h>
#include <GNUstepGUI/GSTheme.h> #include <GNUstepGUI/GSTheme.h>
#include <GNUstepGUI/GSTrackingRect.h>
#include "win32/WIN32Server.h" #include "win32/WIN32Server.h"
#include "win32/WIN32Geometry.h" #include "win32/WIN32Geometry.h"
@ -62,6 +63,12 @@
#include <math.h> #include <math.h>
// To update the cursor..
static BOOL update_cursor = NO;
static BOOL should_handle_cursor = NO;
static NSCursor *current_cursor = nil;
// Forward declarations... // Forward declarations...
static unsigned int mask_for_keystate(BYTE *keyState); static unsigned int mask_for_keystate(BYTE *keyState);
@ -1139,6 +1146,27 @@ LRESULT CALLBACK windowEnumCallback(HWND hwnd, LPARAM lParam)
switch (uMsg) switch (uMsg)
{ {
case WM_MOUSELEAVE:
{
/* If the cursor leave the window remove the GNUstep cursors, send
* the appropriate message and tell GNUstep stop handling
* the cursor.
*/
NSEvent *e;
[GSWindowWithNumber((int)hwnd) resetCursorRects];
e = [NSEvent otherEventWithType: NSAppKitDefined
location: NSMakePoint(-1,-1)
modifierFlags: 0
timestamp: 0
windowNumber: (int)hwnd
context: GSCurrentContext()
subtype: GSAppKitWindowLeave
data1: 0
data2: 0];
[GSCurrentServer() postEvent: e atStart: YES];
should_handle_cursor = NO;
}
break;
case WM_SIZING: case WM_SIZING:
return [self decodeWM_SIZINGParams: hwnd : wParam : lParam]; return [self decodeWM_SIZINGParams: hwnd : wParam : lParam];
break; break;
@ -1212,6 +1240,14 @@ LRESULT CALLBACK windowEnumCallback(HWND hwnd, LPARAM lParam)
[self decodeWM_KILLFOCUSParams: wParam : lParam : hwnd]; [self decodeWM_KILLFOCUSParams: wParam : lParam : hwnd];
break; break;
case WM_SETCURSOR: case WM_SETCURSOR:
if (wParam == (int)hwnd)
{
// Check if GNUstep should handle the cursor.
if (should_handle_cursor)
{
flags._eventHandled = YES;
}
}
break; break;
case WM_QUERYOPEN: case WM_QUERYOPEN:
[self decodeWM_QUERYOPENParams: wParam : lParam : hwnd]; [self decodeWM_QUERYOPENParams: wParam : lParam : hwnd];
@ -1242,7 +1278,27 @@ LRESULT CALLBACK windowEnumCallback(HWND hwnd, LPARAM lParam)
case WM_APP: case WM_APP:
break; break;
case WM_ENTERMENULOOP: case WM_ENTERMENULOOP:
break; /* If the user open a native contextual menu (a non GNUstep window)
* send the appropriate message and tell GNUstep stop handling
* the cursor.
*/
if (wParam)
{
NSEvent *e;
[GSWindowWithNumber((int)hwnd) resetCursorRects];
e = [NSEvent otherEventWithType: NSAppKitDefined
location: NSMakePoint(-1,-1)
modifierFlags: 0
timestamp: 0
windowNumber: (int)hwnd
context: GSCurrentContext()
subtype: GSAppKitWindowLeave
data1: 0
data2: 0];
[GSCurrentServer() postEvent: e atStart: YES];
should_handle_cursor = NO;
}
break;
case WM_EXITMENULOOP: case WM_EXITMENULOOP:
break; break;
case WM_INITMENU: case WM_INITMENU:
@ -1288,8 +1344,12 @@ LRESULT CALLBACK windowEnumCallback(HWND hwnd, LPARAM lParam)
NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCHITTEST", hwnd); NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCHITTEST", hwnd);
break; break;
case WM_NCMOUSEMOVE: //MOUSE case WM_NCMOUSEMOVE: //MOUSE
NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCMOUSEMOVE", hwnd); /* If the user move the mouse over a nonclient area, tell GNUstep
break; * that should stop handle the cursor.
*/
NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCMOUSEMOVE", hwnd);
should_handle_cursor = NO;
break;
case WM_NCLBUTTONDOWN: //MOUSE case WM_NCLBUTTONDOWN: //MOUSE
NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCLBUTTONDOWN", hwnd); NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCLBUTTONDOWN", hwnd);
break; break;
@ -2713,6 +2773,109 @@ process_mouse_event(WIN32Server *svr, HWND hwnd, WPARAM wParam, LPARAM lParam,
} }
// What about other modifiers? // What about other modifiers?
/* Currently GNUstep only proccess events inside the windows (contentview).
* So we should check if this is the first movement inside the window.
* And should consider also the case when this is the last movement inside
* the window.
*/
if (!should_handle_cursor)
{
/* If this is the first movement inside the window, tell GNUstep
* that should handle the cursor and that should check if the
* cursor needs be updated.
*/
should_handle_cursor = YES;
update_cursor = YES;
/* If there are a previous cursor available (maybe a cursor that
* represent a tool) set it as the cursor. If not, set an arrow
* cursor (this is necessary because if the cursor is updated to,
* for example, an I Beam cursor, there will not be a default cursor
* to display when the user moves the mouse over, for example, an
* scrollbar).
*/
if (current_cursor != nil)
{
[current_cursor set];
current_cursor = nil;
}
else
{
[[NSCursor arrowCursor] set];
}
}
else
{
/* If the cursor is not associated to a tracking rectangle, not in
* the push/pop stack, save this. We do this for the case when, for
* example, the user choose a tool in a Tools window which sets a
* cursor for the tool and this cursor should be preserved between
* different windows.
*/
if ([NSCursor count] == 0 &&
![current_cursor isEqual: [NSCursor currentCursor]])
{
ASSIGN(current_cursor, [NSCursor currentCursor]);
}
}
// Check if we need update the cursor.
if (update_cursor)
{
NSView *subview = nil;
NSWindow *gswin = GSWindowWithNumber((int)hwnd);
subview = [[gswin contentView] hitTest: eventLocation];
if (subview != nil && subview->_rFlags.valid_rects)
{
NSArray *tr = subview->_cursor_rects;
NSUInteger count = [tr count];
// Loop through cursor rectangles
if (count > 0)
{
GSTrackingRect *rects[count];
NSUInteger i;
[tr getObjects: rects];
for (i = 0; i < count; ++i)
{
GSTrackingRect *r = rects[i];
BOOL now;
if ([r isValid] == NO)
continue;
/*
* Check for presence of point in rectangle.
*/
now = NSMouseInRect(eventLocation, r->rectangle, NO);
// Mouse inside
if (now)
{
NSEvent *e;
e = [NSEvent enterExitEventWithType: NSCursorUpdate
location: eventLocation
modifierFlags: eventFlags
timestamp: 0
windowNumber: (int)hwnd
context: gcontext
eventNumber: 0
trackingNumber: (int)YES
userData: (void*)r];
[GSCurrentServer() postEvent: e atStart: YES];
//NSLog(@"Add enter event %@ for view %@ rect %@", e, theView, NSStringFromRect(r->rectangle));
}
}
}
}
update_cursor = NO;
}
if (eventType == NSScrollWheel) if (eventType == NSScrollWheel)
{ {
float delta = GET_WHEEL_DELTA_WPARAM(wParam) / 120.0; float delta = GET_WHEEL_DELTA_WPARAM(wParam) / 120.0;