diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl
index 981f8c4550..6b0858dc10 100644
--- a/build/bakefiles/files.bkl
+++ b/build/bakefiles/files.bkl
@@ -2190,11 +2190,14 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
+ src/common/taskbarcmn.cpp
+ src/mac/carbon/drawer.cpp
src/mac/carbon/joystick.cpp
src/mac/carbon/sound.cpp
src/mac/carbon/taskbar.cpp
+ wx/mac/carbon/drawer.h
wx/mac/carbon/joystick.h
wx/mac/carbon/sound.h
wx/mac/carbon/taskbarosx.h
diff --git a/docs/changes.txt b/docs/changes.txt
index 539ef9f7a0..0d86e479df 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -249,6 +249,7 @@ wxMAC:
- Fixed MLTE text control GetLineText and GetLineLength on OSX (RN)
- Added OSX wxTaskBarIcon implementation for the OSX Dock (RN)
+- Added wxDrawerWindow class for drawer windows for OSX >= 10.2 (RN - from Jason Bagley)
wxGTK:
diff --git a/include/wx/defs.h b/include/wx/defs.h
index 465edc94f6..460ec94c0b 100644
--- a/include/wx/defs.h
+++ b/include/wx/defs.h
@@ -1206,6 +1206,9 @@ enum wxBorder
#define wxFRAME_EX_CONTEXTHELP 0x00000004
#define wxDIALOG_EX_CONTEXTHELP 0x00000004
+/* Create a window which is attachable to another top level window */
+#define wxFRAME_DRAWER 0x0020
+
/*
* MDI parent frame style flags
* Can overlap with some of the above.
diff --git a/include/wx/mac/carbon/drawer.h b/include/wx/mac/carbon/drawer.h
new file mode 100644
index 0000000000..11fe42594c
--- /dev/null
+++ b/include/wx/mac/carbon/drawer.h
@@ -0,0 +1,68 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name: drawer.h
+// Purpose: Drawer child window class.
+// Drawer windows appear under their parent window and
+// behave like a drawer, opening and closing to reveal
+// content that does not need to be visible at all times.
+// Author: Jason Bagley
+// Modified by:
+// Created: 2004-30-01
+// RCS-ID: $Id$
+// Copyright: (c) Jason Bagley; Art & Logic, Inc.
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_DRAWERWINDOW_H_
+#define _WX_DRAWERWINDOW_H_
+
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
+#pragma interface "drawer.h"
+#endif
+
+#include "wx/toplevel.h"
+
+#if ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 )
+
+class WXDLLEXPORT wxDrawerWindow : public wxTopLevelWindow
+{
+ DECLARE_DYNAMIC_CLASS(wxDrawerWindow)
+
+public:
+
+ wxDrawerWindow();
+
+ wxDrawerWindow(wxWindow* parent,
+ wxWindowID id,
+ const wxString& title,
+ wxSize size = wxDefaultSize,
+ wxDirection edge = wxLEFT,
+ const wxString& name = "drawerwindow")
+ {
+ this->Create(parent, id, title, size, edge, name);
+ }
+
+ ~wxDrawerWindow();
+
+ // Create a drawer window.
+ // If parent is NULL, create as a tool window.
+ // If parent is not NULL, then wxTopLevelWindow::Attach this window to parent.
+ bool Create(wxWindow *parent,
+ wxWindowID id,
+ const wxString& title,
+ wxSize size = wxDefaultSize,
+ wxDirection edge = wxLEFT,
+ const wxString& name = wxFrameNameStr);
+
+ bool Open(bool show = true); // open or close the drawer, possibility for async param, i.e. animate
+ bool Close() { return this->Open(false); }
+ bool IsOpen() const;
+
+ // Set the edge of the parent where the drawer attaches.
+ bool SetPreferredEdge(wxDirection edge);
+ wxDirection GetPreferredEdge() const;
+ wxDirection GetCurrentEdge() const; // not necessarily the preferred, due to screen constraints
+};
+
+#endif // defined( __WXMAC__ ) && TARGET_API_MAC_OSX && ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 )
+
+#endif // _WX_DRAWERWINDOW_H_
diff --git a/src/mac/carbon/drawer.cpp b/src/mac/carbon/drawer.cpp
new file mode 100644
index 0000000000..14241ebca4
--- /dev/null
+++ b/src/mac/carbon/drawer.cpp
@@ -0,0 +1,208 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name: drawer.cpp
+// Purpose: Drawer child window classes.
+// Drawer windows appear under their parent window and
+// behave like a drawer, opening and closing to reveal
+// content that does not need to be visible at all times.
+// Author: Jason Bagley
+// Modified by:
+// Created: 2004-30-01
+// RCS-ID: $Id$
+// Copyright: (c) Jason Bagley; Art & Logic, Inc.
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+#pragma implementation "control.h"
+#endif
+
+#include "wx/defs.h"
+
+#include "wx/mac/carbon/drawer.h"
+#include "wx/mac/private.h"
+
+#if defined( __WXMAC__ ) && TARGET_API_MAC_OSX && ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 )
+
+// TODO:
+// ¥ Contents do not draw on drawer opening. They do when a window is deactivated
+// with the drawer open, and contents stay visible thereafter.
+
+IMPLEMENT_DYNAMIC_CLASS(wxDrawerWindow, wxWindow)
+
+// Use consants for now.
+// These can be made into member variables and set dynamically.
+const int kLeadingOffset = 20;
+const int kTrailingOffset = 20;
+
+
+// Converts Mac window edge constants to wxDirections, wxLEFT, wxRIGHT, etc.
+static wxDirection WindowEdgeToDirection(OptionBits edge);
+
+// Convert wxDirections to MAc window edge constants.
+static OptionBits DirectionToWindowEdge(wxDirection direction);
+
+
+wxDrawerWindow::wxDrawerWindow()
+{
+}
+
+wxDrawerWindow::~wxDrawerWindow()
+{
+ m_isBeingDeleted = TRUE;
+ this->Show(FALSE);
+}
+
+bool wxDrawerWindow::Create(wxWindow *parent,
+ wxWindowID id, const wxString& title,
+ wxSize size, wxDirection edge, const wxString& name)
+{
+ wxASSERT_MSG(NULL != parent, "wxDrawerWindows must be attached to a parent window.");
+
+ // Constrain the drawer size to the parent window.
+ const wxSize parentSize(parent->GetClientSize());
+ if (wxLEFT == edge || wxRIGHT == edge)
+ {
+ if (size.GetHeight() > parentSize.GetHeight())
+ size.SetHeight(parentSize.GetHeight() - (kLeadingOffset + kTrailingOffset));
+ }
+ else
+ {
+ if (size.GetWidth() > parentSize.GetWidth())
+ size.SetWidth(parentSize.GetWidth() - (kLeadingOffset + kTrailingOffset));
+ }
+
+ // Create the drawer window.
+ const wxPoint pos(0, 0);
+ const wxSize dummySize(0,0);
+ const long style = wxFRAME_DRAWER;
+
+ bool success = wxWindow::Create(parent, id, pos, dummySize, style, name);
+ if (success)
+ {
+ this->MacCreateRealWindow(title, pos, size, style, name);
+ success = (m_macWindow != NULL);
+ }
+
+ if (success)
+ {
+ // Use drawer brush.
+ m_macBackgroundBrush.MacSetTheme(kThemeBrushDrawerBackground);
+ ::SetThemeWindowBackground((WindowRef)m_macWindow,
+ m_macBackgroundBrush.MacGetTheme(), false);
+
+ // Leading and trailing offset are gaps from parent window edges
+ // to where the drawer starts.
+ ::SetDrawerOffsets((WindowRef)m_macWindow, kLeadingOffset, kTrailingOffset);
+
+ // Set the drawers parent.
+ // Is there a better way to get the parent's WindowRef?
+ wxTopLevelWindow* tlwParent = wxDynamicCast(parent, wxTopLevelWindow);
+ if (NULL != tlwParent)
+ {
+ OSStatus status = ::SetDrawerParent((WindowRef)m_macWindow,
+ (WindowRef)tlwParent->MacGetWindowRef());
+ success = (noErr == status);
+ }
+ else
+ success = false;
+ }
+
+ return success && SetPreferredEdge(edge);
+}
+
+wxDirection wxDrawerWindow::GetCurrentEdge() const
+{
+ const OptionBits edge = ::GetDrawerCurrentEdge((WindowRef)m_macWindow);
+ return WindowEdgeToDirection(edge);
+}
+
+wxDirection wxDrawerWindow::GetPreferredEdge() const
+{
+ const OptionBits edge = ::GetDrawerPreferredEdge((WindowRef)m_macWindow);
+ return WindowEdgeToDirection(edge);
+}
+
+bool wxDrawerWindow::IsOpen() const
+{
+ WindowDrawerState state = ::GetDrawerState((WindowRef)m_macWindow);
+ return (state == kWindowDrawerOpen || state == kWindowDrawerOpening);
+}
+
+bool wxDrawerWindow::Open(bool show)
+{
+ static const Boolean kAsynchronous = true;
+ OSStatus status = noErr;
+
+ if (show)
+ {
+ const OptionBits preferredEdge = ::GetDrawerPreferredEdge((WindowRef)m_macWindow);
+ status = ::OpenDrawer((WindowRef)m_macWindow, preferredEdge, kAsynchronous);
+ }
+ else
+ status = ::CloseDrawer((WindowRef)m_macWindow, kAsynchronous);
+
+ return (noErr == status);
+}
+
+bool wxDrawerWindow::SetPreferredEdge(wxDirection edge)
+{
+ const OSStatus status = ::SetDrawerPreferredEdge((WindowRef)m_macWindow,
+ DirectionToWindowEdge(edge));
+ return (noErr == status);
+}
+
+
+OptionBits DirectionToWindowEdge(wxDirection direction)
+{
+ OptionBits edge;
+ switch (direction)
+ {
+ case wxTOP:
+ edge = kWindowEdgeTop;
+ break;
+
+ case wxBOTTOM:
+ edge = kWindowEdgeBottom;
+ break;
+
+ case wxRIGHT:
+ edge = kWindowEdgeRight;
+ break;
+
+ case wxLEFT:
+ default:
+ edge = kWindowEdgeLeft;
+ break;
+ }
+ return edge;
+}
+
+wxDirection WindowEdgeToDirection(OptionBits edge)
+{
+ wxDirection direction;
+ switch (edge)
+ {
+ case kWindowEdgeTop:
+ direction = wxTOP;
+ break;
+
+ case kWindowEdgeBottom:
+ direction = wxBOTTOM;
+ break;
+
+ case kWindowEdgeRight:
+ direction = wxRIGHT;
+ break;
+
+ case kWindowEdgeDefault: // store current preferred and return that here?
+ case kWindowEdgeLeft:
+ default:
+ direction = wxLEFT;
+ break;
+ }
+
+ return direction;
+}
+
+#endif // defined( __WXMAC__ ) && TARGET_API_MAC_OSX && ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 )
+
diff --git a/src/mac/carbon/toplevel.cpp b/src/mac/carbon/toplevel.cpp
index 111ecb1995..23472b4bf8 100644
--- a/src/mac/carbon/toplevel.cpp
+++ b/src/mac/carbon/toplevel.cpp
@@ -983,6 +983,16 @@ void wxTopLevelWindowMac::MacCreateRealWindow( const wxString& title,
{
wclass = kDocumentWindowClass ;
}
+#if ( MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 )
+ else if ( HasFlag( wxFRAME_DRAWER ) )
+ {
+ wclass = kDrawerWindowClass;
+ // Should this be left for compositing check below?
+ // CreateNewWindow will fail without it, should wxDrawerWindow turn
+ // on compositing before calling MacCreateRealWindow?
+ attr |= kWindowCompositingAttribute;// | kWindowStandardHandlerAttribute;
+ }
+#endif //10.2 and up
else
{
if ( HasFlag( wxMINIMIZE_BOX ) || HasFlag( wxMAXIMIZE_BOX ) ||