Difference between revisions of "Cocoa Internals/Application"

From Free Pascal wiki
Jump to navigationJump to search
Line 29: Line 29:
 
With a manual event loop implementation, there's another problem showed up.
 
With a manual event loop implementation, there's another problem showed up.
  
NSWindows are behaving differently depending if NSApplication has started or not. (running property).
+
NSWindows are behaving differently depending if NSApplication has started or not. (running property returning TRUE or FALSE).
  
 
If NSApplication is not running, then NSWindows would not pass the focus to another Window with the application. Instead they would keep the focus (while hidden) or make NO window a focused window (if closed). (see [https://bugs.freepascal.org/view.php?id=32177 #32177])
 
If NSApplication is not running, then NSWindows would not pass the focus to another Window with the application. Instead they would keep the focus (while hidden) or make NO window a focused window (if closed). (see [https://bugs.freepascal.org/view.php?id=32177 #32177])

Revision as of 04:04, 31 December 2017

Cocoa's Application API pretty much matches what LCL provides. It could be possible to simply call NSApp apis, that correspond to LCL APIs. However, there's a major difference, that makes a simple solution not possible. LCL Application provides a methods HandleMessages and ProcessMessagess allowing a manual control over the event-loop.

NSApp doesn't provide any corresponding counter parts, thus it's necessary to process events loops manually.

Manual Event Loop

Cocoa Widgetset implements even loops manually. Apple documentation advises that it's possible, though could be complicated.

The actual event processing code could be found at AppWaitMessage and AppProcessMessage.

procedure TCocoaWidgetSet.AppWaitMessage;
var
  event : NSEvent;
  pool:NSAutoReleasePool;
begin
  pool := NSAutoreleasePool.alloc.init;
  event := NSApp.nextEventMatchingMask_untilDate_inMode_dequeue(NSAnyEventMask, NSDate.distantFuture, NSDefaultRunLoopMode, true);
  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.updateWindows;
  end;
  pool.release;
end;

Sub-classing NSApplication

With a manual event loop implementation, there's another problem showed up.

NSWindows are behaving differently depending if NSApplication has started or not. (running property returning TRUE or FALSE).

If NSApplication is not running, then NSWindows would not pass the focus to another Window with the application. Instead they would keep the focus (while hidden) or make NO window a focused window (if closed). (see #32177)

There are two options to make NSApplication running flag to set to true:

  • use NSApp default run method (which could not be used, due to the need of manual event processing)
  • subclass NSApplication, reimplement "isRunning" (getter of "running" property) and possible "run" method.

The sub-classing option is used, introducing TCocoaApplication class. It overrides two methods:

  • run - the code is actually LCL Loop procedure, which would process ObjC events loop manually
  • isRunning - returns true, if run method was actually called.

See Also