Attached the patch to solve the cursors issues on Windows. The backend
only process the events inside the windows, so we should take cares when
the mouse leave/enter the window. As far as I can see, this patch solves
all the problems with the cursor. Let me know if you are agree with
these changes.

Germán

Index: Source/win32/WIN32Server.m
===================================================================
--- Source/win32/WIN32Server.m	(revisión: 38408)
+++ Source/win32/WIN32Server.m	(copia de trabajo)
@@ -49,6 +49,7 @@
 #include <AppKit/NSTextField.h>
 #include <AppKit/DPSOperators.h>
 #include <GNUstepGUI/GSTheme.h>
+#include <GNUstepGUI/GSTrackingRect.h>
 
 #include "win32/WIN32Server.h"
 #include "win32/WIN32Geometry.h"
@@ -62,6 +63,12 @@
 
 #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...
 static unsigned int mask_for_keystate(BYTE *keyState);
 
@@ -135,6 +142,8 @@
 LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, 
                              WPARAM wParam, LPARAM lParam);
 
+static void remove_cursors();
+
 BOOL CALLBACK LoadDisplayMonitorInfo(HMONITOR hMonitor,
                                     HDC hdcMonitor,
                                     LPRECT lprcMonitor,
@@ -1139,6 +1148,15 @@
  
   switch (uMsg)
     {
+      case WM_MOUSELEAVE:
+	{
+	  /* If the cursor leave the window remove the GNUstep cursors and
+	   * tell GNUstep that should stop handle the cursor.
+	   */
+	  remove_cursors();
+	  should_handle_cursor = NO;
+	}
+	break;
       case WM_SIZING:
         return [self decodeWM_SIZINGParams: hwnd : wParam : lParam];
         break;
@@ -1211,7 +1229,15 @@
         else
           [self decodeWM_KILLFOCUSParams: wParam : lParam : hwnd]; 
         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;
       case WM_QUERYOPEN: 
         [self decodeWM_QUERYOPENParams: wParam : lParam : hwnd]; 
@@ -1241,10 +1267,20 @@
         break;
       case WM_APP: 
         break;  
-      case WM_ENTERMENULOOP: 
+      case WM_ENTERMENULOOP:
+	/* If the user open a native menu remove the GNUstep cursors and
+	 * set an arrow cursor.
+	 */
+	remove_cursors();
+	[[NSCursor arrowCursor] set];
+	break;
+      case WM_EXITMENULOOP:
+	/* Allow GNUstep handle the cursor and check if the cursor
+	 * should be updated.
+	 */
+	update_cursor = YES;
+	should_handle_cursor = YES;
         break;
-      case WM_EXITMENULOOP: 
-        break;
       case WM_INITMENU: 
         break;
       case WM_MENUSELECT: 
@@ -1288,8 +1324,15 @@
         NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCHITTEST", hwnd);
         break;
       case WM_NCMOUSEMOVE: //MOUSE
-        NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCMOUSEMOVE", hwnd);
-        break;
+	/* If the user move the mouse over a nonclient area, remove the
+	 * GNUstep cursors and tell GNUstep that should stop handle the
+	 * cursor. This could seems redundant, since we do this
+	 * on WM_MOUSELEAVE, but ensures a correct behaviour.
+	 */
+	NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCMOUSEMOVE", hwnd);
+	remove_cursors();
+	should_handle_cursor = NO;
+	break;
       case WM_NCLBUTTONDOWN:  //MOUSE
         NSDebugLLog(@"NSEvent", @"Got Message %s for %d", "NCLBUTTONDOWN", hwnd);
         break;
@@ -2713,6 +2756,109 @@
     }
   // 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)
     {
       float delta = GET_WHEEL_DELTA_WPARAM(wParam) / 120.0;
@@ -2888,3 +3034,11 @@
   return [ctxt windowEventProc: hwnd : uMsg : wParam : lParam];
 }
 
+// This function just removes the cursors at push/pop stack.
+static void remove_cursors () {
+  int x;
+  for (x = 0; x < [NSCursor count]; x++)
+    {
+      [[NSCursor currentCursor] pop];
+    }
+}
_______________________________________________
Gnustep-dev mailing list
Gnustep-dev@gnu.org
https://lists.gnu.org/mailman/listinfo/gnustep-dev

Reply via email to