47 #include <ApplicationServices/ApplicationServices.h>
48 #include <OpenGL/OpenGL.h>
49 #include <Cocoa/Cocoa.h>
81 namespace Details = ROOT::MacOSX::Details;
82 namespace Util = ROOT::MacOSX::Util;
83 namespace X11 = ROOT::MacOSX::X11;
84 namespace Quartz = ROOT::Quartz;
85 namespace OpenGL = ROOT::MacOSX::OpenGL;
89 #pragma mark - Display configuration management.
92 void DisplayReconfigurationCallback(CGDirectDisplayID , CGDisplayChangeSummaryFlags flags,
void * )
94 if (flags & kCGDisplayBeginConfigurationFlag)
97 if (flags & kCGDisplayDesktopShapeChangedFlag) {
98 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
"DisplayReconfigurationCallback, gVirtualX"
99 " is either null or has a wrong type");
100 TGCocoa *
const gCocoa =
static_cast<TGCocoa *
>(gVirtualX);
101 gCocoa->ReconfigureDisplay();
105 #pragma mark - Aux. functions called from GUI-rendering part.
108 void SetStrokeForegroundColorFromX11Context(CGContextRef ctx,
const GCValues_t &gcVals)
110 assert(ctx != 0 &&
"SetStrokeForegroundColorFromX11Context, parameter 'ctx' is null");
113 if (gcVals.fMask & kGCForeground)
114 X11::PixelToRGB(gcVals.fForeground, rgb);
116 ::Warning(
"SetStrokeForegroundColorFromX11Context",
117 "x11 context does not have line color information");
119 CGContextSetRGBStrokeColor(ctx, rgb[0], rgb[1], rgb[2], 1.);
123 void SetStrokeDashFromX11Context(CGContextRef ctx,
const GCValues_t &gcVals)
126 assert(ctx != 0 &&
"SetStrokeDashFromX11Context, ctx parameter is null");
128 SetStrokeForegroundColorFromX11Context(ctx, gcVals);
130 static const std::size_t maxLength =
sizeof gcVals.fDashes /
sizeof gcVals.fDashes[0];
131 assert(maxLength >= std::size_t(gcVals.fDashLen) &&
132 "SetStrokeDashFromX11Context, x11 context has bad dash length > sizeof(fDashes)");
134 CGFloat dashes[maxLength] = {};
135 for (Int_t i = 0; i < gcVals.fDashLen; ++i)
136 dashes[i] = gcVals.fDashes[i];
138 CGContextSetLineDash(ctx, gcVals.fDashOffset, dashes, gcVals.fDashLen);
142 void SetStrokeDoubleDashFromX11Context(CGContextRef ,
const GCValues_t & )
145 ::Warning(
"SetStrokeDoubleDashFromX11Context",
"Not implemented yet, kick tpochep!");
149 void SetStrokeParametersFromX11Context(CGContextRef ctx,
const GCValues_t &gcVals)
153 assert(ctx != 0 &&
"SetStrokeParametersFromX11Context, parameter 'ctx' is null");
155 const Mask_t mask = gcVals.fMask;
156 if ((mask & kGCLineWidth) && gcVals.fLineWidth > 1)
157 CGContextSetLineWidth(ctx, gcVals.fLineWidth);
159 CGContextSetLineWidth(ctx, 1.);
161 CGContextSetLineDash(ctx, 0., 0, 0);
163 if (mask & kGCLineStyle) {
164 if (gcVals.fLineStyle == kLineSolid)
165 SetStrokeForegroundColorFromX11Context(ctx, gcVals);
166 else if (gcVals.fLineStyle == kLineOnOffDash)
167 SetStrokeDashFromX11Context(ctx, gcVals);
168 else if (gcVals.fLineStyle == kLineDoubleDash)
169 SetStrokeDoubleDashFromX11Context(ctx ,gcVals);
171 ::Warning(
"SetStrokeParametersFromX11Context",
"line style bit is set,"
172 " but line style is unknown");
173 SetStrokeForegroundColorFromX11Context(ctx, gcVals);
176 SetStrokeForegroundColorFromX11Context(ctx, gcVals);
180 void SetFilledAreaColorFromX11Context(CGContextRef ctx,
const GCValues_t &gcVals)
184 assert(ctx != 0 &&
"SetFilledAreaColorFromX11Context, parameter 'ctx' is null");
187 if (gcVals.fMask & kGCForeground)
188 X11::PixelToRGB(gcVals.fForeground, rgb);
190 ::Warning(
"SetFilledAreaColorFromX11Context",
"no fill color found in x11 context");
192 CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], 1.);
195 struct PatternContext {
200 NSObject<X11Drawable> *fImage;
206 bool HasFillTiledStyle(Mask_t mask, Int_t fillStyle)
208 return (mask & kGCFillStyle) && (fillStyle == kFillTiled);
212 bool HasFillTiledStyle(
const GCValues_t &gcVals)
214 return HasFillTiledStyle(gcVals.fMask, gcVals.fFillStyle);
218 bool HasFillStippledStyle(Mask_t mask, Int_t fillStyle)
220 return (mask & kGCFillStyle) && (fillStyle == kFillStippled);
224 bool HasFillStippledStyle(
const GCValues_t &gcVals)
226 return HasFillStippledStyle(gcVals.fMask, gcVals.fFillStyle);
230 bool HasFillOpaqueStippledStyle(Mask_t mask, Int_t fillStyle)
232 return (mask & kGCFillStyle) && (fillStyle == kFillOpaqueStippled);
236 bool HasFillOpaqueStippledStyle(
const GCValues_t &gcVals)
238 return HasFillOpaqueStippledStyle(gcVals.fMask, gcVals.fFillStyle);
242 void DrawTile(NSObject<X11Drawable> *patternImage, CGContextRef ctx)
244 assert(patternImage != nil &&
"DrawTile, parameter 'patternImage' is nil");
245 assert(ctx != 0 &&
"DrawTile, ctx parameter is null");
247 const CGRect patternRect = CGRectMake(0, 0, patternImage.fWidth, patternImage.fHeight);
248 if ([patternImage isKindOfClass : [QuartzImage
class]]) {
249 CGContextDrawImage(ctx, patternRect, ((QuartzImage *)patternImage).fImage);
250 }
else if ([patternImage isKindOfClass : [QuartzPixmap
class]]){
251 const Util::CFScopeGuard<CGImageRef> imageFromPixmap([((QuartzPixmap *)patternImage) createImageFromPixmap]);
252 assert(imageFromPixmap.Get() != 0 &&
"DrawTile, createImageFromPixmap failed");
253 CGContextDrawImage(ctx, patternRect, imageFromPixmap.Get());
255 assert(0 &&
"DrawTile, pattern is neither a QuartzImage, nor a QuartzPixmap");
259 void DrawPattern(
void *info, CGContextRef ctx)
265 assert(info != 0 &&
"DrawPattern, parameter 'info' is null");
266 assert(ctx != 0 &&
"DrawPattern, parameter 'ctx' is null");
268 const PatternContext *
const patternContext = (PatternContext *)info;
269 const Mask_t mask = patternContext->fMask;
270 const Int_t fillStyle = patternContext->fFillStyle;
272 NSObject<X11Drawable> *
const patternImage = patternContext->fImage;
273 assert(patternImage != nil &&
"DrawPattern, pattern (stipple) image is nil");
274 const CGRect patternRect = CGRectMake(0, 0, patternImage.fWidth, patternImage.fHeight);
276 if (HasFillTiledStyle(mask, fillStyle)) {
277 DrawTile(patternImage, ctx);
278 }
else if (HasFillStippledStyle(mask, fillStyle) || HasFillOpaqueStippledStyle(mask, fillStyle)) {
279 assert([patternImage isKindOfClass : [QuartzImage
class]] &&
280 "DrawPattern, stipple must be a QuartzImage object");
281 QuartzImage *
const image = (QuartzImage *)patternImage;
282 assert(image.fIsStippleMask == YES &&
"DrawPattern, image is not a stipple mask");
286 if (HasFillOpaqueStippledStyle(mask,fillStyle)) {
288 assert((mask & kGCBackground) &&
289 "DrawPattern, fill style is FillOpaqueStippled, but background color is not set in a context");
290 X11::PixelToRGB(patternContext->fBackground, rgb);
291 CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], 1.);
292 CGContextFillRect(ctx, patternRect);
296 assert((mask & kGCForeground) &&
"DrawPattern, foreground color is not set");
297 X11::PixelToRGB(patternContext->fForeground, rgb);
298 CGContextSetRGBFillColor(ctx, rgb[0], rgb[1], rgb[2], 1.);
299 CGContextClipToMask(ctx, patternRect, image.fImage);
300 CGContextFillRect(ctx, patternRect);
303 DrawTile(patternImage, ctx);
308 void SetFillPattern(CGContextRef ctx,
const PatternContext *patternContext)
314 assert(ctx != 0 &&
"SetFillPattern, parameter 'ctx' is null");
315 assert(patternContext != 0 &&
"SetFillPattern, parameter 'patternContext' is null");
316 assert(patternContext->fImage != nil &&
"SetFillPattern, pattern image is nil");
318 const Util::CFScopeGuard<CGColorSpaceRef> patternColorSpace(CGColorSpaceCreatePattern(0));
319 CGContextSetFillColorSpace(ctx, patternColorSpace.Get());
321 CGPatternCallbacks callbacks = {};
322 callbacks.drawPattern = DrawPattern;
323 const CGRect patternRect = CGRectMake(0, 0, patternContext->fImage.fWidth, patternContext->fImage.fHeight);
324 const Util::CFScopeGuard<CGPatternRef> pattern(CGPatternCreate((
void *)patternContext, patternRect, CGAffineTransformIdentity,
325 patternContext->fImage.fWidth, patternContext->fImage.fHeight,
326 kCGPatternTilingNoDistortion,
true, &callbacks));
327 const CGFloat alpha = 1.;
328 CGContextSetFillPattern(ctx, pattern.Get(), &alpha);
329 CGContextSetPatternPhase(ctx, patternContext->fPhase);
333 bool ParentRendersToChild(NSView<X11Window> *child)
335 assert(child != nil &&
"ParentRendersToChild, parameter 'child' is nil");
338 return (X11::ViewIsTextViewFrame(child,
true) || X11::ViewIsHtmlViewFrame(child,
true)) && !child.fContext &&
339 child.fMapState == kIsViewable && child.fParentView.fContext &&
340 !child.fIsOverlapped;
343 class ViewFixer final {
345 ViewFixer(QuartzView *&viewToFix, Drawable_t &widToFix)
347 if (ParentRendersToChild(viewToFix) && [viewToFix.fParentView isKindOfClass:[QuartzView
class]]) {
348 const auto origin = viewToFix.frame.origin;
349 viewToFix = viewToFix.fParentView;
350 widToFix = viewToFix.fID;
351 if ((context = viewToFix.fContext)) {
352 CGContextSaveGState(context);
353 CGContextTranslateCTM(context, origin.x, origin.y);
360 CGContextRestoreGState(context);
362 ViewFixer(
const ViewFixer &rhs) =
delete;
363 ViewFixer &operator = (
const ViewFixer &) =
delete;
366 CGContextRef context =
nullptr;
370 bool IsNonPrintableAsciiCharacter(UniChar c)
372 if (c == 9 || (c >= 32 && c < 127))
379 void FixAscii(std::vector<UniChar> &text)
396 std::replace(text.begin(), text.end(), UniChar(16), UniChar(
' '));
399 text.erase(std::remove_if(text.begin(), text.end(), IsNonPrintableAsciiCharacter), text.end());
406 Atom_t TGCocoa::fgDeleteWindowAtom = 0;
410 : fSelectedDrawable(0),
414 fForegroundProcess(false),
416 fDisplayShapeChanged(true)
418 assert(dynamic_cast<TMacOSXSystem *>(gSystem) !=
nullptr &&
419 "TGCocoa, gSystem is eihter null or has a wrong type");
420 TMacOSXSystem *
const system = (TMacOSXSystem *)gSystem;
422 if (!system->CocoaInitialized())
423 system->InitializeCocoa();
425 fPimpl.reset(
new Details::CocoaPrivate);
427 X11::InitWithPredefinedAtoms(fNameToAtom, fAtomToName);
428 fgDeleteWindowAtom = FindAtom(
"WM_DELETE_WINDOW",
true);
430 CGDisplayRegisterReconfigurationCallback (DisplayReconfigurationCallback, 0);
434 TGCocoa::TGCocoa(
const char *name,
const char *title)
435 : TVirtualX(name, title),
436 fSelectedDrawable(0),
440 fForegroundProcess(false),
442 fDisplayShapeChanged(true)
444 assert(dynamic_cast<TMacOSXSystem *>(gSystem) !=
nullptr &&
445 "TGCocoa, gSystem is eihter null or has a wrong type");
446 TMacOSXSystem *
const system = (TMacOSXSystem *)gSystem;
448 if (!system->CocoaInitialized())
449 system->InitializeCocoa();
451 fPimpl.reset(
new Details::CocoaPrivate);
453 X11::InitWithPredefinedAtoms(fNameToAtom, fAtomToName);
454 fgDeleteWindowAtom = FindAtom(
"WM_DELETE_WINDOW",
true);
456 CGDisplayRegisterReconfigurationCallback (DisplayReconfigurationCallback, 0);
463 CGDisplayRemoveReconfigurationCallback (DisplayReconfigurationCallback, 0);
469 Bool_t TGCocoa::Init(
void * )
478 Int_t TGCocoa::OpenDisplay(
const char * )
485 const char *TGCocoa::DisplayName(
const char *)
492 Int_t TGCocoa::SupportsExtension(
const char *)
const
499 void TGCocoa::CloseDisplay()
505 Display_t TGCocoa::GetDisplay()
const
512 Visual_t TGCocoa::GetVisual()
const
519 Int_t TGCocoa::GetScreen()
const
526 UInt_t TGCocoa::ScreenWidthMM()
const
532 return CGDisplayScreenSize(CGMainDisplayID()).width;
536 Int_t TGCocoa::GetDepth()
const
543 NSArray *
const screens = [NSScreen screens];
544 assert(screens != nil &&
"screens array is nil");
546 NSScreen *
const mainScreen = [screens objectAtIndex : 0];
547 assert(mainScreen != nil &&
"screen with index 0 is nil");
549 return NSBitsPerPixelFromDepth([mainScreen depth]);
553 void TGCocoa::Update(Int_t mode)
555 R__LOCKGUARD(gROOTMutex);
558 assert(gClient != 0 &&
"Update, gClient is null");
560 }
else if (mode > 0) {
562 fPimpl->fX11CommandBuffer.Flush(fPimpl.get());
565 if (fDirectDraw && mode != 2)
566 fPimpl->fX11CommandBuffer.FlushXOROps(fPimpl.get());
570 void TGCocoa::ReconfigureDisplay()
572 fDisplayShapeChanged =
true;
576 X11::Rectangle TGCocoa::GetDisplayGeometry()
const
578 if (fDisplayShapeChanged) {
579 NSArray *
const screens = [NSScreen screens];
580 assert(screens != nil && screens.count != 0 &&
"GetDisplayGeometry, no screens found");
582 NSRect frame = [(NSScreen *)[screens objectAtIndex : 0] frame];
583 CGFloat xMin = frame.origin.x, xMax = xMin + frame.size.width;
584 CGFloat yMin = frame.origin.y, yMax = yMin + frame.size.height;
586 for (NSUInteger i = 1, e = screens.count; i < e; ++i) {
587 frame = [(NSScreen *)[screens objectAtIndex : i] frame];
588 xMin = std::min(xMin, frame.origin.x);
589 xMax = std::max(xMax, frame.origin.x + frame.size.width);
590 yMin = std::min(yMin, frame.origin.y);
591 yMax = std::max(yMax, frame.origin.y + frame.size.height);
594 fDisplayRect.fX = int(xMin);
595 fDisplayRect.fY = int(yMin);
596 fDisplayRect.fWidth = unsigned(xMax - xMin);
597 fDisplayRect.fHeight = unsigned(yMax - yMin);
599 fDisplayShapeChanged =
false;
605 #pragma mark - Window management part.
608 Window_t TGCocoa::GetDefaultRootWindow()
const
611 return fPimpl->GetRootWindowID();
615 Int_t TGCocoa::InitWindow(ULong_t parentID)
627 assert(parentID != 0 &&
"InitWindow, parameter 'parentID' is 0");
630 WindowAttributes_t attr = {};
631 if (fPimpl->IsRootWindow(parentID))
632 ROOT::MacOSX::X11::GetRootWindowAttributes(&attr);
634 [fPimpl->GetWindow(parentID) getAttributes : &attr];
636 return CreateWindow(parentID, 0, 0, attr.fWidth, attr.fHeight, 0, attr.fDepth, attr.fClass, 0, 0, 0);
640 Window_t TGCocoa::GetWindowID(Int_t windowID)
649 void TGCocoa::SelectWindow(Int_t windowID)
652 fSelectedDrawable = windowID;
656 void TGCocoa::ClearWindow()
659 assert(fSelectedDrawable > fPimpl->GetRootWindowID() &&
660 "ClearWindow, fSelectedDrawable is invalid");
662 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(fSelectedDrawable);
663 if (drawable.fIsPixmap) {
668 CGContextRef pixmapCtx = drawable.fContext;
669 assert(pixmapCtx != 0 &&
"ClearWindow, pixmap's context is null");
674 CGContextClearRect(pixmapCtx, CGRectMake(0, 0, drawable.fWidth, drawable.fHeight));
677 ClearArea(fSelectedDrawable, 0, 0, 0, 0);
682 void TGCocoa::GetGeometry(Int_t windowID, Int_t & x, Int_t &y, UInt_t &w, UInt_t &h)
691 if (windowID < 0 || fPimpl->IsRootWindow(windowID)) {
694 WindowAttributes_t attr = {};
695 ROOT::MacOSX::X11::GetRootWindowAttributes(&attr);
701 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(windowID);
705 h = drawable.fHeight;
707 if (!drawable.fIsPixmap) {
708 NSObject<X11Window> *
const window = (NSObject<X11Window> *)drawable;
709 NSPoint srcPoint = {};
712 NSView<X11Window> *
const view = window.fContentView.fParentView ? window.fContentView.fParentView : window.fContentView;
716 const NSPoint dstPoint = X11::TranslateToScreen(view, srcPoint);
724 void TGCocoa::MoveWindow(Int_t windowID, Int_t x, Int_t y)
729 assert(!fPimpl->IsRootWindow(windowID) &&
"MoveWindow, called for root window");
734 [fPimpl->GetWindow(windowID) setX : x Y : y];
738 void TGCocoa::RescaleWindow(Int_t , UInt_t , UInt_t )
746 void TGCocoa::ResizeWindow(Int_t windowID)
754 assert(!fPimpl->IsRootWindow(windowID) &&
755 "ResizeWindow, parameter 'windowID' is a root window's id");
757 const Util::AutoreleasePool pool;
759 NSObject<X11Window> *
const window = fPimpl->GetWindow(windowID);
760 if (window.fBackBuffer) {
761 const Drawable_t currentDrawable = fSelectedDrawable;
762 fSelectedDrawable = windowID;
764 fSelectedDrawable = currentDrawable;
769 void TGCocoa::UpdateWindow(Int_t )
779 assert(fSelectedDrawable > fPimpl->GetRootWindowID() &&
780 "UpdateWindow, fSelectedDrawable is not a valid window id");
783 if (fPimpl->GetDrawable(fSelectedDrawable).fIsPixmap == YES)
786 NSObject<X11Window> *
const window = fPimpl->GetWindow(fSelectedDrawable);
788 if (QuartzPixmap *
const pixmap = window.fBackBuffer) {
789 assert([window.fContentView isKindOfClass : [QuartzView
class]] &&
"UpdateWindow, content view is not a QuartzView");
790 QuartzView *dstView = (QuartzView *)window.fContentView;
792 if (dstView.fIsOverlapped)
795 if (dstView.fContext) {
797 const X11::Rectangle copyArea(0, 0, pixmap.fWidth, pixmap.fHeight);
798 [dstView copy : pixmap area : copyArea withMask : nil clipOrigin : X11::Point() toPoint : X11::Point()];
801 fPimpl->fX11CommandBuffer.AddUpdateWindow(dstView);
808 Window_t TGCocoa::GetCurrentWindow()
const
811 return fSelectedDrawable;
815 void TGCocoa::CloseWindow()
821 Int_t TGCocoa::AddWindow(ULong_t , UInt_t , UInt_t )
831 void TGCocoa::RemoveWindow(ULong_t )
837 Window_t TGCocoa::CreateWindow(Window_t parentID, Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t border, Int_t depth,
838 UInt_t clss,
void *visual, SetWindowAttributes_t *attr, UInt_t wtype)
845 const Util::AutoreleasePool pool;
847 if (fPimpl->IsRootWindow(parentID)) {
849 QuartzWindow *
const newWindow = X11::CreateTopLevelWindow(x, y, w, h, border,
850 depth, clss, visual, attr, wtype);
853 const Util::NSScopeGuard<QuartzWindow> winGuard(newWindow);
854 const Window_t result = fPimpl->RegisterDrawable(newWindow);
855 newWindow.fID = result;
856 [newWindow setAcceptsMouseMovedEvents : YES];
860 NSObject<X11Window> *
const parentWin = fPimpl->GetWindow(parentID);
862 assert([parentWin.fContentView isKindOfClass : [QuartzView
class]] &&
863 "CreateWindow, parent view must be QuartzView");
866 QuartzView *
const childView = X11::CreateChildView((QuartzView *)parentWin.fContentView,
867 x, y, w, h, border, depth, clss, visual, attr, wtype);
868 const Util::NSScopeGuard<QuartzView> viewGuard(childView);
869 const Window_t result = fPimpl->RegisterDrawable(childView);
870 childView.fID = result;
871 [parentWin addChild : childView];
878 void TGCocoa::DestroyWindow(Window_t wid)
898 if (fPimpl->IsRootWindow(wid))
901 BOOL needFocusChange = NO;
904 const Util::AutoreleasePool pool;
906 fPimpl->fX11EventTranslator.CheckUnmappedView(wid);
908 assert(fPimpl->GetDrawable(wid).fIsPixmap == NO &&
909 "DestroyWindow, can not be called for QuartzPixmap or QuartzImage object");
911 NSObject<X11Window> *
const window = fPimpl->GetWindow(wid);
912 if (fPimpl->fX11CommandBuffer.BufferSize())
913 fPimpl->fX11CommandBuffer.RemoveOperationsForDrawable(wid);
916 if ((needFocusChange = window == window.fQuartzWindow && window.fQuartzWindow.fHasFocus))
917 window.fHasFocus = NO;
919 DestroySubwindows(wid);
920 if (window.fEventMask & kStructureNotifyMask)
921 fPimpl->fX11EventTranslator.GenerateDestroyNotify(wid);
924 if (gClient->GetWaitForEvent() == kDestroyNotify && wid == gClient->GetWaitForWindow())
925 gClient->SetWaitForWindow(kNone);
927 fPimpl->DeleteDrawable(wid);
932 X11::WindowLostFocus(wid);
936 void TGCocoa::DestroySubwindows(Window_t wid)
947 if (fPimpl->IsRootWindow(wid))
950 const Util::AutoreleasePool pool;
952 assert(fPimpl->GetDrawable(wid).fIsPixmap == NO &&
953 "DestroySubwindows, can not be called for QuartzPixmap or QuartzImage object");
955 NSObject<X11Window> *window = fPimpl->GetWindow(wid);
960 const Util::NSScopeGuard<NSArray> children([[window.fContentView subviews] copy]);
962 for (NSView<X11Window> *child in children.Get())
963 DestroyWindow(child.fID);
967 void TGCocoa::GetWindowAttributes(Window_t wid, WindowAttributes_t &attr)
974 if (fPimpl->IsRootWindow(wid))
975 ROOT::MacOSX::X11::GetRootWindowAttributes(&attr);
977 [fPimpl->GetWindow(wid) getAttributes : &attr];
981 void TGCocoa::ChangeWindowAttributes(Window_t wid, SetWindowAttributes_t *attr)
988 const Util::AutoreleasePool pool;
990 assert(!fPimpl->IsRootWindow(wid) &&
"ChangeWindowAttributes, called for root window");
991 assert(attr != 0 &&
"ChangeWindowAttributes, parameter 'attr' is null");
993 [fPimpl->GetWindow(wid) setAttributes : attr];
997 void TGCocoa::SelectInput(Window_t windowID, UInt_t eventMask)
1008 if (windowID <= fPimpl->GetRootWindowID())
1011 NSObject<X11Window> *
const window = fPimpl->GetWindow(windowID);
1013 window.fEventMask = eventMask;
1017 void TGCocoa::ReparentChild(Window_t wid, Window_t pid, Int_t x, Int_t y)
1020 using namespace Details;
1022 assert(!fPimpl->IsRootWindow(wid) &&
"ReparentChild, can not re-parent root window");
1024 const Util::AutoreleasePool pool;
1026 NSView<X11Window> *
const view = fPimpl->GetWindow(wid).fContentView;
1027 if (fPimpl->IsRootWindow(pid)) {
1030 [view removeFromSuperview];
1031 view.fParentView = nil;
1033 NSRect frame = view.frame;
1034 frame.origin = NSPoint();
1036 NSUInteger styleMask = kClosableWindowMask | kMiniaturizableWindowMask | kResizableWindowMask;
1037 if (!view.fOverrideRedirect)
1038 styleMask |= kTitledWindowMask;
1040 QuartzWindow *
const newTopLevel = [[QuartzWindow alloc] initWithContentRect : frame
1041 styleMask : styleMask
1042 backing : NSBackingStoreBuffered
1044 [view setX : x Y : y];
1045 [newTopLevel addChild : view];
1047 fPimpl->ReplaceDrawable(wid, newTopLevel);
1050 [newTopLevel release];
1053 [view removeFromSuperview];
1055 NSObject<X11Window> *
const newParent = fPimpl->GetWindow(pid);
1056 assert(newParent.fIsPixmap == NO &&
"ReparentChild, pixmap can not be a new parent");
1057 [view setX : x Y : y];
1058 [newParent addChild : view];
1064 void TGCocoa::ReparentTopLevel(Window_t wid, Window_t pid, Int_t x, Int_t y)
1069 if (fPimpl->IsRootWindow(pid))
1072 const Util::AutoreleasePool pool;
1074 NSView<X11Window> *
const contentView = fPimpl->GetWindow(wid).fContentView;
1075 QuartzWindow *
const topLevel = (QuartzWindow *)[contentView window];
1076 [contentView retain];
1077 [contentView removeFromSuperview];
1078 [topLevel setContentView : nil];
1079 fPimpl->ReplaceDrawable(wid, contentView);
1080 [contentView setX : x Y : y];
1081 [fPimpl->GetWindow(pid) addChild : contentView];
1082 [contentView release];
1086 void TGCocoa::ReparentWindow(Window_t wid, Window_t pid, Int_t x, Int_t y)
1093 assert(!fPimpl->IsRootWindow(wid) &&
"ReparentWindow, can not re-parent root window");
1095 NSView<X11Window> *
const view = fPimpl->GetWindow(wid).fContentView;
1096 if (view.fParentView)
1097 ReparentChild(wid, pid, x, y);
1100 ReparentTopLevel(wid, pid, x, y);
1104 void TGCocoa::MapWindow(Window_t wid)
1109 assert(!fPimpl->IsRootWindow(wid) &&
"MapWindow, called for root window");
1111 const Util::AutoreleasePool pool;
1113 if (MakeProcessForeground())
1114 [fPimpl->GetWindow(wid) mapWindow];
1117 SetApplicationIcon();
1118 Details::PopulateMainMenu();
1124 void TGCocoa::MapSubwindows(Window_t wid)
1129 assert(!fPimpl->IsRootWindow(wid) &&
"MapSubwindows, called for 'root' window");
1131 const Util::AutoreleasePool pool;
1133 if (MakeProcessForeground())
1134 [fPimpl->GetWindow(wid) mapSubwindows];
1138 void TGCocoa::MapRaised(Window_t wid)
1144 assert(!fPimpl->IsRootWindow(wid) &&
"MapRaised, called for root window");
1146 const Util::AutoreleasePool pool;
1148 if (MakeProcessForeground())
1149 [fPimpl->GetWindow(wid) mapRaised];
1152 SetApplicationIcon();
1153 Details::PopulateMainMenu();
1159 void TGCocoa::UnmapWindow(Window_t wid)
1165 assert(!fPimpl->IsRootWindow(wid) &&
"UnmapWindow, called for root window");
1167 const Util::AutoreleasePool pool;
1170 fPimpl->fX11EventTranslator.CheckUnmappedView(wid);
1172 NSObject<X11Window> *
const win = fPimpl->GetWindow(wid);
1175 if (win == win.fQuartzWindow && win.fQuartzWindow.fHasFocus)
1176 X11::WindowLostFocus(win.fID);
1184 if (gClient->GetWaitForEvent() == kUnmapNotify && gClient->GetWaitForWindow() == wid)
1185 gClient->SetWaitForWindow(kNone);
1189 void TGCocoa::RaiseWindow(Window_t wid)
1197 assert(!fPimpl->IsRootWindow(wid) &&
"RaiseWindow, called for root window");
1199 if (!fPimpl->GetWindow(wid).fParentView)
1202 [fPimpl->GetWindow(wid) raiseWindow];
1206 void TGCocoa::LowerWindow(Window_t wid)
1214 assert(!fPimpl->IsRootWindow(wid) &&
"LowerWindow, called for root window");
1216 if (!fPimpl->GetWindow(wid).fParentView)
1219 [fPimpl->GetWindow(wid) lowerWindow];
1223 void TGCocoa::MoveWindow(Window_t wid, Int_t x, Int_t y)
1235 assert(!fPimpl->IsRootWindow(wid) &&
"MoveWindow, called for root window");
1236 const Util::AutoreleasePool pool;
1237 [fPimpl->GetWindow(wid) setX : x Y : y];
1241 void TGCocoa::MoveResizeWindow(Window_t wid, Int_t x, Int_t y, UInt_t w, UInt_t h)
1254 assert(!fPimpl->IsRootWindow(wid) &&
"MoveResizeWindow, called for 'root' window");
1256 const Util::AutoreleasePool pool;
1257 [fPimpl->GetWindow(wid) setX : x Y : y width : w height : h];
1261 void TGCocoa::ResizeWindow(Window_t wid, UInt_t w, UInt_t h)
1266 assert(!fPimpl->IsRootWindow(wid) &&
"ResizeWindow, called for 'root' window");
1268 const Util::AutoreleasePool pool;
1271 const UInt_t siMax = std::numeric_limits<Int_t>::max();
1272 if (w > siMax || h > siMax)
1275 NSSize newSize = {};
1279 [fPimpl->GetWindow(wid) setDrawableSize : newSize];
1283 void TGCocoa::IconifyWindow(Window_t wid)
1289 assert(!fPimpl->IsRootWindow(wid) &&
"IconifyWindow, can not iconify the root window");
1290 assert(fPimpl->GetWindow(wid).fIsPixmap == NO &&
"IconifyWindow, invalid window id");
1292 NSObject<X11Window> *
const win = fPimpl->GetWindow(wid);
1293 assert(win.fQuartzWindow == win &&
"IconifyWindow, can be called only for a top level window");
1295 fPimpl->fX11EventTranslator.CheckUnmappedView(wid);
1297 NSObject<X11Window> *
const window = fPimpl->GetWindow(wid);
1298 if (fPimpl->fX11CommandBuffer.BufferSize())
1299 fPimpl->fX11CommandBuffer.RemoveOperationsForDrawable(wid);
1301 if (window.fQuartzWindow.fHasFocus) {
1302 X11::WindowLostFocus(win.fID);
1303 window.fQuartzWindow.fHasFocus = NO;
1306 [win.fQuartzWindow miniaturize : win.fQuartzWindow];
1310 void TGCocoa::TranslateCoordinates(Window_t srcWin, Window_t dstWin, Int_t srcX, Int_t srcY, Int_t &dstX, Int_t &dstY, Window_t &child)
1321 if (!srcWin || !dstWin)
1324 const bool srcIsRoot = fPimpl->IsRootWindow(srcWin);
1325 const bool dstIsRoot = fPimpl->IsRootWindow(dstWin);
1327 if (srcIsRoot && dstIsRoot) {
1333 if (QuartzWindow *
const qw = X11::FindWindowInPoint(srcX, srcY))
1339 NSPoint srcPoint = {};
1343 NSPoint dstPoint = {};
1347 NSView<X11Window> *
const srcView = fPimpl->GetWindow(srcWin).fContentView;
1348 dstPoint = X11::TranslateToScreen(srcView, srcPoint);
1349 }
else if (srcIsRoot) {
1350 NSView<X11Window> *
const dstView = fPimpl->GetWindow(dstWin).fContentView;
1351 dstPoint = X11::TranslateFromScreen(srcPoint, dstView);
1353 if ([dstView superview]) {
1357 dstPoint = [[dstView superview] convertPoint : dstPoint fromView : dstView];
1358 if (NSView<X11Window> *
const view = (NSView<X11Window> *)[dstView hitTest : dstPoint]) {
1359 if (view != dstView && view.fMapState == kIsViewable)
1364 NSView<X11Window> *
const srcView = fPimpl->GetWindow(srcWin).fContentView;
1365 NSView<X11Window> *
const dstView = fPimpl->GetWindow(dstWin).fContentView;
1367 dstPoint = X11::TranslateCoordinates(srcView, dstView, srcPoint);
1368 if ([dstView superview]) {
1372 const NSPoint pt = [[dstView superview] convertPoint : dstPoint fromView : dstView];
1373 if (NSView<X11Window> *
const view = (NSView<X11Window> *)[dstView hitTest : pt]) {
1374 if (view != dstView && view.fMapState == kIsViewable)
1385 void TGCocoa::GetWindowSize(Drawable_t wid, Int_t &x, Int_t &y, UInt_t &w, UInt_t &h)
1397 if (fPimpl->IsRootWindow(wid)) {
1398 WindowAttributes_t attr = {};
1399 ROOT::MacOSX::X11::GetRootWindowAttributes(&attr);
1405 NSObject<X11Drawable> *window = fPimpl->GetDrawable(wid);
1407 if (!window.fIsPixmap) {
1421 void TGCocoa::SetWindowBackground(Window_t wid, ULong_t color)
1427 assert(!fPimpl->IsRootWindow(wid) &&
"SetWindowBackground, can not set color for root window");
1429 fPimpl->GetWindow(wid).fBackgroundPixel = color;
1433 void TGCocoa::SetWindowBackgroundPixmap(Window_t windowID, Pixmap_t pixmapID)
1442 assert(!fPimpl->IsRootWindow(windowID) &&
1443 "SetWindowBackgroundPixmap, can not set background for a root window");
1444 assert(fPimpl->GetDrawable(windowID).fIsPixmap == NO &&
1445 "SetWindowBackgroundPixmap, invalid window id");
1447 NSObject<X11Window> *
const window = fPimpl->GetWindow(windowID);
1448 if (pixmapID == kNone) {
1449 window.fBackgroundPixmap = nil;
1453 assert(pixmapID > fPimpl->GetRootWindowID() &&
1454 "SetWindowBackgroundPixmap, parameter 'pixmapID' is not a valid pixmap id");
1455 assert(fPimpl->GetDrawable(pixmapID).fIsPixmap == YES &&
1456 "SetWindowBackgroundPixmap, bad drawable");
1458 NSObject<X11Drawable> *
const pixmapOrImage = fPimpl->GetDrawable(pixmapID);
1461 Util::NSScopeGuard<QuartzImage> backgroundImage;
1463 if ([pixmapOrImage isKindOfClass : [QuartzPixmap
class]]) {
1464 backgroundImage.Reset([[QuartzImage alloc] initFromPixmap : (QuartzPixmap *)pixmapOrImage]);
1465 if (backgroundImage.Get())
1466 window.fBackgroundPixmap = backgroundImage.Get();
1468 backgroundImage.Reset([[QuartzImage alloc] initFromImage : (QuartzImage *)pixmapOrImage]);
1469 if (backgroundImage.Get())
1470 window.fBackgroundPixmap = backgroundImage.Get();
1473 if (!backgroundImage.Get())
1475 Error(
"SetWindowBackgroundPixmap",
"QuartzImage initialization failed");
1479 Window_t TGCocoa::GetParent(Window_t windowID)
const
1484 if (windowID <= fPimpl->GetRootWindowID())
1487 NSView<X11Window> *view = fPimpl->GetWindow(windowID).fContentView;
1488 return view.fParentView ? view.fParentView.fID : fPimpl->GetRootWindowID();
1492 void TGCocoa::SetWindowName(Window_t wid,
char *name)
1497 const Util::AutoreleasePool pool;
1499 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
1501 if ([(NSObject *)drawable isKindOfClass : [NSWindow
class]]) {
1502 NSString *
const windowTitle = [NSString stringWithCString : name encoding : NSASCIIStringEncoding];
1503 [(NSWindow *)drawable setTitle : windowTitle];
1508 void TGCocoa::SetIconName(Window_t ,
char * )
1514 void TGCocoa::SetIconPixmap(Window_t , Pixmap_t )
1520 void TGCocoa::SetClassHints(Window_t ,
char * ,
char * )
1526 void TGCocoa::ShapeCombineMask(Window_t windowID, Int_t , Int_t , Pixmap_t pixmapID)
1533 assert(!fPimpl->IsRootWindow(windowID) &&
1534 "ShapeCombineMask, windowID parameter is a 'root' window");
1535 assert(fPimpl->GetDrawable(windowID).fIsPixmap == NO &&
1536 "ShapeCombineMask, windowID parameter is a bad window id");
1537 assert([fPimpl->GetDrawable(pixmapID) isKindOfClass : [QuartzImage class]] &&
1538 "ShapeCombineMask, pixmapID parameter must point to QuartzImage object");
1540 if (fPimpl->GetWindow(windowID).fContentView.fParentView)
1543 QuartzImage *
const srcImage = (QuartzImage *)fPimpl->GetDrawable(pixmapID);
1544 assert(srcImage.fIsStippleMask == YES &&
"ShapeCombineMask, source image is not a stipple mask");
1548 const Util::NSScopeGuard<QuartzImage> image([[QuartzImage alloc] initFromImageFlipped : srcImage]);
1550 QuartzWindow *
const qw = fPimpl->GetWindow(windowID).fQuartzWindow;
1551 qw.fShapeCombineMask = image.Get();
1552 [qw setOpaque : NO];
1553 [qw setBackgroundColor : [NSColor clearColor]];
1557 #pragma mark - "Window manager hints" set of functions.
1560 void TGCocoa::SetMWMHints(Window_t wid, UInt_t value, UInt_t funcs, UInt_t )
1563 using namespace Details;
1565 assert(!fPimpl->IsRootWindow(wid) &&
"SetMWMHints, called for 'root' window");
1567 QuartzWindow *
const qw = fPimpl->GetWindow(wid).fQuartzWindow;
1568 NSUInteger newMask = 0;
1570 if ([qw styleMask] & kTitledWindowMask) {
1571 newMask |= kTitledWindowMask;
1572 newMask |= kClosableWindowMask;
1575 if (value & kMWMFuncAll) {
1576 newMask |= kMiniaturizableWindowMask | kResizableWindowMask;
1578 if (value & kMWMDecorMinimize)
1579 newMask |= kMiniaturizableWindowMask;
1580 if (funcs & kMWMFuncResize)
1581 newMask |= kResizableWindowMask;
1584 [qw setStyleMask : newMask];
1586 if (funcs & kMWMDecorAll) {
1587 if (!qw.fMainWindow) {
1588 [[qw standardWindowButton : NSWindowZoomButton] setEnabled : YES];
1589 [[qw standardWindowButton : NSWindowMiniaturizeButton] setEnabled : YES];
1592 if (!qw.fMainWindow) {
1593 [[qw standardWindowButton : NSWindowZoomButton] setEnabled : funcs & kMWMDecorMaximize];
1594 [[qw standardWindowButton : NSWindowMiniaturizeButton] setEnabled : funcs & kMWMDecorMinimize];
1600 void TGCocoa::SetWMPosition(Window_t , Int_t , Int_t )
1606 void TGCocoa::SetWMSize(Window_t , UInt_t , UInt_t )
1612 void TGCocoa::SetWMSizeHints(Window_t wid, UInt_t wMin, UInt_t hMin, UInt_t wMax, UInt_t hMax, UInt_t , UInt_t )
1614 using namespace Details;
1616 assert(!fPimpl->IsRootWindow(wid) &&
"SetWMSizeHints, called for root window");
1618 const NSUInteger styleMask = kTitledWindowMask | kClosableWindowMask | kMiniaturizableWindowMask | kResizableWindowMask;
1619 const NSRect minRect = [NSWindow frameRectForContentRect : NSMakeRect(0., 0., wMin, hMin) styleMask : styleMask];
1620 const NSRect maxRect = [NSWindow frameRectForContentRect : NSMakeRect(0., 0., wMax, hMax) styleMask : styleMask];
1622 QuartzWindow *
const qw = fPimpl->GetWindow(wid).fQuartzWindow;
1623 [qw setMinSize : minRect.size];
1624 [qw setMaxSize : maxRect.size];
1628 void TGCocoa::SetWMState(Window_t , EInitialState )
1634 void TGCocoa::SetWMTransientHint(Window_t wid, Window_t mainWid)
1645 assert(wid > fPimpl->GetRootWindowID() &&
"SetWMTransientHint, wid parameter is not a valid window id");
1647 if (fPimpl->IsRootWindow(mainWid))
1650 QuartzWindow *
const mainWindow = fPimpl->GetWindow(mainWid).fQuartzWindow;
1652 if (![mainWindow isVisible])
1655 QuartzWindow *
const transientWindow = fPimpl->GetWindow(wid).fQuartzWindow;
1657 if (mainWindow != transientWindow) {
1658 if (transientWindow.fMainWindow) {
1659 if (transientWindow.fMainWindow != mainWindow)
1660 Error(
"SetWMTransientHint",
"window is already transient for other window");
1662 [[transientWindow standardWindowButton : NSWindowZoomButton] setEnabled : NO];
1663 [mainWindow addTransientWindow : transientWindow];
1666 Warning(
"SetWMTransientHint",
"transient and main windows are the same window");
1669 #pragma mark - GUI-rendering part.
1672 void TGCocoa::DrawLineAux(Drawable_t wid,
const GCValues_t &gcVals, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
1675 assert(!fPimpl->IsRootWindow(wid) &&
"DrawLineAux, called for root window");
1677 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
1678 CGContextRef ctx = drawable.fContext;
1679 assert(ctx != 0 &&
"DrawLineAux, context is null");
1681 const Quartz::CGStateGuard ctxGuard(ctx);
1692 CGContextSetAllowsAntialiasing(ctx,
false);
1694 if (!drawable.fIsPixmap)
1695 CGContextTranslateCTM(ctx, 0.5, 0.5);
1698 y1 = Int_t(X11::LocalYROOTToCocoa(drawable, y1));
1699 y2 = Int_t(X11::LocalYROOTToCocoa(drawable, y2));
1702 SetStrokeParametersFromX11Context(ctx, gcVals);
1703 CGContextBeginPath(ctx);
1704 CGContextMoveToPoint(ctx, x1, y1);
1705 CGContextAddLineToPoint(ctx, x2, y2);
1706 CGContextStrokePath(ctx);
1708 CGContextSetAllowsAntialiasing(ctx,
true);
1712 void TGCocoa::DrawLine(Drawable_t wid, GContext_t gc, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
1723 assert(!fPimpl->IsRootWindow(wid) &&
"DrawLine, called for root window");
1724 assert(gc > 0 && gc <= fX11Contexts.size() &&
"DrawLine, invalid context index");
1726 const GCValues_t &gcVals = fX11Contexts[gc - 1];
1728 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
1729 if (!drawable.fIsPixmap) {
1730 NSObject<X11Window> *
const window = (NSObject<X11Window> *)drawable;
1731 QuartzView *view = (QuartzView *)window.fContentView;
1732 const ViewFixer fixer(view, wid);
1733 if (!view.fIsOverlapped && view.fMapState == kIsViewable) {
1735 fPimpl->fX11CommandBuffer.AddDrawLine(wid, gcVals, x1, y1, x2, y2);
1737 DrawLineAux(wid, gcVals, x1, y1, x2, y2);
1740 if (!IsCocoaDraw()) {
1741 fPimpl->fX11CommandBuffer.AddDrawLine(wid, gcVals, x1, y1, x2, y2);
1743 DrawLineAux(wid, gcVals, x1, y1, x2, y2);
1749 void TGCocoa::DrawSegmentsAux(Drawable_t wid,
const GCValues_t &gcVals,
const Segment_t *segments, Int_t nSegments)
1751 assert(!fPimpl->IsRootWindow(wid) &&
"DrawSegmentsAux, called for root window");
1752 assert(segments != 0 &&
"DrawSegmentsAux, segments parameter is null");
1753 assert(nSegments > 0 &&
"DrawSegmentsAux, nSegments <= 0");
1755 for (Int_t i = 0; i < nSegments; ++i)
1756 DrawLineAux(wid, gcVals, segments[i].fX1, segments[i].fY1 - 3, segments[i].fX2, segments[i].fY2 - 3);
1760 void TGCocoa::DrawSegments(Drawable_t wid, GContext_t gc, Segment_t *segments, Int_t nSegments)
1768 assert(!fPimpl->IsRootWindow(wid) &&
"DrawSegments, called for root window");
1769 assert(gc > 0 && gc <= fX11Contexts.size() &&
"DrawSegments, invalid context index");
1770 assert(segments != 0 &&
"DrawSegments, parameter 'segments' is null");
1771 assert(nSegments > 0 &&
"DrawSegments, number of segments <= 0");
1773 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
1774 const GCValues_t &gcVals = fX11Contexts[gc - 1];
1776 if (!drawable.fIsPixmap) {
1777 QuartzView *view = (QuartzView *)fPimpl->GetWindow(wid).fContentView;
1778 const ViewFixer fixer(view, wid);
1780 if (!view.fIsOverlapped && view.fMapState == kIsViewable) {
1782 fPimpl->fX11CommandBuffer.AddDrawSegments(wid, gcVals, segments, nSegments);
1784 DrawSegmentsAux(wid, gcVals, segments, nSegments);
1788 fPimpl->fX11CommandBuffer.AddDrawSegments(wid, gcVals, segments, nSegments);
1790 DrawSegmentsAux(wid, gcVals, segments, nSegments);
1795 void TGCocoa::DrawRectangleAux(Drawable_t wid,
const GCValues_t &gcVals, Int_t x, Int_t y, UInt_t w, UInt_t h)
1798 assert(!fPimpl->IsRootWindow(wid) &&
"DrawRectangleAux, called for root window");
1800 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
1802 if (!drawable.fIsPixmap) {
1811 y = Int_t(X11::LocalYROOTToCocoa(drawable, y + h));
1814 CGContextRef ctx = fPimpl->GetDrawable(wid).fContext;
1815 assert(ctx &&
"DrawRectangleAux, context is null");
1816 const Quartz::CGStateGuard ctxGuard(ctx);
1818 CGContextSetAllowsAntialiasing(ctx,
false);
1820 SetStrokeParametersFromX11Context(ctx, gcVals);
1822 const CGRect rect = CGRectMake(x, y, w, h);
1823 CGContextStrokeRect(ctx, rect);
1825 CGContextSetAllowsAntialiasing(ctx,
true);
1829 void TGCocoa::DrawRectangle(Drawable_t wid, GContext_t gc, Int_t x, Int_t y, UInt_t w, UInt_t h)
1837 assert(!fPimpl->IsRootWindow(wid) &&
"DrawRectangle, called for root window");
1838 assert(gc > 0 && gc <= fX11Contexts.size() &&
"DrawRectangle, invalid context index");
1840 const GCValues_t &gcVals = fX11Contexts[gc - 1];
1842 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
1844 if (!drawable.fIsPixmap) {
1845 NSObject<X11Window> *
const window = (NSObject<X11Window> *)drawable;
1846 QuartzView *view = (QuartzView *)window.fContentView;
1847 const ViewFixer fixer(view, wid);
1849 if (!view.fIsOverlapped && view.fMapState == kIsViewable) {
1851 fPimpl->fX11CommandBuffer.AddDrawRectangle(wid, gcVals, x, y, w, h);
1853 DrawRectangleAux(wid, gcVals, x, y, w, h);
1857 fPimpl->fX11CommandBuffer.AddDrawRectangle(wid, gcVals, x, y, w, h);
1859 DrawRectangleAux(wid, gcVals, x, y, w, h);
1864 void TGCocoa::FillRectangleAux(Drawable_t wid,
const GCValues_t &gcVals, Int_t x, Int_t y, UInt_t w, UInt_t h)
1873 assert(!fPimpl->IsRootWindow(wid) &&
"FillRectangleAux, called for root window");
1875 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
1876 CGContextRef ctx = drawable.fContext;
1877 CGSize patternPhase = {};
1879 if (drawable.fIsPixmap) {
1881 y = Int_t(X11::LocalYROOTToCocoa(drawable, y + h));
1884 const CGRect fillRect = CGRectMake(x, y, w, h);
1886 if (!drawable.fIsPixmap) {
1887 QuartzView *
const view = (QuartzView *)fPimpl->GetWindow(wid).fContentView;
1888 if (view.fParentView) {
1889 const NSPoint origin = [view.fParentView convertPoint : view.frame.origin toView : nil];
1890 patternPhase.width = origin.x;
1891 patternPhase.height = origin.y;
1895 const Quartz::CGStateGuard ctxGuard(ctx);
1897 if (HasFillStippledStyle(gcVals) || HasFillOpaqueStippledStyle(gcVals) || HasFillTiledStyle(gcVals)) {
1898 PatternContext patternContext = {gcVals.fMask, gcVals.fFillStyle, 0, 0, nil, patternPhase};
1900 if (HasFillStippledStyle(gcVals) || HasFillOpaqueStippledStyle(gcVals)) {
1901 assert(gcVals.fStipple != kNone &&
1902 "FillRectangleAux, fill_style is FillStippled/FillOpaqueStippled,"
1903 " but no stipple is set in a context");
1905 patternContext.fForeground = gcVals.fForeground;
1906 patternContext.fImage = fPimpl->GetDrawable(gcVals.fStipple);
1908 if (HasFillOpaqueStippledStyle(gcVals))
1909 patternContext.fBackground = gcVals.fBackground;
1911 assert(gcVals.fTile != kNone &&
1912 "FillRectangleAux, fill_style is FillTiled, but not tile is set in a context");
1914 patternContext.fImage = fPimpl->GetDrawable(gcVals.fTile);
1917 SetFillPattern(ctx, &patternContext);
1918 CGContextFillRect(ctx, fillRect);
1923 SetFilledAreaColorFromX11Context(ctx, gcVals);
1924 CGContextFillRect(ctx, fillRect);
1928 void TGCocoa::FillRectangle(Drawable_t wid, GContext_t gc, Int_t x, Int_t y, UInt_t w, UInt_t h)
1937 assert(!fPimpl->IsRootWindow(wid) &&
"FillRectangle, called for root window");
1938 assert(gc > 0 && gc <= fX11Contexts.size() &&
"FillRectangle, invalid context index");
1940 const GCValues_t &gcVals = fX11Contexts[gc - 1];
1941 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
1943 if (!drawable.fIsPixmap) {
1944 NSObject<X11Window> *
const window = (NSObject<X11Window> *)drawable;
1945 QuartzView *view = (QuartzView *)window.fContentView;
1946 const ViewFixer fixer(view, wid);
1947 if (!view.fIsOverlapped && view.fMapState == kIsViewable) {
1949 fPimpl->fX11CommandBuffer.AddFillRectangle(wid, gcVals, x, y, w, h);
1951 FillRectangleAux(wid, gcVals, x, y, w, h);
1954 FillRectangleAux(wid, gcVals, x, y, w, h);
1958 void TGCocoa::FillPolygonAux(Window_t wid,
const GCValues_t &gcVals,
const Point_t *polygon, Int_t nPoints)
1966 assert(!fPimpl->IsRootWindow(wid) &&
"FillPolygonAux, called for root window");
1967 assert(polygon != 0 &&
"FillPolygonAux, parameter 'polygon' is null");
1968 assert(nPoints > 0 &&
"FillPolygonAux, number of points must be positive");
1970 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
1971 CGContextRef ctx = drawable.fContext;
1973 CGSize patternPhase = {};
1975 if (!drawable.fIsPixmap) {
1976 QuartzView *
const view = (QuartzView *)fPimpl->GetWindow(wid).fContentView;
1977 const NSPoint origin = [view convertPoint : view.frame.origin toView : nil];
1978 patternPhase.width = origin.x;
1979 patternPhase.height = origin.y;
1982 const Quartz::CGStateGuard ctxGuard(ctx);
1984 CGContextSetAllowsAntialiasing(ctx,
false);
1986 if (HasFillStippledStyle(gcVals) || HasFillOpaqueStippledStyle(gcVals) || HasFillTiledStyle(gcVals)) {
1987 PatternContext patternContext = {gcVals.fMask, gcVals.fFillStyle, 0, 0, nil, patternPhase};
1989 if (HasFillStippledStyle(gcVals) || HasFillOpaqueStippledStyle(gcVals)) {
1990 assert(gcVals.fStipple != kNone &&
1991 "FillRectangleAux, fill style is FillStippled/FillOpaqueStippled,"
1992 " but no stipple is set in a context");
1994 patternContext.fForeground = gcVals.fForeground;
1995 patternContext.fImage = fPimpl->GetDrawable(gcVals.fStipple);
1997 if (HasFillOpaqueStippledStyle(gcVals))
1998 patternContext.fBackground = gcVals.fBackground;
2000 assert(gcVals.fTile != kNone &&
2001 "FillRectangleAux, fill_style is FillTiled, but not tile is set in a context");
2003 patternContext.fImage = fPimpl->GetDrawable(gcVals.fTile);
2006 SetFillPattern(ctx, &patternContext);
2008 SetFilledAreaColorFromX11Context(ctx, gcVals);
2013 CGContextBeginPath(ctx);
2014 if (!drawable.fIsPixmap) {
2015 CGContextMoveToPoint(ctx, polygon[0].fX, polygon[0].fY - 2);
2016 for (Int_t i = 1; i < nPoints; ++i)
2017 CGContextAddLineToPoint(ctx, polygon[i].fX, polygon[i].fY - 2);
2019 CGContextMoveToPoint(ctx, polygon[0].fX, X11::LocalYROOTToCocoa(drawable, polygon[0].fY + 2));
2020 for (Int_t i = 1; i < nPoints; ++i)
2021 CGContextAddLineToPoint(ctx, polygon[i].fX, X11::LocalYROOTToCocoa(drawable, polygon[i].fY + 2));
2024 CGContextFillPath(ctx);
2025 CGContextSetAllowsAntialiasing(ctx,
true);
2029 void TGCocoa::FillPolygon(Window_t wid, GContext_t gc, Point_t *polygon, Int_t nPoints)
2048 assert(polygon != 0 &&
"FillPolygon, parameter 'polygon' is null");
2049 assert(nPoints > 0 &&
"FillPolygon, number of points must be positive");
2050 assert(gc > 0 && gc <= fX11Contexts.size() &&
"FillPolygon, invalid context index");
2052 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
2053 const GCValues_t &gcVals = fX11Contexts[gc - 1];
2055 if (!drawable.fIsPixmap) {
2056 QuartzView *view = (QuartzView *)fPimpl->GetWindow(wid).fContentView;
2057 const ViewFixer fixer(view, wid);
2059 if (!view.fIsOverlapped && view.fMapState == kIsViewable) {
2061 fPimpl->fX11CommandBuffer.AddFillPolygon(wid, gcVals, polygon, nPoints);
2063 FillPolygonAux(wid, gcVals, polygon, nPoints);
2067 fPimpl->fX11CommandBuffer.AddFillPolygon(wid, gcVals, polygon, nPoints);
2069 FillPolygonAux(wid, gcVals, polygon, nPoints);
2074 void TGCocoa::CopyAreaAux(Drawable_t src, Drawable_t dst,
const GCValues_t &gcVals, Int_t srcX, Int_t srcY,
2075 UInt_t width, UInt_t height, Int_t dstX, Int_t dstY)
2081 assert(!fPimpl->IsRootWindow(src) &&
"CopyAreaAux, src parameter is root window");
2082 assert(!fPimpl->IsRootWindow(dst) &&
"CopyAreaAux, dst parameter is root window");
2086 const Util::AutoreleasePool pool;
2088 NSObject<X11Drawable> *
const srcDrawable = fPimpl->GetDrawable(src);
2089 NSObject<X11Drawable> *
const dstDrawable = fPimpl->GetDrawable(dst);
2091 const X11::Point dstPoint(dstX, dstY);
2092 const X11::Rectangle copyArea(srcX, srcY, width, height);
2094 QuartzImage *mask = nil;
2095 if ((gcVals.fMask & kGCClipMask) && gcVals.fClipMask) {
2096 assert(fPimpl->GetDrawable(gcVals.fClipMask).fIsPixmap == YES &&
2097 "CopyArea, mask is not a pixmap");
2098 mask = (QuartzImage *)fPimpl->GetDrawable(gcVals.fClipMask);
2101 X11::Point clipOrigin;
2102 if (gcVals.fMask & kGCClipXOrigin)
2103 clipOrigin.fX = gcVals.fClipXOrigin;
2104 if (gcVals.fMask & kGCClipYOrigin)
2105 clipOrigin.fY = gcVals.fClipYOrigin;
2107 [dstDrawable copy : srcDrawable area : copyArea withMask : mask clipOrigin : clipOrigin toPoint : dstPoint];
2111 void TGCocoa::CopyArea(Drawable_t src, Drawable_t dst, GContext_t gc, Int_t srcX, Int_t srcY,
2112 UInt_t width, UInt_t height, Int_t dstX, Int_t dstY)
2117 assert(!fPimpl->IsRootWindow(src) &&
"CopyArea, src parameter is root window");
2118 assert(!fPimpl->IsRootWindow(dst) &&
"CopyArea, dst parameter is root window");
2119 assert(gc > 0 && gc <= fX11Contexts.size() &&
"CopyArea, invalid context index");
2121 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(dst);
2122 const GCValues_t &gcVals = fX11Contexts[gc - 1];
2124 if (!drawable.fIsPixmap) {
2125 QuartzView *view = (QuartzView *)fPimpl->GetWindow(dst).fContentView;
2126 const ViewFixer fixer(view, dst);
2128 if (!view.fIsOverlapped && view.fMapState == kIsViewable) {
2130 fPimpl->fX11CommandBuffer.AddCopyArea(src, dst, gcVals, srcX, srcY, width, height, dstX, dstY);
2132 CopyAreaAux(src, dst, gcVals, srcX, srcY, width, height, dstX, dstY);
2135 if (fPimpl->GetDrawable(src).fIsPixmap) {
2137 CopyAreaAux(src, dst, gcVals, srcX, srcY, width, height, dstX, dstY);
2140 fPimpl->fX11CommandBuffer.AddCopyArea(src, dst, gcVals, srcX, srcY, width, height, dstX, dstY);
2142 CopyAreaAux(src, dst, gcVals, srcX, srcY, width, height, dstX, dstY);
2148 void TGCocoa::DrawStringAux(Drawable_t wid,
const GCValues_t &gcVals, Int_t x, Int_t y,
const char *text, Int_t len)
2151 assert(!fPimpl->IsRootWindow(wid) &&
"DrawStringAux, called for root window");
2153 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
2154 CGContextRef ctx = drawable.fContext;
2155 assert(ctx != 0 &&
"DrawStringAux, context is null");
2157 const Quartz::CGStateGuard ctxGuard(ctx);
2159 CGContextSetTextMatrix(ctx, CGAffineTransformIdentity);
2162 if (!drawable.fIsPixmap) {
2163 CGContextTranslateCTM(ctx, 0., drawable.fHeight);
2164 CGContextScaleCTM(ctx, 1., -1.);
2168 CGContextSetAllowsAntialiasing(ctx,
true);
2170 assert(gcVals.fMask & kGCFont &&
"DrawString, font is not set in a context");
2173 len = std::strlen(text);
2175 CGFloat textColor[4] = {0., 0., 0., 1.};
2177 if (gcVals.fMask & kGCForeground)
2178 X11::PixelToRGB(gcVals.fForeground, textColor);
2180 CGContextSetRGBFillColor(ctx, textColor[0], textColor[1], textColor[2], textColor[3]);
2185 std::vector<UniChar> unichars((
unsigned char *)text, (
unsigned char *)text + len);
2188 Quartz::DrawTextLineNoKerning(ctx, (CTFontRef)gcVals.fFont, unichars, x, X11::LocalYROOTToCocoa(drawable, y));
2192 void TGCocoa::DrawString(Drawable_t wid, GContext_t gc, Int_t x, Int_t y,
const char *text, Int_t len)
2198 assert(!fPimpl->IsRootWindow(wid) &&
"DrawString, called for root window");
2199 assert(gc > 0 && gc <= fX11Contexts.size() &&
"DrawString, invalid context index");
2201 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
2202 const GCValues_t &gcVals = fX11Contexts[gc - 1];
2203 assert(gcVals.fMask & kGCFont &&
"DrawString, font is not set in a context");
2205 if (!drawable.fIsPixmap) {
2206 QuartzView *view = (QuartzView *)fPimpl->GetWindow(wid).fContentView;
2207 const ViewFixer fixer(view, wid);
2209 if (!view.fIsOverlapped && view.fMapState == kIsViewable) {
2211 fPimpl->fX11CommandBuffer.AddDrawString(wid, gcVals, x, y, text, len);
2213 DrawStringAux(wid, gcVals, x, y, text, len);
2218 fPimpl->fX11CommandBuffer.AddDrawString(wid, gcVals, x, y, text, len);
2220 DrawStringAux(wid, gcVals, x, y, text, len);
2225 void TGCocoa::ClearAreaAux(Window_t windowID, Int_t x, Int_t y, UInt_t w, UInt_t h)
2227 assert(!fPimpl->IsRootWindow(windowID) &&
"ClearAreaAux, called for root window");
2229 QuartzView *
const view = (QuartzView *)fPimpl->GetWindow(windowID).fContentView;
2230 assert(view.fContext != 0 &&
"ClearAreaAux, view.fContext is null");
2238 if (!view.fBackgroundPixmap) {
2240 CGFloat rgb[3] = {};
2241 X11::PixelToRGB(view.fBackgroundPixel, rgb);
2243 const Quartz::CGStateGuard ctxGuard(view.fContext);
2244 CGContextSetRGBFillColor(view.fContext, rgb[0], rgb[1], rgb[2], 1.);
2245 CGContextFillRect(view.fContext, CGRectMake(x, y, w, h));
2247 const CGRect fillRect = CGRectMake(x, y, w, h);
2249 CGSize patternPhase = {};
2250 if (view.fParentView) {
2251 const NSPoint origin = [view.fParentView convertPoint : view.frame.origin toView : nil];
2252 patternPhase.width = origin.x;
2253 patternPhase.height = origin.y;
2255 const Quartz::CGStateGuard ctxGuard(view.fContext);
2257 PatternContext patternContext = {Mask_t(), 0, 0, 0, view.fBackgroundPixmap, patternPhase};
2258 SetFillPattern(view.fContext, &patternContext);
2259 CGContextFillRect(view.fContext, fillRect);
2264 void TGCocoa::ClearArea(Window_t wid, Int_t x, Int_t y, UInt_t w, UInt_t h)
2273 assert(!fPimpl->IsRootWindow(wid) &&
"ClearArea, called for root window");
2276 QuartzView *view = (QuartzView *)fPimpl->GetWindow(wid).fContentView;
2277 if (ParentRendersToChild(view))
2280 if (!view.fIsOverlapped && view.fMapState == kIsViewable) {
2282 fPimpl->fX11CommandBuffer.AddClearArea(wid, x, y, w, h);
2284 ClearAreaAux(wid, x, y, w, h);
2289 void TGCocoa::ClearWindow(Window_t wid)
2297 ClearArea(wid, 0, 0, 0, 0);
2300 #pragma mark - Pixmap management.
2303 Int_t TGCocoa::OpenPixmap(UInt_t w, UInt_t h)
2306 NSSize newSize = {};
2310 Util::NSScopeGuard<QuartzPixmap> pixmap([[QuartzPixmap alloc] initWithW : w H : h
2311 scaleFactor : [[NSScreen mainScreen] backingScaleFactor]]);
2313 pixmap.Get().fID = fPimpl->RegisterDrawable(pixmap.Get());
2314 return (Int_t)pixmap.Get().fID;
2317 Error(
"OpenPixmap",
"QuartzPixmap initialization failed");
2323 Int_t TGCocoa::ResizePixmap(Int_t wid, UInt_t w, UInt_t h)
2325 assert(!fPimpl->IsRootWindow(wid) &&
"ResizePixmap, called for root window");
2327 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
2328 assert(drawable.fIsPixmap == YES &&
"ResizePixmap, invalid drawable");
2330 QuartzPixmap *pixmap = (QuartzPixmap *)drawable;
2331 if (w == pixmap.fWidth && h == pixmap.fHeight)
2334 if ([pixmap resizeW : w H : h scaleFactor : [[NSScreen mainScreen] backingScaleFactor]])
2341 void TGCocoa::SelectPixmap(Int_t pixmapID)
2343 assert(pixmapID > (Int_t)fPimpl->GetRootWindowID() &&
2344 "SelectPixmap, parameter 'pixmapID' is not a valid id");
2346 fSelectedDrawable = pixmapID;
2350 void TGCocoa::CopyPixmap(Int_t pixmapID, Int_t x, Int_t y)
2352 assert(pixmapID > (Int_t)fPimpl->GetRootWindowID() &&
2353 "CopyPixmap, parameter 'pixmapID' is not a valid id");
2354 assert(fSelectedDrawable > fPimpl->GetRootWindowID() &&
2355 "CopyPixmap, fSelectedDrawable is not a valid window id");
2357 NSObject<X11Drawable> *
const source = fPimpl->GetDrawable(pixmapID);
2358 assert([source isKindOfClass : [QuartzPixmap
class]] &&
2359 "CopyPixmap, source is not a pixmap");
2360 QuartzPixmap *
const pixmap = (QuartzPixmap *)source;
2362 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(fSelectedDrawable);
2363 NSObject<X11Drawable> * destination = nil;
2365 if (drawable.fIsPixmap) {
2366 destination = drawable;
2368 NSObject<X11Window> *
const window = fPimpl->GetWindow(fSelectedDrawable);
2369 if (window.fBackBuffer) {
2370 destination = window.fBackBuffer;
2372 Warning(
"CopyPixmap",
"Operation skipped, since destination"
2373 " window is not double buffered");
2378 const X11::Rectangle copyArea(0, 0, pixmap.fWidth, pixmap.fHeight);
2379 const X11::Point dstPoint(x, y);
2381 [destination copy : pixmap area : copyArea withMask : nil clipOrigin : X11::Point() toPoint : dstPoint];
2385 void TGCocoa::ClosePixmap()
2388 assert(fSelectedDrawable > fPimpl->GetRootWindowID() &&
"ClosePixmap, no drawable selected");
2389 assert(fPimpl->GetDrawable(fSelectedDrawable).fIsPixmap == YES &&
"ClosePixmap, selected drawable is not a pixmap");
2391 DeletePixmap(fSelectedDrawable);
2392 fSelectedDrawable = 0;
2395 #pragma mark - Different functions to create pixmap from different data sources. Used by GUI.
2396 #pragma mark - These functions implement TVirtualX interface, some of them dupilcate others.
2399 Pixmap_t TGCocoa::CreatePixmap(Drawable_t , UInt_t w, UInt_t h)
2402 return OpenPixmap(w, h);
2406 Pixmap_t TGCocoa::CreatePixmap(Drawable_t ,
const char *bitmap, UInt_t width, UInt_t height,
2407 ULong_t foregroundPixel, ULong_t backgroundPixel, Int_t depth)
2412 assert(bitmap != 0 &&
"CreatePixmap, parameter 'bitmap' is null");
2413 assert(width > 0 &&
"CreatePixmap, parameter 'width' is 0");
2414 assert(height > 0 &&
"CreatePixmap, parameter 'height' is 0");
2416 std::vector<unsigned char> imageData (depth > 1 ? width * height * 4 : width * height);
2418 X11::FillPixmapBuffer((
unsigned char*)bitmap, width, height, foregroundPixel,
2419 backgroundPixel, depth, &imageData[0]);
2422 Util::NSScopeGuard<QuartzImage> image;
2425 image.Reset([[QuartzImage alloc] initWithW : width H : height data: &imageData[0]]);
2427 image.Reset([[QuartzImage alloc] initMaskWithW : width H : height bitmapMask : &imageData[0]]);
2430 Error(
"CreatePixmap",
"QuartzImage initialization failed");
2434 image.Get().fID = fPimpl->RegisterDrawable(image.Get());
2435 return image.Get().fID;
2439 Pixmap_t TGCocoa::CreatePixmapFromData(
unsigned char *bits, UInt_t width, UInt_t height)
2442 assert(bits != 0 &&
"CreatePixmapFromData, data parameter is null");
2443 assert(width != 0 &&
"CreatePixmapFromData, width parameter is 0");
2444 assert(height != 0 &&
"CreatePixmapFromData, height parameter is 0");
2448 std::vector<unsigned char> imageData(bits, bits + width * height * 4);
2451 unsigned char *p = &imageData[0];
2452 for (
unsigned i = 0, e = width * height; i < e; ++i, p += 4)
2453 std::swap(p[0], p[2]);
2456 Util::NSScopeGuard<QuartzImage> image([[QuartzImage alloc] initWithW : width
2457 H : height data : &imageData[0]]);
2461 Error(
"CreatePixmapFromData",
"QuartzImage initialziation failed");
2465 image.Get().fID = fPimpl->RegisterDrawable(image.Get());
2466 return image.Get().fID;
2470 Pixmap_t TGCocoa::CreateBitmap(Drawable_t ,
const char *bitmap, UInt_t width, UInt_t height)
2473 assert(std::numeric_limits<unsigned char>::digits == 8 &&
"CreateBitmap, ASImage requires octets");
2481 std::vector<unsigned char> imageData(width * height);
2484 for (
unsigned i = 0, j = 0, e = width / 8 * height; i < e; ++i) {
2485 for(
unsigned bit = 0; bit < 8; ++bit, ++j) {
2486 if (bitmap[i] & (1 << bit))
2494 Util::NSScopeGuard<QuartzImage> image([[QuartzImage alloc] initMaskWithW : width
2495 H : height bitmapMask : &imageData[0]]);
2498 Error(
"CreateBitmap",
"QuartzImage initialization failed");
2502 image.Get().fID = fPimpl->RegisterDrawable(image.Get());
2503 return image.Get().fID;
2507 void TGCocoa::DeletePixmapAux(Pixmap_t pixmapID)
2509 fPimpl->DeleteDrawable(pixmapID);
2513 void TGCocoa::DeletePixmap(Pixmap_t pixmapID)
2516 assert(fPimpl->GetDrawable(pixmapID).fIsPixmap == YES &&
"DeletePixmap, object is not a pixmap");
2517 fPimpl->fX11CommandBuffer.AddDeletePixmap(pixmapID);
2521 Int_t TGCocoa::AddPixmap(ULong_t , UInt_t , UInt_t )
2530 unsigned char *TGCocoa::GetColorBits(Drawable_t wid, Int_t x, Int_t y, UInt_t w, UInt_t h)
2533 if (fPimpl->IsRootWindow(wid)) {
2534 Warning(
"GetColorBits",
"Called for root window");
2536 assert(x >= 0 &&
"GetColorBits, parameter 'x' is negative");
2537 assert(y >= 0 &&
"GetColorBits, parameter 'y' is negative");
2538 assert(w != 0 &&
"GetColorBits, parameter 'w' is 0");
2539 assert(h != 0 &&
"GetColorBits, parameter 'h' is 0");
2541 const X11::Rectangle area(x, y, w, h);
2542 return [fPimpl->GetDrawable(wid) readColorBits : area];
2548 #pragma mark - XImage emulation.
2551 Drawable_t TGCocoa::CreateImage(UInt_t width, UInt_t height)
2557 return OpenPixmap(width, height);
2561 void TGCocoa::GetImageSize(Drawable_t wid, UInt_t &width, UInt_t &height)
2564 assert(wid > fPimpl->GetRootWindowID() &&
"GetImageSize, parameter 'wid' is invalid");
2566 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(wid);
2567 width = drawable.fWidth;
2568 height = drawable.fHeight;
2572 void TGCocoa::PutPixel(Drawable_t imageID, Int_t x, Int_t y, ULong_t pixel)
2581 assert([fPimpl->GetDrawable(imageID) isKindOfClass : [QuartzPixmap class]] &&
2582 "PutPixel, parameter 'imageID' is a bad pixmap id");
2583 assert(x >= 0 &&
"PutPixel, parameter 'x' is negative");
2584 assert(y >= 0 &&
"PutPixel, parameter 'y' is negative");
2586 QuartzPixmap *
const pixmap = (QuartzPixmap *)fPimpl->GetDrawable(imageID);
2588 unsigned char rgb[3] = {};
2589 X11::PixelToRGB(pixel, rgb);
2590 [pixmap putPixel : rgb X : x Y : y];
2594 void TGCocoa::PutImage(Drawable_t drawableID, GContext_t gc, Drawable_t imageID, Int_t dstX, Int_t dstY,
2595 Int_t srcX, Int_t srcY, UInt_t width, UInt_t height)
2601 CopyArea(imageID, drawableID, gc, srcX, srcY, width, height, dstX, dstY);
2605 void TGCocoa::DeleteImage(Drawable_t imageID)
2608 assert([fPimpl->GetDrawable(imageID) isKindOfClass : [QuartzPixmap class]] &&
2609 "DeleteImage, imageID parameter is not a valid image id");
2610 DeletePixmap(imageID);
2613 #pragma mark - Mouse related code.
2616 void TGCocoa::GrabButton(Window_t wid, EMouseButton button, UInt_t keyModifiers, UInt_t eventMask,
2617 Window_t , Cursor_t , Bool_t grab)
2631 assert(!fPimpl->IsRootWindow(wid) &&
"GrabButton, called for 'root' window");
2633 NSObject<X11Window> *
const widget = fPimpl->GetWindow(wid);
2636 widget.fPassiveGrabOwnerEvents = YES;
2637 widget.fPassiveGrabButton = button;
2638 widget.fPassiveGrabEventMask = eventMask;
2639 widget.fPassiveGrabKeyModifiers = keyModifiers;
2642 widget.fPassiveGrabOwnerEvents = NO;
2643 widget.fPassiveGrabButton = -1;
2644 widget.fPassiveGrabEventMask = 0;
2645 widget.fPassiveGrabKeyModifiers = 0;
2650 void TGCocoa::GrabPointer(Window_t wid, UInt_t eventMask, Window_t , Cursor_t , Bool_t grab, Bool_t ownerEvents)
2658 NSView<X11Window> *
const view = fPimpl->GetWindow(wid).fContentView;
2659 assert(!fPimpl->IsRootWindow(wid) &&
"GrabPointer, called for 'root' window");
2662 fPimpl->fX11EventTranslator.SetPointerGrab(view, eventMask, ownerEvents);
2666 fPimpl->fX11EventTranslator.CancelPointerGrab();
2671 void TGCocoa::ChangeActivePointerGrab(Window_t, UInt_t, Cursor_t)
2680 void TGCocoa::SetKeyAutoRepeat(Bool_t )
2687 void TGCocoa::GrabKey(Window_t wid, Int_t keyCode, UInt_t rootKeyModifiers, Bool_t grab)
2717 assert(!fPimpl->IsRootWindow(wid) &&
"GrabKey, called for root window");
2719 NSView<X11Window> *
const view = fPimpl->GetWindow(wid).fContentView;
2720 const NSUInteger cocoaKeyModifiers = X11::GetCocoaKeyModifiersFromROOTKeyModifiers(rootKeyModifiers);
2723 [view addPassiveKeyGrab : keyCode modifiers : cocoaKeyModifiers];
2725 [view removePassiveKeyGrab : keyCode modifiers : cocoaKeyModifiers];
2729 Int_t TGCocoa::KeysymToKeycode(UInt_t keySym)
2736 return X11::MapKeySymToKeyCode(keySym);
2740 Window_t TGCocoa::GetInputFocus()
2744 return fPimpl->fX11EventTranslator.GetInputFocus();
2748 void TGCocoa::SetInputFocus(Window_t wid)
2751 assert(!fPimpl->IsRootWindow(wid) &&
"SetInputFocus, called for root window");
2754 fPimpl->fX11EventTranslator.SetInputFocus(nil);
2756 fPimpl->fX11EventTranslator.SetInputFocus(fPimpl->GetWindow(wid).fContentView);
2760 void TGCocoa::LookupString(Event_t *event,
char *buf, Int_t length, UInt_t &keysym)
2772 assert(buf != 0 &&
"LookupString, parameter 'buf' is null");
2773 assert(length >= 2 &&
"LookupString, parameter 'length' - not enough memory to return null-terminated ASCII string");
2775 X11::MapUnicharToKeySym(event->fCode, buf, length, keysym);
2778 #pragma mark - Font management.
2781 FontStruct_t TGCocoa::LoadQueryFont(
const char *fontName)
2785 assert(fontName != 0 &&
"LoadQueryFont, fontName is null");
2788 if (ParseXLFDName(fontName, xlfd)) {
2790 if (!xlfd.fFamilyName.length() || xlfd.fFamilyName ==
"*")
2791 xlfd.fFamilyName =
"Courier";
2792 if (!xlfd.fPixelSize)
2793 xlfd.fPixelSize = 11;
2794 return fPimpl->fFontManager.LoadFont(xlfd);
2797 return FontStruct_t();
2801 FontH_t TGCocoa::GetFontHandle(FontStruct_t fs)
2807 void TGCocoa::DeleteFont(FontStruct_t fs)
2809 fPimpl->fFontManager.UnloadFont(fs);
2813 Bool_t TGCocoa::HasTTFonts()
const
2821 Int_t TGCocoa::TextWidth(FontStruct_t font,
const char *s, Int_t len)
2824 return fPimpl->fFontManager.GetTextWidth(font, s, len);
2828 void TGCocoa::GetFontProperties(FontStruct_t font, Int_t &maxAscent, Int_t &maxDescent)
2831 fPimpl->fFontManager.GetFontProperties(font, maxAscent, maxDescent);
2835 FontStruct_t TGCocoa::GetFontStruct(FontH_t fh)
2842 return (FontStruct_t)fh;
2846 void TGCocoa::FreeFontStruct(FontStruct_t )
2854 char **TGCocoa::ListFonts(
const char *fontName, Int_t maxNames, Int_t &count)
2858 if (fontName && fontName[0]) {
2860 if (X11::ParseXLFDName(fontName, xlfd))
2861 return fPimpl->fFontManager.ListFonts(xlfd, maxNames, count);
2868 void TGCocoa::FreeFontNames(
char **fontList)
2874 fPimpl->fFontManager.FreeFontNames(fontList);
2877 #pragma mark - Color management.
2880 Bool_t TGCocoa::ParseColor(Colormap_t ,
const char *colorName, ColorStruct_t &color)
2885 return fPimpl->fX11ColorParser.ParseColor(colorName, color);
2889 Bool_t TGCocoa::AllocColor(Colormap_t , ColorStruct_t &color)
2891 const unsigned red = unsigned(
double(color.fRed) / 0xFFFF * 0xFF);
2892 const unsigned green = unsigned(
double(color.fGreen) / 0xFFFF * 0xFF);
2893 const unsigned blue = unsigned(
double(color.fBlue) / 0xFFFF * 0xFF);
2894 color.fPixel = red << 16 | green << 8 | blue;
2899 void TGCocoa::QueryColor(Colormap_t , ColorStruct_t & color)
2902 color.fRed = (color.fPixel >> 16 & 0xFF) * 0xFFFF / 0xFF;
2903 color.fGreen = (color.fPixel >> 8 & 0xFF) * 0xFFFF / 0xFF;
2904 color.fBlue = (color.fPixel & 0xFF) * 0xFFFF / 0xFF;
2908 void TGCocoa::FreeColor(Colormap_t , ULong_t )
2914 ULong_t TGCocoa::GetPixel(Color_t rootColorIndex)
2917 if (
const TColor *
const color = gROOT->GetColor(rootColorIndex)) {
2918 Float_t red = 0.f, green = 0.f, blue = 0.f;
2919 color->GetRGB(red, green, blue);
2920 pixel = unsigned(red * 255) << 16;
2921 pixel |= unsigned(green * 255) << 8;
2922 pixel |= unsigned(blue * 255);
2929 void TGCocoa::GetPlanes(Int_t &nPlanes)
2932 nPlanes = GetDepth();
2936 void TGCocoa::GetRGB(Int_t , Float_t &, Float_t &, Float_t &)
2942 void TGCocoa::SetRGB(Int_t , Float_t , Float_t , Float_t )
2951 Colormap_t TGCocoa::GetColormap()
const
2953 return Colormap_t();
2956 #pragma mark - Graphical context management.
2959 GContext_t TGCocoa::CreateGC(Drawable_t , GCValues_t *gval)
2962 fX11Contexts.push_back(*gval);
2963 return fX11Contexts.size();
2967 void TGCocoa::SetForeground(GContext_t gc, ULong_t foreground)
2976 assert(gc <= fX11Contexts.size() && gc > 0 &&
"ChangeGC, invalid context id");
2978 GCValues_t &x11Context = fX11Contexts[gc - 1];
2979 x11Context.fMask |= kGCForeground;
2980 x11Context.fForeground = foreground;
2984 void TGCocoa::ChangeGC(GContext_t gc, GCValues_t *gval)
2987 assert(gc <= fX11Contexts.size() && gc > 0 &&
"ChangeGC, invalid context id");
2988 assert(gval != 0 &&
"ChangeGC, gval parameter is null");
2990 GCValues_t &x11Context = fX11Contexts[gc - 1];
2991 const Mask_t &mask = gval->fMask;
2992 x11Context.fMask |= mask;
2997 if (mask & kGCFunction)
2998 x11Context.fFunction = gval->fFunction;
2999 if (mask & kGCPlaneMask)
3000 x11Context.fPlaneMask = gval->fPlaneMask;
3001 if (mask & kGCForeground)
3002 x11Context.fForeground = gval->fForeground;
3003 if (mask & kGCBackground)
3004 x11Context.fBackground = gval->fBackground;
3005 if (mask & kGCLineWidth)
3006 x11Context.fLineWidth = gval->fLineWidth;
3007 if (mask & kGCLineStyle)
3008 x11Context.fLineStyle = gval->fLineStyle;
3009 if (mask & kGCCapStyle)
3010 x11Context.fCapStyle = gval->fCapStyle;
3011 if (mask & kGCJoinStyle)
3012 x11Context.fJoinStyle = gval->fJoinStyle;
3013 if (mask & kGCFillRule)
3014 x11Context.fFillRule = gval->fFillRule;
3015 if (mask & kGCArcMode)
3016 x11Context.fArcMode = gval->fArcMode;
3017 if (mask & kGCFillStyle)
3018 x11Context.fFillStyle = gval->fFillStyle;
3020 x11Context.fTile = gval->fTile;
3021 if (mask & kGCStipple)
3022 x11Context.fStipple = gval->fStipple;
3023 if (mask & kGCTileStipXOrigin)
3024 x11Context.fTsXOrigin = gval->fTsXOrigin;
3025 if (mask & kGCTileStipYOrigin)
3026 x11Context.fTsYOrigin = gval->fTsYOrigin;
3028 x11Context.fFont = gval->fFont;
3029 if (mask & kGCSubwindowMode)
3030 x11Context.fSubwindowMode = gval->fSubwindowMode;
3031 if (mask & kGCGraphicsExposures)
3032 x11Context.fGraphicsExposures = gval->fGraphicsExposures;
3033 if (mask & kGCClipXOrigin)
3034 x11Context.fClipXOrigin = gval->fClipXOrigin;
3035 if (mask & kGCClipYOrigin)
3036 x11Context.fClipYOrigin = gval->fClipYOrigin;
3037 if (mask & kGCClipMask)
3038 x11Context.fClipMask = gval->fClipMask;
3039 if (mask & kGCDashOffset)
3040 x11Context.fDashOffset = gval->fDashOffset;
3041 if (mask & kGCDashList) {
3042 const unsigned nDashes =
sizeof x11Context.fDashes /
sizeof x11Context.fDashes[0];
3043 for (
unsigned i = 0; i < nDashes; ++i)
3044 x11Context.fDashes[i] = gval->fDashes[i];
3045 x11Context.fDashLen = gval->fDashLen;
3050 void TGCocoa::CopyGC(GContext_t src, GContext_t dst, Mask_t mask)
3052 assert(src <= fX11Contexts.size() && src > 0 &&
"CopyGC, bad source context");
3053 assert(dst <= fX11Contexts.size() && dst > 0 &&
"CopyGC, bad destination context");
3055 GCValues_t srcContext = fX11Contexts[src - 1];
3056 srcContext.fMask = mask;
3058 ChangeGC(dst, &srcContext);
3062 void TGCocoa::GetGCValues(GContext_t gc, GCValues_t &gval)
3066 const GCValues_t &gcVal = fX11Contexts[gc - 1];
3071 void TGCocoa::DeleteGC(GContext_t )
3076 #pragma mark - Cursor management.
3079 Cursor_t TGCocoa::CreateCursor(ECursor cursor)
3090 return Cursor_t(cursor + 1);
3094 void TGCocoa::SetCursor(Int_t wid, ECursor cursor)
3098 assert(!fPimpl->IsRootWindow(wid) &&
"SetCursor, called for root window");
3100 NSView<X11Window> *
const view = fPimpl->GetWindow(wid).fContentView;
3101 view.fCurrentCursor = cursor;
3105 void TGCocoa::SetCursor(Window_t wid, Cursor_t cursorID)
3110 SetCursor(Int_t(wid), ECursor(cursorID - 1));
3112 SetCursor(Int_t(wid), kPointer);
3116 void TGCocoa::QueryPointer(Int_t &x, Int_t &y)
3121 const NSPoint screenPoint = [NSEvent mouseLocation];
3122 x = X11::GlobalXCocoaToROOT(screenPoint.x);
3123 y = X11::GlobalYCocoaToROOT(screenPoint.y);
3127 void TGCocoa::QueryPointer(Window_t winID, Window_t &rootWinID, Window_t &childWinID,
3128 Int_t &rootX, Int_t &rootY, Int_t &winX, Int_t &winY, UInt_t &mask)
3137 rootWinID = fPimpl->GetRootWindowID();
3139 NSPoint screenPoint = [NSEvent mouseLocation];
3140 screenPoint.x = X11::GlobalXCocoaToROOT(screenPoint.x);
3141 screenPoint.y = X11::GlobalYCocoaToROOT(screenPoint.y);
3142 rootX = screenPoint.x;
3143 rootY = screenPoint.y;
3146 if (winID > fPimpl->GetRootWindowID()) {
3147 NSObject<X11Window> *
const window = fPimpl->GetWindow(winID);
3148 const NSPoint winPoint = X11::TranslateFromScreen(screenPoint, window.fContentView);
3152 winX = screenPoint.x;
3153 winY = screenPoint.y;
3157 if (QuartzWindow *
const childWin = X11::FindWindowInPoint(screenPoint.x, screenPoint.y)) {
3158 childWinID = childWin.fID;
3159 mask = X11::GetModifiers();
3166 #pragma mark - OpenGL management.
3169 Double_t TGCocoa::GetOpenGLScalingFactor()
3174 return [[NSScreen mainScreen] backingScaleFactor];
3178 Window_t TGCocoa::CreateOpenGLWindow(Window_t parentID, UInt_t width, UInt_t height,
3179 const std::vector<std::pair<UInt_t, Int_t> > &formatComponents)
3183 typedef std::pair<UInt_t, Int_t> component_type;
3184 typedef std::vector<component_type>::size_type size_type;
3187 std::vector<NSOpenGLPixelFormatAttribute> attribs;
3188 for (size_type i = 0, e = formatComponents.size(); i < e; ++i) {
3189 const component_type &comp = formatComponents[i];
3191 if (comp.first == Rgl::kDoubleBuffer) {
3192 attribs.push_back(NSOpenGLPFADoubleBuffer);
3193 }
else if (comp.first == Rgl::kDepth) {
3194 attribs.push_back(NSOpenGLPFADepthSize);
3195 attribs.push_back(comp.second > 0 ? comp.second : 32);
3196 }
else if (comp.first == Rgl::kAccum) {
3197 attribs.push_back(NSOpenGLPFAAccumSize);
3198 attribs.push_back(comp.second > 0 ? comp.second : 1);
3199 }
else if (comp.first == Rgl::kStencil) {
3200 attribs.push_back(NSOpenGLPFAStencilSize);
3201 attribs.push_back(comp.second > 0 ? comp.second : 8);
3202 }
else if (comp.first == Rgl::kMultiSample) {
3203 attribs.push_back(NSOpenGLPFAMultisample);
3204 attribs.push_back(NSOpenGLPFASampleBuffers);
3205 attribs.push_back(1);
3206 attribs.push_back(NSOpenGLPFASamples);
3207 attribs.push_back(comp.second ? comp.second : 8);
3211 attribs.push_back(0);
3213 NSOpenGLPixelFormat *
const pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes : &attribs[0]];
3214 const Util::NSScopeGuard<NSOpenGLPixelFormat> formatGuard(pixelFormat);
3216 NSView<X11Window> *parentView = nil;
3217 if (!fPimpl->IsRootWindow(parentID)) {
3218 parentView = fPimpl->GetWindow(parentID).fContentView;
3219 assert([parentView isKindOfClass : [QuartzView
class]] &&
3220 "CreateOpenGLWindow, parent view must be QuartzView");
3223 NSRect viewFrame = {};
3224 viewFrame.size.width = width;
3225 viewFrame.size.height = height;
3227 ROOTOpenGLView *
const glView = [[ROOTOpenGLView alloc] initWithFrame : viewFrame pixelFormat : pixelFormat];
3228 const Util::NSScopeGuard<ROOTOpenGLView> viewGuard(glView);
3230 Window_t glID = kNone;
3233 [parentView addChild : glView];
3234 glID = fPimpl->RegisterDrawable(glView);
3239 QuartzWindow *parent = [[QuartzWindow alloc] initWithGLView : glView];
3240 const Util::NSScopeGuard<QuartzWindow> winGuard(parent);
3244 Error(
"CreateOpenGLWindow",
"QuartzWindow allocation/initialization"
3245 " failed for a top-level GL widget");
3249 glID = fPimpl->RegisterDrawable(parent);
3257 Handle_t TGCocoa::CreateOpenGLContext(Window_t windowID, Handle_t sharedID)
3259 assert(!fPimpl->IsRootWindow(windowID) &&
3260 "CreateOpenGLContext, parameter 'windowID' is a root window");
3261 assert([fPimpl->GetWindow(windowID).fContentView isKindOfClass : [ROOTOpenGLView class]] &&
3262 "CreateOpenGLContext, view is not an OpenGL view");
3264 NSOpenGLContext *
const sharedContext = fPimpl->GetGLContextForHandle(sharedID);
3265 ROOTOpenGLView *
const glView = (ROOTOpenGLView *)fPimpl->GetWindow(windowID);
3267 const Util::NSScopeGuard<NSOpenGLContext>
3268 newContext([[NSOpenGLContext alloc] initWithFormat : glView.pixelFormat shareContext : sharedContext]);
3269 glView.fOpenGLContext = newContext.Get();
3270 const Handle_t ctxID = fPimpl->RegisterGLContext(newContext.Get());
3276 void TGCocoa::CreateOpenGLContext(Int_t )
3282 Bool_t TGCocoa::MakeOpenGLContextCurrent(Handle_t ctxID, Window_t windowID)
3284 using namespace Details;
3286 assert(ctxID > 0 &&
"MakeOpenGLContextCurrent, invalid context id");
3288 NSOpenGLContext *
const glContext = fPimpl->GetGLContextForHandle(ctxID);
3290 Error(
"MakeOpenGLContextCurrent",
"No OpenGL context found for id %d",
int(ctxID));
3295 ROOTOpenGLView *
const glView = (ROOTOpenGLView *)fPimpl->GetWindow(windowID).fContentView;
3297 if (OpenGL::GLViewIsValidDrawable(glView)) {
3298 if ([glContext view] != glView)
3299 [glContext setView : glView];
3301 if (glView.fUpdateContext) {
3303 glView.fUpdateContext = NO;
3306 glView.fOpenGLContext = glContext;
3307 [glContext makeCurrentContext];
3318 NSView *fakeView = nil;
3319 QuartzWindow *fakeWindow = fPimpl->GetFakeGLWindow();
3323 SetWindowAttributes_t attr = {};
3325 const UInt_t width = std::max(glView.frame.size.width, CGFloat(100));
3326 const UInt_t height = std::max(glView.frame.size.height, CGFloat(100));
3328 NSRect viewFrame = {};
3329 viewFrame.size.width = width;
3330 viewFrame.size.height = height;
3332 const NSUInteger styleMask = kTitledWindowMask | kClosableWindowMask |
3333 kMiniaturizableWindowMask | kResizableWindowMask;
3336 fakeWindow = [[QuartzWindow alloc] initWithContentRect : viewFrame styleMask : styleMask
3337 backing : NSBackingStoreBuffered defer : NO windowAttributes : &attr];
3338 Util::NSScopeGuard<QuartzWindow> winGuard(fakeWindow);
3340 fakeView = fakeWindow.fContentView;
3341 [fakeView setHidden : NO];
3343 fPimpl->SetFakeGLWindow(fakeWindow);
3346 fakeView = fakeWindow.fContentView;
3347 [fakeView setHidden : NO];
3350 glView.fOpenGLContext = nil;
3351 [glContext setView : fakeView];
3352 [glContext makeCurrentContext];
3359 Handle_t TGCocoa::GetCurrentOpenGLContext()
3361 NSOpenGLContext *
const currentContext = [NSOpenGLContext currentContext];
3362 if (!currentContext) {
3363 Error(
"GetCurrentOpenGLContext",
"The current OpenGL context is null");
3367 const Handle_t contextID = fPimpl->GetHandleForGLContext(currentContext);
3369 Error(
"GetCurrentOpenGLContext",
"The current OpenGL context was"
3370 " not created/registered by TGCocoa");
3376 void TGCocoa::FlushOpenGLBuffer(Handle_t ctxID)
3378 assert(ctxID > 0 &&
"FlushOpenGLBuffer, invalid context id");
3380 NSOpenGLContext *
const glContext = fPimpl->GetGLContextForHandle(ctxID);
3381 assert(glContext != nil &&
"FlushOpenGLBuffer, bad context id");
3383 if (glContext != [NSOpenGLContext currentContext])
3387 [glContext flushBuffer];
3391 void TGCocoa::DeleteOpenGLContext(Int_t ctxID)
3396 NSOpenGLContext *
const glContext = fPimpl->GetGLContextForHandle(ctxID);
3397 if (NSView *
const v = [glContext view]) {
3398 if ([v isKindOfClass : [ROOTOpenGLView
class]])
3399 ((ROOTOpenGLView *)v).fOpenGLContext = nil;
3401 [glContext clearDrawable];
3404 if (glContext == [NSOpenGLContext currentContext])
3405 [NSOpenGLContext clearCurrentContext];
3407 fPimpl->DeleteGLContext(ctxID);
3410 #pragma mark - Off-screen rendering for TPad/TCanvas.
3413 void TGCocoa::SetDoubleBuffer(Int_t windowID, Int_t mode)
3416 assert(windowID > (Int_t)fPimpl->GetRootWindowID() &&
"SetDoubleBuffer called for root window");
3418 if (windowID == 999) {
3419 Warning(
"SetDoubleBuffer",
"called with wid == 999");
3422 fSelectedDrawable = windowID;
3423 mode ? SetDoubleBufferON() : SetDoubleBufferOFF();
3428 void TGCocoa::SetDoubleBufferOFF()
3434 void TGCocoa::SetDoubleBufferON()
3437 fDirectDraw =
false;
3439 assert(fSelectedDrawable > fPimpl->GetRootWindowID() &&
3440 "SetDoubleBufferON, called, but no correct window was selected before");
3442 NSObject<X11Window> *
const window = fPimpl->GetWindow(fSelectedDrawable);
3444 assert(window.fIsPixmap == NO &&
3445 "SetDoubleBufferON, selected drawable is a pixmap, can not attach pixmap to pixmap");
3447 const unsigned currW = window.fWidth;
3448 const unsigned currH = window.fHeight;
3450 if (QuartzPixmap *
const currentPixmap = window.fBackBuffer) {
3451 if (currH == currentPixmap.fHeight && currW == currentPixmap.fWidth)
3455 Util::NSScopeGuard<QuartzPixmap> pixmap([[QuartzPixmap alloc] initWithW : currW
3456 H : currH scaleFactor : [[NSScreen mainScreen] backingScaleFactor]]);
3458 window.fBackBuffer = pixmap.Get();
3461 Error(
"SetDoubleBufferON",
"QuartzPixmap initialization failed");
3465 void TGCocoa::SetDrawMode(EDrawMode mode)
3473 #pragma mark - Event management part.
3476 void TGCocoa::SendEvent(Window_t wid, Event_t *event)
3478 if (fPimpl->IsRootWindow(wid))
3485 Event_t newEvent = *event;
3486 newEvent.fWindow = wid;
3487 fPimpl->fX11EventTranslator.fEventQueue.push_back(newEvent);
3491 void TGCocoa::NextEvent(Event_t &event)
3493 assert(fPimpl->fX11EventTranslator.fEventQueue.size() > 0 &&
"NextEvent, event queue is empty");
3495 event = fPimpl->fX11EventTranslator.fEventQueue.front();
3496 fPimpl->fX11EventTranslator.fEventQueue.pop_front();
3500 Int_t TGCocoa::EventsPending()
3502 return (Int_t)fPimpl->fX11EventTranslator.fEventQueue.size();
3507 Bool_t TGCocoa::CheckEvent(Window_t windowID, EGEventType type, Event_t &event)
3509 typedef X11::EventQueue_t::iterator iterator_type;
3511 iterator_type it = fPimpl->fX11EventTranslator.fEventQueue.begin();
3512 iterator_type eIt = fPimpl->fX11EventTranslator.fEventQueue.end();
3514 for (; it != eIt; ++it) {
3515 const Event_t &queuedEvent = *it;
3516 if (queuedEvent.fWindow == windowID && queuedEvent.fType == type) {
3517 event = queuedEvent;
3518 fPimpl->fX11EventTranslator.fEventQueue.erase(it);
3527 Handle_t TGCocoa::GetNativeEvent()
const
3534 #pragma mark - "Drag and drop", "Copy and paste", X11 properties.
3537 Atom_t TGCocoa::InternAtom(
const char *name, Bool_t onlyIfExist)
3541 assert(name != 0 &&
"InternAtom, parameter 'name' is null");
3542 return FindAtom(name, !onlyIfExist);
3546 void TGCocoa::SetPrimarySelectionOwner(Window_t windowID)
3558 assert(!fPimpl->IsRootWindow(windowID) &&
3559 "SetPrimarySelectionOwner, windowID parameter is a 'root' window");
3560 assert(fPimpl->GetDrawable(windowID).fIsPixmap == NO &&
3561 "SetPrimarySelectionOwner, windowID parameter is not a valid window");
3563 const Atom_t primarySelectionAtom = FindAtom(
"XA_PRIMARY",
false);
3564 assert(primarySelectionAtom != kNone &&
3565 "SetPrimarySelectionOwner, predefined XA_PRIMARY atom was not found");
3567 fSelectionOwners[primarySelectionAtom] = windowID;
3572 Bool_t TGCocoa::SetSelectionOwner(Window_t windowID, Atom_t &selection)
3583 assert(!fPimpl->IsRootWindow(windowID) &&
3584 "SetSelectionOwner, windowID parameter is a 'root' window'");
3585 assert(fPimpl->GetDrawable(windowID).fIsPixmap == NO &&
3586 "SetSelectionOwner, windowID parameter is not a valid window");
3588 fSelectionOwners[selection] = windowID;
3595 Window_t TGCocoa::GetPrimarySelectionOwner()
3601 const Atom_t primarySelectionAtom = FindAtom(
"XA_PRIMARY",
false);
3602 assert(primarySelectionAtom != kNone &&
3603 "GetPrimarySelectionOwner, predefined XA_PRIMARY atom was not found");
3605 return fSelectionOwners[primarySelectionAtom];
3609 void TGCocoa::ConvertPrimarySelection(Window_t windowID, Atom_t clipboard, Time_t when)
3626 assert(!fPimpl->IsRootWindow(windowID) &&
3627 "ConvertPrimarySelection, parameter 'windowID' is root window");
3628 assert(fPimpl->GetDrawable(windowID).fIsPixmap == NO &&
3629 "ConvertPrimarySelection, parameter windowID parameter is not a window id");
3631 Atom_t primarySelectionAtom = FindAtom(
"XA_PRIMARY",
false);
3632 assert(primarySelectionAtom != kNone &&
3633 "ConvertPrimarySelection, XA_PRIMARY predefined atom not found");
3635 Atom_t stringAtom = FindAtom(
"XA_STRING",
false);
3636 assert(stringAtom != kNone &&
3637 "ConvertPrimarySelection, XA_STRING predefined atom not found");
3639 ConvertSelection(windowID, primarySelectionAtom, stringAtom, clipboard, when);
3643 void TGCocoa::ConvertSelection(Window_t windowID, Atom_t &selection, Atom_t &target,
3644 Atom_t &property, Time_t &)
3655 assert(!fPimpl->IsRootWindow(windowID) &&
3656 "ConvertSelection, parameter 'windowID' is root window'");
3657 assert(fPimpl->GetDrawable(windowID).fIsPixmap == NO &&
3658 "ConvertSelection, parameter 'windowID' is not a window id");
3660 Event_t newEvent = {};
3661 selection_iterator selIter = fSelectionOwners.find(selection);
3663 if (selIter != fSelectionOwners.end())
3664 newEvent.fType = kSelectionRequest;
3666 newEvent.fType = kSelectionNotify;
3668 newEvent.fWindow = windowID;
3669 newEvent.fUser[0] = windowID;
3670 newEvent.fUser[1] = selection;
3671 newEvent.fUser[2] = target;
3672 newEvent.fUser[3] = property;
3674 SendEvent(windowID, &newEvent);
3678 Int_t TGCocoa::GetProperty(Window_t windowID, Atom_t propertyID, Long_t, Long_t, Bool_t, Atom_t,
3679 Atom_t *actualType, Int_t *actualFormat, ULong_t *nItems,
3680 ULong_t *bytesAfterReturn,
unsigned char **propertyReturn)
3689 if (fPimpl->IsRootWindow(windowID))
3692 assert(fPimpl->GetDrawable(windowID).fIsPixmap == NO &&
3693 "GetProperty, parameter 'windowID' is not a valid window id");
3694 assert(propertyID > 0 && propertyID <= fAtomToName.size() &&
3695 "GetProperty, parameter 'propertyID' is not a valid atom");
3696 assert(actualType != 0 &&
"GetProperty, parameter 'actualType' is null");
3697 assert(actualFormat != 0 &&
"GetProperty, parameter 'actualFormat' is null");
3698 assert(bytesAfterReturn != 0 &&
"GetProperty, parameter 'bytesAfterReturn' is null");
3699 assert(propertyReturn != 0 &&
"GetProperty, parameter 'propertyReturn' is null");
3701 const Util::AutoreleasePool pool;
3703 *bytesAfterReturn = 0;
3704 *propertyReturn = 0;
3707 const std::string &atomName = fAtomToName[propertyID - 1];
3708 NSObject<X11Window> *window = fPimpl->GetWindow(windowID);
3710 if (![window hasProperty : atomName.c_str()]) {
3711 Error(
"GetProperty",
"Unknown property %s requested", atomName.c_str());
3715 unsigned tmpFormat = 0, tmpElements = 0;
3716 *propertyReturn = [window getProperty : atomName.c_str() returnType : actualType
3717 returnFormat : &tmpFormat nElements : &tmpElements];
3718 *actualFormat = (Int_t)tmpFormat;
3719 *nItems = tmpElements;
3725 void TGCocoa::GetPasteBuffer(Window_t windowID, Atom_t propertyID, TString &text,
3726 Int_t &nChars, Bool_t clearBuffer)
3738 assert(!fPimpl->IsRootWindow(windowID) &&
3739 "GetPasteBuffer, parameter 'windowID' is root window");
3740 assert(fPimpl->GetDrawable(windowID).fIsPixmap == NO &&
3741 "GetPasteBuffer, parameter 'windowID' is not a valid window");
3742 assert(propertyID && propertyID <= fAtomToName.size() &&
3743 "GetPasteBuffer, parameter 'propertyID' is not a valid atom");
3745 const Util::AutoreleasePool pool;
3747 const std::string &atomString = fAtomToName[propertyID - 1];
3748 NSObject<X11Window> *window = fPimpl->GetWindow(windowID);
3750 if (![window hasProperty : atomString.c_str()]) {
3751 Error(
"GetPasteBuffer",
"No property %s on a window", atomString.c_str());
3756 unsigned tmpFormat = 0, nElements = 0;
3758 const Util::ScopedArray<char>
3759 propertyData((
char *)[window getProperty : atomString.c_str()
3760 returnType : &tmpType returnFormat : &tmpFormat
3761 nElements : &nElements]);
3763 assert(tmpFormat == 8 &&
"GetPasteBuffer, property has wrong format");
3765 text.Insert(0, propertyData.Get(), nElements);
3766 nChars = (Int_t)nElements;
3771 [window removeProperty : atomString.c_str()];
3776 void TGCocoa::ChangeProperty(Window_t windowID, Atom_t propertyID, Atom_t type,
3777 UChar_t *data, Int_t len)
3802 assert(!fPimpl->IsRootWindow(windowID) &&
3803 "ChangeProperty, parameter 'windowID' is root window");
3804 assert(fPimpl->GetDrawable(windowID).fIsPixmap == NO &&
3805 "ChangeProperty, parameter 'windowID' is not a valid window id");
3806 assert(propertyID && propertyID <= fAtomToName.size() &&
3807 "ChangeProperty, parameter 'propertyID' is not a valid atom");
3809 const Util::AutoreleasePool pool;
3811 const std::string &atomString = fAtomToName[propertyID - 1];
3813 NSObject<X11Window> *
const window = fPimpl->GetWindow(windowID);
3814 [window setProperty : atomString.c_str() data : data size : len forType : type format : 8];
3819 void TGCocoa::ChangeProperties(Window_t windowID, Atom_t propertyID, Atom_t type,
3820 Int_t format, UChar_t *data, Int_t len)
3836 assert(!fPimpl->IsRootWindow(windowID) &&
3837 "ChangeProperties, parameter 'windowID' is root window");
3838 assert(fPimpl->GetDrawable(windowID).fIsPixmap == NO &&
3839 "ChangeProperties, parameter 'windowID' is not a valid window id");
3840 assert(propertyID && propertyID <= fAtomToName.size() &&
3841 "ChangeProperties, parameter 'propertyID' is not a valid atom");
3843 const Util::AutoreleasePool pool;
3845 const std::string &atomName = fAtomToName[propertyID - 1];
3847 NSObject<X11Window> *
const window = fPimpl->GetWindow(windowID);
3848 [window setProperty : atomName.c_str() data : data
3849 size : len forType : type format : format];
3854 void TGCocoa::DeleteProperty(Window_t windowID, Atom_t &propertyID)
3866 assert(!fPimpl->IsRootWindow(windowID) &&
3867 "DeleteProperty, parameter 'windowID' is root window");
3868 assert(fPimpl->GetDrawable(windowID).fIsPixmap == NO &&
3869 "DeleteProperty, parameter 'windowID' is not a valid window");
3870 assert(propertyID && propertyID <= fAtomToName.size() &&
3871 "DeleteProperty, parameter 'propertyID' is not a valid atom");
3873 const std::string &atomString = fAtomToName[propertyID - 1];
3874 [fPimpl->GetWindow(windowID) removeProperty : atomString.c_str()];
3878 void TGCocoa::SetDNDAware(Window_t windowID, Atom_t *typeList)
3890 assert(windowID > fPimpl->GetRootWindowID() &&
3891 "SetDNDAware, parameter 'windowID' is not a valid window id");
3892 assert(fPimpl->GetDrawable(windowID).fIsPixmap == NO &&
3893 "SetDNDAware, parameter 'windowID' is not a window");
3895 const Util::AutoreleasePool pool;
3897 QuartzView *
const view = (QuartzView *)fPimpl->GetWindow(windowID).fContentView;
3898 NSArray *
const supportedTypes = [NSArray arrayWithObjects : NSFilenamesPboardType, nil];
3902 [view registerForDraggedTypes : supportedTypes];
3904 view.fIsDNDAware = YES;
3906 FindAtom(
"XdndAware",
true);
3907 const Atom_t xaAtomAtom = FindAtom(
"XA_ATOM",
false);
3909 assert(xaAtomAtom == 4 &&
"SetDNDAware, XA_ATOM is not defined");
3914 assert(
sizeof(
unsigned) == 4 &&
"SetDNDAware, sizeof(unsigned) must be 4");
3916 std::vector<unsigned> propertyData;
3917 propertyData.push_back(4);
3920 for (
unsigned i = 0; typeList[i]; ++i)
3921 propertyData.push_back(unsigned(typeList[i]));
3924 [view setProperty : "XdndAware" data : (unsigned char *)&propertyData[0]
3925 size : propertyData.size() forType : xaAtomAtom format : 32];
3929 Bool_t TGCocoa::IsDNDAware(Window_t windowID, Atom_t * )
3933 if (windowID <= fPimpl->GetRootWindowID())
3936 assert(fPimpl->GetDrawable(windowID).fIsPixmap == NO &&
3937 "IsDNDAware, windowID parameter is not a window");
3939 QuartzView *
const view = (QuartzView *)fPimpl->GetWindow(windowID).fContentView;
3940 return view.fIsDNDAware;
3944 void TGCocoa::SetTypeList(Window_t, Atom_t, Atom_t *)
3948 ::Warning(
"SetTypeList",
"Not implemented");
3952 Window_t TGCocoa::FindRWindow(Window_t winID, Window_t dragWinID, Window_t inputWinID,
int x,
int y,
int maxDepth)
3971 NSView<X11Window> *
const testView = X11::FindDNDAwareViewInPoint(
3972 fPimpl->IsRootWindow(winID) ? nil : fPimpl->GetWindow(winID).fContentView,
3973 dragWinID, inputWinID, x, y, maxDepth);
3975 return testView.fID;
3980 #pragma mark - Noops.
3983 UInt_t TGCocoa::ExecCommand(TGWin32Command * )
3990 Int_t TGCocoa::GetDoubleBuffer(Int_t )
3997 void TGCocoa::GetCharacterUp(Float_t &chupx, Float_t &chupy)
4000 chupx = chupy = 0.f;
4004 Pixmap_t TGCocoa::ReadGIF(Int_t , Int_t ,
const char * , Window_t )
4013 Int_t TGCocoa::RequestLocator(Int_t , Int_t , Int_t &, Int_t &)
4045 Int_t TGCocoa::RequestString(Int_t , Int_t ,
char * )
4056 void TGCocoa::SetCharacterUp(Float_t , Float_t )
4062 void TGCocoa::SetClipOFF(Int_t )
4068 void TGCocoa::SetClipRegion(Int_t , Int_t , Int_t , UInt_t , UInt_t )
4079 void TGCocoa::SetTextMagnitude(Float_t )
4085 void TGCocoa::Sync(Int_t )
4094 void TGCocoa::Warp(Int_t ix, Int_t iy, Window_t winID)
4105 NSPoint newCursorPosition = {};
4106 newCursorPosition.x = ix;
4107 newCursorPosition.y = iy;
4109 if (fPimpl->GetRootWindowID() == winID) {
4111 newCursorPosition.x = X11::GlobalXROOTToCocoa(newCursorPosition.x);
4113 assert(fPimpl->GetDrawable(winID).fIsPixmap == NO &&
4114 "Warp, drawable is not a window");
4115 newCursorPosition = X11::TranslateToScreen(fPimpl->GetWindow(winID).fContentView,
4119 CGWarpMouseCursorPosition(NSPointToCGPoint(newCursorPosition));
4123 Int_t TGCocoa::WriteGIF(
char * )
4132 void TGCocoa::WritePixmap(Int_t , UInt_t , UInt_t ,
char * )
4142 Bool_t TGCocoa::NeedRedraw(ULong_t , Bool_t )
4162 Bool_t TGCocoa::CreatePictureFromFile(Drawable_t ,
4166 PictureAttributes_t &)
4177 Bool_t TGCocoa::CreatePictureFromData(Drawable_t ,
char ** ,
4180 PictureAttributes_t & )
4190 Bool_t TGCocoa::ReadPictureDataFromFile(
const char * ,
char *** )
4199 void TGCocoa::DeletePictureData(
void * )
4205 void TGCocoa::SetDashes(GContext_t , Int_t ,
const char * , Int_t )
4224 void TGCocoa::Bell(Int_t )
4230 void TGCocoa::WMDeleteNotify(Window_t )
4236 void TGCocoa::SetClipRectangles(GContext_t , Int_t , Int_t ,
4237 Rectangle_t * , Int_t )
4246 Region_t TGCocoa::CreateRegion()
4254 void TGCocoa::DestroyRegion(Region_t )
4260 void TGCocoa::UnionRectWithRegion(Rectangle_t * , Region_t , Region_t )
4271 Region_t TGCocoa::PolygonRegion(Point_t * , Int_t , Bool_t )
4283 void TGCocoa::UnionRegion(Region_t , Region_t , Region_t )
4294 void TGCocoa::IntersectRegion(Region_t , Region_t , Region_t )
4304 void TGCocoa::SubtractRegion(Region_t , Region_t , Region_t )
4310 void TGCocoa::XorRegion(Region_t , Region_t , Region_t )
4322 Bool_t TGCocoa::EmptyRegion(Region_t )
4330 Bool_t TGCocoa::PointInRegion(Int_t , Int_t , Region_t )
4338 Bool_t TGCocoa::EqualRegion(Region_t , Region_t )
4346 void TGCocoa::GetRegionBox(Region_t , Rectangle_t * )
4351 #pragma mark - Details and aux. functions.
4354 ROOT::MacOSX::X11::EventTranslator *TGCocoa::GetEventTranslator()
const
4356 return &fPimpl->fX11EventTranslator;
4360 ROOT::MacOSX::X11::CommandBuffer *TGCocoa::GetCommandBuffer()
const
4362 return &fPimpl->fX11CommandBuffer;
4366 void TGCocoa::CocoaDrawON()
4372 void TGCocoa::CocoaDrawOFF()
4374 assert(fCocoaDraw > 0 &&
"CocoaDrawOFF, was already off");
4379 bool TGCocoa::IsCocoaDraw()
const
4381 return bool(fCocoaDraw);
4385 void *TGCocoa::GetCurrentContext()
4387 NSObject<X11Drawable> *
const drawable = fPimpl->GetDrawable(fSelectedDrawable);
4388 if (!drawable.fIsPixmap) {
4389 Error(
"GetCurrentContext",
"TCanvas/TPad's internal error,"
4390 " selected drawable is not a pixmap!");
4394 return drawable.fContext;
4398 bool TGCocoa::MakeProcessForeground()
4406 if (!fForegroundProcess) {
4407 ProcessSerialNumber psn = {0, kCurrentProcess};
4409 const OSStatus res1 = TransformProcessType(&psn, kProcessTransformToForegroundApplication);
4414 if (res1 != noErr && res1 != paramErr) {
4415 Error(
"MakeProcessForeground",
"TransformProcessType failed with code %d",
int(res1));
4418 #ifdef MAC_OS_X_VERSION_10_9
4420 [[NSApplication sharedApplication] activateIgnoringOtherApps : YES];
4422 const OSErr res2 = SetFrontProcess(&psn);
4423 if (res2 != noErr) {
4424 Error(
"MakeProcessForeground",
"SetFrontProcess failed with code %d", res2);
4429 fForegroundProcess =
true;
4431 #ifdef MAC_OS_X_VERSION_10_9
4433 [[NSApplication sharedApplication] activateIgnoringOtherApps : YES];
4435 ProcessSerialNumber psn = {};
4437 OSErr res = GetCurrentProcess(&psn);
4439 Error(
"MakeProcessForeground",
"GetCurrentProcess failed with code %d", res);
4443 res = SetFrontProcess(&psn);
4445 Error(
"MapProcessForeground",
"SetFrontProcess failed with code %d", res);
4455 Atom_t TGCocoa::FindAtom(
const std::string &atomName,
bool addIfNotFound)
4457 const std::map<std::string, Atom_t>::const_iterator it = fNameToAtom.find(atomName);
4459 if (it != fNameToAtom.end())
4461 else if (addIfNotFound) {
4463 fAtomToName.push_back(atomName);
4464 fNameToAtom[atomName] = Atom_t(fAtomToName.size());
4466 return Atom_t(fAtomToName.size());
4473 void TGCocoa::SetApplicationIcon()
4476 const char *
const iconDirectoryPath = gEnv->GetValue(
"Gui.IconPath",TROOT::GetIconPath());
4477 if (iconDirectoryPath) {
4478 const Util::ScopedArray<char> fileName(gSystem->Which(iconDirectoryPath,
"Root6Icon.png", kReadPermission));
4479 if (fileName.Get()) {
4480 const Util::AutoreleasePool pool;
4482 NSString *cocoaStr = [NSString stringWithCString : fileName.Get() encoding : NSASCIIStringEncoding];
4483 NSImage *image = [[[NSImage alloc] initWithContentsOfFile : cocoaStr] autorelease];
4484 [NSApp setApplicationIconImage : image];