#else
#include <gtk/gtkfeatures.h>
#endif
- extern const unsigned int gtk_major_version;
- extern const unsigned int gtk_minor_version;
- extern const unsigned int gtk_micro_version;
#endif
#include "wx/platinfo.h"
// static data
// ----------------------------------------------------------------------------
-#if defined(__WXPALMOS__)
-int wxWindowBase::ms_lastControlId = 32767;
-#elif defined(__WXPM__)
-int wxWindowBase::ms_lastControlId = 2000;
-#else
-int wxWindowBase::ms_lastControlId = -200;
-#endif
IMPLEMENT_ABSTRACT_CLASS(wxWindowBase, wxEvtHandler)
m_windowSizer = (wxSizer *) NULL;
m_containingSizer = (wxSizer *) NULL;
m_autoLayout = false;
+ m_freeId = false;
#if wxUSE_DRAG_AND_DROP
m_dropTarget = (wxDropTarget *)NULL;
// ids are limited to 16 bits under MSW so if you care about portability,
// it's not a good idea to use ids out of this range (and negative ids are
// reserved for wxWidgets own usage)
- wxASSERT_MSG( id == wxID_ANY || (id >= 0 && id < 32767),
+ wxASSERT_MSG( id == wxID_ANY || (id >= 0 && id < 32767) ||
+ (id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST),
_T("invalid id value") );
// generate a new id if the user doesn't care about it
- m_windowId = id == wxID_ANY ? NewControlId() : id;
+ if ( id == wxID_ANY )
+ {
+ m_windowId = NewControlId();
+
+ // remember to call ReleaseControlId() when this window is destroyed
+ m_freeId = true;
+ }
+ else // valid id specified
+ {
+ m_windowId = id;
+ }
// don't use SetWindowStyleFlag() here, this function should only be called
// to change the flag after creation as it tries to reflect the changes in
{
wxASSERT_MSG( GetCapture() != this, wxT("attempt to destroy window with mouse capture") );
+ // mark the id as unused if we allocated it for this control
+ if ( m_freeId )
+ ReleaseControlId(m_windowId);
+
// FIXME if these 2 cases result from programming errors in the user code
// we should probably assert here instead of silently fixing them
// logic is the same as above
if ( !m_hasFgCol && !m_foregroundColour.Ok() )
{
- wxASSERT_MSG( !m_hasFgCol, _T("we have invalid explicit fg colour?") );
-
wxColour colFg = GetDefaultAttributes().colFg;
if ( !colFg.Ok() )
UpdateWindowUI(wxUPDATE_UI_RECURSE);
}
+// ----------------------------------------------------------------------------
+// menu-related functions
+// ----------------------------------------------------------------------------
+
+#if wxUSE_MENUS
+
+// this is used to pass the id of the selected item from the menu event handler
+// to the main function itself
+//
+// it's ok to use a global here as there can be at most one popup menu shown at
+// any time
+static int gs_popupMenuSelection = wxID_NONE;
+
+void wxWindowBase::InternalOnPopupMenu(wxCommandEvent& event)
+{
+ // store the id in a global variable where we'll retrieve it from later
+ gs_popupMenuSelection = event.GetId();
+}
+
+int
+wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y)
+{
+ gs_popupMenuSelection = wxID_NONE;
+
+ Connect(wxEVT_COMMAND_MENU_SELECTED,
+ wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu),
+ NULL,
+ this);
+
+ PopupMenu(&menu, x, y);
+
+ Disconnect(wxEVT_COMMAND_MENU_SELECTED,
+ wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu),
+ NULL,
+ this);
+
+ return gs_popupMenuSelection;
+}
+
+#endif // wxUSE_MENUS
+
// methods for drawing the sizers in a visible way
#ifdef __WXDEBUG__
{
border = GetDefaultBorder();
}
+ else if ( border == wxBORDER_THEME )
+ {
+ border = GetDefaultBorderForControl();
+ }
return border;
}
{
#ifdef wxHAS_NATIVE_TAB_TRAVERSAL
// native code doesn't process our wxNavigationKeyEvents anyhow
+ wxUnusedVar(flags);
return false;
#else // !wxHAS_NATIVE_TAB_TRAVERSAL
wxNavigationKeyEvent eventNav;
return x;
}
+// ----------------------------------------------------------------------------
+// Window (and menu items) identifiers management
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
+// this array contains, in packed form, the "in use" flags for the entire
+// auto-generated ids range: N-th element of the array contains the flags for
+// ids in [wxID_AUTO_LOWEST + 8*N, wxID_AUTO_LOWEST + 8*N + 7] range
+//
+// initially no ids are in use and we allocate them consecutively, but after we
+// exhaust the entire range, we wrap around and reuse the ids freed in the
+// meanwhile
+wxByte gs_autoIdsInUse[(wxID_AUTO_HIGHEST - wxID_AUTO_LOWEST + 1)/8 + 1] = { 0 };
+
+// this is an optimization used until we wrap around wxID_AUTO_HIGHEST: if this
+// value is < wxID_AUTO_HIGHEST we know that we haven't wrapped yet and so can
+// allocate the ids simply by incrementing it
+static wxWindowID gs_nextControlId = wxID_AUTO_LOWEST;
+
+void MarkAutoIdUsed(wxWindowID id)
+{
+ id -= wxID_AUTO_LOWEST;
+
+ const int theByte = id / 8;
+ const int theBit = id % 8;
+
+ gs_autoIdsInUse[theByte] |= 1 << theBit;
+}
+
+void FreeAutoId(wxWindowID id)
+{
+ id -= wxID_AUTO_LOWEST;
+
+ const int theByte = id / 8;
+ const int theBit = id % 8;
+
+ gs_autoIdsInUse[theByte] &= ~(1 << theBit);
+}
+
+bool IsAutoIdInUse(wxWindowID id)
+{
+ id -= wxID_AUTO_LOWEST;
+
+ const int theByte = id / 8;
+ const int theBit = id % 8;
+
+ return (gs_autoIdsInUse[theByte] & (1 << theBit)) != 0;
+}
+
+} // anonymous namespace
+
+
+/* static */
+bool wxWindowBase::IsAutoGeneratedId(wxWindowID id)
+{
+ if ( id < wxID_AUTO_LOWEST || id > wxID_AUTO_HIGHEST )
+ return false;
+
+ // we shouldn't have any stray ids in this range
+ wxASSERT_MSG( IsAutoIdInUse(id), "unused automatically generated id?" );
+
+ return true;
+}
+
+wxWindowID wxWindowBase::NewControlId(int count)
+{
+ wxASSERT_MSG( count > 0, "can't allocate less than 1 id" );
+
+ if ( gs_nextControlId + count - 1 <= wxID_AUTO_HIGHEST )
+ {
+ // we haven't wrapped yet, so we can just grab the next count ids
+ wxWindowID id = gs_nextControlId;
+
+ while ( count-- )
+ MarkAutoIdUsed(gs_nextControlId++);
+
+ return id;
+ }
+ else // we've already wrapped or are now going to
+ {
+ // brute-force search for the id values
+
+ // number of consecutive free ids found so far
+ int found = 0;
+
+ for ( wxWindowID id = wxID_AUTO_LOWEST; id <= wxID_AUTO_HIGHEST; id++ )
+ {
+ if ( !IsAutoIdInUse(id) )
+ {
+ // found another consecutive available id
+ found++;
+ if ( found == count )
+ {
+ // mark all count consecutive free ids we found as being in
+ // use now and rewind back to the start of available range
+ // in the process
+ while ( count-- )
+ MarkAutoIdUsed(id--);
+
+ return id;
+ }
+ }
+ else // this id is in use
+ {
+ // reset the number of consecutive free values found
+ found = 0;
+ }
+ }
+ }
+
+ // if we get here, there are not enough consecutive free ids
+ return wxID_NONE;
+}
+
+void wxWindowBase::ReleaseControlId(wxWindowID id)
+{
+ wxCHECK_RET( IsAutoGeneratedId(id), "can't release non auto-generated id" );
+
+ FreeAutoId(id);
+}