14 #include <Cocoa/Cocoa.h>
31 #ifdef MAC_OS_X_VERSION_10_12
32 const NSUInteger kEventMaskAny = NSEventMaskAny;
33 const NSEventType kApplicationDefined = NSEventTypeApplicationDefined;
35 const NSUInteger kEventMaskAny = NSAnyEventMask;
36 const NSEventType kApplicationDefined = NSApplicationDefined;
44 @interface RunStopper : NSObject
47 @implementation RunStopper
63 NSEvent* stopEvent = [NSEvent otherEventWithType : ROOT::MacOSX::Details::kApplicationDefined
64 location : NSMakePoint(0., 0.) modifierFlags : 0 timestamp : 0.
65 windowNumber : 0 context : nil subtype: 0 data1 : 0 data2 : 0];
66 [NSApp postEvent : stopEvent atStart : true];
79 # define HOWMANY(x, y) (((x)+((y)-1))/(y))
82 const Int_t kNFDBITS = (
sizeof(Long_t) * 8);
84 const Int_t kFDSETSIZE = FD_SETSIZE;
86 const Int_t kFDSETSIZE = 256;
92 ULong_t fds_bits[HOWMANY(kFDSETSIZE, kNFDBITS)];
94 TFdSet() { memset(fds_bits, 0,
sizeof(fds_bits)); }
95 TFdSet(
const TFdSet &org) { memcpy(fds_bits, org.fds_bits,
sizeof(org.fds_bits)); }
96 TFdSet &operator=(
const TFdSet &rhs)
99 memcpy(fds_bits, rhs.fds_bits,
sizeof(rhs.fds_bits));
103 void Zero() { memset(fds_bits, 0,
sizeof(fds_bits)); }
106 if (n >= 0 && n < kFDSETSIZE) {
107 fds_bits[n/kNFDBITS] |= (1UL << (n % kNFDBITS));
109 ::Fatal(
"TFdSet::Set",
"fd (%d) out of range [0..%d]", n, kFDSETSIZE-1);
114 if (n >= 0 && n < kFDSETSIZE) {
115 fds_bits[n/kNFDBITS] &= ~(1UL << (n % kNFDBITS));
117 ::Fatal(
"TFdSet::Clr",
"fd (%d) out of range [0..%d]", n, kFDSETSIZE-1);
122 if (n >= 0 && n < kFDSETSIZE) {
123 return (fds_bits[n/kNFDBITS] & (1UL << (n % kNFDBITS))) != 0;
125 ::Fatal(
"TFdSet::IsSet",
"fd (%d) out of range [0..%d]", n, kFDSETSIZE-1);
129 ULong_t *GetBits() {
return (ULong_t *)fds_bits; }
141 void InitializeCocoa();
143 bool SetFileDescriptors(
const TSeqCollection *fileHandlers);
144 void UnregisterFileDescriptor(CFFileDescriptorRef fd);
145 void CloseFileDescriptors();
147 enum DescriptorType {
153 void SetFileDescriptor(
int fd, DescriptorType fdType);
155 std::set<CFFileDescriptorRef> fCFFileDescriptors;
157 ROOT::MacOSX::Util::AutoreleasePool fPool;
158 bool fCocoaInitialized;
160 static MacOSXSystem *fgInstance;
163 MacOSXSystem *MacOSXSystem::fgInstance = 0;
168 void TMacOSXSystem_ReadCallback(CFFileDescriptorRef fdref, CFOptionFlags ,
void * )
171 const int nativeFD = CFFileDescriptorGetNativeDescriptor(fdref);
174 assert(MacOSXSystem::fgInstance != 0 &&
"TMacOSXSystem_ReadCallback, MacOSXSystem's singleton is null");
175 MacOSXSystem::fgInstance->UnregisterFileDescriptor(fdref);
177 CFFileDescriptorInvalidate(fdref);
180 NSEvent *fdEvent = [NSEvent otherEventWithType : kApplicationDefined
181 location : NSMakePoint(0, 0) modifierFlags : 0
182 timestamp: 0. windowNumber : 0 context : nil
183 subtype : 0 data1 : nativeFD data2 : 0];
184 [NSApp postEvent : fdEvent atStart : NO];
188 void TMacOSXSystem_WriteCallback(CFFileDescriptorRef fdref, CFOptionFlags ,
void * )
191 const int nativeFD = CFFileDescriptorGetNativeDescriptor(fdref);
194 assert(MacOSXSystem::fgInstance != 0 &&
"TMacOSXSystem_WriteCallback, MacOSXSystem's singleton is null");
195 MacOSXSystem::fgInstance->UnregisterFileDescriptor(fdref);
197 CFFileDescriptorInvalidate(fdref);
200 NSEvent *fdEvent = [NSEvent otherEventWithType : kApplicationDefined
201 location : NSMakePoint(0, 0) modifierFlags : 0
202 timestamp: 0. windowNumber : 0 context : nil
203 subtype : 0 data1 : nativeFD data2 : 0];
204 [NSApp postEvent : fdEvent atStart : NO];
210 MacOSXSystem::MacOSXSystem()
212 fCocoaInitialized(false)
214 assert(fgInstance == 0 &&
"MacOSXSystem, fgInstance was initialized already");
219 MacOSXSystem::~MacOSXSystem()
221 if (fCocoaInitialized)
222 CloseFileDescriptors();
226 void MacOSXSystem::InitializeCocoa()
228 assert(fCocoaInitialized ==
false &&
"InitializeCocoa, Cocoa was initialized already");
230 [NSApplication sharedApplication];
232 fCocoaInitialized =
true;
236 bool MacOSXSystem::SetFileDescriptors(
const TSeqCollection *fileHandlers)
243 assert(fileHandlers != 0 &&
"SetFileDescriptors, parameter 'fileHandlers' is null");
249 TIter next(fileHandlers);
250 while (TFileHandler *
const handler = static_cast<TFileHandler *>(next())) {
251 assert(handler->GetFd() != -1 && "SetFileDescriptors, invalid file descriptor");
253 if (handler->HasReadInterest())
254 SetFileDescriptor(handler->GetFd(), kDTRead);
256 if (handler->HasWriteInterest())
257 SetFileDescriptor(handler->GetFd(), kDTWrite);
259 }
catch (
const std::exception &) {
260 CloseFileDescriptors();
268 void MacOSXSystem::UnregisterFileDescriptor(CFFileDescriptorRef fd)
273 std::set<CFFileDescriptorRef>::iterator fdIter = fCFFileDescriptors.find(fd);
274 assert(fdIter != fCFFileDescriptors.end() &&
"InvalidateFileDescriptor, file descriptor was not found");
275 fCFFileDescriptors.erase(fdIter);
279 void MacOSXSystem::CloseFileDescriptors()
282 assert(fCocoaInitialized ==
true &&
"CloseFileDescriptors, Cocoa was not initialized");
284 std::set<CFFileDescriptorRef>::iterator fdIter = fCFFileDescriptors.begin(), end = fCFFileDescriptors.end();
286 for (; fdIter != end; ++fdIter) {
287 CFFileDescriptorInvalidate(*fdIter);
291 fCFFileDescriptors.clear();
295 void MacOSXSystem::SetFileDescriptor(
int fd, DescriptorType fdType)
298 assert(fCocoaInitialized ==
true &&
"SetFileDescriptors, Cocoa was not initialized");
300 assert(fd != -1 &&
"SetFileDescriptor, invalid file descriptor");
302 const bool read = fdType == kDTRead;
303 CFFileDescriptorRef fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd,
false,
304 read ? TMacOSXSystem_ReadCallback : TMacOSXSystem_WriteCallback, 0);
307 throw std::runtime_error(
"MacOSXSystem::SetFileDescriptors: CFFileDescriptorCreate failed");
309 CFFileDescriptorEnableCallBacks(fdref, read ? kCFFileDescriptorReadCallBack : kCFFileDescriptorWriteCallBack);
310 CFRunLoopSourceRef runLoopSource = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
312 if (!runLoopSource) {
314 throw std::runtime_error(
"MacOSXSystem::SetFileDescriptors: CFFileDescriptorCreateRunLoopSource failed");
317 CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSource, kCFRunLoopDefaultMode);
318 CFRelease(runLoopSource);
320 fCFFileDescriptors.insert(fdref);
327 namespace Private = ROOT::MacOSX::Details;
329 ClassImp(TMacOSXSystem)
332 TMacOSXSystem::TMacOSXSystem()
333 : fPimpl(new Private::MacOSXSystem),
334 fCocoaInitialized(false),
340 TMacOSXSystem::~TMacOSXSystem()
345 void TMacOSXSystem::DispatchOneEvent(Bool_t pendingOnly)
350 if (fFirstDispatch) {
351 if (!fCocoaInitialized && !gROOT->IsBatch())
354 fFirstDispatch =
false;
357 if (!fCocoaInitialized)
358 return TUnixSystem::DispatchOneEvent(pendingOnly);
360 Bool_t pollOnce = pendingOnly;
363 const ROOT::MacOSX::Util::AutoreleasePool pool;
365 if (ProcessPendingEvents()) {
368 if (gXDisplay && gXDisplay->Notify()) {
369 gVirtualX->Update(2);
370 gVirtualX->Update(3);
377 if (fNfd > 0 && fFileHandler && fFileHandler->GetSize() > 0)
378 if (CheckDescriptors())
386 if (pendingOnly && !pollOnce)
390 if (fSigcnt > 0 && fSignalHandler->GetSize() > 0)
391 if (CheckSignals(kTRUE))
392 if (!pendingOnly)
return;
399 if (fTimers && fTimers->GetSize() > 0) {
400 if (DispatchTimers(kTRUE)) {
402 nextto = NextTimeOut(kTRUE);
403 if (nextto > kItimerResolution || nextto == -1)
409 nextto = NextTimeOut(kTRUE);
421 if (gXDisplay && gXDisplay->Notify()) {
422 gVirtualX->Update(2);
423 gVirtualX->Update(3);
434 bool TMacOSXSystem::CocoaInitialized()
const
436 return fCocoaInitialized;
440 void TMacOSXSystem::InitializeCocoa()
442 if (fCocoaInitialized)
447 fPimpl->InitializeCocoa();
449 const ROOT::MacOSX::Util::AutoreleasePool pool;
458 const ROOT::MacOSX::Util::NSScopeGuard<RunStopper> stopper([[RunStopper alloc] init]);
461 [stopper.Get() performSelector : @selector(stopRun) withObject : nil afterDelay : 0.05];
464 fCocoaInitialized =
true;
468 bool TMacOSXSystem::ProcessPendingEvents()
470 assert(fCocoaInitialized ==
true &&
"ProcessPendingEvents, called while Cocoa was not initialized");
472 bool processed =
false;
473 while (NSEvent *event = [NSApp nextEventMatchingMask : Private::kEventMaskAny
474 untilDate : nil inMode : NSDefaultRunLoopMode dequeue : YES]) {
475 [NSApp sendEvent : event];
482 void TMacOSXSystem::WaitEvents(Long_t nextto)
486 assert(fCocoaInitialized ==
true &&
"WaitEvents, called while Cocoa was not initialized");
488 if (fFileHandler && !fPimpl->SetFileDescriptors(fFileHandler)) {
490 Fatal(
"WaitForAllEvents",
"SetFileDesciptors failed");
493 NSDate *untilDate = nil;
495 untilDate = [NSDate dateWithTimeIntervalSinceNow : nextto / 1000.];
497 untilDate = [NSDate distantFuture];
503 NSEvent *
event = [NSApp nextEventMatchingMask : Private::kEventMaskAny
504 untilDate : untilDate inMode : NSDefaultRunLoopMode dequeue : YES];
506 if (event.type == Private::kApplicationDefined)
507 ProcessApplicationDefinedEvent(event);
509 [NSApp sendEvent : event];
512 while ((event = [NSApp nextEventMatchingMask : Private::kEventMaskAny
513 untilDate : nil inMode : NSDefaultRunLoopMode dequeue : YES]))
515 if (event.type == Private::kApplicationDefined)
516 ProcessApplicationDefinedEvent(event);
518 [NSApp sendEvent : event];
521 fPimpl->CloseFileDescriptors();
523 gVirtualX->Update(2);
524 gVirtualX->Update(3);
528 void TMacOSXSystem::AddFileHandler(TFileHandler *fh)
531 if (fh->GetFd() == -1)
532 Error("AddFileHandler", "invalid file descriptor");
534 TUnixSystem::AddFileHandler(fh);
539 TFileHandler *TMacOSXSystem::RemoveFileHandler(TFileHandler *fh)
542 return TUnixSystem::RemoveFileHandler(fh);
548 void TMacOSXSystem::ProcessApplicationDefinedEvent(
void *e)
553 assert(fCocoaInitialized ==
true &&
554 "ProcessApplicationDefinedEvent, called while Cocoa was not initialized");
556 NSEvent *
event = (NSEvent *)e;
557 assert(event != nil &&
558 "ProcessApplicationDefinedEvent, event parameter is nil");
559 assert(event.type == Private::kApplicationDefined &&
560 "ProcessApplicationDefinedEvent, event parameter has wrong type");
562 bool descriptorFound =
false;
564 if (fReadmask->IsSet(event.data1)) {
565 fReadready->Set(event.data1);
566 descriptorFound =
true;
569 if (fWritemask->IsSet(event.data1)) {
570 fWriteready->Set(event.data1);
571 descriptorFound =
true;
574 if (!descriptorFound) {
575 Error(
"ProcessApplicationDefinedEvent",
"file descriptor %d was not found",
int(event.data1));