Index: Source/win32/WIN32Server.m =================================================================== --- Source/win32/WIN32Server.m (revisiĆ³n: 38408) +++ Source/win32/WIN32Server.m (copia de trabajo) @@ -49,6 +49,7 @@ #include #include #include +#include #include "win32/WIN32Server.h" #include "win32/WIN32Geometry.h" @@ -62,6 +63,12 @@ #include +// 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]; + } +}