<commit_before>// @(#)root/graf2d:$Id$
// Author: <NAME>   29/11/2011

/*************************************************************************
 * 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
#include <algorithm>
#endif

#include <stdexcept>
#include <cassert>

#include <OpenGL/OpenGL.h>
#include <Cocoa/Cocoa.h>

#include "ROOTApplicationDelegate.h"
#include "ROOTOpenGLView.h"
#include "CocoaPrivate.h"
#include "QuartzWindow.h"
#include "CocoaUtils.h"

namespace ROOT {
namespace MacOSX {
namespace Details {

//______________________________________________________________________________
CocoaPrivate::CocoaPrivate()
               : fCurrentDrawableID(GetRootWindowID() + 1), //Any real window has id > rootID.
                                                            //0 is also used by some X11 functions as None.
                 fFreeGLContextID(1),
                 fApplicationDelegate([[ROOTApplicationDelegate alloc] init])
{
   //Init NSApplication, if it was not done yet.
   Util::AutoreleasePool pool;
   [NSApplication sharedApplication];
}

//______________________________________________________________________________
CocoaPrivate::~CocoaPrivate()
{
}

//______________________________________________________________________________
Window_t CocoaPrivate::GetRootWindowID()const
{
   //First I had root ID == 0, but this is None in X11 and
   //it can be used by ROOT, for example, I had trouble with
   //gClient able to found TGWindow for None - crash!
   return 1;
}

//______________________________________________________________________________
bool CocoaPrivate::IsRootWindow(Window_t windowID)const
{
   return windowID == GetRootWindowID();
}

//______________________________________________________________________________
Drawable_t CocoaPrivate::RegisterDrawable(NSObject *nsObj)
{
   //Return integer identifier for a new "drawable" (like in X11)

   if (fCurrentDrawableID == 999)//I have to skip this, many thanks to ROOT who uses 999 as "all windows".
      ++fCurrentDrawableID;

   Drawable_t newID = fCurrentDrawableID;

   if (fFreeDrawableIDs.size()) {
      newID = fFreeDrawableIDs.back();
      fFreeDrawableIDs.pop_back();
   } else
      fCurrentDrawableID++;

   assert(fDrawables.find(newID) == fDrawables.end() && "RegisterDrawable, id for new drawable is still in use");
   fDrawables[newID] = nsObj;

   return newID;
}

//______________________________________________________________________________
NSObject<X11Drawable> *CocoaPrivate::GetDrawable(Drawable_t drawableID)const
{
   const_drawable_iterator drawableIter = fDrawables.find(drawableID);
   
#ifdef DEBUG_ROOT_COCOA
   if (drawableIter == fDrawables.end()) {
      NSLog(@"Fatal error: requested non-existing drawable %lu", drawableID);
      //We do not care about efficiency, ROOT's gonna die on assert :)
      std::vector<Drawable_t>::const_iterator deletedDrawable = std::find(fFreeDrawableIDs.begin(), fFreeDrawableIDs.end(), drawableID);
      if (deletedDrawable != fFreeDrawableIDs.end()) {
         NSLog(@"This drawable was deleted already");
      } else {
         NSLog(@"This drawable not found among allocated/deleted drawables");
      }
   }
#endif
   assert(drawableIter != fDrawables.end() && "GetDrawable, non-existing drawable requested");
   return drawableIter->second.Get();
}

//______________________________________________________________________________
NSObject<X11Window> *CocoaPrivate::GetWindow(Window_t windowID)const
{
   const_drawable_iterator winIter = fDrawables.find(windowID);
#ifdef DEBUG_ROOT_COCOA
   if (winIter == fDrawables.end()) {
      NSLog(@"Fatal error: requested non-existing drawable %lu", windowID);
      //We do not care about efficiency, ROOT's gonna die on assert :)
      std::vector<Drawable_t>::const_iterator deletedDrawable = std::find(fFreeDrawableIDs.begin(), fFreeDrawableIDs.end(), windowID);
      if (deletedDrawable != fFreeDrawableIDs.end()) {
         NSLog(@"This window was deleted already");
      } else {
         NSLog(@"This window not found among allocated/deleted drawables");
      }
   }
#endif
   assert(winIter != fDrawables.end() && "GetWindow, non-existing window requested");
   return (NSObject<X11Window> *)winIter->second.Get();
}

//______________________________________________________________________________
void CocoaPrivate::DeleteDrawable(Drawable_t drawableID)
{
   drawable_iterator drawableIter = fDrawables.find(drawableID);
   assert(drawableIter != fDrawables.end() && "DeleteDrawable, non existing drawableID");

   //Probably, I'll need some additional cleanup here later. Now just delete NSObject and
   //reuse its id.
   NSObject<X11Drawable> * const base = drawableIter->second.Get();
   if ([base isKindOfClass : [QuartzView class]]) {
      [(QuartzView *)base removeFromSuperview];
      ((QuartzView *)base).fParentView = nil;
   } else if ([base isKindOfClass : [QuartzWindow class]]) {
      QuartzWindow *qw = (QuartzWindow *)base;

      qw.fContentView.fParentView = nil;
      [qw.fContentView removeFromSuperview];
      qw.contentView = nil;

      //Remove transient windows?
      /*
      const Util::NSScopeGuard<NSArray> children([[qw childWindows] copy]);
      for (QuartzWindow *child in children.Get()) {
         child.fMainWindow = nil;
         [qw removeChildWindow : child];
      }
      */

      if (qw.fMainWindow) {
         [qw.fMainWindow removeChildWindow : qw];
         qw.fMainWindow = nil;
      }
   }

//   fFreeDrawableIDs.push_back(drawableID);
   fDrawables.erase(drawableIter);//StrongReference should do work here.
}

//______________________________________________________________________________
Handle_t CocoaPrivate::RegisterGLContext(NSOpenGLContext *glContext)
{
   assert(fGLContextToHandle.find(glContext) == fGLContextToHandle.end() && "RegisterGLContext, context was registered already");

   //Strong es-guarantee guarantee - if we have an exception, everything is rolled-back.
<commit_msg>Mark a window as deleted in DestroyDrawable for the case Cocoa internally increased the reference counter itself (thus, preventing window from real deletion).<commit_after>// @(#)root/graf2d:$Id$
// Author: <NAME>   29/11/2011

/*************************************************************************
 * 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
#include <algorithm>
#endif

#include <stdexcept>
#include <cassert>

#include <OpenGL/OpenGL.h>
#include <Cocoa/Cocoa.h>

#include "ROOTApplicationDelegate.h"
#include "ROOTOpenGLView.h"
#include "CocoaPrivate.h"
#include "QuartzWindow.h"
#include "CocoaUtils.h"

namespace ROOT {
namespace MacOSX {
namespace Details {

//______________________________________________________________________________
CocoaPrivate::CocoaPrivate()
               : fCurrentDrawableID(GetRootWindowID() + 1), //Any real window has id > rootID.
                                                            //0 is also used by some X11 functions as None.
                 fFreeGLContextID(1),
                 fApplicationDelegate([[ROOTApplicationDelegate alloc] init])
{
   //Init NSApplication, if it was not done yet.
   Util::AutoreleasePool pool;
   [NSApplication sharedApplication];
}

//______________________________________________________________________________
CocoaPrivate::~CocoaPrivate()
{
}

//______________________________________________________________________________
Window_t CocoaPrivate::GetRootWindowID()const
{
   //First I had root ID == 0, but this is None in X11 and
   //it can be used by ROOT, for example, I had trouble with
   //gClient able to found TGWindow for None - crash!
   return 1;
}

//______________________________________________________________________________
bool CocoaPrivate::IsRootWindow(Window_t windowID)const
{
   return windowID == GetRootWindowID();
}

//______________________________________________________________________________
Drawable_t CocoaPrivate::RegisterDrawable(NSObject *nsObj)
{
   //Return integer identifier for a new "drawable" (like in X11)

   if (fCurrentDrawableID == 999)//I have to skip this, many thanks to ROOT who uses 999 as "all windows".
      ++fCurrentDrawableID;

   Drawable_t newID = fCurrentDrawableID;

   if (fFreeDrawableIDs.size()) {
      newID = fFreeDrawableIDs.back();
      fFreeDrawableIDs.pop_back();
   } else
      fCurrentDrawableID++;

   assert(fDrawables.find(newID) == fDrawables.end() && "RegisterDrawable, id for new drawable is still in use");
   fDrawables[newID] = nsObj;

   return newID;
}

//______________________________________________________________________________
NSObject<X11Drawable> *CocoaPrivate::GetDrawable(Drawable_t drawableID)const
{
   const_drawable_iterator drawableIter = fDrawables.find(drawableID);
   
#ifdef DEBUG_ROOT_COCOA
   if (drawableIter == fDrawables.end()) {
      NSLog(@"Fatal error: requested non-existing drawable %lu", drawableID);
      //We do not care about efficiency, ROOT's gonna die on assert :)
      std::vector<Drawable_t>::const_iterator deletedDrawable = std::find(fFreeDrawableIDs.begin(), fFreeDrawableIDs.end(), drawableID);
      if (deletedDrawable != fFreeDrawableIDs.end()) {
         NSLog(@"This drawable was deleted already");
      } else {
         NSLog(@"This drawable not found among allocated/deleted drawables");
      }
   }
#endif
   assert(drawableIter != fDrawables.end() && "GetDrawable, non-existing drawable requested");
   return drawableIter->second.Get();
}

//______________________________________________________________________________
NSObject<X11Window> *CocoaPrivate::GetWindow(Window_t windowID)const
{
   const_drawable_iterator winIter = fDrawables.find(windowID);
#ifdef DEBUG_ROOT_COCOA
   if (winIter == fDrawables.end()) {
      NSLog(@"Fatal error: requested non-existing drawable %lu", windowID);
      //We do not care about efficiency, ROOT's gonna die on assert :)
      std::vector<Drawable_t>::const_iterator deletedDrawable = std::find(fFreeDrawableIDs.begin(), fFreeDrawableIDs.end(), windowID);
      if (deletedDrawable != fFreeDrawableIDs.end()) {
         NSLog(@"This window was deleted already");
      } else {
         NSLog(@"This window not found among allocated/deleted drawables");
      }
   }
#endif
   assert(winIter != fDrawables.end() && "GetWindow, non-existing window requested");
   return (NSObject<X11Window> *)winIter->second.Get();
}

//______________________________________________________________________________
void CocoaPrivate::DeleteDrawable(Drawable_t drawableID)
{
   drawable_iterator drawableIter = fDrawables.find(drawableID);
   assert(drawableIter != fDrawables.end() && "DeleteDrawable, non existing drawableID");

   //Probably, I'll need some additional cleanup here later. Now just delete NSObject and
   //reuse its id.
   NSObject<X11Drawable> * const base = drawableIter->second.Get();
   if ([base isKindOfClass : [QuartzView class]]) {
      [(QuartzView *)base removeFromSuperview];
      ((QuartzView *)base).fParentView = nil;
   } else if ([base isKindOfClass : [QuartzWindow class]]) {
      QuartzWindow *qw = (QuartzWindow *)base;

      qw.fContentView.fParentView = nil;
      [qw.fContentView removeFromSuperview];
      qw.contentView = nil;

      qw.fIsDeleted = YES;
      //Remove transient windows?
      /*
      const Util::NSScopeGuard<NSArray> children([[qw childWindows] copy]);
      for (QuartzWindow *child in children.Get()) {
         child.fMainWindow = nil;
         [qw removeChildWindow : child];
      }
      */

      if (qw.fMainWindow) {
         [qw.fMainWindow removeChildWindow : qw];
         qw.fMainWindow = nil;
      }
   }

//   fFreeDrawableIDs.push_back(drawableID);
   fDrawables.erase(drawableIter);//StrongReference should do work here.
}

//______________________________________________________________________________
Handle_t CocoaPrivate::RegisterGLContext(NSOpenGLContext *glContext)
{
   assert(fGLContextToHandle.find(glContext) == fGLContextToHandle.end() && "RegisterGLContext, context was registered already");

   //Strong es-guarantee guarantee - if we have an exception, everything is rolled-back.

{'fraction_non_alphanumeric': 0.1229345165238678, 'fraction_numerical': 0.006425948592411261, 'mean_word_length': 3.760742898761835, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2468580', 'n_tokens_mistral': 3587, 'n_tokens_neox': 3493, 'n_words': 878}