View Issue Details

IDProjectCategoryView StatusLast Update
0035547LazarusWidgetsetpublic2019-05-12 03:16
ReporterDavid JenkinsAssigned ToDmitry Boyarintsev 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product Version2.0.3 (SVN)Product Build 
Target VersionFixed in Version 
Summary0035547: Cocoa combo box drop down resets when background tasks running and mouse tracking prevents syncing
DescriptionIf background tasks are running, combobox dropdowns will not stay down but close back up. If the dropdown is forced to stay down then the additional problem of mouse tracking loops preventing background syncing is exhibited.
Steps To ReproduceRun background thread that synchronized to foreground such that TCocoaWidgetSet.SendCheckSynchronizeMessage() is periodically called (Application.QueueAsyncCall from background thread will do this). Then try to open a combobox.

Attached example project mouseback.zip does this.
Additional InformationThe problem is that NSComboBoxCell.popup calls NSComboBoxCell.filterEvent which calls NSApplication.nextEventMatchingMask:untilDate:inMode:dequeue() to watch for keyboard/mouse/gesture events to indicate that editing/selection in the combobox has finished and the dropdown should close.

The NSApplicationDefined event that is sent off by TCocoaWidgetSet.SendCheckSynchronizeMessage() is caught and interpreted as a editing done event and the dropdown is closed.

Since nextEventMatchingMask is already overridden in CocoaInt, the offending message can be caught there (move the code up from TCocoaWidgetSet.AppWaitMessage and TCocoaWidgetSet.AppProcessMessages) and then return Result = nil.

This fixes the problem with the drop down but it then exposes the problem that background syncing does not work during the mouse tracking loop (see lcl/interfaces/carbon/carbonobject.EventTimerCallback). The NSComboBoxCell.filterEvent() keeps looping on nextEventMatchingMask waiting for input to close the dropdown and Applicaiton.ProcessAsyncCallQueue is never called.

Suggested fix is to add call to Application.ProcessAsynCallQueue to TCocoaApplication.nextEventMatchingMask_untilDate_inMode_dequeue(). This is done in the same spot where the NSApplicationDefined event is caught and CheckSynchronize is called (moved here in above step).

A patch is attached.
TagsNo tags attached.
Fixed in Revision61207
LazTarget-
WidgetsetCocoa
Attached Files
  • MouseBackground.zip (4,084 bytes)
  • MouseBack.patch (3,002 bytes)
    Index: Lazarus/laz-src/lcl/interfaces/cocoa/cocoaint.pas
    ===================================================================
    --- Lazarus/laz-src/lcl/interfaces/cocoa/cocoaint.pas	(revision 23905)
    +++ Lazarus/laz-src/lcl/interfaces/cocoa/cocoaint.pas	(revision 23907)
    @@ -474,6 +474,9 @@
         or (tp = NSOtherMouseDragged);
     end;
     
    +type
    +  TCrackerApplication = class(TApplication);
    +
     function TCocoaApplication.nextEventMatchingMask_untilDate_inMode_dequeue(
       mask: NSUInteger; expiration: NSDate; mode: NSString; deqFlag: LCLObjCBoolean
       ): NSEvent;
    @@ -487,22 +490,35 @@
       Result:=inherited nextEventMatchingMask_untilDate_inMode_dequeue(mask,
         expiration, mode, deqFlag);
       {$endif}
    -  if Assigned(Result)
    -    and ((mode = NSEventTrackingRunLoopMode) or mode.isEqualToString(NSEventTrackingRunLoopMode))
    -    and Assigned(TrackedControl)
    -  then
    +  if Assigned(Result) then
       begin
    -    if Result.type_ = NSLeftMouseUp then
    +    if (Result.type_ = NSApplicationDefined)
    +      and (Result.subtype = LCLEventSubTypeMessage)
    +      and (Result.data1 = LM_NULL)
    +      and (Result.data2 = WidgetSet.AppHandle)
    +    then
         begin
    -      //todo: send callback!
    -      TrackedControl := nil;
    +      CheckSynchronize;
    +      NSApp.updateWindows;
    +      TCrackerApplication(Application).ProcessAsyncCallQueue;
    +      Result := nil
         end
    -    else
    -    if isMouseMoveEvent(Result.type_) then
    +    else if ((mode = NSEventTrackingRunLoopMode) or mode.isEqualToString(NSEventTrackingRunLoopMode))
    +      and Assigned(TrackedControl)
    +    then
         begin
    -      cb := TrackedControl.lclGetCallback;
    -      if Assigned(cb) then cb.MouseMove(Result);
    -    end;
    +      if Result.type_ = NSLeftMouseUp then
    +      begin
    +        //todo: send callback!
    +        TrackedControl := nil;
    +      end
    +      else
    +      if isMouseMoveEvent(Result.type_) then
    +      begin
    +        cb := TrackedControl.lclGetCallback;
    +        if Assigned(cb) then cb.MouseMove(Result);
    +      end
    +     end;
       end;
     
     end;
    Index: Lazarus/laz-src/lcl/interfaces/cocoa/cocoaobject.inc
    ===================================================================
    --- Lazarus/laz-src/lcl/interfaces/cocoa/cocoaobject.inc	(revision 23905)
    +++ Lazarus/laz-src/lcl/interfaces/cocoa/cocoaobject.inc	(revision 23907)
    @@ -108,10 +108,7 @@
         {$endif}
         if event <> nil then
         begin
    -      if (event.type_ = NSApplicationDefined) and (event.subtype = LCLEventSubTypeMessage) and (event.data1 = LM_NULL) and (event.data2 = AppHandle) then
    -        CheckSynchronize
    -      else
    -        NSApp.sendEvent(event);
    +      NSApp.sendEvent(event);
           NSApp.updateWindows;
         end;
     
    @@ -140,10 +137,7 @@
       {$endif}
       if event <> nil then
       begin
    -    if (event.type_ = NSApplicationDefined) and (event.subtype = LCLEventSubTypeMessage) and (event.data1 = LM_NULL) and (event.data2 = AppHandle) then
    -      CheckSynchronize
    -    else
    -      NSApp.sendEvent(event);
    +    NSApp.sendEvent(event);
         NSApp.updateWindows;
       end;
     
    
    MouseBack.patch (3,002 bytes)

Activities

David Jenkins

2019-05-08 23:21

reporter  

MouseBackground.zip (4,084 bytes)
MouseBack.patch (3,002 bytes)
Index: Lazarus/laz-src/lcl/interfaces/cocoa/cocoaint.pas
===================================================================
--- Lazarus/laz-src/lcl/interfaces/cocoa/cocoaint.pas	(revision 23905)
+++ Lazarus/laz-src/lcl/interfaces/cocoa/cocoaint.pas	(revision 23907)
@@ -474,6 +474,9 @@
     or (tp = NSOtherMouseDragged);
 end;
 
+type
+  TCrackerApplication = class(TApplication);
+
 function TCocoaApplication.nextEventMatchingMask_untilDate_inMode_dequeue(
   mask: NSUInteger; expiration: NSDate; mode: NSString; deqFlag: LCLObjCBoolean
   ): NSEvent;
@@ -487,22 +490,35 @@
   Result:=inherited nextEventMatchingMask_untilDate_inMode_dequeue(mask,
     expiration, mode, deqFlag);
   {$endif}
-  if Assigned(Result)
-    and ((mode = NSEventTrackingRunLoopMode) or mode.isEqualToString(NSEventTrackingRunLoopMode))
-    and Assigned(TrackedControl)
-  then
+  if Assigned(Result) then
   begin
-    if Result.type_ = NSLeftMouseUp then
+    if (Result.type_ = NSApplicationDefined)
+      and (Result.subtype = LCLEventSubTypeMessage)
+      and (Result.data1 = LM_NULL)
+      and (Result.data2 = WidgetSet.AppHandle)
+    then
     begin
-      //todo: send callback!
-      TrackedControl := nil;
+      CheckSynchronize;
+      NSApp.updateWindows;
+      TCrackerApplication(Application).ProcessAsyncCallQueue;
+      Result := nil
     end
-    else
-    if isMouseMoveEvent(Result.type_) then
+    else if ((mode = NSEventTrackingRunLoopMode) or mode.isEqualToString(NSEventTrackingRunLoopMode))
+      and Assigned(TrackedControl)
+    then
     begin
-      cb := TrackedControl.lclGetCallback;
-      if Assigned(cb) then cb.MouseMove(Result);
-    end;
+      if Result.type_ = NSLeftMouseUp then
+      begin
+        //todo: send callback!
+        TrackedControl := nil;
+      end
+      else
+      if isMouseMoveEvent(Result.type_) then
+      begin
+        cb := TrackedControl.lclGetCallback;
+        if Assigned(cb) then cb.MouseMove(Result);
+      end
+     end;
   end;
 
 end;
Index: Lazarus/laz-src/lcl/interfaces/cocoa/cocoaobject.inc
===================================================================
--- Lazarus/laz-src/lcl/interfaces/cocoa/cocoaobject.inc	(revision 23905)
+++ Lazarus/laz-src/lcl/interfaces/cocoa/cocoaobject.inc	(revision 23907)
@@ -108,10 +108,7 @@
     {$endif}
     if event <> nil then
     begin
-      if (event.type_ = NSApplicationDefined) and (event.subtype = LCLEventSubTypeMessage) and (event.data1 = LM_NULL) and (event.data2 = AppHandle) then
-        CheckSynchronize
-      else
-        NSApp.sendEvent(event);
+      NSApp.sendEvent(event);
       NSApp.updateWindows;
     end;
 
@@ -140,10 +137,7 @@
   {$endif}
   if event <> nil then
   begin
-    if (event.type_ = NSApplicationDefined) and (event.subtype = LCLEventSubTypeMessage) and (event.data1 = LM_NULL) and (event.data2 = AppHandle) then
-      CheckSynchronize
-    else
-      NSApp.sendEvent(event);
+    NSApp.sendEvent(event);
     NSApp.updateWindows;
   end;
 
MouseBack.patch (3,002 bytes)

Dmitry Boyarintsev

2019-05-12 03:16

developer   ~0116140

thanks for the patch applied.
please test and close if ok

Issue History

Date Modified Username Field Change
2019-05-08 23:21 David Jenkins New Issue
2019-05-08 23:21 David Jenkins File Added: MouseBackground.zip
2019-05-08 23:21 David Jenkins File Added: MouseBack.patch
2019-05-12 03:16 Dmitry Boyarintsev Assigned To => Dmitry Boyarintsev
2019-05-12 03:16 Dmitry Boyarintsev Status new => resolved
2019-05-12 03:16 Dmitry Boyarintsev Resolution open => fixed
2019-05-12 03:16 Dmitry Boyarintsev Fixed in Revision => 61207
2019-05-12 03:16 Dmitry Boyarintsev LazTarget => -
2019-05-12 03:16 Dmitry Boyarintsev Widgetset Cocoa => Cocoa
2019-05-12 03:16 Dmitry Boyarintsev Note Added: 0116140