]> git.saurik.com Git - wxWidgets.git/blobdiff - src/cocoa/window.mm
deTABbed wxQsort()
[wxWidgets.git] / src / cocoa / window.mm
index 83874d9ad0f167de021140d10015e7213eb5c0ae..2eaaafc97baa0cb1623ee4c1b09574d0f91d3d07 100644 (file)
@@ -24,6 +24,7 @@
 #include "wx/cocoa/string.h"
 #include "wx/cocoa/trackingrectmanager.h"
 
+#import <Foundation/NSArray.h>
 #import <Foundation/NSRunLoop.h>
 #include "wx/cocoa/objc/NSView.h"
 #import <AppKit/NSEvent.h>
 #import <AppKit/NSBezierPath.h>
 #endif //def WXCOCOA_FILL_DUMMY_VIEW
 
+/* NSComparisonResult is typedef'd as an enum pre-Leopard but typedef'd as
+ * NSInteger post-Leopard.  Pre-Leopard the Cocoa toolkit expects a function
+ * returning int and not NSComparisonResult.  Post-Leopard the Cocoa toolkit
+ * expects a function returning the new non-enum NSComparsionResult.
+ * Hence we create a typedef named CocoaWindowCompareFunctionResult.
+ */
+#if defined(NSINTEGER_DEFINED)
+typedef NSComparisonResult CocoaWindowCompareFunctionResult;
+#else
+typedef int CocoaWindowCompareFunctionResult;
+#endif
+
 // A category for methods that are only present in Panther's SDK
 @interface NSView(wxNSViewPrePantherCompatibility)
 - (void)getRectsBeingDrawn:(const NSRect **)rects count:(int *)count;
@@ -368,6 +381,9 @@ wxWindow::~wxWindow()
 
 void wxWindowCocoa::CocoaAddChild(wxWindowCocoa *child)
 {
+    // Pool here due to lack of one during wx init phase
+    wxAutoNSAutoreleasePool pool;
+
     NSView *childView = child->GetNSViewForSuperview();
 
     wxASSERT(childView);
@@ -458,7 +474,7 @@ bool wxWindowCocoa::Cocoa_drawRect(const NSRect &rect)
 
     // Set m_updateRegion
     const NSRect *rects = &rect; // The bounding box of the region
-    int countRects = 1;
+    NSInteger countRects = 1;
     // Try replacing the larger rectangle with a list of smaller ones:
     if ([GetNSView() respondsToSelector:@selector(getRectsBeingDrawn:count:)])
         [GetNSView() getRectsBeingDrawn:&rects count:&countRects];
@@ -654,6 +670,15 @@ bool wxWindowCocoa::Cocoa_resetCursorRects()
     return true;
 }
 
+bool wxWindowCocoa::SetCursor(const wxCursor &cursor)
+{
+    if(!wxWindowBase::SetCursor(cursor))
+        return false;
+    // Invalidate the cursor rects so the cursor will change
+    [[GetNSView() window] invalidateCursorRectsForView:GetNSView()];
+    return true;
+}
+
 bool wxWindowCocoa::Cocoa_viewDidMoveToWindow()
 {
     wxLogTrace(wxTRACE_COCOA,wxT("wxWindow=%p::viewDidMoveToWindow"),this);
@@ -1007,19 +1032,82 @@ void wxWindow::DoSetVirtualSize( int x, int y )
 
 bool wxWindow::SetFont(const wxFont& font)
 {
-    // TODO
-    return true;
+    // FIXME: We may need to handle wx font inheritance.
+    return wxWindowBase::SetFont(font);
 }
 
-static int CocoaRaiseWindowCompareFunction(id first, id second, void *target)
+#if 0 // these are used when debugging the algorithm.
+static char const * const comparisonresultStrings[] =
+{   "<"
+,   "=="
+,   ">"
+};
+#endif
+
+class CocoaWindowCompareContext
+{
+    DECLARE_NO_COPY_CLASS(CocoaWindowCompareContext)
+public:
+    CocoaWindowCompareContext(); // Not implemented
+    CocoaWindowCompareContext(NSView *target, NSArray *subviews)
+    {
+        m_target = target;
+        // Cocoa sorts subviews in-place.. make a copy
+        m_subviews = [subviews copy];
+    }
+    ~CocoaWindowCompareContext()
+    {   // release the copy
+        [m_subviews release];
+    }
+    NSView* target()
+    {   return m_target; }
+    NSArray* subviews()
+    {   return m_subviews; }
+    /* Helper function that returns the comparison based off of the original ordering */
+    CocoaWindowCompareFunctionResult CompareUsingOriginalOrdering(id first, id second)
+    {
+        NSUInteger firstI = [m_subviews indexOfObjectIdenticalTo:first];
+        NSUInteger secondI = [m_subviews indexOfObjectIdenticalTo:second];
+        // NOTE: If either firstI or secondI is NSNotFound then it will be NSIntegerMax and thus will
+        // likely compare higher than the other view which is reasonable considering the only way that
+        // can happen is if the subview was added after our call to subviews but before the call to
+        // sortSubviewsUsingFunction:context:.  Thus we don't bother checking.  Particularly because
+        // that case should never occur anyway because that would imply a multi-threaded GUI call
+        // which is a big no-no with Cocoa.
+
+        // Subviews are ordered from back to front meaning one that is already lower will have an lower index.
+        NSComparisonResult result = (firstI < secondI)
+            ?   NSOrderedAscending /* -1 */
+            :   (firstI > secondI)
+                ?   NSOrderedDescending /* 1 */
+                :   NSOrderedSame /* 0 */;
+
+#if 0 // Enable this if you need to debug the algorithm.
+        NSLog(@"%@ [%d] %s %@ [%d]\n", first, firstI, comparisonresultStrings[result+1], second, secondI);
+#endif
+        return result;
+    }
+private:
+    /* The subview we are trying to Raise or Lower */
+    NSView *m_target;
+    /* A copy of the original array of subviews */
+    NSArray *m_subviews;
+};
+
+/* Causes Cocoa to raise the target view to the top of the Z-Order by telling the sort function that
+ * the target view is always higher than every other view.  When comparing two views neither of
+ * which is the target, it returns the correct response based on the original ordering
+ */
+static CocoaWindowCompareFunctionResult CocoaRaiseWindowCompareFunction(id first, id second, void *ctx)
 {
+    CocoaWindowCompareContext *compareContext = (CocoaWindowCompareContext*)ctx;
     // first should be ordered higher
-    if(first==target)
+    if(first==compareContext->target())
         return NSOrderedDescending;
     // second should be ordered higher
-    if(second==target)
+    if(second==compareContext->target())
         return NSOrderedAscending;
-    return NSOrderedSame;
+    return compareContext->CompareUsingOriginalOrdering(first,second);
 }
 
 // Raise the window to the top of the Z order
@@ -1027,29 +1115,47 @@ void wxWindow::Raise()
 {
 //    wxAutoNSAutoreleasePool pool;
     NSView *nsview = GetNSViewForSuperview();
-    [[nsview superview] sortSubviewsUsingFunction:
+    NSView *superview = [nsview superview];
+    CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
+
+    [superview sortSubviewsUsingFunction:
             CocoaRaiseWindowCompareFunction
-        context: nsview];
+        context: &compareContext];
 }
 
-static int CocoaLowerWindowCompareFunction(id first, id second, void *target)
+/* Causes Cocoa to lower the target view to the bottom of the Z-Order by telling the sort function that
+ * the target view is always lower than every other view.  When comparing two views neither of
+ * which is the target, it returns the correct response based on the original ordering
+ */
+static CocoaWindowCompareFunctionResult CocoaLowerWindowCompareFunction(id first, id second, void *ctx)
 {
+    CocoaWindowCompareContext *compareContext = (CocoaWindowCompareContext*)ctx;
     // first should be ordered lower
-    if(first==target)
+    if(first==compareContext->target())
         return NSOrderedAscending;
     // second should be ordered lower
-    if(second==target)
+    if(second==compareContext->target())
         return NSOrderedDescending;
-    return NSOrderedSame;
+    return compareContext->CompareUsingOriginalOrdering(first,second);
 }
 
 // Lower the window to the bottom of the Z order
 void wxWindow::Lower()
 {
     NSView *nsview = GetNSViewForSuperview();
-    [[nsview superview] sortSubviewsUsingFunction:
+    NSView *superview = [nsview superview];
+    CocoaWindowCompareContext compareContext(nsview, [superview subviews]);
+
+#if 0
+    NSLog(@"Target:\n%@\n", nsview);
+    NSLog(@"Before:\n%@\n", compareContext.subviews());
+#endif
+    [superview sortSubviewsUsingFunction:
             CocoaLowerWindowCompareFunction
-        context: nsview];
+        context: &compareContext];
+#if 0
+    NSLog(@"After:\n%@\n", [superview subviews]);
+#endif
 }
 
 bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
@@ -1153,6 +1259,9 @@ void wxCocoaTrackingRectManager::StopSynthesizingEvents()
 
 void wxCocoaTrackingRectManager::BuildTrackingRect()
 {
+    // Pool here due to lack of one during wx init phase
+    wxAutoNSAutoreleasePool pool;
+
     wxASSERT_MSG(!m_isTrackingRectActive, wxT("Tracking rect was not cleared"));
     if([m_window->GetNSView() window] != nil)
     {