<commit_before>// @(#)root/graf2d:$Id$
// Author: <NAME>   16/02/2012

/*************************************************************************
 * Copyright (C) 1995-2012, <NAME> and <NAME>.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//#define DEBUG_ROOT_COCOA

//#define NDEBUG

#ifdef DEBUG_ROOT_COCOA
#import <iostream>
#import <fstream>

#import "TClass.h"
#endif

#import <algorithm>
#import <stdexcept>
#import <cassert>

#import "QuartzWindow.h"
#import "QuartzPixmap.h"
#import "QuartzUtils.h"
#import "CocoaUtils.h"
#import "X11Buffer.h"
#import "X11Events.h"
#import "TGWindow.h"
#import "TGClient.h"
#import "TSystem.h"
#import "TGCocoa.h"

namespace ROOT {
namespace MacOSX {
namespace X11 {

//______________________________________________________________________________
QuartzWindow *CreateTopLevelWindow(Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t /*border*/, Int_t depth,
                                   UInt_t clss, void */*visual*/, SetWindowAttributes_t *attr, UInt_t)
{
   NSRect winRect = {};
   winRect.origin.x = x; 
   winRect.origin.y = GlobalYROOTToCocoa(y);
   winRect.size.width = w;
   winRect.size.height = h;

   //TODO check mask.
   const NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask;
   //
   QuartzWindow *newWindow = [[QuartzWindow alloc] initWithContentRect : winRect styleMask : styleMask backing : NSBackingStoreBuffered defer : YES windowAttributes : attr];
   if (!newWindow)
      throw std::runtime_error("CreateTopLevelWindow failed");
   //
   newWindow.fDepth = depth;
   newWindow.fClass = clss;

   return newWindow;
}

//______________________________________________________________________________
QuartzView *CreateChildView(QuartzView * /*parent*/, Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t /*border*/, Int_t /*depth*/,
                            UInt_t /*clss*/, void * /*visual*/, SetWindowAttributes_t *attr, UInt_t /*wtype*/)
{
   NSRect viewRect = {};
   viewRect.origin.x = x;
   viewRect.origin.y = y;
   viewRect.size.width = w;
   viewRect.size.height = h;
   
   QuartzView *view = [[QuartzView alloc] initWithFrame : viewRect windowAttributes : attr];
   if (!view)
      throw std::runtime_error("CreateChildView failed");
   
   return view;
}

//______________________________________________________________________________
void GetRootWindowAttributes(WindowAttributes_t *attr)
{
   //'root' window does not exist, but we can request its attributes.
   assert(attr != 0 && "GetRootWindowAttributes, attr parameter is null");
   
   NSArray *screens = [NSScreen screens];
   assert(screens != nil && "screens array is nil");
   
   NSScreen *mainScreen = [screens objectAtIndex : 0];
   assert(mainScreen != nil && "screen with index 0 is nil");

   *attr = WindowAttributes_t();
   
   attr->fX = 0;
   attr->fY = 0;
   
   const NSRect frame = [mainScreen frame];
   
   attr->fWidth = frame.size.width;
   attr->fHeight = frame.size.height;
   attr->fBorderWidth = 0;
   attr->fYourEventMask = 0;
   attr->fAllEventMasks = 0;//???

   attr->fDepth = NSBitsPerPixelFromDepth([mainScreen depth]);
   attr->fVisual = 0;
   attr->fRoot = 0;
}


//Coordinate conversion.

//TODO: check how TGX11 extracts/changes window attributes.

//______________________________________________________________________________
int GlobalYCocoaToROOT(CGFloat yCocoa)
{
   NSArray *screens = [NSScreen screens];
   assert(screens != nil && "GlobalYCocoaToROOT, screens array is nil");
   
   NSScreen *mainScreen = [screens objectAtIndex : 0];
   assert(mainScreen != nil && "GlobalYCocoaToROOT, screen at index 0 is nil");
   
   return int(mainScreen.frame.size.height - yCocoa);
}

//______________________________________________________________________________
int GlobalYROOTToCocoa(CGFloat yROOT)
{
   //hehe :)) actually, no need in this function.
   NSArray *screens = [NSScreen screens];
   assert(screens != nil && "GlobalYROOTToCocoa, screens array is nil");
   
   NSScreen *mainScreen = [screens objectAtIndex : 0];
   assert(mainScreen != nil && "GlobalYROOTToCocoa, screen at index 0 is nil");
   
   return int(mainScreen.frame.size.height - yROOT);
}

//______________________________________________________________________________
int LocalYCocoaToROOT(NSView<X11Window> *parentView, CGFloat yCocoa)
{
   assert(parentView != nil && "LocalYCocoaToROOT, parent view is nil");
   
   return int(parentView.frame.size.height - yCocoa);
}

//______________________________________________________________________________
int LocalYROOTToCocoa(NSView<X11Window> *parentView, CGFloat yROOT)
{
   //:)
   assert(parentView != nil && "LocalYROOTToCocoa, parent view is nil");
   
   return int(parentView.frame.size.height - yROOT);
}


//______________________________________________________________________________
int LocalYROOTToCocoa(NSObject<X11Drawable> *drawable, CGFloat yROOT)
{
   //:)
   assert(drawable != nil && "LocalYROOTToCocoa, drawable is nil");
   
   return int(drawable.fHeight - yROOT);
}

//______________________________________________________________________________
NSPoint TranslateToScreen(NSView<X11Window> *from, NSPoint point)
{
   assert(from != nil && "TranslateToScreen, 'from' parameter is nil");
   
   //TODO: I do not know, if I can use convertToBacking ..... - have to check this.
   NSPoint winPoint = [from convertPoint : point toView : nil];
   NSPoint screenPoint = [[from window] convertBaseToScreen : winPoint];; 
   //TODO: This is Cocoa's coordinates, but for ROOT I have to convert.
   screenPoint.y = GlobalYCocoaToROOT(screenPoint.y);

   return screenPoint;
}

//______________________________________________________________________________
NSPoint TranslateFromScreen(NSPoint point, NSView<X11Window> *to)
{
   assert(to != nil && "TranslateFromScreen, 'to' parameter is nil");
   
   point.y = GlobalYROOTToCocoa(point.y);

   //May be I can use convertBackingTo .... have to check this.
   const NSPoint winPoint = [[to window] convertScreenToBase : point];
   return [to convertPoint : winPoint fromView : nil];
}

//______________________________________________________________________________
NSPoint TranslateCoordinates(NSView<X11Window> *from, NSView<X11Window> *to, NSPoint sourcePoint)
{
   //Both views are valid.
   assert(from != nil && "TranslateCoordinates, 'from' parameter is nil");
   assert(to != nil && "TranslateCoordinates, 'to' parameter is nil");

   if ([from window] == [to window]) {
      //Both views are in the same window.
      return [to convertPoint : sourcePoint fromView : from];      
   } else {
      //May be, I can do it in one call, but it's not obvious for me
      //what is 'pixel aligned backing store coordinates' and
      //if they are the same as screen coordinates.
      
      const NSPoint win1Point = [from convertPoint : sourcePoint toView : nil];
      const NSPoint screenPoint = [[from window] convertBaseToScreen : win1Point];
      const NSPoint win2Point = [[to window] convertScreenToBase : screenPoint];

      return [to convertPoint : win2Point fromView : nil];
   }
}

//______________________________________________________________________________
bool ScreenPointIsInView(NSView<X11Window> *view, Int_t x, Int_t y)
{
   assert(view != nil && "ScreenPointIsInView, view parameter is nil");
   
   NSPoint point = {};
   point.x = x, point.y = y;
   point = TranslateFromScreen(point, view);
   const NSRect viewFrame = view.frame;

   if (point.x < 0 || point.x > viewFrame.size.width)
      return false;
   if (point.y < 0 || point.y > viewFrame.size.height)
      return false;
   
   return true;
}

//______________________________________________________________________________
QuartzWindow *FindWindowInPoint(Int_t x, Int_t y)
{
   const Util::AutoreleasePool pool;//array's counter is increased, all object in array are also retained.

   NSArray *orderedWindows = [NSApp orderedWindows];
   for (NSWindow *window in orderedWindows) {
      if (![window isKindOfClass : [QuartzWindow class]])
         continue;
      QuartzWindow *qw = (QuartzWindow *)window;
      //Check if point is inside.
      if (ScreenPointIsInView(qw.fContentView, x, y))
         return qw;
   }
   
   return nil;
}

//______________________________________________________________________________
NSView<X11Window> *FindDNDAwareViewInPoint(NSArray *children, Window_t dragWinID, Window_t inputWinID, Int_t x, Int_t y, Int_t maxDepth)
{
   assert(children != nil && "FindDNDAwareViewInPoint, children parameter is nil");
   
   if (maxDepth <= 0)
      return nil;

   NSEnumerator *reverseEnumerator = [children reverseObjectEnumerator];
   for (NSView<X11Window> *child in reverseEnumerator) {
      if (!ScreenPointIsInView(child, x, y))
         continue;
      if (child.fIsDNDAware && child.fID != dragWinID && child.fID != inputWinID)
         return child;//got it!
            
      NSView<X11Window> *testView = FindDNDAwareViewInPoint(child, dragWinID, inputWinID, x, y, maxDepth - 1);
      if (testView)
         return testView;
   }

   return nil;
}

//______________________________________________________________________________
NSView<X11Window> *FindDNDAwareViewInPoint(NSView *parentView, Window_t dragWinID, Window_t inputWinID, Int_t x, Int_t y, Int_t maxDepth)
{
   //X and Y are ROOT's screen coordinates (Y is inverted).
   if (maxDepth <= 0)
      return nil;

   const Util::AutoreleasePool pool;

   if (!parentView) {//Start from the screen as a 'root' window.
      NSArray *orderedWindows = [NSApp orderedWindows];
      for (NSWindow *window in orderedWindows) {
         if (![window isKindOfClass : [QuartzWindow class]])
            continue;
         QuartzWindow *qw = (QuartzWindow *)window;
         if (qw.fMapState != kIsViewable)
            continue;

         //First, check this view itself, my be we found what we need already.
         NSView<X11Window> *testView = qw.fContentView;<commit_msg>Simplify a window search recursion.<commit_after>// @(#)root/graf2d:$Id$
// Author: <NAME>   16/02/2012

/*************************************************************************
 * Copyright (C) 1995-2012, <NAME> and <NAME>.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//#define DEBUG_ROOT_COCOA

//#define NDEBUG

#ifdef DEBUG_ROOT_COCOA
#import <iostream>
#import <fstream>

#import "TClass.h"
#endif

#import <algorithm>
#import <stdexcept>
#import <cassert>

#import "QuartzWindow.h"
#import "QuartzPixmap.h"
#import "QuartzUtils.h"
#import "CocoaUtils.h"
#import "X11Buffer.h"
#import "X11Events.h"
#import "TGWindow.h"
#import "TGClient.h"
#import "TSystem.h"
#import "TGCocoa.h"

namespace ROOT {
namespace MacOSX {
namespace X11 {

//______________________________________________________________________________
QuartzWindow *CreateTopLevelWindow(Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t /*border*/, Int_t depth,
                                   UInt_t clss, void */*visual*/, SetWindowAttributes_t *attr, UInt_t)
{
   NSRect winRect = {};
   winRect.origin.x = x; 
   winRect.origin.y = GlobalYROOTToCocoa(y);
   winRect.size.width = w;
   winRect.size.height = h;

   //TODO check mask.
   const NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask;
   //
   QuartzWindow *newWindow = [[QuartzWindow alloc] initWithContentRect : winRect styleMask : styleMask backing : NSBackingStoreBuffered defer : YES windowAttributes : attr];
   if (!newWindow)
      throw std::runtime_error("CreateTopLevelWindow failed");
   //
   newWindow.fDepth = depth;
   newWindow.fClass = clss;

   return newWindow;
}

//______________________________________________________________________________
QuartzView *CreateChildView(QuartzView * /*parent*/, Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t /*border*/, Int_t /*depth*/,
                            UInt_t /*clss*/, void * /*visual*/, SetWindowAttributes_t *attr, UInt_t /*wtype*/)
{
   NSRect viewRect = {};
   viewRect.origin.x = x;
   viewRect.origin.y = y;
   viewRect.size.width = w;
   viewRect.size.height = h;
   
   QuartzView *view = [[QuartzView alloc] initWithFrame : viewRect windowAttributes : attr];
   if (!view)
      throw std::runtime_error("CreateChildView failed");
   
   return view;
}

//______________________________________________________________________________
void GetRootWindowAttributes(WindowAttributes_t *attr)
{
   //'root' window does not exist, but we can request its attributes.
   assert(attr != 0 && "GetRootWindowAttributes, attr parameter is null");
   
   NSArray *screens = [NSScreen screens];
   assert(screens != nil && "screens array is nil");
   
   NSScreen *mainScreen = [screens objectAtIndex : 0];
   assert(mainScreen != nil && "screen with index 0 is nil");

   *attr = WindowAttributes_t();
   
   attr->fX = 0;
   attr->fY = 0;
   
   const NSRect frame = [mainScreen frame];
   
   attr->fWidth = frame.size.width;
   attr->fHeight = frame.size.height;
   attr->fBorderWidth = 0;
   attr->fYourEventMask = 0;
   attr->fAllEventMasks = 0;//???

   attr->fDepth = NSBitsPerPixelFromDepth([mainScreen depth]);
   attr->fVisual = 0;
   attr->fRoot = 0;
}


//Coordinate conversion.

//TODO: check how TGX11 extracts/changes window attributes.

//______________________________________________________________________________
int GlobalYCocoaToROOT(CGFloat yCocoa)
{
   NSArray *screens = [NSScreen screens];
   assert(screens != nil && "GlobalYCocoaToROOT, screens array is nil");
   
   NSScreen *mainScreen = [screens objectAtIndex : 0];
   assert(mainScreen != nil && "GlobalYCocoaToROOT, screen at index 0 is nil");
   
   return int(mainScreen.frame.size.height - yCocoa);
}

//______________________________________________________________________________
int GlobalYROOTToCocoa(CGFloat yROOT)
{
   //hehe :)) actually, no need in this function.
   NSArray *screens = [NSScreen screens];
   assert(screens != nil && "GlobalYROOTToCocoa, screens array is nil");
   
   NSScreen *mainScreen = [screens objectAtIndex : 0];
   assert(mainScreen != nil && "GlobalYROOTToCocoa, screen at index 0 is nil");
   
   return int(mainScreen.frame.size.height - yROOT);
}

//______________________________________________________________________________
int LocalYCocoaToROOT(NSView<X11Window> *parentView, CGFloat yCocoa)
{
   assert(parentView != nil && "LocalYCocoaToROOT, parent view is nil");
   
   return int(parentView.frame.size.height - yCocoa);
}

//______________________________________________________________________________
int LocalYROOTToCocoa(NSView<X11Window> *parentView, CGFloat yROOT)
{
   //:)
   assert(parentView != nil && "LocalYROOTToCocoa, parent view is nil");
   
   return int(parentView.frame.size.height - yROOT);
}


//______________________________________________________________________________
int LocalYROOTToCocoa(NSObject<X11Drawable> *drawable, CGFloat yROOT)
{
   //:)
   assert(drawable != nil && "LocalYROOTToCocoa, drawable is nil");
   
   return int(drawable.fHeight - yROOT);
}

//______________________________________________________________________________
NSPoint TranslateToScreen(NSView<X11Window> *from, NSPoint point)
{
   assert(from != nil && "TranslateToScreen, 'from' parameter is nil");
   
   //TODO: I do not know, if I can use convertToBacking ..... - have to check this.
   NSPoint winPoint = [from convertPoint : point toView : nil];
   NSPoint screenPoint = [[from window] convertBaseToScreen : winPoint];; 
   //TODO: This is Cocoa's coordinates, but for ROOT I have to convert.
   screenPoint.y = GlobalYCocoaToROOT(screenPoint.y);

   return screenPoint;
}

//______________________________________________________________________________
NSPoint TranslateFromScreen(NSPoint point, NSView<X11Window> *to)
{
   assert(to != nil && "TranslateFromScreen, 'to' parameter is nil");
   
   point.y = GlobalYROOTToCocoa(point.y);

   //May be I can use convertBackingTo .... have to check this.
   const NSPoint winPoint = [[to window] convertScreenToBase : point];
   return [to convertPoint : winPoint fromView : nil];
}

//______________________________________________________________________________
NSPoint TranslateCoordinates(NSView<X11Window> *from, NSView<X11Window> *to, NSPoint sourcePoint)
{
   //Both views are valid.
   assert(from != nil && "TranslateCoordinates, 'from' parameter is nil");
   assert(to != nil && "TranslateCoordinates, 'to' parameter is nil");

   if ([from window] == [to window]) {
      //Both views are in the same window.
      return [to convertPoint : sourcePoint fromView : from];      
   } else {
      //May be, I can do it in one call, but it's not obvious for me
      //what is 'pixel aligned backing store coordinates' and
      //if they are the same as screen coordinates.
      
      const NSPoint win1Point = [from convertPoint : sourcePoint toView : nil];
      const NSPoint screenPoint = [[from window] convertBaseToScreen : win1Point];
      const NSPoint win2Point = [[to window] convertScreenToBase : screenPoint];

      return [to convertPoint : win2Point fromView : nil];
   }
}

//______________________________________________________________________________
bool ScreenPointIsInView(NSView<X11Window> *view, Int_t x, Int_t y)
{
   assert(view != nil && "ScreenPointIsInView, view parameter is nil");
   
   NSPoint point = {};
   point.x = x, point.y = y;
   point = TranslateFromScreen(point, view);
   const NSRect viewFrame = view.frame;

   if (point.x < 0 || point.x > viewFrame.size.width)
      return false;
   if (point.y < 0 || point.y > viewFrame.size.height)
      return false;
   
   return true;
}

//______________________________________________________________________________
QuartzWindow *FindWindowInPoint(Int_t x, Int_t y)
{
   const Util::AutoreleasePool pool;//array's counter is increased, all object in array are also retained.

   NSArray *orderedWindows = [NSApp orderedWindows];
   for (NSWindow *window in orderedWindows) {
      if (![window isKindOfClass : [QuartzWindow class]])
         continue;
      QuartzWindow *qw = (QuartzWindow *)window;
      //Check if point is inside.
      if (ScreenPointIsInView(qw.fContentView, x, y))
         return qw;
   }
   
   return nil;
}

//______________________________________________________________________________
NSView<X11Window> *FindDNDAwareViewInPoint(NSArray *children, Window_t dragWinID, Window_t inputWinID, Int_t x, Int_t y, Int_t maxDepth)
{
   assert(children != nil && "FindDNDAwareViewInPoint, children parameter is nil");
   
   if (maxDepth <= 0)
      return nil;

   NSEnumerator *reverseEnumerator = [children reverseObjectEnumerator];
   for (NSView<X11Window> *child in reverseEnumerator) {
      if (!ScreenPointIsInView(child, x, y))
         continue;
      if (child.fIsDNDAware && child.fID != dragWinID && child.fID != inputWinID)
         return child;//got it!
            
      NSView<X11Window> *testView = FindDNDAwareViewInPoint([child subviews], dragWinID, inputWinID, x, y, maxDepth - 1);
      if (testView)
         return testView;
   }

   return nil;
}

//______________________________________________________________________________
NSView<X11Window> *FindDNDAwareViewInPoint(NSView *parentView, Window_t dragWinID, Window_t inputWinID, Int_t x, Int_t y, Int_t maxDepth)
{
   //X and Y are ROOT's screen coordinates (Y is inverted).
   if (maxDepth <= 0)
      return nil;

   const Util::AutoreleasePool pool;

   if (!parentView) {//Start from the screen as a 'root' window.
      NSArray *orderedWindows = [NSApp orderedWindows];
      for (NSWindow *window in orderedWindows) {
         if (![window isKindOfClass : [QuartzWindow class]])
            continue;
         QuartzWindow *qw = (QuartzWindow *)window;
         if (qw.fMapState != kIsViewable)
            continue;

         //First, check this view itself, my be we found what we need already.
         NSView<X11Window> *testView = qw.fContentView;
{'fraction_non_alphanumeric': 0.11814895155459147, 'fraction_numerical': 0.007134249216678718, 'mean_word_length': 3.6989807474518686, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7198845', 'n_tokens_mistral': 6228, 'n_tokens_neox': 6015, 'n_words': 1624}