Merged 47994 from trunk. WARNING: changes runtime behavior:
Implement transformation between the wxDisplay coordinate system and the Cocoa screen coordinate system. Use this to fix TLW initial positioning/sizing (including wxTopLevelWindow, wxFrame, and wxDialog) Use this to implement wxWindow::DoScreenToClient and DoClientToScreen Copyright 2007 Software 2000 Ltd. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_8_BRANCH@47995 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -80,6 +80,7 @@ protected:
|
||||
static wxCocoaNSWindowHash sm_cocoaHash;
|
||||
virtual void CocoaReplaceView(WX_NSView oldView, WX_NSView newView);
|
||||
static unsigned int NSWindowStyleForWxStyle(long style);
|
||||
static NSRect MakeInitialNSWindowContentRect(const wxPoint& pos, const wxSize& size, unsigned int cocoaStyleMask);
|
||||
|
||||
static wxTopLevelWindowCocoa *sm_cocoaDeactivateWindow;
|
||||
// ------------------------------------------------------------------------
|
||||
|
@@ -18,6 +18,22 @@
|
||||
#import <Foundation/NSGeometry.h>
|
||||
#endif //def __OBJC__
|
||||
|
||||
// We can only import Foundation/NSGeometry.h from Objective-C code but it's
|
||||
// nice to be able to use NSPoint and NSRect in the declarations of helper
|
||||
// methods so we must define them as opaque structs identically to the way
|
||||
// they are defined by the real header.
|
||||
// NOTE: We specifically use these regardless of C++ or Objective-C++ mode so
|
||||
// the compiler will complain if we got the definitions wrong. In regular
|
||||
// C++ mode there is no way to know if we got the definitons right so
|
||||
// we depend on at least one Objective-C++ file including this header.
|
||||
#if defined(__LP64__) || defined(NS_BUILD_32_LIKE_64)
|
||||
typedef struct CGPoint NSPoint;
|
||||
typedef struct CGRect NSRect;
|
||||
#else
|
||||
typedef struct _NSPoint NSPoint;
|
||||
typedef struct _NSRect NSRect;
|
||||
#endif
|
||||
|
||||
DECLARE_WXCOCOA_OBJC_CLASS(NSAffineTransform);
|
||||
|
||||
class wxWindowCocoaHider;
|
||||
@@ -142,6 +158,8 @@ protected:
|
||||
NSPoint CocoaTransformWxToBounds(NSPoint pointWx);
|
||||
NSRect CocoaTransformWxToBounds(NSRect rectWx);
|
||||
#endif //def __OBJC__
|
||||
static wxPoint OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(NSRect windowFrame);
|
||||
static NSPoint OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(wxCoord x, wxCoord y, wxCoord width, wxCoord height, bool keepOriginVisible);
|
||||
// ------------------------------------------------------------------------
|
||||
// Implementation
|
||||
// ------------------------------------------------------------------------
|
||||
|
@@ -57,13 +57,9 @@ bool wxDialog::Create(wxWindow *parent, wxWindowID winid,
|
||||
if (parent)
|
||||
parent->AddChild(this);
|
||||
|
||||
NSRect cocoaRect = NSMakeRect(300,300,200,200);
|
||||
unsigned int cocoaStyle = NSWindowStyleForWxStyle(style);
|
||||
|
||||
unsigned int cocoaStyle = 0;
|
||||
cocoaStyle |= NSTitledWindowMask;
|
||||
cocoaStyle |= NSClosableWindowMask;
|
||||
cocoaStyle |= NSMiniaturizableWindowMask;
|
||||
cocoaStyle |= NSResizableWindowMask;
|
||||
NSRect cocoaRect = MakeInitialNSWindowContentRect(pos,size,cocoaStyle);
|
||||
|
||||
m_cocoaNSWindow = NULL;
|
||||
SetNSPanel([[NSPanel alloc] initWithContentRect:cocoaRect styleMask:cocoaStyle backing:NSBackingStoreBuffered defer:NO]);
|
||||
|
@@ -86,6 +86,23 @@ unsigned int wxTopLevelWindowCocoa::NSWindowStyleForWxStyle(long style)
|
||||
return styleMask;
|
||||
}
|
||||
|
||||
NSRect wxTopLevelWindowCocoa::MakeInitialNSWindowContentRect(const wxPoint& pos, const wxSize& size, unsigned int cocoaStyleMask)
|
||||
{
|
||||
// Arbitrarily use (100,100) as the origin when default coords are given.
|
||||
wxCoord x = pos.x!=wxDefaultCoord ? pos.x : 100;
|
||||
wxCoord y = pos.y!=wxDefaultCoord ? pos.y : 100;
|
||||
|
||||
wxCoord w = WidthDefault(size.x);
|
||||
wxCoord h = HeightDefault(size.y);
|
||||
|
||||
NSPoint cocoaOrigin = OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(x,y,w,h,true);
|
||||
|
||||
return [NSWindow
|
||||
contentRectForFrameRect:NSMakeRect(cocoaOrigin.x,cocoaOrigin.y,w,h)
|
||||
styleMask:cocoaStyleMask];
|
||||
|
||||
}
|
||||
|
||||
bool wxTopLevelWindowCocoa::Create(wxWindow *parent,
|
||||
wxWindowID winid,
|
||||
const wxString& title,
|
||||
@@ -107,30 +124,7 @@ bool wxTopLevelWindowCocoa::Create(wxWindow *parent,
|
||||
if(style & wxFRAME_TOOL_WINDOW)
|
||||
cocoaStyle |= NSUtilityWindowMask;
|
||||
|
||||
// Create frame and check and handle default position and size
|
||||
int realx,
|
||||
realy;
|
||||
|
||||
// WX has no set default position - the carbon port caps the low
|
||||
// end at 20, 50. Here we do the same, except instead of setting
|
||||
// it to 20 and 50, we set it to 100 and 100 if the values are too low
|
||||
if (pos.x < 20)
|
||||
realx = 100;
|
||||
else
|
||||
realx = pos.x;
|
||||
|
||||
if (pos.y < 50)
|
||||
realy = 100;
|
||||
else
|
||||
realy = pos.y;
|
||||
|
||||
int realw = WidthDefault(size.x);
|
||||
int realh = HeightDefault(size.y);
|
||||
|
||||
// NOTE: y-origin needs to be flipped.
|
||||
NSRect cocoaRect = [NSWindow
|
||||
contentRectForFrameRect:NSMakeRect(realx,realy,realw,realh)
|
||||
styleMask:cocoaStyle];
|
||||
NSRect cocoaRect = MakeInitialNSWindowContentRect(pos,size,cocoaStyle);
|
||||
|
||||
m_cocoaNSWindow = NULL;
|
||||
m_cocoaNSView = NULL;
|
||||
@@ -408,7 +402,9 @@ void wxTopLevelWindowCocoa::DoMoveWindow(int x, int y, int width, int height)
|
||||
{
|
||||
wxLogTrace(wxTRACE_COCOA_TopLevelWindow_Size,wxT("wxTopLevelWindow=%p::DoMoveWindow(%d,%d,%d,%d)"),this,x,y,width,height);
|
||||
|
||||
NSRect cocoaRect = NSMakeRect(x,y,width,height);
|
||||
NSPoint cocoaOrigin = OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(x,y,width,height,false);
|
||||
|
||||
NSRect cocoaRect = NSMakeRect(cocoaOrigin.x,cocoaOrigin.y,width,height);
|
||||
[m_cocoaNSWindow setFrame: cocoaRect display:NO];
|
||||
}
|
||||
|
||||
@@ -424,10 +420,14 @@ void wxTopLevelWindowCocoa::DoGetSize(int *w, int *h) const
|
||||
|
||||
void wxTopLevelWindowCocoa::DoGetPosition(int *x, int *y) const
|
||||
{
|
||||
NSRect cocoaRect = [m_cocoaNSWindow frame];
|
||||
if(x)
|
||||
*x=(int)cocoaRect.origin.x;
|
||||
if(y)
|
||||
*y=(int)cocoaRect.origin.y;
|
||||
wxLogTrace(wxTRACE_COCOA_TopLevelWindow_Size,wxT("wxTopLevelWindow=%p::DoGetPosition = (%d,%d)"),this,(int)cocoaRect.origin.x,(int)cocoaRect.origin.y);
|
||||
NSRect windowFrame = [m_cocoaNSWindow frame];
|
||||
|
||||
wxPoint theWxOrigin = OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(windowFrame);
|
||||
|
||||
if(*x)
|
||||
*x = theWxOrigin.x;
|
||||
if(*y)
|
||||
*y = theWxOrigin.y;
|
||||
|
||||
wxLogTrace(wxTRACE_COCOA_TopLevelWindow_Size,wxT("wxTopLevelWindow=%p::DoGetPosition = (%d,%d)"),this,(int)theWxOrigin.x,(int)theWxOrigin.y);
|
||||
}
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#import <Foundation/NSException.h>
|
||||
#import <AppKit/NSApplication.h>
|
||||
#import <AppKit/NSWindow.h>
|
||||
#import <AppKit/NSScreen.h>
|
||||
|
||||
// Turn this on to paint green over the dummy views for debugging
|
||||
#undef WXCOCOA_FILL_DUMMY_VIEW
|
||||
@@ -59,6 +60,10 @@ typedef int CocoaWindowCompareFunctionResult;
|
||||
- (void)getRectsBeingDrawn:(const NSRect **)rects count:(int *)count;
|
||||
@end
|
||||
|
||||
// ========================================================================
|
||||
// Helper functions for converting to/from wxWidgets coordinates and a
|
||||
// specified NSView's coordinate system.
|
||||
// ========================================================================
|
||||
NSPoint CocoaTransformNSViewBoundsToWx(NSView *nsview, NSPoint pointBounds)
|
||||
{
|
||||
wxCHECK_MSG(nsview, pointBounds, wxT("Need to have a Cocoa view to do translation"));
|
||||
@@ -111,6 +116,149 @@ NSRect CocoaTransformNSViewWxToBounds(NSView *nsview, NSRect rectWx)
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Screen coordinate helpers
|
||||
// ============================================================================
|
||||
|
||||
/*
|
||||
General observation about Cocoa screen coordinates:
|
||||
It is documented that the first object of the [NSScreen screens] array is the screen with the menubar.
|
||||
|
||||
It is not documented (but true as far as I can tell) that (0,0) in Cocoa screen coordinates is always
|
||||
the BOTTOM-right corner of this screen. Recall that Cocoa uses cartesian coordinates so y-increase is up.
|
||||
|
||||
It isn't clearly documented but visibleFrame returns a rectangle in screen coordinates, not a rectangle
|
||||
relative to that screen's frame. The only real way to test this is to configure two screens one atop
|
||||
the other such that the menubar screen is on top. The Dock at the bottom of the screen will then
|
||||
eat into the visibleFrame of screen 1 by incrementing it's y-origin. Thus if you arrange two
|
||||
1920x1200 screens top/bottom then screen 1 (the bottom screen) will have frame origin (0,-1200) and
|
||||
visibleFrame origin (0,-1149) which is exactly 51 pixels higher than the full frame origin.
|
||||
|
||||
In wxCocoa, we somewhat arbitrarily declare that wx (0,0) is the TOP-left of screen 0's frame (the entire screen).
|
||||
However, this isn't entirely arbitrary because the Quartz Display Services (CGDisplay) uses this same scheme.
|
||||
This works out nicely because wxCocoa's wxDisplay is implemented using Quartz Display Services instead of NSScreen.
|
||||
*/
|
||||
|
||||
namespace { // file namespace
|
||||
|
||||
class wxCocoaPrivateScreenCoordinateTransformer
|
||||
{
|
||||
DECLARE_NO_COPY_CLASS(wxCocoaPrivateScreenCoordinateTransformer)
|
||||
public:
|
||||
wxCocoaPrivateScreenCoordinateTransformer();
|
||||
~wxCocoaPrivateScreenCoordinateTransformer();
|
||||
wxPoint OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(NSRect windowFrame);
|
||||
NSPoint OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(wxCoord x, wxCoord y, wxCoord width, wxCoord height, bool keepOriginVisible);
|
||||
|
||||
protected:
|
||||
NSScreen *m_screenZero;
|
||||
NSRect m_screenZeroFrame;
|
||||
};
|
||||
|
||||
// NOTE: This is intended to be a short-lived object. A future enhancment might
|
||||
// make it a global and reconfigure it upon some notification that the screen layout
|
||||
// has changed.
|
||||
inline wxCocoaPrivateScreenCoordinateTransformer::wxCocoaPrivateScreenCoordinateTransformer()
|
||||
{
|
||||
NSArray *screens = [NSScreen screens];
|
||||
|
||||
[screens retain];
|
||||
|
||||
m_screenZero = nil;
|
||||
if(screens != nil && [screens count] > 0)
|
||||
m_screenZero = [[screens objectAtIndex:0] retain];
|
||||
|
||||
[screens release];
|
||||
|
||||
if(m_screenZero != nil)
|
||||
m_screenZeroFrame = [m_screenZero frame];
|
||||
else
|
||||
{
|
||||
wxLogWarning(wxT("Can't translate to/from wx screen coordinates and Cocoa screen coordinates"));
|
||||
// Just blindly assume 1024x768 so that at least we can sort of flip things around into
|
||||
// Cocoa coordinates.
|
||||
// NOTE: Theoretically this case should never happen anyway.
|
||||
m_screenZeroFrame = NSMakeRect(0,0,1024,768);
|
||||
}
|
||||
}
|
||||
|
||||
inline wxCocoaPrivateScreenCoordinateTransformer::~wxCocoaPrivateScreenCoordinateTransformer()
|
||||
{
|
||||
[m_screenZero release];
|
||||
m_screenZero = nil;
|
||||
}
|
||||
|
||||
inline wxPoint wxCocoaPrivateScreenCoordinateTransformer::OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(NSRect windowFrame)
|
||||
{
|
||||
// x and y are in wx screen coordinates which we're going to arbitrarily define such that
|
||||
// (0,0) is the TOP-left of screen 0 (the one with the menubar)
|
||||
// NOTE WELL: This means that (0,0) is _NOT_ an appropriate position for a window.
|
||||
|
||||
wxPoint theWxOrigin;
|
||||
|
||||
// Working in Cocoa's screen coordinates we must realize that the x coordinate we want is
|
||||
// the distance between the left side (origin.x) of the window's frame and the left side of
|
||||
// screen zero's frame.
|
||||
theWxOrigin.x = windowFrame.origin.x - m_screenZeroFrame.origin.x;
|
||||
|
||||
// Working in Cocoa's screen coordinates we must realize that the y coordinate we want is
|
||||
// actually the distance between the top-left of the screen zero frame and the top-left
|
||||
// of the window's frame.
|
||||
|
||||
theWxOrigin.y = (m_screenZeroFrame.origin.y + m_screenZeroFrame.size.height) - (windowFrame.origin.y + windowFrame.size.height);
|
||||
|
||||
return theWxOrigin;
|
||||
}
|
||||
|
||||
inline NSPoint wxCocoaPrivateScreenCoordinateTransformer::OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(wxCoord x, wxCoord y, wxCoord width, wxCoord height, bool keepOriginVisible)
|
||||
{
|
||||
NSPoint theCocoaOrigin;
|
||||
|
||||
// The position is in wx screen coordinates which we're going to arbitrarily define such that
|
||||
// (0,0) is the TOP-left of screen 0 (the one with the menubar)
|
||||
|
||||
// NOTE: The usable rectangle is smaller and hence we have the keepOriginVisible flag
|
||||
// which will move the origin downward and/or left as necessary if the origin is
|
||||
// inside the screen0 rectangle (i.e. x/y >= 0 in wx coordinates) and outside the
|
||||
// visible frame (i.e. x/y < the top/left of the screen0 visible frame in wx coordinates)
|
||||
// We don't munge origin coordinates < 0 because it actually is possible that the menubar is on
|
||||
// the top of the bottom screen and thus that origin is completely valid!
|
||||
if(keepOriginVisible && (m_screenZero != nil))
|
||||
{
|
||||
// Do al of this in wx coordinates because it's far simpler since we're dealing with top/left points
|
||||
wxPoint visibleOrigin = OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates([m_screenZero visibleFrame]);
|
||||
if(x >= 0 && x < visibleOrigin.x)
|
||||
x = visibleOrigin.x;
|
||||
if(y >= 0 && y < visibleOrigin.y)
|
||||
y = visibleOrigin.y;
|
||||
}
|
||||
|
||||
// The x coordinate is simple as it's just relative to screen zero's frame
|
||||
theCocoaOrigin.x = m_screenZeroFrame.origin.x + x;
|
||||
// Working in Cocoa's coordinates think to start at the bottom of screen zero's frame and add
|
||||
// the height of that rect which gives us the coordinate for the top of the visible rect. Now realize that
|
||||
// the wx coordinates are flipped so if y is say 10 then we want to be 10 pixels down from that and thus
|
||||
// we subtract y. But then we still need to take into account the size of the window which is h and subtract
|
||||
// that to get the bottom-left origin of the rectangle.
|
||||
theCocoaOrigin.y = m_screenZeroFrame.origin.y + m_screenZeroFrame.size.height - y - height;
|
||||
|
||||
return theCocoaOrigin;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
wxPoint wxWindowCocoa::OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(NSRect windowFrame)
|
||||
{
|
||||
wxCocoaPrivateScreenCoordinateTransformer transformer;
|
||||
return transformer.OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(windowFrame);
|
||||
}
|
||||
|
||||
NSPoint wxWindowCocoa::OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(wxCoord x, wxCoord y, wxCoord width, wxCoord height, bool keepOriginVisible)
|
||||
{
|
||||
wxCocoaPrivateScreenCoordinateTransformer transformer;
|
||||
return transformer.OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(x,y,width,height,keepOriginVisible);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// wxWindowCocoaHider
|
||||
// ========================================================================
|
||||
@@ -947,12 +1095,49 @@ void wxWindow::DoReleaseMouse()
|
||||
|
||||
void wxWindow::DoScreenToClient(int *x, int *y) const
|
||||
{
|
||||
// TODO
|
||||
// Point in cocoa screen coordinates:
|
||||
NSPoint cocoaScreenPoint = OriginInCocoaScreenCoordinatesForRectInWxDisplayCoordinates(x!=NULL?*x:0, y!=NULL?*y:0, 0, 0, false);
|
||||
NSView *clientView = const_cast<wxWindow*>(this)->GetNSView();
|
||||
NSWindow *theWindow = [clientView window];
|
||||
|
||||
// Point in window's base coordinate system:
|
||||
NSPoint windowPoint = [theWindow convertScreenToBase:cocoaScreenPoint];
|
||||
// Point in view's bounds coordinate system
|
||||
NSPoint boundsPoint = [clientView convertPoint:windowPoint fromView:nil];
|
||||
// Point in wx client coordinates:
|
||||
NSPoint theWxClientPoint = CocoaTransformNSViewBoundsToWx(clientView, boundsPoint);
|
||||
if(x!=NULL)
|
||||
*x = theWxClientPoint.x;
|
||||
if(y!=NULL)
|
||||
*y = theWxClientPoint.y;
|
||||
}
|
||||
|
||||
void wxWindow::DoClientToScreen(int *x, int *y) const
|
||||
{
|
||||
// TODO
|
||||
// Point in wx client coordinates
|
||||
NSPoint theWxClientPoint = NSMakePoint(x!=NULL?*x:0, y!=NULL?*y:0);
|
||||
|
||||
NSView *clientView = const_cast<wxWindow*>(this)->GetNSView();
|
||||
|
||||
// Point in the view's bounds coordinate system
|
||||
NSPoint boundsPoint = CocoaTransformNSViewWxToBounds(clientView, theWxClientPoint);
|
||||
|
||||
// Point in the window's base coordinate system
|
||||
NSPoint windowPoint = [clientView convertPoint:boundsPoint toView:nil];
|
||||
|
||||
NSWindow *theWindow = [clientView window];
|
||||
// Point in Cocoa's screen coordinates
|
||||
NSPoint screenPoint = [theWindow convertBaseToScreen:windowPoint];
|
||||
|
||||
// Act as though this was the origin of a 0x0 rectangle
|
||||
NSRect screenPointRect = NSMakeRect(screenPoint.x, screenPoint.y, 0, 0);
|
||||
|
||||
// Convert that rectangle to wx coordinates
|
||||
wxPoint theWxScreenPoint = OriginInWxDisplayCoordinatesForRectInCocoaScreenCoordinates(screenPointRect);
|
||||
if(*x)
|
||||
*x = theWxScreenPoint.x;
|
||||
if(*y)
|
||||
*y = theWxScreenPoint.y;
|
||||
}
|
||||
|
||||
// Get size *available for subwindows* i.e. excluding menu bar etc.
|
||||
|
Reference in New Issue
Block a user