16 #ifdef DEBUG_ROOT_COCOA
28 #include <Availability.h>
36 #include "RConfigure.h"
53 #pragma mark - Create a window or a view.
56 QuartzWindow *CreateTopLevelWindow(Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t , Int_t depth,
57 UInt_t clss,
void *, SetWindowAttributes_t *attr, UInt_t)
59 using namespace Details;
62 winRect.origin.x = GlobalXROOTToCocoa(x);
63 winRect.origin.y = GlobalYROOTToCocoa(y + h);
64 winRect.size.width = w;
65 winRect.size.height = h;
67 const NSUInteger styleMask = kTitledWindowMask | kClosableWindowMask |
68 kMiniaturizableWindowMask | kResizableWindowMask;
70 QuartzWindow *
const newWindow = [[QuartzWindow alloc] initWithContentRect : winRect
72 backing : NSBackingStoreBuffered
74 windowAttributes : attr];
76 throw std::runtime_error(
"CreateTopLevelWindow failed");
78 newWindow.fDepth = depth;
79 newWindow.fClass = clss;
85 QuartzView *CreateChildView(QuartzView * , Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t , Int_t ,
86 UInt_t ,
void * , SetWindowAttributes_t *attr, UInt_t )
89 viewRect.origin.x = x;
90 viewRect.origin.y = y;
91 viewRect.size.width = w;
92 viewRect.size.height = h;
94 QuartzView *
const view = [[QuartzView alloc] initWithFrame : viewRect windowAttributes : attr];
96 throw std::runtime_error(
"CreateChildView failed");
101 #pragma mark - root window (does not really exist, it's our desktop built of all screens).
104 void GetRootWindowAttributes(WindowAttributes_t *attr)
107 assert(attr != 0 &&
"GetRootWindowAttributes, parameter 'attr' is null");
110 NSArray *
const screens = [NSScreen screens];
111 assert(screens != nil &&
"screens array is nil");
112 NSScreen *
const mainScreen = [screens objectAtIndex : 0];
113 assert(mainScreen != nil &&
"screen with index 0 is nil");
115 *attr = WindowAttributes_t();
117 assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
118 "GetRootWindowAttributes, gVirtualX is either null or has a wrong type");
120 TGCocoa *
const gCocoa =
static_cast<TGCocoa *
>(gVirtualX);
122 const Rectangle &frame = gCocoa->GetDisplayGeometry();
126 attr->fWidth = frame.fWidth;
127 attr->fHeight = frame.fHeight;
128 attr->fBorderWidth = 0;
129 attr->fYourEventMask = 0;
130 attr->fAllEventMasks = 0;
132 attr->fDepth = NSBitsPerPixelFromDepth([mainScreen depth]);
138 #pragma mark - Coordinate conversions.
141 NSPoint ConvertPointFromBaseToScreen(NSWindow *window, NSPoint windowPoint)
143 assert(window != nil &&
"ConvertPointFromBaseToScreen, parameter 'window' is nil");
149 tmpRect.origin = windowPoint;
150 tmpRect.size = NSMakeSize(1., 1.);
151 tmpRect = [window convertRectToScreen : tmpRect];
153 return tmpRect.origin;
157 NSPoint ConvertPointFromScreenToBase(NSPoint screenPoint, NSWindow *window)
159 assert(window != nil &&
"ConvertPointFromScreenToBase, parameter 'window' is nil");
165 tmpRect.origin = screenPoint;
166 tmpRect.size = NSMakeSize(1., 1.);
167 tmpRect = [window convertRectFromScreen : tmpRect];
169 return tmpRect.origin;
173 int GlobalYCocoaToROOT(CGFloat yCocoa)
179 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
180 "GlobalYCocoaToROOT, gVirtualX is either nul or has a wrong type");
182 const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
184 return int(frame.fHeight - (yCocoa - frame.fY));
188 int GlobalXCocoaToROOT(CGFloat xCocoa)
190 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
191 "GlobalXCocoaToROOT, gVirtualX is either nul or has a wrong type");
192 const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
194 return int(xCocoa - frame.fX);
198 int GlobalYROOTToCocoa(CGFloat yROOT)
200 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
201 "GlobalYROOTToCocoa, gVirtualX is either nul or has a wrong type");
202 const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
204 return int(frame.fY + (frame.fHeight - yROOT));
208 int GlobalXROOTToCocoa(CGFloat xROOT)
210 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
211 "GlobalXROOTToCocoa, gVirtualX is either nul or has a wrong type");
212 const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
214 return int(frame.fX + xROOT);
218 int LocalYCocoaToROOT(NSView<X11Window> *parentView, CGFloat yCocoa)
220 assert(parentView != nil &&
"LocalYCocoaToROOT, parent view is nil");
222 return int(parentView.frame.size.height - yCocoa);
226 int LocalYROOTToCocoa(NSView<X11Window> *parentView, CGFloat yROOT)
229 assert(parentView != nil &&
"LocalYROOTToCocoa, parent view is nil");
231 return int(parentView.frame.size.height - yROOT);
236 int LocalYROOTToCocoa(NSObject<X11Drawable> *drawable, CGFloat yROOT)
239 assert(drawable != nil &&
"LocalYROOTToCocoa, drawable is nil");
241 return int(drawable.fHeight - yROOT);
245 NSPoint TranslateToScreen(NSView<X11Window> *from, NSPoint point)
247 assert(from != nil &&
"TranslateToScreen, parameter 'from' is nil");
249 const NSPoint winPoint = [from convertPoint : point toView : nil];
251 NSPoint screenPoint = ConvertPointFromBaseToScreen([from window], winPoint);
252 screenPoint.x = GlobalXCocoaToROOT(screenPoint.x);
253 screenPoint.y = GlobalYCocoaToROOT(screenPoint.y);
259 NSPoint TranslateFromScreen(NSPoint point, NSView<X11Window> *to)
261 assert(to != nil &&
"TranslateFromScreen, parameter 'to' is nil");
263 point.x = GlobalXROOTToCocoa(point.x);
264 point.y = GlobalYROOTToCocoa(point.y);
265 point = ConvertPointFromScreenToBase(point, [to window]);
267 return [to convertPoint : point fromView : nil];
271 NSPoint TranslateCoordinates(NSView<X11Window> *from, NSView<X11Window> *to, NSPoint sourcePoint)
274 assert(from != nil &&
"TranslateCoordinates, parameter 'from' is nil");
275 assert(to != nil &&
"TranslateCoordinates, parameter 'to' is nil");
277 if ([from window] == [to window]) {
279 return [to convertPoint : sourcePoint fromView : from];
287 const NSPoint win1Point = [from convertPoint : sourcePoint toView : nil];
288 const NSPoint screenPoint = ConvertPointFromBaseToScreen([from window], win1Point);
289 const NSPoint win2Point = ConvertPointFromScreenToBase(screenPoint, [to window]);
291 return [to convertPoint : win2Point fromView : nil];
296 bool ScreenPointIsInView(NSView<X11Window> *view, Int_t x, Int_t y)
298 assert(view != nil &&
"ScreenPointIsInView, parameter 'view' is nil");
301 point.x = x, point.y = y;
302 point = TranslateFromScreen(point, view);
303 const NSRect viewFrame = view.frame;
305 if (point.x < 0 || point.x > viewFrame.size.width)
307 if (point.y < 0 || point.y > viewFrame.size.height)
313 #pragma mark - Different FindView/Window functions iterating on the ROOT's windows/views.
316 QuartzWindow *FindWindowInPoint(Int_t x, Int_t y)
319 const Util::AutoreleasePool pool;
321 NSArray *
const orderedWindows = [NSApp orderedWindows];
322 for (NSWindow *window in orderedWindows) {
323 if (![window isKindOfClass : [QuartzWindow
class]])
325 QuartzWindow *
const qw = (QuartzWindow *)window;
329 if (ScreenPointIsInView(qw.fContentView, x, y))
337 NSView<X11Window> *FindDNDAwareViewInPoint(NSArray *children, Window_t dragWinID,
338 Window_t inputWinID, Int_t x, Int_t y, Int_t maxDepth)
340 assert(children != nil &&
"FindDNDAwareViewInPoint, parameter 'children' is nil");
345 NSEnumerator *
const reverseEnumerator = [children reverseObjectEnumerator];
346 for (NSView<X11Window> *child in reverseEnumerator) {
347 if (!ScreenPointIsInView(child, x, y))
349 if (child.fIsDNDAware && child.fID != dragWinID && child.fID != inputWinID)
352 NSView<X11Window> *
const testView = FindDNDAwareViewInPoint([child subviews], dragWinID,
353 inputWinID, x, y, maxDepth - 1);
362 NSView<X11Window> *FindDNDAwareViewInPoint(NSView *parentView, Window_t dragWinID, Window_t inputWinID,
363 Int_t x, Int_t y, Int_t maxDepth)
369 const Util::AutoreleasePool pool;
372 NSArray *
const orderedWindows = [NSApp orderedWindows];
373 for (NSWindow *window in orderedWindows) {
374 if (![window isKindOfClass : [QuartzWindow
class]])
376 QuartzWindow *
const qw = (QuartzWindow *)window;
381 if (qw.fMapState != kIsViewable)
385 NSView<X11Window> *testView = qw.fContentView;
386 if (!ScreenPointIsInView(testView, x, y))
389 if (testView.fIsDNDAware && testView.fID != dragWinID && testView.fID != inputWinID)
393 NSArray *
const children = [testView subviews];
394 testView = FindDNDAwareViewInPoint(children, dragWinID, inputWinID, x, y, maxDepth - 1);
403 return FindDNDAwareViewInPoint([parentView subviews], dragWinID, inputWinID, x, y, maxDepth);
408 QuartzWindow *FindWindowUnderPointer()
410 const Util::AutoreleasePool pool;
412 NSArray *
const orderedWindows = [NSApp orderedWindows];
413 for (NSWindow *nsWindow in orderedWindows) {
414 if (![nsWindow isKindOfClass : [QuartzWindow
class]])
417 QuartzWindow *
const qWindow = (QuartzWindow *)nsWindow;
419 if (qWindow.fIsDeleted)
422 if (qWindow.fMapState != kIsViewable)
425 const NSPoint mousePosition = [qWindow mouseLocationOutsideOfEventStream];
426 const NSSize windowSize = qWindow.frame.size;
427 if (mousePosition.x >= 0 && mousePosition.x <= windowSize.width &&
428 mousePosition.y >= 0 && mousePosition.y <= windowSize.height)
436 NSView<X11Window> *FindViewUnderPointer()
438 const Util::AutoreleasePool pool;
440 if (QuartzWindow *topLevel = FindWindowUnderPointer()) {
441 const NSPoint mousePosition = [topLevel mouseLocationOutsideOfEventStream];
442 return (NSView<X11Window> *)[[topLevel contentView] hitTest : mousePosition];
449 QuartzWindow *FindWindowForPointerEvent(NSEvent *pointerEvent)
455 assert(pointerEvent != nil &&
456 "FindWindowForPointerEvent, parameter 'pointerEvent' is nil");
458 const Util::AutoreleasePool pool;
460 NSArray *
const orderedWindows = [NSApp orderedWindows];
461 for (NSWindow *nsWindow in orderedWindows) {
462 if (![nsWindow isKindOfClass : [QuartzWindow
class]])
465 QuartzWindow *
const qWindow = (QuartzWindow *)nsWindow;
467 if (qWindow.fIsDeleted)
471 if (qWindow.fMapState != kIsViewable)
474 NSPoint mousePosition = [pointerEvent locationInWindow];
477 if ([pointerEvent window]) {
480 mousePosition = ConvertPointFromBaseToScreen([pointerEvent window], mousePosition);
485 mousePosition = ConvertPointFromScreenToBase(mousePosition, qWindow);
487 const NSSize windowSize = qWindow.frame.size;
488 if (mousePosition.x >= 0 && mousePosition.x <= windowSize.width &&
489 mousePosition.y >= 0 && mousePosition.y <= windowSize.height)
497 NSView<X11Window> *FindViewForPointerEvent(NSEvent *pointerEvent)
502 assert(pointerEvent != nil &&
503 "FindViewForPointerEvent, parameter 'pointerEvent' is nil");
505 const Util::AutoreleasePool pool;
507 if (QuartzWindow *topLevel = FindWindowForPointerEvent(pointerEvent)) {
508 NSPoint mousePosition = [pointerEvent locationInWindow];
509 if ([pointerEvent window])
510 mousePosition = ConvertPointFromBaseToScreen([pointerEvent window], mousePosition);
514 mousePosition = ConvertPointFromScreenToBase(mousePosition, topLevel);
516 return (NSView<X11Window> *)[[topLevel contentView] hitTest : mousePosition];
522 #pragma mark - Downscale image ("reading color bits" on retina macs).
525 std::vector<unsigned char> DownscaledImageData(
unsigned w,
unsigned h, CGImageRef image)
527 assert(w != 0 && h != 0 &&
"DownscaledImageData, invalid geometry");
528 assert(image !=
nullptr &&
"DonwscaledImageData, invalid parameter 'image'");
530 std::vector<unsigned char> result;
532 result.resize(w * h * 4);
533 }
catch (
const std::bad_alloc &) {
534 NSLog(
@"DownscaledImageData, memory allocation failed");
538 const Util::CFScopeGuard<CGColorSpaceRef> colorSpace(CGColorSpaceCreateDeviceRGB());
539 if (!colorSpace.Get()) {
540 NSLog(
@"DownscaledImageData, CGColorSpaceCreateDeviceRGB failed");
544 Util::CFScopeGuard<CGContextRef> ctx(CGBitmapContextCreateWithData(&result[0], w, h, 8,
545 w * 4, colorSpace.Get(),
546 kCGImageAlphaPremultipliedLast, NULL, 0));
548 NSLog(
@"DownscaledImageData, CGBitmapContextCreateWithData failed");
552 CGContextDrawImage(ctx.Get(), CGRectMake(0, 0, w, h), image);
557 #pragma mark - "Focus management" - just make another window key window.
560 void WindowLostFocus(Window_t winID)
563 if (![NSApp isActive])
566 const Util::AutoreleasePool pool;
568 NSArray *
const orderedWindows = [NSApp orderedWindows];
569 for (NSWindow *nsWindow in orderedWindows) {
570 if (![nsWindow isKindOfClass : [QuartzWindow
class]])
573 QuartzWindow *
const qWindow = (QuartzWindow *)nsWindow;
575 if (qWindow.fIsDeleted || qWindow.fMapState != kIsViewable || qWindow.fID == winID)
578 if (qWindow.fContentView.fOverrideRedirect)
581 [qWindow makeKeyAndOrderFront : qWindow];
586 #pragma mark - 'shape mask' - to create a window with arbitrary (probably non-rectangle) shape.
589 void ClipToShapeMask(NSView<X11Window> *view, CGContextRef ctx)
591 assert(view != nil &&
"ClipToShapeMask, parameter 'view' is nil");
592 assert(ctx != 0 &&
"ClipToShapeMask, parameter 'ctx' is null");
594 QuartzWindow *
const topLevelParent = view.fQuartzWindow;
595 assert(topLevelParent.fShapeCombineMask != nil &&
596 "ClipToShapeMask, fShapeCombineMask is nil on a top-level window");
597 assert(topLevelParent.fShapeCombineMask.fImage != 0 &&
598 "ClipToShapeMask, shape mask is null");
604 if (!view.fParentView) {
606 const CGRect clipRect = CGRectMake(0, 0, topLevelParent.fShapeCombineMask.fWidth,
607 topLevelParent.fShapeCombineMask.fHeight);
608 CGContextClipToMask(ctx, clipRect, topLevelParent.fShapeCombineMask.fImage);
610 NSRect clipRect = view.frame;
612 clipRect.origin = [view.fParentView convertPoint : clipRect.origin
613 toView : [view window].contentView];
614 clipRect.origin.y = X11::LocalYROOTToCocoa((NSView<X11Window> *)[view window].contentView,
615 clipRect.origin.y + clipRect.size.height);
617 if (AdjustCropArea(topLevelParent.fShapeCombineMask, clipRect)) {
618 const Util::CFScopeGuard<CGImageRef>
619 clipImageGuard(CGImageCreateWithImageInRect(topLevelParent.fShapeCombineMask.fImage,
620 NSRectToCGRect(clipRect)));
621 clipRect.origin = NSPoint();
622 CGContextClipToMask(ctx, NSRectToCGRect(clipRect), clipImageGuard.Get());
626 CGContextClipToRect(ctx, rect);
631 #pragma mark - Window's geometry and attributes.
634 void SetWindowAttributes(
const SetWindowAttributes_t *attr, NSObject<X11Window> *window)
636 assert(attr != 0 &&
"SetWindowAttributes, parameter 'attr' is null");
637 assert(window != nil &&
"SetWindowAttributes, parameter 'window' is nil");
639 const Mask_t mask = attr->fMask;
641 if (mask & kWABackPixel)
642 window.fBackgroundPixel = attr->fBackgroundPixel;
644 if (mask & kWAEventMask)
645 window.fEventMask = attr->fEventMask;
647 if (mask & kWABitGravity)
648 window.fBitGravity = attr->fBitGravity;
650 if (mask & kWAWinGravity)
651 window.fWinGravity = attr->fWinGravity;
653 if (mask & kWAOverrideRedirect) {
654 if ([(NSObject *)window isKindOfClass : [QuartzWindow
class]]) {
655 QuartzWindow *
const qw = (QuartzWindow *)window;
656 [qw setStyleMask : Details::kBorderlessWindowMask];
657 [qw setAlphaValue : 0.95];
660 window.fOverrideRedirect = YES;
665 void GetWindowGeometry(NSObject<X11Window> *win, WindowAttributes_t *dst)
667 assert(win != nil &&
"GetWindowGeometry, parameter 'win' is nil");
668 assert(dst != 0 &&
"GetWindowGeometry, parameter 'dst' is null");
673 dst->fWidth = win.fWidth;
674 dst->fHeight = win.fHeight;
678 void GetWindowAttributes(NSObject<X11Window> *window, WindowAttributes_t *dst)
680 assert(window != nil &&
"GetWindowAttributes, parameter 'window' is nil");
681 assert(dst != 0 &&
"GetWindowAttributes, parameter 'attr' is null");
683 *dst = WindowAttributes_t();
686 GetWindowGeometry(window, dst);
689 dst->fBorderWidth = 0;
690 dst->fDepth = window.fDepth;
695 dst->fClass = window.fClass;
696 dst->fBitGravity = window.fBitGravity;
697 dst->fWinGravity = window.fWinGravity;
699 dst->fBackingStore = kAlways;
700 dst->fBackingPlanes = 0;
703 dst->fBackingPixel = 0;
710 dst->fMapInstalled = kTRUE;
712 dst->fMapState = window.fMapState;
714 dst->fAllEventMasks = window.fEventMask;
715 dst->fYourEventMask = window.fEventMask;
720 dst->fOverrideRedirect = window.fOverrideRedirect;
729 #pragma mark - Comparators (I need them when changing a window's z-order).
733 #ifdef MAC_OS_X_VERSION_10_11
734 NSComparisonResult CompareViewsToLower(__kindof NSView *view1, __kindof NSView *view2,
void *context)
736 NSComparisonResult CompareViewsToLower(
id view1,
id view2,
void *context)
739 id topView = (id)context;
740 if (view1 == topView)
741 return NSOrderedAscending;
742 if (view2 == topView)
743 return NSOrderedDescending;
745 return NSOrderedSame;
750 #ifdef MAC_OS_X_VERSION_10_11
751 NSComparisonResult CompareViewsToRaise(__kindof NSView *view1, __kindof NSView *view2,
void *context)
753 NSComparisonResult CompareViewsToRaise(
id view1,
id view2,
void *context)
756 id topView = (id)context;
757 if (view1 == topView)
758 return NSOrderedDescending;
759 if (view2 == topView)
760 return NSOrderedAscending;
762 return NSOrderedSame;
765 #pragma mark - Cursor's area.
768 NSPoint GetCursorHotStop(NSImage *image, ECursor cursor)
770 assert(image != nil &&
"CursroHotSpot, parameter 'image' is nil");
772 const NSSize imageSize = image.size;
774 if (cursor == kArrowRight)
775 return NSMakePoint(imageSize.width, imageSize.height / 2);
777 return NSMakePoint(imageSize.width / 2, imageSize.height / 2);
781 NSCursor *CreateCustomCursor(ECursor currentCursor)
784 const char *pngFileName = 0;
786 switch (currentCursor) {
788 pngFileName =
"move_cursor.png";
791 pngFileName =
"hor_arrow_cursor.png";
794 pngFileName =
"ver_arrow_cursor.png";
797 pngFileName =
"right_arrow_cursor.png";
800 pngFileName =
"rotate.png";
804 pngFileName =
"top_right_cursor.png";
808 pngFileName =
"top_left_cursor.png";
814 const char *
const path = gSystem->Which(TROOT::GetIconPath(), pngFileName, kReadPermission);
815 const Util::ScopedArray<const char> arrayGuard(path);
817 if (!path || path[0] == 0) {
822 NSString *nsPath = [NSString stringWithFormat : @"%s", path];
823 NSImage *
const cursorImage = [[NSImage alloc] initWithContentsOfFile : nsPath];
828 const NSPoint hotSpot(X11::GetCursorHotStop(cursorImage, currentCursor));
829 NSCursor *
const customCursor = [[[NSCursor alloc] initWithImage : cursorImage
830 hotSpot : hotSpot] autorelease];
832 [cursorImage release];
841 NSCursor *CreateCursor(ECursor currentCursor)
852 NSCursor *cursor = nil;
853 switch (currentCursor) {
855 cursor = [NSCursor crosshairCursor];
858 cursor = [NSCursor arrowCursor];
861 cursor = [NSCursor openHandCursor];
864 cursor = [NSCursor resizeLeftCursor];
867 cursor = [NSCursor resizeRightCursor];
870 cursor = [NSCursor resizeUpCursor];
873 cursor = [NSCursor resizeDownCursor];
876 cursor = [NSCursor IBeamCursor];
881 cursor = CreateCustomCursor(currentCursor);
894 #pragma mark - Workarounds for a text view and its descendants.
897 bool ViewIsTextView(
unsigned viewID)
899 const TGWindow *
const window = gClient->GetWindowById(viewID);
905 return dynamic_cast<const TGTextView*
>(window);
909 bool ViewIsTextView(NSView<X11Window> *view)
911 assert(view != nil &&
"ViewIsTextView, parameter 'view' is nil");
913 return ViewIsTextView(view.fID);
917 bool ViewIsTextViewFrame(NSView<X11Window> *view,
bool checkParent)
919 assert(view != nil &&
"ViewIsTextViewFrame, parameter 'view' is nil");
921 const TGWindow *
const window = gClient->GetWindowById(view.fID);
928 if (!dynamic_cast<const TGViewFrame*>(window))
934 if (!view.fParentView)
937 return ViewIsTextView(view.fParentView);
941 bool ViewIsHtmlView(
unsigned viewID)
943 const TGWindow *
const window = gClient->GetWindowById(viewID);
949 return window->TestBit(TGWindow::kIsHtmlView);
953 bool ViewIsHtmlView(NSView<X11Window> *view)
955 assert(view != nil &&
"ViewIsHtmlView, parameter 'view' is nil");
957 return ViewIsHtmlView(view.fID);
961 bool ViewIsHtmlViewFrame(NSView<X11Window> *view,
bool checkParent)
964 assert(view != nil &&
"ViewIsHtmlViewFrame, parameter 'view' is nil");
966 const TGWindow *
const window = gClient->GetWindowById(view.fID);
973 if (!dynamic_cast<const TGViewFrame*>(window))
979 if (!view.fParentView)
982 return ViewIsHtmlView(view.fParentView);
986 NSView<X11Window> *FrameForTextView(NSView<X11Window> *textView)
988 assert(textView != nil &&
"FrameForTextView, parameter 'textView' is nil");
990 for (NSView<X11Window> *child in [textView subviews]) {
991 if (ViewIsTextViewFrame(child,
false))
999 NSView<X11Window> *FrameForHtmlView(NSView<X11Window> *htmlView)
1001 assert(htmlView != nil &&
"FrameForHtmlView, parameter 'htmlView' is nil");
1003 for (NSView<X11Window> *child in [htmlView subviews]) {
1004 if (ViewIsHtmlViewFrame(child,
false))
1011 #pragma mark - Workarounds for 'paint out of paint events'.
1014 bool LockFocus(NSView<X11Window> *view)
1016 assert(view != nil &&
"LockFocus, parameter 'view' is nil");
1017 assert([view isKindOfClass : [QuartzView
class]] &&
1018 "LockFocus, QuartzView is expected");
1020 if ([view lockFocusIfCanDraw]) {
1021 NSGraphicsContext *nsContext = [NSGraphicsContext currentContext];
1022 assert(nsContext != nil &&
"LockFocus, currentContext is nil");
1023 CGContextRef currContext = (CGContextRef)[nsContext graphicsPort];
1024 assert(currContext != 0 &&
"LockFocus, graphicsPort is null");
1026 ((QuartzView *)view).fContext = currContext;
1035 void UnlockFocus(NSView<X11Window> *view)
1037 assert(view != nil &&
"UnlockFocus, parameter 'view' is nil");
1038 assert([view isKindOfClass : [QuartzView
class]] &&
1039 "UnlockFocus, QuartzView is expected");
1042 ((QuartzView *)view).fContext = 0;
1049 namespace Quartz = ROOT::Quartz;
1050 namespace Util = ROOT::MacOSX::Util;
1051 namespace X11 = ROOT::MacOSX::X11;
1052 namespace Details = ROOT::MacOSX::Details;
1054 #ifdef DEBUG_ROOT_COCOA
1056 #pragma mark - 'loggers'.
1061 void log_attributes(
const SetWindowAttributes_t *attr,
unsigned winID)
1066 static std::ofstream logfile(
"win_attr.txt");
1068 const Mask_t mask = attr->fMask;
1069 if (mask & kWABackPixmap)
1070 logfile<<
"win "<<winID<<
": BackPixmap\n";
1071 if (mask & kWABackPixel)
1072 logfile<<
"win "<<winID<<
": BackPixel\n";
1073 if (mask & kWABorderPixmap)
1074 logfile<<
"win "<<winID<<
": BorderPixmap\n";
1075 if (mask & kWABorderPixel)
1076 logfile<<
"win "<<winID<<
": BorderPixel\n";
1077 if (mask & kWABorderWidth)
1078 logfile<<
"win "<<winID<<
": BorderWidth\n";
1079 if (mask & kWABitGravity)
1080 logfile<<
"win "<<winID<<
": BitGravity\n";
1081 if (mask & kWAWinGravity)
1082 logfile<<
"win "<<winID<<
": WinGravity\n";
1083 if (mask & kWABackingStore)
1084 logfile<<
"win "<<winID<<
": BackingStore\n";
1085 if (mask & kWABackingPlanes)
1086 logfile<<
"win "<<winID<<
": BackingPlanes\n";
1087 if (mask & kWABackingPixel)
1088 logfile<<
"win "<<winID<<
": BackingPixel\n";
1089 if (mask & kWAOverrideRedirect)
1090 logfile<<
"win "<<winID<<
": OverrideRedirect\n";
1091 if (mask & kWASaveUnder)
1092 logfile<<
"win "<<winID<<
": SaveUnder\n";
1093 if (mask & kWAEventMask)
1094 logfile<<
"win "<<winID<<
": EventMask\n";
1095 if (mask & kWADontPropagate)
1096 logfile<<
"win "<<winID<<
": DontPropagate\n";
1097 if (mask & kWAColormap)
1098 logfile<<
"win "<<winID<<
": Colormap\n";
1099 if (mask & kWACursor)
1100 logfile<<
"win "<<winID<<
": Cursor\n";
1104 void print_mask_info(ULong_t mask)
1106 if (mask & kButtonPressMask)
1107 NSLog(
@"button press mask");
1108 if (mask & kButtonReleaseMask)
1109 NSLog(
@"button release mask");
1110 if (mask & kExposureMask)
1111 NSLog(
@"exposure mask");
1112 if (mask & kPointerMotionMask)
1113 NSLog(
@"pointer motion mask");
1114 if (mask & kButtonMotionMask)
1115 NSLog(
@"button motion mask");
1116 if (mask & kEnterWindowMask)
1117 NSLog(
@"enter notify mask");
1118 if (mask & kLeaveWindowMask)
1119 NSLog(
@"leave notify mask");
1126 @implementation QuartzWindow
1128 @synthesize fMainWindow;
1129 @synthesize fHasFocus;
1131 #pragma mark - QuartzWindow's life cycle.
1134 - (id) initWithContentRect : (NSRect) contentRect styleMask : (NSUInteger) windowStyle
1135 backing : (NSBackingStoreType) bufferingType defer : (BOOL) deferCreation
1136 windowAttributes : (const SetWindowAttributes_t *) attr
1138 self = [
super initWithContentRect : contentRect styleMask : windowStyle
1139 backing : bufferingType defer : deferCreation];
1143 [
self setAllowsConcurrentViewDrawing : NO];
1145 self.delegate =
self;
1147 NSRect contentViewRect = contentRect;
1148 contentViewRect.origin.x = 0.f;
1149 contentViewRect.origin.y = 0.f;
1151 fContentView = [[QuartzView alloc] initWithFrame : contentViewRect windowAttributes : 0];
1153 [
self setContentView : fContentView];
1155 [fContentView release];
1156 fDelayedTransient = NO;
1159 X11::SetWindowAttributes(attr,
self);
1169 - (id) initWithGLView : (ROOTOpenGLView *) glView
1171 using namespace Details;
1173 assert(glView != nil &&
"-initWithGLView, parameter 'glView' is nil");
1175 const NSUInteger styleMask = kTitledWindowMask | kClosableWindowMask |
1176 kMiniaturizableWindowMask | kResizableWindowMask;
1178 NSRect contentRect = glView.frame;
1179 contentRect.origin = NSPoint();
1181 self = [
super initWithContentRect : contentRect styleMask : styleMask
1182 backing : NSBackingStoreBuffered defer : NO];
1186 [
self setAllowsConcurrentViewDrawing : NO];
1187 self.delegate =
self;
1188 fContentView = glView;
1189 [
self setContentView : fContentView];
1190 fDelayedTransient = NO;
1201 [fShapeCombineMask release];
1212 - (void) setContentView:(NSView *)cv
1214 [
super setContentView:cv];
1215 if ([cv isKindOfClass:[QuartzView
class]])
1216 fContentView = (QuartzView *)cv;
1222 - (void) setFIsDeleted : (BOOL) deleted
1224 fIsDeleted = deleted;
1227 #pragma mark - Forwaring: I want to forward a lot of property setters/getters to the content view.
1230 - (void) forwardInvocation : (NSInvocation *) anInvocation
1235 if ([fContentView respondsToSelector : [anInvocation selector]]) {
1236 [anInvocation invokeWithTarget : fContentView];
1238 [
super forwardInvocation : anInvocation];
1243 - (NSMethodSignature*) methodSignatureForSelector : (
SEL) selector
1245 NSMethodSignature *signature = [
super methodSignatureForSelector : selector];
1249 signature = [fContentView methodSignatureForSelector : selector];
1256 - (void) addTransientWindow : (QuartzWindow *) window
1264 assert(window != nil &&
"-addTransientWindow:, parameter 'window' is nil");
1266 window.fMainWindow =
self;
1268 if (window.fMapState != kIsViewable) {
1271 window.fDelayedTransient = YES;
1273 [
self addChildWindow : window ordered : NSWindowAbove];
1274 window.fDelayedTransient = NO;
1279 - (void) makeKeyAndOrderFront : (
id) sender
1281 #pragma unused(sender)
1286 #ifdef MAC_OS_X_VERSION_10_9
1287 [
self setCollectionBehavior : NSWindowCollectionBehaviorMoveToActiveSpace];
1289 [
self setCollectionBehavior : NSWindowCollectionBehaviorCanJoinAllSpaces];
1292 [
super makeKeyAndOrderFront : self];
1294 [
self setCollectionBehavior : NSWindowCollectionBehaviorDefault];
1298 - (void) setFDelayedTransient : (BOOL) d
1300 fDelayedTransient = d;
1304 - (QuartzImage *) fShapeCombineMask
1306 return fShapeCombineMask;
1310 - (void) setFShapeCombineMask : (QuartzImage *) mask
1312 if (mask != fShapeCombineMask) {
1313 [fShapeCombineMask release];
1315 fShapeCombineMask = [mask retain];
1321 #pragma mark - X11Drawable's protocol.
1331 - (BOOL) fIsOpenGLWidget
1338 - (CGFloat) fScaleFactor
1342 return self.screen.backingScaleFactor;
1348 return X11::GlobalXCocoaToROOT(
self.frame.origin.x);
1354 return X11::GlobalYCocoaToROOT(
self.frame.origin.y +
self.frame.size.height);
1360 return self.frame.size.width;
1364 - (unsigned) fHeight
1369 assert(fContentView != nil &&
"-fHeight:, content view is nil");
1371 return fContentView.frame.size.height;
1375 - (void) setDrawableSize : (NSSize) newSize
1378 assert(!(newSize.width < 0) &&
"-setDrawableSize:, width is negative");
1379 assert(!(newSize.height < 0) &&
"-setDrawableSize:, height is negative");
1381 NSRect frame =
self.frame;
1383 const CGFloat dY = fContentView ? frame.size.height - fContentView.frame.size.height : 0.;
1385 frame.origin.y = frame.origin.y + frame.size.height - newSize.height - dY;
1386 frame.size = newSize;
1387 frame.size.height += dY;
1388 [
self setFrame : frame display : YES];
1392 - (void) setX : (
int) x Y : (
int) y width : (
unsigned) w height : (
unsigned) h
1394 NSSize newSize = {};
1397 [
self setContentSize : newSize];
1400 NSPoint topLeft = {};
1401 topLeft.x = X11::GlobalXROOTToCocoa(x);
1402 topLeft.y = X11::GlobalYROOTToCocoa(y);
1404 [
self setFrameTopLeftPoint : topLeft];
1408 - (void) setX : (
int) x Y : (
int) y
1410 NSPoint topLeft = {};
1411 topLeft.x = X11::GlobalXROOTToCocoa(x);
1412 topLeft.y = X11::GlobalYROOTToCocoa(y);
1414 [
self setFrameTopLeftPoint : topLeft];
1418 - (void) copy : (NSObject<X11Drawable> *) src area : (X11::Rectangle) area withMask : (QuartzImage *) mask
1419 clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
1424 [fContentView copy : src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
1428 - (
unsigned char *) readColorBits : (X11::Rectangle) area
1433 return [fContentView readColorBits : area];
1436 #pragma mark - X11Window protocol's implementation.
1439 - (QuartzView *) fParentView
1445 - (void) setFParentView : (QuartzView *) parent
1447 #pragma unused(parent)
1451 - (NSView<X11Window> *) fContentView
1453 return fContentView;
1457 - (QuartzWindow *) fQuartzWindow
1465 - (void) setFBackgroundPixel : (
unsigned long) backgroundColor
1470 if (!fShapeCombineMask) {
1471 CGFloat rgba[] = {0., 0., 0., 1.};
1472 X11::PixelToRGB(backgroundColor, rgba);
1474 [
self setBackgroundColor : [NSColor colorWithColorSpace : [NSColorSpace deviceRGBColorSpace] components : rgba count : 4]];
1477 fContentView.fBackgroundPixel = backgroundColor;
1481 - (
unsigned long) fBackgroundPixel
1486 return fContentView.fBackgroundPixel;
1496 if ([fContentView isHidden])
1503 - (void) addChild : (NSView<X11Window> *) child
1505 assert(child != nil &&
"-addChild:, parameter 'child' is nil");
1507 if (!fContentView) {
1509 assert([child isKindOfClass : [QuartzView
class]] &&
1510 "-addChild: gl view in a top-level window as content view is not supported");
1512 fContentView = (QuartzView *)child;
1513 [
self setContentView : child];
1514 fContentView.fParentView = nil;
1516 [fContentView addChild : child];
1520 - (void) getAttributes : (WindowAttributes_t *) attr
1525 assert(attr &&
"-getAttributes:, parameter 'attr' is nil");
1527 X11::GetWindowAttributes(
self, attr);
1531 - (void) setAttributes : (const SetWindowAttributes_t *) attr
1533 assert(attr != 0 &&
"-setAttributes:, parameter 'attr' is null");
1535 #ifdef DEBUG_ROOT_COCOA
1536 log_attributes(attr,
self.fID);
1539 X11::SetWindowAttributes(attr,
self);
1548 const Util::AutoreleasePool pool;
1550 [fContentView setHidden : NO];
1551 [
self makeKeyAndOrderFront : self];
1552 [fContentView configureNotifyTree];
1554 if (fDelayedTransient) {
1555 fDelayedTransient = NO;
1556 [fMainWindow addChildWindow : self ordered : NSWindowAbove];
1566 const Util::AutoreleasePool pool;
1568 [fContentView setHidden : NO];
1569 [
self makeKeyAndOrderFront : self];
1570 [fContentView configureNotifyTree];
1572 if (fDelayedTransient) {
1573 fDelayedTransient = NO;
1574 [fMainWindow addChildWindow : self ordered : NSWindowAbove];
1579 - (void) mapSubwindows
1584 const Util::AutoreleasePool pool;
1586 [fContentView mapSubwindows];
1587 [fContentView configureNotifyTree];
1591 - (void) unmapWindow
1596 [fContentView setHidden : YES];
1597 [
self orderOut : self];
1599 if (fMainWindow && !fDelayedTransient) {
1600 [fMainWindow removeChildWindow : self];
1605 #pragma mark - Events.
1608 - (void) sendEvent : (NSEvent *) theEvent
1617 if (theEvent.type == Details::kLeftMouseDown || theEvent.type == Details::kRightMouseDown) {
1618 bool generateFakeRelease =
false;
1620 const NSPoint windowPoint = [theEvent locationInWindow];
1622 if (windowPoint.x <= 4 || windowPoint.x >=
self.fWidth - 4)
1623 generateFakeRelease =
true;
1625 if (windowPoint.y <= 4 || windowPoint.y >=
self.fHeight - 4)
1626 generateFakeRelease =
true;
1628 const NSPoint viewPoint = [fContentView convertPoint : windowPoint fromView : nil];
1630 if (viewPoint.y <= 0 && windowPoint.y >= 0)
1631 generateFakeRelease =
true;
1633 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1634 "-sendEvent:, gVirtualX is either null or not of TGCocoa type");
1636 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
1637 if (vx->GetEventTranslator()->HasPointerGrab() && generateFakeRelease) {
1638 vx->GetEventTranslator()->GenerateButtonReleaseEvent(fContentView, theEvent,
1639 theEvent.type == Details::kLeftMouseDown ?
1640 kButton1 : kButton3);
1648 [
super sendEvent : theEvent];
1651 #pragma mark - NSWindowDelegate's methods.
1654 - (BOOL) windowShouldClose : (
id) sender
1656 #pragma unused(sender)
1660 if ([[
self childWindows] count])
1664 Event_t closeEvent = {};
1665 closeEvent.fWindow = fContentView.fID;
1666 closeEvent.fType = kClientMessage;
1667 closeEvent.fFormat = 32;
1668 closeEvent.fHandle = TGCocoa::fgDeleteWindowAtom;
1669 closeEvent.fUser[0] = TGCocoa::fgDeleteWindowAtom;
1671 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1672 "-windowShouldClose:, gVirtualX is either null or has a type different from TGCocoa");
1673 ((TGCocoa *)gVirtualX)->SendEvent(fContentView.fID, &closeEvent);
1681 - (void) windowDidBecomeKey : (NSNotification *) aNotification
1683 #pragma unused(aNotification)
1688 if (!fContentView.fOverrideRedirect) {
1691 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1692 "-windowDidBecomeKey:, gVirtualX is null or not of TGCocoa type");
1693 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
1694 vx->GetEventTranslator()->GenerateFocusChangeEvent(
self.fContentView);
1700 - (void) windowDidResignKey : (NSNotification *) aNotification
1702 #pragma unused(aNotification)
1708 #pragma mark - Passive key grab info.
1710 @implementation PassiveKeyGrab
1713 - (id) initWithKey : (unichar) keyCode modifiers : (NSUInteger) modifiers
1715 if (
self = [super init]) {
1717 fModifiers = modifiers;
1724 - (BOOL) matchKey : (unichar) keyCode modifiers : (NSUInteger) modifiers
1726 return keyCode == fKeyCode && modifiers == fModifiers;
1730 - (BOOL) matchKey : (unichar) keyCode
1732 return keyCode == fKeyCode;
1736 - (unichar) fKeyCode
1742 - (NSUInteger) fModifiers
1749 #pragma mark - X11 property emulation.
1751 @interface QuartzWindowProperty : NSObject {
1752 NSData *fPropertyData;
1757 @property (nonatomic, readonly) Atom_t fType;
1761 @implementation QuartzWindowProperty
1766 - (id) initWithData : (
unsigned char *) data size : (
unsigned) dataSize type : (Atom_t) type format : (
unsigned) format
1768 if (
self = [super init]) {
1770 fPropertyData = nil;
1774 [
self resetPropertyData : data size : dataSize type : type format : format];
1783 [fPropertyData release];
1789 - (void) resetPropertyData : (
unsigned char *) data size : (
unsigned) dataSize
1790 type : (Atom_t) type format : (
unsigned) format
1792 [fPropertyData release];
1797 else if (format == 32)
1800 fPropertyData = [[NSData dataWithBytes : data length : dataSize] retain];
1806 - (NSData *) fPropertyData
1808 return fPropertyData;
1812 - (unsigned) fFormat
1819 #pragma mark - QuartzView.
1825 @implementation QuartzView
1828 @synthesize fContext;
1831 @synthesize fEventMask;
1834 @synthesize fBitGravity;
1835 @synthesize fWinGravity;
1836 @synthesize fBackgroundPixel;
1837 @synthesize fOverrideRedirect;
1840 @synthesize fHasFocus;
1841 @synthesize fParentView;
1843 @synthesize fPassiveGrabButton;
1844 @synthesize fPassiveGrabEventMask;
1845 @synthesize fPassiveGrabKeyModifiers;
1846 @synthesize fActiveGrabEventMask;
1847 @synthesize fPassiveGrabOwnerEvents;
1848 @synthesize fSnapshotDraw;
1849 @synthesize fCurrentCursor;
1850 @synthesize fIsDNDAware;
1852 #pragma mark - Lifetime.
1855 - (id) initWithFrame : (NSRect) frame windowAttributes : (const SetWindowAttributes_t *)attr
1857 if (
self = [super initWithFrame : frame]) {
1863 fPassiveGrabButton = -1;
1864 fPassiveGrabEventMask = 0;
1865 fPassiveGrabOwnerEvents = NO;
1867 fPassiveKeyGrabs = [[NSMutableArray alloc] init];
1869 [
self setCanDrawConcurrently : NO];
1871 [
self setHidden : YES];
1875 X11::SetWindowAttributes(attr,
self);
1877 fCurrentCursor = kPointer;
1878 fX11Properties = [[NSMutableDictionary alloc] init];
1880 fCurrentGrabType = X11::kPGNoGrab;
1881 fActiveGrabEventMask = 0;
1882 fActiveGrabOwnerEvents = YES;
1891 [fBackBuffer release];
1892 [fPassiveKeyGrabs release];
1893 [fX11Properties release];
1894 [fBackgroundPixmap release];
1898 #pragma mark - Tracking area.
1903 - (void) updateTrackingAreas
1905 [
super updateTrackingAreas];
1910 const Util::AutoreleasePool pool;
1912 if (NSArray *trackingArray = [
self trackingAreas]) {
1913 const NSUInteger size = [trackingArray count];
1914 for (NSUInteger i = 0; i < size; ++i) {
1915 NSTrackingArea *
const t = [trackingArray objectAtIndex : i];
1916 [
self removeTrackingArea : t];
1920 const NSUInteger trackerOptions = NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited |
1921 NSTrackingActiveInActiveApp | NSTrackingInVisibleRect |
1922 NSTrackingEnabledDuringMouseDrag | NSTrackingCursorUpdate;
1925 frame.size.width =
self.fWidth;
1926 frame.size.height =
self.fHeight;
1928 NSTrackingArea *
const tracker = [[NSTrackingArea alloc] initWithRect : frame
1929 options : trackerOptions owner : self userInfo : nil];
1930 [
self addTrackingArea : tracker];
1935 - (void) updateTrackingAreasAfterRaise
1937 [
self updateTrackingAreas];
1939 for (QuartzView *childView in [
self subviews])
1940 [childView updateTrackingAreasAfterRaise];
1943 #pragma mark - X11Drawable protocol.
1952 - (BOOL) fIsOpenGLWidget
1958 - (CGFloat) fScaleFactor
1960 return self.fQuartzWindow.fScaleFactor;
1966 return self.frame.origin.x;
1972 return self.frame.origin.y;
1978 return self.frame.size.width;
1982 - (unsigned) fHeight
1984 return self.frame.size.height;
1988 - (void) setDrawableSize : (NSSize) newSize
1990 assert(!(newSize.width < 0) &&
"-setDrawableSize, width is negative");
1991 assert(!(newSize.height < 0) &&
"-setDrawableSize, height is negative");
1997 NSRect frame =
self.frame;
1998 frame.size = newSize;
2004 - (void) setX : (
int) x Y : (
int) y width : (
unsigned) w height : (
unsigned) h
2006 NSRect newFrame = {};
2007 newFrame.origin.x = x;
2008 newFrame.origin.y = y;
2009 newFrame.size.width = w;
2010 newFrame.size.height = h;
2012 self.frame = newFrame;
2016 - (void) setX : (
int) x Y : (
int) y
2018 NSRect newFrame =
self.frame;
2019 newFrame.origin.x = x;
2020 newFrame.origin.y = y;
2022 self.frame = newFrame;
2026 - (void) copyImage : (QuartzImage *) srcImage area : (X11::Rectangle) area
2027 withMask : (QuartzImage *) mask clipOrigin : (X11::Point) clipXY
2028 toPoint : (X11::Point) dstPoint
2031 assert(srcImage != nil &&
2032 "-copyImage:area:withMask:clipOrigin:toPoint:, parameter 'srcImage' is nil");
2033 assert(srcImage.fImage != nil &&
2034 "-copyImage:area:withMask:clipOrigin:toPoint:, srcImage.fImage is nil");
2037 assert(
self.fContext != 0 &&
2038 "-copyImage:area:withMask:clipOrigin:toPoint:, self.fContext is null");
2040 if (!X11::AdjustCropArea(srcImage, area)) {
2041 NSLog(
@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2042 " srcRect and copyRect do not intersect");
2048 CGImageRef subImage = 0;
2049 bool needSubImage =
false;
2050 if (area.fX || area.fY || area.fWidth != srcImage.fWidth || area.fHeight != srcImage.fHeight) {
2051 needSubImage =
true;
2052 subImage = X11::CreateSubImage(srcImage, area);
2054 NSLog(
@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2055 " subimage creation failed");
2059 subImage = srcImage.fImage;
2062 const Quartz::CGStateGuard ctxGuard(
self.fContext);
2065 CGContextTranslateCTM(
self.fContext, 0.,
self.fHeight);
2066 CGContextScaleCTM(
self.fContext, 1., -1.);
2070 assert(mask.fImage != nil &&
2071 "-copyImage:area:withMask:clipOrigin:toPoint:, mask.fImage is nil");
2072 assert(CGImageIsMask(mask.fImage) ==
true &&
2073 "-copyImage:area:withMask:clipOrigin:toPoint:, mask.fImage is not a mask");
2075 const CGFloat clipY = X11::LocalYROOTToCocoa(
self, CGFloat(clipXY.fY) + mask.fHeight);
2077 const CGRect clipRect = CGRectMake(clipXY.fX, clipY, mask.fWidth, mask.fHeight);
2078 CGContextClipToMask(
self.fContext, clipRect, mask.fImage);
2083 const CGFloat dstY = X11::LocalYROOTToCocoa(
self, CGFloat(dstPoint.fY) + area.fHeight);
2085 const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2086 CGContextDrawImage(
self.fContext, imageRect, subImage);
2089 CGImageRelease(subImage);
2093 - (void) copyView : (QuartzView *) srcView area : (X11::Rectangle) area toPoint : (X11::Point) dstPoint
2098 assert(srcView != nil &&
"-copyView:area:toPoint:, parameter 'srcView' is nil");
2100 const NSRect frame = [srcView frame];
2102 NSBitmapImageRep *
const imageRep = [srcView bitmapImageRepForCachingDisplayInRect : frame];
2104 NSLog(
@"QuartzView: -copyView:area:toPoint failed");
2108 assert(srcView != nil &&
"-copyView:area:toPoint:, parameter 'srcView' is nil");
2109 assert(
self.fContext != 0 &&
"-copyView:area:toPoint, self.fContext is null");
2114 CGContextRef ctx = srcView.fContext;
2115 srcView.fSnapshotDraw = YES;
2116 [srcView cacheDisplayInRect : frame toBitmapImageRep : imageRep];
2117 srcView.fSnapshotDraw = NO;
2118 srcView.fContext = ctx;
2120 const CGRect subImageRect = CGRectMake(area.fX, area.fY, area.fWidth, area.fHeight);
2121 const Util::CFScopeGuard<CGImageRef> subImage(CGImageCreateWithImageInRect(imageRep.CGImage, subImageRect));
2123 if (!subImage.Get()) {
2124 NSLog(
@"QuartzView: -copyView:area:toPoint, CGImageCreateWithImageInRect failed");
2128 const Quartz::CGStateGuard ctxGuard(
self.fContext);
2129 const CGRect imageRect = CGRectMake(dstPoint.fX,
2130 [
self visibleRect].size.height - (CGFloat(dstPoint.fY) + area.fHeight),
2131 area.fWidth, area.fHeight);
2133 CGContextTranslateCTM(
self.fContext, 0., [
self visibleRect].size.height);
2134 CGContextScaleCTM(
self.fContext, 1., -1.);
2136 CGContextDrawImage(
self.fContext, imageRect, subImage.Get());
2140 - (void) copyPixmap : (QuartzPixmap *) srcPixmap area : (X11::Rectangle) area
2141 withMask : (QuartzImage *) mask clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
2144 assert(srcPixmap != nil &&
"-copyPixmap:area:withMask:clipOrigin:toPoint:, parameter 'srcPixmap' is nil");
2146 if (!X11::AdjustCropArea(srcPixmap, area)) {
2147 NSLog(
@"QuartzView: -copyPixmap:area:withMask:clipOrigin:toPoint,"
2148 " no intersection between pixmap rectangle and cropArea");
2153 assert(
self.fContext != 0 &&
2154 "-copyPixmap:area:withMask:clipOrigin:toPoint:, self.fContext is null");
2157 const Quartz::CGStateGuard ctxGuard(
self.fContext);
2159 CGContextTranslateCTM(
self.fContext, 0.,
self.frame.size.height);
2160 CGContextScaleCTM(
self.fContext, 1., -1.);
2162 const Util::CFScopeGuard<CGImageRef> imageFromPixmap([srcPixmap createImageFromPixmap]);
2163 assert(imageFromPixmap.Get() != 0 &&
2164 "-copyPixmap:area:withMask:clipOrigin:toPoint:, createImageFromPixmap failed");
2166 CGImageRef subImage = 0;
2167 bool needSubImage =
false;
2168 if (area.fX || area.fY || area.fWidth != srcPixmap.fWidth || area.fHeight != srcPixmap.fHeight) {
2169 needSubImage =
true;
2170 const CGRect subImageRect = CGRectMake(area.fX, area.fY, area.fHeight, area.fWidth);
2171 subImage = CGImageCreateWithImageInRect(imageFromPixmap.Get(), subImageRect);
2173 NSLog(
@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2174 " subimage creation failed");
2178 subImage = imageFromPixmap.Get();
2181 assert(mask.fImage != nil &&
2182 "-copyPixmap:area:withMask:clipOrigin:toPoint:, mask.fImage is nil");
2183 assert(CGImageIsMask(mask.fImage) ==
true &&
2184 "-copyPixmap:area:withMask:clipOrigin:toPoint:, mask.fImage is not a mask");
2187 const CGFloat clipY = X11::LocalYROOTToCocoa(
self, CGFloat(clipXY.fY) + mask.fHeight);
2189 const CGRect clipRect = CGRectMake(clipXY.fX, clipY, mask.fWidth, mask.fHeight);
2190 CGContextClipToMask(
self.fContext, clipRect, mask.fImage);
2194 const CGFloat dstY = X11::LocalYCocoaToROOT(
self, CGFloat(dstPoint.fY) + area.fHeight);
2195 const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2196 CGContextDrawImage(
self.fContext, imageRect, imageFromPixmap.Get());
2199 CGImageRelease(subImage);
2204 - (void) copyImage : (QuartzImage *) srcImage area : (X11::Rectangle) area
2205 toPoint : (X11::Point) dstPoint
2207 assert(srcImage != nil &&
"-copyImage:area:toPoint:, parameter 'srcImage' is nil");
2208 assert(srcImage.fImage != nil &&
"-copyImage:area:toPoint:, srcImage.fImage is nil");
2209 assert(
self.fContext != 0 &&
"-copyImage:area:toPoint:, fContext is null");
2211 if (!X11::AdjustCropArea(srcImage, area)) {
2212 NSLog(
@"QuartzView: -copyImage:area:toPoint, image and copy area do not intersect");
2216 CGImageRef subImage = 0;
2217 bool needSubImage =
false;
2218 if (area.fX || area.fY || area.fWidth != srcImage.fWidth || area.fHeight != srcImage.fHeight) {
2219 needSubImage =
true;
2220 subImage = X11::CreateSubImage(srcImage, area);
2222 NSLog(
@"QuartzView: -copyImage:area:toPoint:, subimage creation failed");
2226 subImage = srcImage.fImage;
2228 const Quartz::CGStateGuard ctxGuard(
self.fContext);
2230 CGContextTranslateCTM(
self.fContext, 0.,
self.fHeight);
2231 CGContextScaleCTM(
self.fContext, 1., -1.);
2234 const CGFloat dstY = X11::LocalYCocoaToROOT(
self, CGFloat(dstPoint.fY) + area.fHeight);
2236 const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2237 CGContextDrawImage(
self.fContext, imageRect, subImage);
2240 CGImageRelease(subImage);
2244 - (void) copy : (NSObject<X11Drawable> *) src area : (X11::Rectangle) area
2245 withMask : (QuartzImage *)mask clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
2247 assert(src != nil &&
"-copy:area:withMask:clipOrigin:toPoint:, parameter 'src' is nil");
2248 assert(area.fWidth && area.fHeight &&
"-copy:area:withMask:clipOrigin:toPoint:, area to copy is empty");
2250 if ([src isKindOfClass : [QuartzWindow
class]]) {
2252 QuartzWindow *
const qw = (QuartzWindow *)src;
2254 [
self copyView : (QuartzView *)qw.fContentView area : area toPoint : dstPoint];
2255 }
else if ([src isKindOfClass : [QuartzView
class]]) {
2257 [
self copyView : (QuartzView *)src area : area toPoint : dstPoint];
2258 }
else if ([src isKindOfClass : [QuartzPixmap
class]]) {
2259 [
self copyPixmap : (QuartzPixmap *)src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
2260 }
else if ([src isKindOfClass : [QuartzImage
class]]) {
2261 [
self copyImage : (QuartzImage *)src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
2263 assert(0 &&
"-copy:area:withMask:clipOrigin:toPoint:, src is of unknown type");
2268 - (
unsigned char *) readColorBits : (X11::Rectangle) area
2274 assert(area.fWidth && area.fHeight &&
"-readColorBits:, area to copy is empty");
2277 const NSRect visRect = [
self visibleRect];
2278 const X11::Rectangle srcRect(
int(visRect.origin.x),
int(visRect.origin.y),
2279 unsigned(visRect.size.width),
unsigned(visRect.size.height));
2281 if (!X11::AdjustCropArea(srcRect, area)) {
2282 NSLog(
@"QuartzView: -readColorBits:, visible rect of view and copy area do not intersect");
2287 NSBitmapImageRep *
const imageRep = [
self bitmapImageRepForCachingDisplayInRect : visRect];
2289 NSLog(
@"QuartzView: -readColorBits:, bitmapImageRepForCachingDisplayInRect failed");
2293 CGContextRef ctx =
self.fContext;
2294 [
self cacheDisplayInRect : visRect toBitmapImageRep : imageRep];
2295 self.fContext = ctx;
2297 const NSInteger bitsPerPixel = [imageRep bitsPerPixel];
2299 assert(bitsPerPixel == 32 &&
"-readColorBits:, no alpha channel???");
2300 const NSInteger bytesPerRow = [imageRep bytesPerRow];
2301 unsigned dataWidth = bytesPerRow / (bitsPerPixel / 8);
2303 unsigned char *srcData =
nullptr;
2304 std::vector<unsigned char> downscaled;
2305 if ([
self.window.screen backingScaleFactor] > 1 && imageRep.CGImage) {
2306 downscaled = X11::DownscaledImageData(area.fWidth, area.fHeight, imageRep.CGImage);
2307 if (downscaled.size())
2308 srcData = &downscaled[0];
2309 dataWidth = area.fWidth;
2311 srcData = [imageRep bitmapData];
2314 NSLog(
@"QuartzView: -readColorBits:, failed to obtain backing store contents");
2319 unsigned char *data =
nullptr;
2322 data =
new unsigned char[area.fWidth * area.fHeight * 4];
2323 }
catch (
const std::bad_alloc &) {
2324 NSLog(
@"QuartzView: -readColorBits:, memory allocation failed");
2328 unsigned char *dstPixel = data;
2329 const unsigned char *line = srcData + area.fY * dataWidth * 4;
2330 const unsigned char *srcPixel = line + area.fX * 4;
2332 for (
unsigned i = 0; i < area.fHeight; ++i) {
2333 for (
unsigned j = 0; j < area.fWidth; ++j, srcPixel += 4, dstPixel += 4) {
2334 dstPixel[0] = srcPixel[2];
2335 dstPixel[1] = srcPixel[1];
2336 dstPixel[2] = srcPixel[0];
2337 dstPixel[3] = srcPixel[3];
2340 line += dataWidth * 4;
2341 srcPixel = line + area.fX * 4;
2348 - (void) setFBackgroundPixmap : (QuartzImage *) pixmap
2350 if (fBackgroundPixmap != pixmap) {
2351 [fBackgroundPixmap release];
2353 fBackgroundPixmap = [pixmap retain];
2355 fBackgroundPixmap = nil;
2360 - (QuartzImage *) fBackgroundPixmap
2364 return fBackgroundPixmap;
2370 if ([
self isHidden])
2373 for (QuartzView *parent = fParentView; parent; parent = parent.fParentView) {
2374 if ([parent isHidden])
2375 return kIsUnviewable;
2392 - (void) setFHasFocus : (BOOL) focus
2394 #pragma unused(focus)
2402 - (QuartzPixmap *) fBackBuffer
2408 - (void) setFBackBuffer : (QuartzPixmap *) backBuffer
2410 if (fBackBuffer != backBuffer) {
2411 [fBackBuffer release];
2414 fBackBuffer = [backBuffer retain];
2421 - (NSView<X11Window> *) fContentView
2427 - (QuartzWindow *) fQuartzWindow
2429 return (QuartzWindow *)[
self window];
2433 - (void) activatePassiveGrab
2435 fCurrentGrabType = X11::kPGPassiveGrab;
2439 - (void) activateImplicitGrab
2441 fCurrentGrabType = X11::kPGImplicitGrab;
2445 - (void) activateGrab : (
unsigned) eventMask ownerEvents : (BOOL) ownerEvents
2447 fCurrentGrabType = X11::kPGActiveGrab;
2448 fActiveGrabEventMask = eventMask;
2449 fActiveGrabOwnerEvents = ownerEvents;
2455 fCurrentGrabType = X11::kPGNoGrab;
2456 fActiveGrabEventMask = 0;
2457 fActiveGrabOwnerEvents = YES;
2461 - (BOOL) acceptsCrossingEvents : (
unsigned) eventMask
2463 bool accepts = fEventMask & eventMask;
2466 if (fCurrentGrabType == X11::kPGPassiveGrab)
2467 accepts = accepts || (fPassiveGrabEventMask & eventMask);
2469 if (fCurrentGrabType == X11::kPGActiveGrab) {
2470 if (fActiveGrabOwnerEvents)
2471 accepts = accepts || (fActiveGrabOwnerEvents & eventMask);
2473 accepts = fActiveGrabOwnerEvents & eventMask;
2480 - (void) addChild : (NSView<X11Window> *) child
2482 assert(child != nil &&
"-addChild:, parameter 'child' is nil");
2484 [
self addSubview : child];
2485 child.fParentView =
self;
2489 - (void) getAttributes : (WindowAttributes_t *) attr
2491 assert(attr != 0 &&
"-getAttributes:, parameter 'attr' is null");
2493 X11::GetWindowAttributes(
self, attr);
2497 - (void) setAttributes : (const SetWindowAttributes_t *)attr
2499 assert(attr != 0 &&
"-setAttributes:, parameter 'attr' is null");
2501 #ifdef DEBUG_ROOT_COCOA
2502 log_attributes(attr, fID);
2505 X11::SetWindowAttributes(attr,
self);
2512 QuartzView *
const parent = fParentView;
2513 [
self removeFromSuperview];
2514 [parent addSubview : self];
2515 [
self setHidden : NO];
2521 [
self setHidden : NO];
2525 - (void) mapSubwindows
2527 for (QuartzView * v in [
self subviews])
2532 - (void) unmapWindow
2534 [
self setHidden : YES];
2538 - (BOOL) fIsOverlapped
2540 return fIsOverlapped;
2544 - (void) setOverlapped : (BOOL) overlap
2546 fIsOverlapped = overlap;
2547 for (NSView<X11Window> *child in [
self subviews])
2548 [child setOverlapped : overlap];
2552 - (void) raiseWindow
2565 using namespace X11;
2567 for (QuartzView *sibling in [fParentView subviews]) {
2568 if (
self == sibling)
2570 if ([sibling isHidden])
2573 if (NSEqualRects(sibling.frame,
self.frame)) {
2574 [sibling setOverlapped : YES];
2575 [sibling setHidden : YES];
2579 [
self setOverlapped : NO];
2581 [
self setHidden : NO];
2583 [fParentView sortSubviewsUsingFunction : CompareViewsToRaise context : (void *)self];
2585 [
self updateTrackingAreasAfterRaise];
2587 [
self setNeedsDisplay : YES];
2591 - (void) lowerWindow
2595 using namespace X11;
2597 NSEnumerator *
const reverseEnumerator = [[fParentView subviews] reverseObjectEnumerator];
2598 for (QuartzView *sibling in reverseEnumerator) {
2599 if (sibling ==
self)
2602 if (NSEqualRects(sibling.frame,
self.frame)) {
2603 [sibling setOverlapped : NO];
2605 [sibling setHidden : NO];
2607 [sibling setNeedsDisplay : YES];
2608 [
self setOverlapped : YES];
2610 [
self setHidden : YES];
2616 [fParentView sortSubviewsUsingFunction : CompareViewsToLower context : (void*)self];
2628 - (void) configureNotifyTree
2630 if (
self.fMapState == kIsViewable || fIsOverlapped == YES) {
2631 if (fEventMask & kStructureNotifyMask) {
2632 assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
2633 "-configureNotifyTree, gVirtualX is either null or has type different from TGCocoa");
2634 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
2635 vx->GetEventTranslator()->GenerateConfigureNotifyEvent(
self,
self.frame);
2638 for (NSView<X11Window> *v in [
self subviews])
2639 [v configureNotifyTree];
2643 #pragma mark - Key grabs.
2646 - (void) addPassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2648 [
self removePassiveKeyGrab : keyCode modifiers : modifiers];
2649 PassiveKeyGrab *
const newGrab = [[PassiveKeyGrab alloc] initWithKey : keyCode
2650 modifiers : modifiers];
2651 [fPassiveKeyGrabs addObject : newGrab];
2656 - (void) removePassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2658 const NSUInteger count = [fPassiveKeyGrabs count];
2659 for (NSUInteger i = 0; i < count; ++i) {
2660 PassiveKeyGrab *grab = [fPassiveKeyGrabs objectAtIndex : i];
2661 if ([grab matchKey : keyCode modifiers : modifiers]) {
2662 [fPassiveKeyGrabs removeObjectAtIndex : i];
2669 - (PassiveKeyGrab *) findPassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2671 NSEnumerator *
const enumerator = [fPassiveKeyGrabs objectEnumerator];
2672 while (PassiveKeyGrab *grab = (PassiveKeyGrab *)[enumerator nextObject]) {
2673 if ([grab matchKey : keyCode modifiers : modifiers])
2681 - (PassiveKeyGrab *) findPassiveKeyGrab : (unichar) keyCode
2684 NSEnumerator *
const enumerator = [fPassiveKeyGrabs objectEnumerator];
2685 while (PassiveKeyGrab *grab = (PassiveKeyGrab *)[enumerator nextObject]) {
2686 if ([grab matchKey : keyCode])
2693 #pragma mark - Painting mechanics.
2696 - (void) drawRect : (NSRect) dirtyRect
2698 #pragma unused(dirtyRect)
2700 using namespace X11;
2703 if (TGWindow *
const window = gClient->GetWindowById(fID)) {
2705 if (ViewIsTextViewFrame(
self,
true) ||ViewIsHtmlViewFrame(
self,
true))
2708 NSGraphicsContext *
const nsContext = [NSGraphicsContext currentContext];
2709 assert(nsContext != nil &&
"-drawRect:, currentContext returned nil");
2711 TGCocoa *
const vx = (TGCocoa *)gVirtualX;
2714 fContext = (CGContextRef)[nsContext graphicsPort];
2715 assert(fContext != 0 &&
"-drawRect:, graphicsPort returned null");
2717 const Quartz::CGStateGuard ctxGuard(fContext);
2720 if (
self.fQuartzWindow.fShapeCombineMask)
2721 X11::ClipToShapeMask(
self, fContext);
2726 if (dynamic_cast<const TGContainer*>(window))
2727 vx->GetEventTranslator()->GenerateExposeEvent(
self, [
self visibleRect]);
2729 if (fEventMask & kExposureMask) {
2730 if (ViewIsTextView(
self)) {
2732 [NSColor.whiteColor setFill];
2733 NSRectFill(dirtyRect);
2734 NSView<X11Window> *
const viewFrame = FrameForTextView(
self);
2736 vx->GetEventTranslator()->GenerateExposeEvent(viewFrame, viewFrame.visibleRect);
2739 if (ViewIsHtmlView(
self)) {
2740 NSView<X11Window> *
const viewFrame = FrameForHtmlView(
self);
2742 vx->GetEventTranslator()->GenerateExposeEvent(viewFrame, viewFrame.visibleRect);
2746 gClient->NeedRedraw(window, kTRUE);
2748 if (!fSnapshotDraw) {
2751 gClient->CancelRedraw(window);
2752 vx->GetCommandBuffer()->RemoveGraphicsOperationsForWindow(fID);
2758 const X11::Rectangle copyArea(0, 0, fBackBuffer.fWidth, fBackBuffer.fHeight);
2759 [
self copy : fBackBuffer area : copyArea withMask : nil
2760 clipOrigin : X11::Point() toPoint : X11::Point()];
2764 #ifdef DEBUG_ROOT_COCOA
2765 CGContextSetRGBStrokeColor(fContext, 1., 0., 0., 1.);
2766 CGContextStrokeRect(fContext, dirtyRect);
2771 #ifdef DEBUG_ROOT_COCOA
2772 NSLog(
@"QuartzView: -drawRect: method, no window for id %u was found", fID);
2778 #pragma mark - Geometry.
2781 - (void) setFrame : (NSRect) newFrame
2786 if (NSEqualRects(newFrame,
self.frame))
2789 [
super setFrame : newFrame];
2793 - (void) setFrameSize : (NSSize) newSize
2797 [
super setFrameSize : newSize];
2799 if ((fEventMask & kStructureNotifyMask) && (
self.fMapState == kIsViewable || fIsOverlapped == YES)) {
2800 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2801 "setFrameSize:, gVirtualX is either null or has a type, different from TGCocoa");
2802 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
2803 vx->GetEventTranslator()->GenerateConfigureNotifyEvent(
self,
self.frame);
2806 [
self setNeedsDisplay : YES];
2809 #pragma mark - Event handling.
2812 - (void) mouseDown : (NSEvent *) theEvent
2814 assert(fID != 0 &&
"-mouseDown:, fID is 0");
2816 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2817 "-mouseDown:, gVirtualX is either null or has a type, different from TGCocoa");
2818 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
2819 vx->GetEventTranslator()->GenerateButtonPressEvent(
self, theEvent, kButton1);
2823 - (void) scrollWheel : (NSEvent*) theEvent
2825 assert(fID != 0 &&
"-scrollWheel:, fID is 0");
2828 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2829 "-scrollWheel:, gVirtualX is either null or has a type, different from TGCocoa");
2831 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
2832 const CGFloat deltaY = [theEvent deltaY];
2834 vx->GetEventTranslator()->GenerateButtonPressEvent(
self, theEvent, kButton5);
2835 vx->GetEventTranslator()->GenerateButtonReleaseEvent(
self, theEvent, kButton5);
2836 }
else if (deltaY > 0) {
2837 vx->GetEventTranslator()->GenerateButtonPressEvent(
self, theEvent, kButton4);
2838 vx->GetEventTranslator()->GenerateButtonReleaseEvent(
self, theEvent, kButton4);
2842 #ifdef DEBUG_ROOT_COCOA
2844 - (void) printViewInformation
2846 assert(fID != 0 &&
"-printWindowInformation, fID is 0");
2847 const TGWindow *
const window = gClient->GetWindowById(fID);
2848 assert(window != 0 &&
"printWindowInformation, window not found");
2850 NSLog(
@"-----------------View %u info:---------------------", fID);
2851 NSLog(
@"ROOT's window class is %s", window->IsA()->GetName());
2852 NSLog(
@"event mask is:");
2853 print_mask_info(fEventMask);
2854 NSLog(
@"grab mask is:");
2855 print_mask_info(fPassiveGrabEventMask);
2856 NSLog(
@"view's geometry: x == %g, y == %g, w == %g, h == %g",
self.frame.origin.x,
2857 self.frame.origin.y,
self.frame.size.width,
self.frame.size.height);
2858 NSLog(
@"----------------End of view info------------------");
2863 - (void) rightMouseDown : (NSEvent *) theEvent
2865 assert(fID != 0 &&
"-rightMouseDown:, fID is 0");
2867 #ifdef DEBUG_ROOT_COCOA
2868 [
self printViewInformation];
2871 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2872 "-rightMouseDown:, gVirtualX is either null or has type different from TGCocoa");
2873 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
2874 vx->GetEventTranslator()->GenerateButtonPressEvent(
self, theEvent, kButton3);
2878 - (void) otherMouseDown : (NSEvent *) theEvent
2880 assert(fID != 0 &&
"-otherMouseDown:, fID is 0");
2884 if ([theEvent buttonNumber] == 2) {
2887 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2888 "-otherMouseDown:, gVirtualX is either null or has type different from TGCocoa");
2889 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
2890 vx->GetEventTranslator()->GenerateButtonPressEvent(
self, theEvent, kButton2);
2895 - (void) mouseUp : (NSEvent *) theEvent
2897 assert(fID != 0 &&
"-mouseUp:, fID is 0");
2899 assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
2900 "-mouseUp:, gVirtualX is either null or has type different from TGCocoa");
2901 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
2902 vx->GetEventTranslator()->GenerateButtonReleaseEvent(
self, theEvent, kButton1);
2906 - (void) rightMouseUp : (NSEvent *) theEvent
2909 assert(fID != 0 &&
"-rightMouseUp:, fID is 0");
2911 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2912 "-rightMouseUp:, gVirtualX is either null or has type different from TGCocoa");
2914 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
2915 vx->GetEventTranslator()->GenerateButtonReleaseEvent(
self, theEvent, kButton3);
2919 - (void) otherMouseUp : (NSEvent *) theEvent
2921 assert(fID != 0 &&
"-otherMouseUp:, fID is 0");
2924 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2925 "-otherMouseUp:, gVirtualX is either null or has type different from TGCocoa");
2926 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
2927 vx->GetEventTranslator()->GenerateButtonReleaseEvent(
self, theEvent, kButton2);
2931 - (void) mouseEntered : (NSEvent *) theEvent
2933 assert(fID != 0 &&
"-mouseEntered:, fID is 0");
2934 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2935 "-mouseEntered:, gVirtualX is null or not of TGCocoa type");
2937 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
2938 vx->GetEventTranslator()->GenerateCrossingEvent(theEvent);
2942 - (void) mouseExited : (NSEvent *) theEvent
2944 assert(fID != 0 &&
"-mouseExited:, fID is 0");
2946 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2947 "-mouseExited:, gVirtualX is null or not of TGCocoa type");
2949 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
2950 vx->GetEventTranslator()->GenerateCrossingEvent(theEvent);
2954 - (void) mouseMoved : (NSEvent *) theEvent
2956 assert(fID != 0 &&
"-mouseMoved:, fID is 0");
2961 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2962 "-mouseMoved:, gVirtualX is null or not of TGCocoa type");
2964 TGCocoa *vx =
static_cast<TGCocoa *
>(gVirtualX);
2965 vx->GetEventTranslator()->GeneratePointerMotionEvent(theEvent);
2969 - (void) mouseDragged : (NSEvent *) theEvent
2971 assert(fID != 0 &&
"-mouseDragged:, fID is 0");
2973 TGCocoa *
const vx =
dynamic_cast<TGCocoa *
>(gVirtualX);
2974 assert(vx != 0 &&
"-mouseDragged:, gVirtualX is null or not of TGCocoa type");
2976 vx->GetEventTranslator()->GeneratePointerMotionEvent(theEvent);
2980 - (void) rightMouseDragged : (NSEvent *) theEvent
2982 assert(fID != 0 &&
"-rightMouseDragged:, fID is 0");
2984 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2985 "-rightMouseDragged:, gVirtualX is null or not of TGCocoa type");
2987 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
2988 vx->GetEventTranslator()->GeneratePointerMotionEvent(theEvent);
2992 - (void) otherMouseDragged : (NSEvent *) theEvent
2994 assert(fID != 0 &&
"-otherMouseDragged:, fID is 0");
2996 if ([theEvent buttonNumber] == 2) {
2997 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2998 "-otherMouseDragged:, gVirtualX is null or not of TGCocoa type");
2999 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
3000 vx->GetEventTranslator()->GeneratePointerMotionEvent(theEvent);
3005 - (void) keyDown : (NSEvent *) theEvent
3007 assert(fID != 0 &&
"-keyDown:, fID is 0");
3009 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3010 "-keyDown:, gVirtualX is null or not of TGCocoa type");
3012 NSView<X11Window> *eventView =
self;
3013 if (NSView<X11Window> *pointerView = X11::FindViewUnderPointer())
3014 eventView = pointerView;
3016 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
3017 vx->GetEventTranslator()->GenerateKeyPressEvent(eventView, theEvent);
3021 - (void) keyUp : (NSEvent *) theEvent
3023 assert(fID != 0 &&
"-keyUp:, fID is 0");
3025 assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
3026 "-keyUp:, gVirtualX is null or not of TGCocoa type");
3028 TGCocoa *
const vx =
static_cast<TGCocoa *
>(gVirtualX);
3029 NSView<X11Window> *eventView =
self;
3030 if (NSView<X11Window> *pointerView = X11::FindViewUnderPointer())
3031 eventView = pointerView;
3033 vx->GetEventTranslator()->GenerateKeyReleaseEvent(eventView, theEvent);
3036 #pragma mark - First responder stuff.
3039 - (BOOL) acceptsFirstMouse : (NSEvent *) theEvent
3041 #pragma unused(theEvent)
3046 - (BOOL) acceptsFirstResponder
3051 #pragma mark - Cursors.
3054 - (void) setFCurrentCursor : (ECursor) cursor
3056 if (cursor != fCurrentCursor) {
3057 fCurrentCursor = cursor;
3058 [
self.fQuartzWindow invalidateCursorRectsForView : self];
3063 - (NSCursor *) createCustomCursor
3065 const char *pngFileName = 0;
3067 switch (fCurrentCursor) {
3069 pngFileName =
"move_cursor.png";
3072 pngFileName =
"hor_arrow_cursor.png";
3075 pngFileName =
"ver_arrow_cursor.png";
3078 pngFileName =
"right_arrow_cursor.png";
3081 pngFileName =
"rotate.png";
3085 pngFileName =
"top_right_cursor.png";
3089 pngFileName =
"top_left_cursor.png";
3095 const char *
const path = gSystem->Which(TROOT::GetIconPath(), pngFileName, kReadPermission);
3096 const Util::ScopedArray<const char> arrayGuard(path);
3098 if (!path || path[0] == 0) {
3103 NSString *nsPath = [NSString stringWithFormat : @"%s", path];
3104 NSImage *
const cursorImage = [[NSImage alloc] initWithContentsOfFile : nsPath];
3109 NSPoint hotSpot = X11::GetCursorHotStop(cursorImage, fCurrentCursor);
3110 NSCursor *
const customCursor = [[[NSCursor alloc] initWithImage : cursorImage
3111 hotSpot : hotSpot] autorelease];
3113 [cursorImage release];
3115 return customCursor;
3122 - (void) resetCursorRects
3124 if (NSCursor *
const cursor = X11::CreateCursor(fCurrentCursor))
3125 [
self addCursorRect : self.visibleRect cursor : cursor];
3129 - (void) cursorUpdate
3131 if (NSCursor *
const cursor = X11::CreateCursor(fCurrentCursor)) {
3139 - (void) cursorUpdate : (NSEvent *) event
3141 #pragma unused(event)
3153 [
self performSelector : @selector(cursorUpdate) withObject : nil afterDelay : 0.05f];
3156 #pragma mark - Emulated X11 properties.
3159 - (void) setProperty : (const
char *) propName data : (
unsigned char *) propData
3160 size : (
unsigned) dataSize forType : (Atom_t) dataType format : (
unsigned) format
3162 assert(propName != 0 &&
"-setProperty:data:size:forType:, parameter 'propName' is null");
3163 assert(propData != 0 &&
"-setProperty:data:size:forType:, parameter 'propData' is null");
3164 assert(dataSize != 0 &&
"-setProperty:data:size:forType:, parameter 'dataSize' is 0");
3166 NSString *
const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3167 QuartzWindowProperty *
property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3171 [property resetPropertyData : propData size : dataSize type : dataType format : format];
3174 property = [[QuartzWindowProperty alloc] initWithData : propData size : dataSize
3175 type : dataType format : format];
3176 [fX11Properties setObject : property forKey : key];
3182 - (BOOL) hasProperty : (const
char *) propName
3184 assert(propName != 0 &&
"-hasProperty:, propName parameter is null");
3186 NSString *
const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3187 QuartzWindowProperty *
const property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3189 return property != nil;
3193 - (
unsigned char *) getProperty : (const
char *) propName returnType : (Atom_t *) type
3194 returnFormat : (
unsigned *) format nElements : (
unsigned *) nElements
3196 assert(propName != 0 &&
3197 "-getProperty:returnType:returnFormat:nElements:, parameter 'propName' is null");
3199 "-getProperty:returnType:returnFormat:nElements:, parameter 'type' is null");
3200 assert(format != 0 &&
3201 "-getProperty:returnType:returnFormat:nElements:, parameter 'format' is null");
3202 assert(nElements != 0 &&
3203 "-getProperty:returnType:returnFormat:nElements:, parameter 'nElements' is null");
3205 NSString *
const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3206 QuartzWindowProperty *
const property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3207 assert(property != 0 &&
3208 "-getProperty:returnType:returnFormat:nElements, property not found");
3210 NSData *
const propData =
property.fPropertyData;
3212 const NSUInteger dataSize = [propData length];
3213 unsigned char *buff = 0;
3215 buff =
new unsigned char[dataSize]();
3216 }
catch (
const std::bad_alloc &) {
3218 NSLog(
@"QuartzWindow: -getProperty:returnType:returnFormat:nElements:,"
3219 " memory allocation failed");
3223 [propData getBytes : buff length : dataSize];
3224 *format =
property.fFormat;
3226 *nElements = dataSize;
3229 *nElements= dataSize / 2;
3230 else if (*format == 32)
3231 *nElements = dataSize / 4;
3233 *type =
property.fType;
3239 - (void) removeProperty : (const
char *) propName
3241 assert(propName != 0 &&
"-removeProperty:, parameter 'propName' is null");
3243 NSString *
const key = [NSString stringWithCString : propName
3244 encoding : NSASCIIStringEncoding];
3245 [fX11Properties removeObjectForKey : key];
3250 - (NSDragOperation) draggingEntered : (
id<NSDraggingInfo>) sender
3252 NSPasteboard *
const pasteBoard = [sender draggingPasteboard];
3253 const NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
3255 if ([[pasteBoard types] containsObject : NSFilenamesPboardType] && (sourceDragMask & NSDragOperationCopy))
3256 return NSDragOperationCopy;
3258 return NSDragOperationNone;
3262 - (BOOL) performDragOperation : (
id<NSDraggingInfo>) sender
3273 NSPasteboard *
const pasteBoard = [sender draggingPasteboard];
3274 const NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
3276 if ([[pasteBoard types] containsObject : NSFilenamesPboardType] && (sourceDragMask & NSDragOperationCopy)) {
3280 const Atom_t textUriAtom = gVirtualX->InternAtom(
"text/uri-list", kFALSE);
3282 NSArray *
const files = [pasteBoard propertyListForType : NSFilenamesPboardType];
3283 for (NSString *path in files) {
3285 NSString *
const item = [@"file://" stringByAppendingString : path];
3287 const NSUInteger len = [item lengthOfBytesUsingEncoding : NSASCIIStringEncoding] + 1;
3289 std::vector<unsigned char> propertyData(len);
3290 [item getCString : (char *)&propertyData[0] maxLength : propertyData.size()
3291 encoding : NSASCIIStringEncoding];
3293 NSView<X11Window> *
const targetView =
self.fQuartzWindow.fContentView;
3294 [targetView setProperty : "_XC_DND_DATA" data : &propertyData[0]
3295 size : propertyData.size() forType : textUriAtom format : 8];
3296 }
catch (
const std::bad_alloc &) {
3298 NSLog(
@"QuartzView: -performDragOperation:, memory allocation failed");
3309 Event_t event1 = {};
3310 event1.fType = kClientMessage;
3311 event1.fWindow = fID;
3312 event1.fHandle = gVirtualX->InternAtom(
"XdndEnter", kFALSE);
3313 event1.fUser[0] = long(fID);
3314 event1.fUser[2] = textUriAtom;
3316 gVirtualX->SendEvent(fID, &event1);
3319 Event_t event2 = {};
3320 event2.fType = kClientMessage;
3321 event2.fWindow = fID;
3322 event2.fHandle = gVirtualX->InternAtom(
"XdndPosition", kFALSE);
3323 event2.fUser[0] = long(fID);
3324 event2.fUser[2] = 0;
3325 NSPoint dropPoint = [sender draggingLocation];
3328 dropPoint = [
self convertPoint : dropPoint fromView : nil];
3330 dropPoint = X11::TranslateToScreen(
self, dropPoint);
3331 event2.fUser[2] = UShort_t(dropPoint.y) | (UShort_t(dropPoint.x) << 16);
3333 gVirtualX->SendEvent(fID, &event2);
3335 Event_t event3 = {};
3336 event3.fType = kClientMessage;
3337 event3.fWindow = fID;
3338 event3.fHandle = gVirtualX->InternAtom(
"XdndDrop", kFALSE);
3340 gVirtualX->SendEvent(fID, &event3);