From c5fb56c07a3718798459a69c74b3124ab58c65b5 Mon Sep 17 00:00:00 2001 From: David Webster Date: Tue, 2 Nov 1999 04:36:20 +0000 Subject: [PATCH] new wxMenu stuff and thread implementations git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4291 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/os2/menu.cpp | 1075 +++++++++++++++--------------------------- src/os2/menuitem.cpp | 179 ++++--- src/os2/thread.cpp | 606 +++++++++--------------- src/os2/utils.cpp | 62 ++- src/os2/utilsexc.cpp | 76 ++- 5 files changed, 815 insertions(+), 1183 deletions(-) diff --git a/src/os2/menu.cpp b/src/os2/menu.cpp index d5d5e3ca70..c1d89ce224 100644 --- a/src/os2/menu.cpp +++ b/src/os2/menu.cpp @@ -17,6 +17,7 @@ #include "wx/menu.h" #include "wx/utils.h" #include "wx/intl.h" + #include "wx/log.h" #endif #if wxUSE_OWNER_DRAWN @@ -24,9 +25,6 @@ #endif #include "wx/os2/private.h" -#include "wx/menu.h" -#include "wx/menuitem.h" -#include "wx/log.h" // other standard headers #include @@ -62,134 +60,111 @@ static const int idMenuTitle = -2; // --------------------------------------------------------------------------- // Construct a menu with optional title (then use append) -void wxMenu::Init(const wxString& title, const wxFunction func ) +void wxMenu::Init() { - m_title = title; - m_parent = NULL; - m_eventHandler = this; - m_pInvokingWindow = NULL; - m_doBreak = FALSE ; - m_noItems = 0; - m_menuBar = NULL; - m_hMenu = 0; //(WXHMENU) CreatePopupMenu(); - m_savehMenu = 0 ; - m_topLevelMenu = this; - m_clientData = (void*) NULL; + m_doBreak = FALSE; - if ( !!m_title ) + // create the menu + m_hMenu = (WXHMENU)0; // CreatePopupMenu(); + if ( !m_hMenu ) { - Append(idMenuTitle, m_title) ; - AppendSeparator() ; + wxLogLastError("CreatePopupMenu"); } - Callback(func); + // if we have a title, insert it in the beginning of the menu + if ( !!m_title ) + { + Append(idMenuTitle, m_title); + AppendSeparator(); + } } // The wxWindow destructor will take care of deleting the submenus. wxMenu::~wxMenu() { - // free Windows resources - if ( m_hMenu ) + // we should free Windows resources only if Windows doesn't do it for us + // which happens if we're attached to a menubar or a submenu of another + // menu + if ( !IsAttached() && !GetParent() ) { -// ::DestroyMenu((HMENU)m_hMenu); - m_hMenu = 0; +/* + if ( !::DestroyMenu(GetHmenu()) ) + { + wxLogLastError("DestroyMenu"); + } +*/ } - // delete submenus - wxNode *node = m_menuItems.First(); - while ( node ) - { - wxMenuItem *item = (wxMenuItem *)node->Data(); - - // Delete child menus. - // Beware: they must not be appended to children list!!! - // (because order of delete is significant) - if ( item->IsSubMenu() ) - item->DeleteSubMenu(); - - wxNode *next = node->Next(); - delete item; - delete node; - node = next; - } +#if wxUSE_ACCEL + // delete accels + WX_CLEAR_ARRAY(m_accels); +#endif // wxUSE_ACCEL } void wxMenu::Break() { + // this will take effect during the next call to Append() m_doBreak = TRUE; } -// function appends a new item or submenu to the menu -void wxMenu::Append(wxMenuItem *pItem) +#if wxUSE_ACCEL + +int wxMenu::FindAccel(int id) const { - wxCHECK_RET( pItem != NULL, wxT("can't append NULL item to the menu") ); + size_t n, count = m_accels.GetCount(); + for ( n = 0; n < count; n++ ) + { + if ( m_accels[n]->m_command == id ) + return n; + } -#if wxUSE_ACCEL - // check for accelerators: they are given after '\t' - wxString label = pItem->GetName(); - int posTab = label.Find(wxT('\t')); - if ( posTab != wxNOT_FOUND ) { - // parse the accelerator string - int keyCode = 0; - int accelFlags = wxACCEL_NORMAL; - wxString current; - for ( size_t n = (size_t)posTab + 1; n < label.Len(); n++ ) { - if ( (label[n] == '+') || (label[n] == '-') ) { - if ( current == _("ctrl") ) - accelFlags |= wxACCEL_CTRL; - else if ( current == _("alt") ) - accelFlags |= wxACCEL_ALT; - else if ( current == _("shift") ) - accelFlags |= wxACCEL_SHIFT; - else { - wxLogDebug(wxT("Unknown accel modifier: '%s'"), - current.c_str()); - } - - current.Empty(); - } - else { - current += wxTolower(label[n]); - } - } + return wxNOT_FOUND; +} - if ( current.IsEmpty() ) { - wxLogDebug(wxT("No accel key found, accel string ignored.")); - } - else { - if ( current.Len() == 1 ) { - // it's a letter - keyCode = wxToupper(current[0U]); - } - else { - // it should be a function key - if ( current[0U] == 'f' && isdigit(current[1U]) && - (current.Len() == 2 || - (current.Len() == 3 && isdigit(current[2U]))) ) { - int n; - wxSscanf(current.c_str() + 1, wxT("%d"), &n); - - keyCode = VK_F1 + n - 1; - } - else { - wxLogDebug(wxT("Unrecognized accel key '%s', accel " - "string ignored."), current.c_str()); - } - } - } +void wxMenu::UpdateAccel(wxMenuItem *item) +{ + // find the (new) accel for this item + wxAcceleratorEntry *accel = wxGetAccelFromString(item->GetText()); + if ( accel ) + accel->m_command = item->GetId(); - if ( keyCode ) { - // do add an entry - m_accelKeyCodes.Add(keyCode); - m_accelFlags.Add(accelFlags); - m_accelIds.Add(pItem->GetId()); - } + // find the old one + int n = FindAccel(item->GetId()); + if ( n == wxNOT_FOUND ) + { + // no old, add new if any + if ( accel ) + m_accels.Add(accel); + else + return; // skipping RebuildAccelTable() below + } + else + { + // replace old with new or just remove the old one if no new + delete m_accels[n]; + if ( accel ) + m_accels[n] = accel; + else + m_accels.Remove(n); } + + if ( IsAttached() ) + { + m_menuBar->RebuildAccelTable(); + } +} + #endif // wxUSE_ACCEL - UINT flags = 0; +// append a new item or submenu to the menu +bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos) +{ +#if wxUSE_ACCEL + UpdateAccel(pItem); +#endif // wxUSE_ACCEL - // TODO: + UINT flags = 0; +// TODO: /* // if "Break" has just been called, insert a menu break before this item // (and don't forget to reset the flag) @@ -207,13 +182,11 @@ void wxMenu::Append(wxMenuItem *pItem) UINT id; wxMenu *submenu = pItem->GetSubMenu(); if ( submenu != NULL ) { - wxASSERT( submenu->GetHMenu() != (WXHMENU) NULL ); + wxASSERT_MSG( submenu->GetHMenu(), wxT("invalid submenu") ); + + submenu->SetParent(this); id = (UINT)submenu->GetHMenu(); - submenu->m_topLevelMenu = m_topLevelMenu; - submenu->m_parent = this; - submenu->m_savehMenu = (WXHMENU)id; - submenu->m_hMenu = 0; flags |= MF_POPUP; } @@ -221,28 +194,44 @@ void wxMenu::Append(wxMenuItem *pItem) id = pItem->GetId(); } - const char* pData; + LPCTSTR pData; #if wxUSE_OWNER_DRAWN if ( pItem->IsOwnerDrawn() ) { // want to get {Measure|Draw}Item messages? // item draws itself, pass pointer to it in data parameter flags |= MF_OWNERDRAW; - pData = (const char*)pItem; + pData = (LPCTSTR)pItem; } else #endif { // menu is just a normal string (passed in data parameter) flags |= MF_STRING; - pData = label; + + pData = (char*)pItem->GetText().c_str(); } - if ( !::AppendMenu(GetHmenu(), flags, id, pData) ) + + BOOL ok; + if ( pos == (size_t)-1 ) { - wxLogLastError("AppendMenu"); + ok = ::AppendMenu(GetHmenu(), flags, id, pData); } else { - if ( id == idMenuTitle ) + ok = ::InsertMenu(GetHmenu(), pos, flags | MF_BYPOSITION, id, pData); + } + + if ( !ok ) + { + wxLogLastError("Insert or AppendMenu"); + + return FALSE; + } + else + { + // if we just appended the title, highlight it +#ifdef __WIN32__ + if ( (int)id == idMenuTitle ) { // visually select the menu title MENUITEMINFO mii; @@ -255,82 +244,80 @@ void wxMenu::Append(wxMenuItem *pItem) wxLogLastError(wxT("SetMenuItemInfo")); } } - m_menuItems.Append(pItem); - m_noItems++; +#endif // __WIN32__ + + // if we're already attached to the menubar, we must update it + if ( IsAttached() ) + { + m_menuBar->Refresh(); + } + + return TRUE; } */ + return FALSE; } -void wxMenu::AppendSeparator() -{ - Append(new wxMenuItem(this, ID_SEPARATOR)); -} - -// Pullright item -void wxMenu::Append(int id, - const wxString& label, - wxMenu *SubMenu, - const wxString& helpString) +bool wxMenu::DoAppend(wxMenuItem *item) { - Append(new wxMenuItem(this, id, label, helpString, FALSE, SubMenu)); + return wxMenuBase::DoAppend(item) && DoInsertOrAppend(item); } -// Ordinary menu item -void wxMenu::Append(int id, - const wxString& label, - const wxString& helpString, - bool checkable) +bool wxMenu::DoInsert(size_t pos, wxMenuItem *item) { - // 'checkable' parameter is useless for Windows. - Append(new wxMenuItem(this, id, label, helpString, checkable)); + return wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos); } -// delete item by id -void wxMenu::Delete(int id) +wxMenuItem *wxMenu::DoRemove(wxMenuItem *item) { - wxMenuItem *item = NULL; - int pos; - wxNode *node; - for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++) + // we need to find the items position in the child list + size_t pos; + wxMenuItemList::Node *node = GetMenuItems().GetFirst(); + for ( pos = 0; node; pos++ ) { - item = (wxMenuItem *)node->Data(); - if ( item->GetId() == id ) + if ( node->GetData() == item ) break; + + node = node->GetNext(); } - wxCHECK_RET( node, wxT("wxMenu::Delete(): item doesn't exist") ); + // DoRemove() (unlike Remove) can only be called for existing item! + wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") ); - HMENU menu = GetHmenu(); +#if wxUSE_ACCEL + // remove the corresponding accel from the accel table + int n = FindAccel(item->GetId()); + if ( n != wxNOT_FOUND ) + { + delete m_accels[n]; - wxMenu *pSubMenu = item->GetSubMenu(); - if ( pSubMenu != NULL ) + m_accels.Remove(n); + } + //else: this item doesn't have an accel, nothing to do +#endif // wxUSE_ACCEL +/* + // remove the item from the menu + if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) ) { -// RemoveMenu(menu, (UINT)pos, MF_BYPOSITION); - pSubMenu->m_hMenu = pSubMenu->m_savehMenu; - pSubMenu->m_savehMenu = 0; - pSubMenu->m_parent = NULL; - // RemoveChild(item->subMenu); - pSubMenu->m_topLevelMenu = NULL; - // TODO: Why isn't subMenu deleted here??? - // Will put this in for now. Assuming this is supposed - // to delete the menu, not just remove it. - item->DeleteSubMenu(); + wxLogLastError("RemoveMenu"); + } +*/ + if ( IsAttached() ) + { + // otherwise, the chane won't be visible + m_menuBar->Refresh(); } -// else -// { -// DeleteMenu(menu, (UINT)pos, MF_BYPOSITION); -// } - m_menuItems.DeleteNode(node); - delete item; + // and from internal data structures + return wxMenuBase::DoRemove(item); } -#if wxUSE_ACCEL - // --------------------------------------------------------------------------- // accelerator helpers // --------------------------------------------------------------------------- +#if wxUSE_ACCEL + // create the wxAcceleratorEntries for our accels and put them into provided // array - return the number of accels we have size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const @@ -338,7 +325,7 @@ size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const size_t count = GetAccelCount(); for ( size_t n = 0; n < count; n++ ) { - (*accels++).Set(m_accelFlags[n], m_accelKeyCodes[n], m_accelIds[n]); + *accels++ = *m_accels[n]; } return count; @@ -347,84 +334,7 @@ size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const #endif // wxUSE_ACCEL // --------------------------------------------------------------------------- -// wxMenu functions implemented in wxMenuItem -// --------------------------------------------------------------------------- - -void wxMenu::Enable(int id, bool Flag) -{ - wxMenuItem *item = FindItemForId(id); - wxCHECK_RET( item != NULL, wxT("can't enable non-existing menu item") ); - - item->Enable(Flag); -} - -bool wxMenu::IsEnabled(int id) const -{ - wxMenuItem *item = FindItemForId(id); - wxCHECK_MSG( item != NULL, FALSE, wxT("invalid item id") ); - - return item->IsEnabled(); -} - -void wxMenu::Check(int id, bool Flag) -{ - wxMenuItem *item = FindItemForId(id); - wxCHECK_RET( item != NULL, wxT("can't get status of non-existing menu item") ); - - item->Check(Flag); -} - -bool wxMenu::IsChecked(int id) const -{ - wxMenuItem *item = FindItemForId(id); - wxCHECK_MSG( item != NULL, FALSE, wxT("invalid item id") ); - - return item->IsChecked(); -} - -void wxMenu::SetLabel(int id, const wxString& label) -{ - wxMenuItem *item = FindItemForId(id) ; - wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") ); - - item->SetName(label); -} - -wxString wxMenu::GetLabel(int id) const -{ - wxString label; - wxMenuItem *pItem = FindItemForId(id) ; - if (pItem) - label = pItem->GetName() ; - else - wxFAIL_MSG(wxT("wxMenu::GetLabel: item doesn't exist")); - - return label; -} - -void wxMenu::SetHelpString(int itemId, const wxString& helpString) -{ - wxMenuItem *item = FindItemForId (itemId); - if (item) - item->SetHelp(helpString); - else - wxFAIL_MSG(wxT("wxMenu::SetHelpString: item doesn't exist")); -} - -wxString wxMenu::GetHelpString (int itemId) const -{ - wxString help; - wxMenuItem *item = FindItemForId (itemId); - if (item) - help = item->GetHelp(); - else - wxFAIL_MSG(wxT("wxMenu::GetHelpString: item doesn't exist")); - - return help; -} - -// --------------------------------------------------------------------------- -// wxMenu title +// set wxMenu title // --------------------------------------------------------------------------- void wxMenu::SetTitle(const wxString& label) @@ -433,43 +343,49 @@ void wxMenu::SetTitle(const wxString& label) m_title = label; HMENU hMenu = GetHmenu(); -// TODO -/* + if ( hasNoTitle ) { if ( !label.IsEmpty() ) { - if ( !InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING, - (unsigned)idMenuTitle, m_title) || - !InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) ) +/* + if ( !::InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING, + (unsigned)idMenuTitle, m_title) || + !::InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) ) { - wxLogLastError(wxT("InsertMenu")); + wxLogLastError("InsertMenu"); } +*/ } } else { if ( label.IsEmpty() ) { +/* // remove the title and the separator after it if ( !RemoveMenu(hMenu, 0, MF_BYPOSITION) || !RemoveMenu(hMenu, 0, MF_BYPOSITION) ) { wxLogLastError("RemoveMenu"); } +*/ } else { +/* // modify the title if ( !ModifyMenu(hMenu, 0u, - MF_BYPOSITION | MF_STRING, - (unsigned)idMenuTitle, m_title) ) + MF_BYPOSITION | MF_STRING, + (unsigned)idMenuTitle, m_title) ) { wxLogLastError("ModifyMenu"); } +*/ } } - +/* +#ifdef __WIN32__ // put the title string in bold face if ( !m_title.IsEmpty() ) { @@ -483,14 +399,10 @@ void wxMenu::SetTitle(const wxString& label) wxLogLastError("SetMenuItemInfo"); } } +#endif // Win32 */ } -const wxString wxMenu::GetTitle() const -{ - return m_title; -} - // --------------------------------------------------------------------------- // event processing // --------------------------------------------------------------------------- @@ -499,6 +411,7 @@ bool wxMenu::OS2Command(WXUINT WXUNUSED(param), WXWORD id) { // ignore commands from the menu title + // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!! if ( id != (WXWORD)idMenuTitle ) { wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED); @@ -515,12 +428,14 @@ bool wxMenu::ProcessCommand(wxCommandEvent & event) { bool processed = FALSE; +#if WXWIN_COMPATIBILITY // Try a callback if (m_callback) { (void)(*(m_callback))(*this, event); processed = TRUE; } +#endif // WXWIN_COMPATIBILITY // Try the menu's event handler if ( !processed && GetEventHandler()) @@ -537,63 +452,6 @@ bool wxMenu::ProcessCommand(wxCommandEvent & event) return processed; } -// --------------------------------------------------------------------------- -// Item search -// --------------------------------------------------------------------------- - -// Finds the item id matching the given string, -1 if not found. -int wxMenu::FindItem (const wxString& itemString) const -{ - wxString itemLabel = wxStripMenuCodes(itemString); - for ( wxNode *node = m_menuItems.First(); node; node = node->Next() ) - { - wxMenuItem *item = (wxMenuItem *)node->Data(); - if ( item->IsSubMenu() ) - { - int ans = item->GetSubMenu()->FindItem(itemString); - if ( ans != wxNOT_FOUND ) - return ans; - } - else if ( !item->IsSeparator() ) - { - wxString label = wxStripMenuCodes(item->GetName()); - if ( itemLabel == label ) - return item->GetId(); - } - } - - return wxNOT_FOUND; -} - -wxMenuItem *wxMenu::FindItemForId(int itemId, wxMenu ** itemMenu) const -{ - if ( itemMenu ) - *itemMenu = NULL; - - wxMenuItem *item = NULL; - for ( wxNode *node = m_menuItems.First(); node && !item; node = node->Next() ) - { - item = (wxMenuItem *)node->Data(); - - if ( item->GetId() == itemId ) - { - if (itemMenu) - *itemMenu = (wxMenu *)this; - } - else if ( item->IsSubMenu() ) - { - item = item->GetSubMenu()->FindItemForId(itemId, itemMenu); - } - else - { - // don't exit the loop - item = NULL; - } - } - - return item; -} - // --------------------------------------------------------------------------- // other // --------------------------------------------------------------------------- @@ -605,16 +463,23 @@ void wxMenu::Attach(wxMenuBar *menubar) wxASSERT_MSG( !m_menuBar, wxT("menu belongs to 2 menubars, expect a crash") ); m_menuBar = menubar; - m_savehMenu = m_hMenu; - m_hMenu = 0; } void wxMenu::Detach() { wxASSERT_MSG( m_menuBar, wxT("can't detach menu if it's not attached") ); - m_hMenu = m_savehMenu; - m_savehMenu = 0; + m_menuBar = NULL; +} + +wxWindow *wxMenu::GetWindow() const +{ + if ( m_invokingWindow != NULL ) + return m_invokingWindow; + else if ( m_menuBar != NULL) + return m_menuBar->GetFrame(); + + return NULL; } // --------------------------------------------------------------------------- @@ -624,9 +489,6 @@ void wxMenu::Detach() void wxMenuBar::Init() { m_eventHandler = this; - m_menuCount = 0; - m_menus = NULL; - m_titles = NULL; m_menuBarFrame = NULL; m_hMenu = 0; } @@ -645,48 +507,46 @@ wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[]) { Init(); - m_menuCount = count; - m_menus = menus; - m_titles = new wxString[count]; + m_titles.Alloc(count); - int i; - for ( i = 0; i < count; i++ ) - m_titles[i] = titles[i]; + for ( int i = 0; i < count; i++ ) + { + m_menus.Append(menus[i]); + m_titles.Add(titles[i]); - for ( i = 0; i < count; i++ ) - m_menus[i]->Attach(this); + menus[i]->Attach(this); + } } wxMenuBar::~wxMenuBar() { - for ( int i = 0; i < m_menuCount; i++ ) - { - delete m_menus[i]; - } - - delete[] m_menus; - delete[] m_titles; } // --------------------------------------------------------------------------- // wxMenuBar helpers // --------------------------------------------------------------------------- -void wxMenuBar::Refresh() +void wxMenuBar::Refresh( + bool WXUNUSED(bEraseBackground) +, const wxRect* WXUNUSED(pRect) +) { - wxCHECK_RET( m_menuBarFrame, wxT("can't refresh a menubar withotu a frame") ); + wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") ); -// TODO DrawMenuBar((HWND)m_menuBarFrame->GetHWND()) ; +// DrawMenuBar(GetHwndOf(m_menuBarFrame)); } WXHMENU wxMenuBar::Create() { if (m_hMenu != 0 ) - return m_hMenu; + return m_hMenu; wxCHECK_MSG( !m_hMenu, TRUE, wxT("menubar already created") ); - m_hMenu = 0; // TODO: (WXHMENU)::CreateMenu(); +// TODO: +/* + + m_hMenu = (WXHMENU)::CreateMenu(); if ( !m_hMenu ) { @@ -694,134 +554,57 @@ WXHMENU wxMenuBar::Create() } else { - for ( int i = 0; i < m_menuCount; i++ ) + size_t count = GetMenuCount(); + for ( size_t i = 0; i < count; i++ ) { -// if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING, -// (UINT)m_menus[i]->GetHMenu(), -// m_titles[i]) ) -// { -// wxLogLastError("AppendMenu"); -// } + if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING, + (UINT)m_menus[i]->GetHMenu(), + m_titles[i]) ) + { + wxLogLastError("AppendMenu"); + } } } return m_hMenu; +*/ + return (WXHMENU)0; } // --------------------------------------------------------------------------- -// wxMenuBar functions forwarded to wxMenuItem +// wxMenuBar functions to work with the top level submenus // --------------------------------------------------------------------------- -// Must only be used AFTER menu has been attached to frame, -// otherwise use individual menus to enable/disable items -void wxMenuBar::Enable(int id, bool enable) -{ - wxMenu *itemMenu = NULL; - wxMenuItem *item = FindItemForId(id, &itemMenu) ; - - wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") ); - - item->Enable(enable); -} - -void wxMenuBar::EnableTop(int pos, bool enable) -{ - int flag = 0; // TODO enable ? MF_ENABLED : MF_GRAYED;; - -// EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | flag); -} - -// Must only be used AFTER menu has been attached to frame, -// otherwise use individual menus -void wxMenuBar::Check(int id, bool check) -{ - wxMenu *itemMenu = NULL; - wxMenuItem *item = FindItemForId(id, &itemMenu) ; - - wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") ); - wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") ); - - item->Check(check); -} - -bool wxMenuBar::IsChecked(int id) const -{ - wxMenu *itemMenu = NULL; - wxMenuItem *item = FindItemForId(id, &itemMenu) ; - - wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsChecked(): no such item") ); - -// int flag = ::GetMenuState(GetHmenuOf(itemMenu), id, MF_BYCOMMAND); - -// return (flag & MF_CHECKED) != 0; - return FALSE; -} - -bool wxMenuBar::IsEnabled(int id) const -{ - wxMenu *itemMenu = NULL; - wxMenuItem *item = FindItemForId(id, &itemMenu) ; - - wxCHECK_MSG( item, FALSE, wxT("wxMenuBar::IsEnabled(): no such item") ); - -// int flag = ::GetMenuState(GetHmenuOf(itemMenu), id, MF_BYCOMMAND) ; - - // don't "and" with MF_ENABLED because its value is 0 -// return (flag & MF_DISABLED) == 0; - return FALSE; -} - -void wxMenuBar::SetLabel(int id, const wxString& label) -{ - wxMenu *itemMenu = NULL; - wxMenuItem *item = FindItemForId(id, &itemMenu) ; - - wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") ); - - item->SetName(label); -} +// NB: we don't support owner drawn top level items for now, if we do these +// functions would have to be changed to use wxMenuItem as well -wxString wxMenuBar::GetLabel(int id) const +void wxMenuBar::EnableTop(size_t pos, bool enable) { - wxMenu *itemMenu = NULL; - wxMenuItem *item = FindItemForId(id, &itemMenu) ; - - wxCHECK_MSG( item, wxT(""), wxT("wxMenuBar::GetLabel(): no such item") ); - - return item->GetName(); -} + wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") ); -void wxMenuBar::SetHelpString (int id, const wxString& helpString) -{ - wxMenu *itemMenu = NULL; - wxMenuItem *item = FindItemForId(id, &itemMenu) ; +// int flag = enable ? MF_ENABLED : MF_GRAYED; - wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") ); +// EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | flag); - item->SetHelp(helpString); + Refresh(); } -wxString wxMenuBar::GetHelpString (int id) const +void wxMenuBar::SetLabelTop(size_t pos, const wxString& label) { - wxMenu *itemMenu = NULL; - wxMenuItem *item = FindItemForId(id, &itemMenu) ; - - wxCHECK_MSG( item, wxT(""), wxT("wxMenuBar::GetHelpString(): no such item") ); - - return item->GetHelp(); -} + wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") ); -// --------------------------------------------------------------------------- -// wxMenuBar functions to work with the top level submenus -// --------------------------------------------------------------------------- + m_titles[pos] = label; -// NB: we don't support owner drawn top level items for now, if we do these -// functions would have to be changed to use wxMenuItem as well + if ( !IsAttached() ) + { + return; + } + //else: have to modify the existing menu -void wxMenuBar::SetLabelTop(int pos, const wxString& label) -{ +// TODO: +/* UINT id; - UINT flagsOld = 0; // TODO: ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION); + UINT flagsOld = ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION); if ( flagsOld == 0xFFFFFFFF ) { wxLogLastError(wxT("GetMenuState")); @@ -829,96 +612,40 @@ void wxMenuBar::SetLabelTop(int pos, const wxString& label) return; } -// if ( flagsOld & MF_POPUP ) -// { -// // HIBYTE contains the number of items in the submenu in this case -// flagsOld &= 0xff ; -// id = (UINT)::GetSubMenu((HMENU)m_hMenu, pos) ; -// } -// else -// { -// id = pos; -// } - -// if ( ::ModifyMenu(GetHmenu(), pos, MF_BYPOSITION | MF_STRING | flagsOld, -// id, label) == 0xFFFFFFFF ) -// { -// wxLogLastError("ModifyMenu"); -// } -} - -wxString wxMenuBar::GetLabelTop(int pos) const -{ - int len = 0; // TODO: ::GetMenuString((HMENU)m_hMenu, pos, NULL, 0, MF_BYCOMMAND); - - len++; // for the NUL character - wxString label; -// ::GetMenuString(GetHmenu(), pos, label.GetWriteBuf(len), len, MF_BYCOMMAND); - label.UngetWriteBuf(); - - return label; -} - -// --------------------------------------------------------------------------- -// wxMenuBar notifications -// --------------------------------------------------------------------------- - -bool wxMenuBar::OnDelete(wxMenu *a_menu, int pos) -{ - if ( !m_menuBarFrame ) - return TRUE; - - // TODO -/* - if ( ::RemoveMenu((HMENU)m_hMenu, (UINT)pos, MF_BYPOSITION) ) + if ( flagsOld & MF_POPUP ) { - // VZ: I'm not sure about what's going on here, so I leave an assert - wxASSERT_MSG( m_menus[pos] == a_menu, wxT("what is this parameter for??") ); - - a_menu->Detach(); - - if ( m_menuBarFrame ) - Refresh(); - - return TRUE; + // HIBYTE contains the number of items in the submenu in this case + flagsOld &= 0xff; + id = (UINT)::GetSubMenu((HMENU)m_hMenu, pos); } else { - wxLogLastError("RemoveMenu"); + id = pos; + } + + if ( ::ModifyMenu(GetHmenu(), pos, MF_BYPOSITION | MF_STRING | flagsOld, + id, label) == (int)0xFFFFFFFF ) + { + wxLogLastError("ModifyMenu"); } */ - return FALSE; + Refresh(); } -bool wxMenuBar::OnAppend(wxMenu *a_menu, const wxChar *title) +wxString wxMenuBar::GetLabelTop(size_t pos) const { - WXHMENU submenu = a_menu->GetHMenu(); - if ( !submenu ) - return FALSE; + wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString, + wxT("invalid menu index in wxMenuBar::GetLabelTop") ); - if ( !m_menuBarFrame ) - return TRUE; - - a_menu->Attach(this); - -// if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING, -// (UINT)submenu, title) ) -// { -// wxLogLastError(wxT("AppendMenu")); -// } - - Refresh(); - - return TRUE; + return m_titles[pos]; } -// --------------------------------------------------------------------------- -// wxMenuBar construction -// --------------------------------------------------------------------------- int wxMenuBar::FindMenu(const wxString& title) { wxString menuTitle = wxStripMenuCodes(title); - for ( int i = 0; i < m_menuCount; i++ ) + + size_t count = GetMenuCount(); + for ( size_t i = 0; i < count; i++ ) { wxString title = wxStripMenuCodes(m_titles[i]); if ( menuTitle == title ) @@ -929,135 +656,155 @@ int wxMenuBar::FindMenu(const wxString& title) } +// --------------------------------------------------------------------------- +// wxMenuBar construction +// --------------------------------------------------------------------------- -void wxMenuBar::ReplaceMenu(int pos, wxMenu * new_menu, const wxString& title) +wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title) { - if (m_menuBarFrame) return; - - if ( pos >= 0 && pos < m_menuCount ) + wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title); + if ( !menuOld ) + return FALSE; + m_titles[pos] = title; +// TODO: +/* + if ( IsAttached() ) { - wxMenu *old_menu = m_menus[pos]; - m_menus[pos] = new_menu; - delete old_menu; - } + // can't use ModifyMenu() because it deletes the submenu it replaces + if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) ) + { + wxLogLastError("RemoveMenu"); + } -} + if ( !::InsertMenu(GetHmenu(), (UINT)pos, + MF_BYPOSITION | MF_POPUP | MF_STRING, + (UINT)GetHmenuOf(menu), title) ) + { + wxLogLastError("InsertMenu"); + } + +#if wxUSE_ACCEL + if ( menuOld->HasAccels() || menu->HasAccels() ) + { + // need to rebuild accell table + RebuildAccelTable(); + } +#endif // wxUSE_ACCEL + Refresh(); + } +*/ + return menuOld; +} -void wxMenuBar::Insert(int pos, wxMenu * menu, const wxString& title) +bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title) { - if (m_menuBarFrame) return; - if ( pos < 0 && pos >= m_menuCount ) return; + if ( !wxMenuBarBase::Insert(pos, menu, title) ) + return FALSE; - m_menuCount ++; - wxMenu **new_menus = new wxMenu *[m_menuCount]; - wxString *new_titles = new wxString[m_menuCount]; - int i; + m_titles.Insert(title, pos); - for (i = 0; i < pos; i++) + menu->Attach(this); +// TODO: +/* + if ( IsAttached() ) { - new_menus[i] = m_menus[i]; - m_menus[i] = NULL; - new_titles[i] = m_titles[i]; - m_titles[i] = wxT(""); - } + if ( !::InsertMenu(GetHmenu(), pos, + MF_BYPOSITION | MF_POPUP | MF_STRING, + (UINT)GetHmenuOf(menu), title) ) + { + wxLogLastError("InsertMenu"); + } - new_menus[pos] = (wxMenu *)menu; - new_titles[i] = title; +#if wxUSE_ACCEL + if ( menu->HasAccels() ) + { + // need to rebuild accell table + RebuildAccelTable(); + } +#endif // wxUSE_ACCEL - for (i = pos+1; i < m_menuCount; i++) - { - new_menus[i] = m_menus[i-1]; - m_menus[i-1] = NULL; - new_titles[i] = m_titles[i-1]; - m_titles[i-1] = wxT(""); + Refresh(); } - if (m_menus) - { - delete[]m_menus; - delete[]m_titles; - } - m_menus = new_menus; - m_titles = new_titles; - - menu->SetParent(this); - +*/ + return TRUE; } - -void wxMenuBar::Append (wxMenu * menu, const wxString& title) +bool wxMenuBar::Append(wxMenu *menu, const wxString& title) { - if (!OnAppend(menu, title)) - return; + WXHMENU submenu = menu ? menu->GetHMenu() : 0; + wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") ); - m_menuCount ++; - wxMenu **new_menus = new wxMenu *[m_menuCount]; - wxString *new_titles = new wxString[m_menuCount]; - int i; + if ( !wxMenuBarBase::Append(menu, title) ) + return FALSE; - for (i = 0; i < m_menuCount - 1; i++) - { - new_menus[i] = m_menus[i]; - m_menus[i] = NULL; - new_titles[i] = m_titles[i]; - m_titles[i] = wxT(""); - } - if (m_menus) + menu->Attach(this); + + m_titles.Add(title); +// TODO: +/* + if ( IsAttached() ) { - delete[]m_menus; - delete[]m_titles; - } - m_menus = new_menus; - m_titles = new_titles; + if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING, + (UINT)submenu, title) ) + { + wxLogLastError(wxT("AppendMenu")); + } - m_menus[m_menuCount - 1] = (wxMenu *)menu; - m_titles[m_menuCount - 1] = title; +#if wxUSE_ACCEL + if ( menu->HasAccels() ) + { + // need to rebuild accell table + RebuildAccelTable(); + } +#endif // wxUSE_ACCEL - menu->SetParent(this); + Refresh(); + } +*/ + return TRUE; } -void wxMenuBar::Delete(wxMenu * menu, int i) +wxMenu *wxMenuBar::Remove(size_t pos) { - int j; - int ii = (int) i; - - if (menu != 0) { - for (ii = 0; ii < m_menuCount; ii++) { - if (m_menus[ii] == menu) - break; + wxMenu *menu = wxMenuBarBase::Remove(pos); + if ( !menu ) + return NULL; +// TODO: +/* + if ( IsAttached() ) + { + if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) ) + { + wxLogLastError("RemoveMenu"); } - if (ii >= m_menuCount) - return; - } else { - if (ii < 0 || ii >= m_menuCount) - return; - menu = m_menus[ii]; - } - if (!OnDelete(menu, ii)) - return; + menu->Detach(); - menu->SetParent(NULL); +#if wxUSE_ACCEL + if ( menu->HasAccels() ) + { + // need to rebuild accell table + RebuildAccelTable(); + } +#endif // wxUSE_ACCEL - -- m_menuCount; - for (j = ii; j < m_menuCount; j++) { - m_menus[j] = m_menus[j + 1]; - m_titles[j] = m_titles[j + 1]; + Refresh(); } -} - -void wxMenuBar::Attach(wxFrame *frame) -{ - wxASSERT_MSG( !m_menuBarFrame, wxT("menubar already attached!") ); - m_menuBarFrame = frame; + m_titles.Remove(pos); +*/ + return menu; +} #if wxUSE_ACCEL - // create the accel table - we consider that the menubar construction is - // finished + +void wxMenuBar::RebuildAccelTable() +{ + // merge the accelerators of all menus into one accel table size_t nAccelCount = 0; - int i; - for ( i = 0; i < m_menuCount; i++ ) + size_t i, count = GetMenuCount(); + for ( i = 0; i < count; i++ ) { nAccelCount += m_menus[i]->GetAccelCount(); } @@ -1067,7 +814,7 @@ void wxMenuBar::Attach(wxFrame *frame) wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount]; nAccelCount = 0; - for ( i = 0; i < m_menuCount; i++ ) + for ( i = 0; i < count; i++ ) { nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]); } @@ -1076,13 +823,25 @@ void wxMenuBar::Attach(wxFrame *frame) delete [] accelEntries; } +} + +#endif // wxUSE_ACCEL + +void wxMenuBar::Attach(wxFrame *frame) +{ + wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") ); + + m_menuBarFrame = frame; + +#if wxUSE_ACCEL + RebuildAccelTable(); #endif // wxUSE_ACCEL } void wxMenuBar::Detach() { // ::DestroyMenu((HMENU)m_hMenu); - m_hMenu = NULL; + m_hMenu = (WXHMENU)NULL; m_menuBarFrame = NULL; } @@ -1096,7 +855,8 @@ int wxMenuBar::FindMenuItem(const wxString& menuString, const wxString& itemString) const { wxString menuLabel = wxStripMenuCodes(menuString); - for ( int i = 0; i < m_menuCount; i++ ) + size_t count = GetMenuCount(); + for ( size_t i = 0; i < count; i++ ) { wxString title = wxStripMenuCodes(m_titles[i]); if ( menuString == title ) @@ -1106,83 +866,18 @@ int wxMenuBar::FindMenuItem(const wxString& menuString, return wxNOT_FOUND; } -wxMenuItem *wxMenuBar::FindItemForId (int id, wxMenu **itemMenu) const +wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const { if ( itemMenu ) *itemMenu = NULL; wxMenuItem *item = NULL; - for ( int i = 0; !item && (i < m_menuCount); i++ ) + size_t count = GetMenuCount(); + for ( size_t i = 0; !item && (i < count); i++ ) { - item = m_menus[i]->FindItemForId(id, itemMenu); + item = m_menus[i]->FindItem(id, itemMenu); } return item; } - -// ---------------------------------------------------------------------------- -// helper functions -// ---------------------------------------------------------------------------- - -wxWindow *wxMenu::GetWindow() const -{ - if ( m_pInvokingWindow != NULL ) - return m_pInvokingWindow; - else if ( m_menuBar != NULL) - return m_menuBar->GetFrame(); - - return NULL; -} - -WXHMENU wxMenu::GetHMenu() const -{ - if ( m_hMenu != 0 ) - return m_hMenu; - else if ( m_savehMenu != 0 ) - return m_savehMenu; - - wxFAIL_MSG(wxT("wxMenu without HMENU")); - - return 0; -} - -// Update a menu and all submenus recursively. source is the object that has -// the update event handlers defined for it. If NULL, the menu or associated -// window will be used. -void wxMenu::UpdateUI(wxEvtHandler* source) -{ - if (!source && GetInvokingWindow()) - source = GetInvokingWindow()->GetEventHandler(); - if (!source) - source = GetEventHandler(); - if (!source) - source = this; - - wxNode* node = GetItems().First(); - while (node) - { - wxMenuItem* item = (wxMenuItem*) node->Data(); - if ( !item->IsSeparator() ) - { - wxWindowID id = item->GetId(); - wxUpdateUIEvent event(id); - event.SetEventObject( source ); - - if (source->ProcessEvent(event)) - { - if (event.GetSetText()) - SetLabel(id, event.GetText()); - if (event.GetSetChecked()) - Check(id, event.GetChecked()); - if (event.GetSetEnabled()) - Enable(id, event.GetEnabled()); - } - - if (item->GetSubMenu()) - item->GetSubMenu()->UpdateUI(source); - } - node = node->Next(); - } -} - diff --git a/src/os2/menuitem.cpp b/src/os2/menuitem.cpp index 1c1353c558..9b55f35a19 100644 --- a/src/os2/menuitem.cpp +++ b/src/os2/menuitem.cpp @@ -27,18 +27,29 @@ #include "wx/string.h" #endif -#include "wx/ownerdrw.h" #include "wx/menuitem.h" #include "wx/log.h" +#if wxUSE_ACCEL + #include "wx/accel.h" +#endif // wxUSE_ACCEL + #include "wx/os2/private.h" // --------------------------------------------------------------------------- -// convenience macro +// macro // --------------------------------------------------------------------------- +// hide the ugly cast #define GetHMenuOf(menu) ((HMENU)menu->GetHMenu()) +// conditional compilation +#if wxUSE_OWNER_DRAWN + #define OWNER_DRAWN_ONLY( code ) if ( IsOwnerDrawn() ) code +#else // !wxUSE_OWNER_DRAWN + #define OWNER_DRAWN_ONLY( code ) +#endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN + // ============================================================================ // implementation // ============================================================================ @@ -48,12 +59,11 @@ // ---------------------------------------------------------------------------- #if !defined(USE_SHARED_LIBRARY) || !USE_SHARED_LIBRARY -#if wxUSE_OWNER_DRAWN - IMPLEMENT_DYNAMIC_CLASS2(wxMenuItem, wxObject, wxOwnerDrawn) -#else //!USE_OWNER_DRAWN - IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject) -#endif //USE_OWNER_DRAWN - + #if wxUSE_OWNER_DRAWN + IMPLEMENT_DYNAMIC_CLASS2(wxMenuItem, wxMenuItemBase, wxOwnerDrawn) + #else //!USE_OWNER_DRAWN + IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxMenuItemBase) + #endif //USE_OWNER_DRAWN #endif //USE_SHARED_LIBRARY // ---------------------------------------------------------------------------- @@ -63,17 +73,15 @@ // ctor & dtor // ----------- -wxMenuItem::wxMenuItem(wxMenu *pParentMenu, int id, - const wxString& strName, const wxString& strHelp, +wxMenuItem::wxMenuItem(wxMenu *pParentMenu, + int id, + const wxString& text, + const wxString& strHelp, bool bCheckable, wxMenu *pSubMenu) : #if wxUSE_OWNER_DRAWN - wxOwnerDrawn(strName, bCheckable), -#else //no owner drawn support - m_bCheckable(bCheckable), - m_strName(strName), -#endif //owner drawn - m_strHelp(strHelp) + wxOwnerDrawn(text, bCheckable) +#endif // owner drawn { wxASSERT_MSG( pParentMenu != NULL, wxT("a menu item should have a parent") ); @@ -88,13 +96,16 @@ wxMenuItem::wxMenuItem(wxMenu *pParentMenu, int id, ResetOwnerDrawn(); #undef SYS_COLOR -#endif - - m_pParentMenu = pParentMenu; - m_pSubMenu = pSubMenu; - m_bEnabled = TRUE; - m_bChecked = FALSE; - m_idItem = id; +#endif // wxUSE_OWNER_DRAWN + + m_parentMenu = pParentMenu; + m_subMenu = pSubMenu; + m_isEnabled = TRUE; + m_isChecked = FALSE; + m_id = id; + m_text = text; + m_isCheckable = bCheckable; + m_help = strHelp; } wxMenuItem::~wxMenuItem() @@ -107,74 +118,96 @@ wxMenuItem::~wxMenuItem() // return the id for calling Win32 API functions int wxMenuItem::GetRealId() const { - return m_pSubMenu ? (int)m_pSubMenu->GetHMenu() : GetId(); + return m_subMenu ? (int)m_subMenu->GetHMenu() : GetId(); +} + +// get item state +// -------------- + +bool wxMenuItem::IsChecked() const +{ +/* + int flag = ::GetMenuState(GetHMenuOf(m_parentMenu), GetId(), MF_BYCOMMAND); + + // don't "and" with MF_ENABLED because its value is 0 + return (flag & MF_DISABLED) == 0; +*/ + return FALSE; +} + +wxString wxMenuItem::GetLabel() const +{ + return wxStripMenuCodes(m_text); } -// delete the sub menu -// ------------------- -void wxMenuItem::DeleteSubMenu() +// accelerators +// ------------ + +#if wxUSE_ACCEL + +wxAcceleratorEntry *wxMenuItem::GetAccel() const { - delete m_pSubMenu; - m_pSubMenu = NULL; + return wxGetAccelFromString(GetText()); } +#endif // wxUSE_ACCEL + // change item state // ----------------- -void wxMenuItem::Enable(bool bDoEnable) +void wxMenuItem::Enable(bool enable) { - // TODO: + if ( m_isEnabled == enable ) + return; /* - if ( m_bEnabled != bDoEnable ) { - long rc = EnableMenuItem(GetHMenuOf(m_pParentMenu), - GetRealId(), - MF_BYCOMMAND | - (bDoEnable ? MF_ENABLED : MF_GRAYED)); - - if ( rc == -1 ) { - wxLogLastError("EnableMenuItem"); - } + long rc = EnableMenuItem(GetHMenuOf(m_parentMenu), + GetRealId(), + MF_BYCOMMAND | + (enable ? MF_ENABLED : MF_GRAYED)); - m_bEnabled = bDoEnable; + if ( rc == -1 ) { + wxLogLastError("EnableMenuItem"); } */ + wxMenuItemBase::Enable(enable); } -void wxMenuItem::Check(bool bDoCheck) +void wxMenuItem::Check(bool check) { - wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") ); + wxCHECK_RET( m_isCheckable, wxT("only checkable items may be checked") ); - // TODO: + if ( m_isChecked == check ) + return; /* - if ( m_bChecked != bDoCheck ) { - long rc = CheckMenuItem(GetHMenuOf(m_pParentMenu), - GetId(), - MF_BYCOMMAND | - (bDoCheck ? MF_CHECKED : MF_UNCHECKED)); - - if ( rc == -1 ) { - wxLogLastError("CheckMenuItem"); - } + long rc = CheckMenuItem(GetHMenuOf(m_parentMenu), + GetRealId(), + MF_BYCOMMAND | + (check ? MF_CHECKED : MF_UNCHECKED)); - m_bChecked = bDoCheck; + if ( rc == -1 ) { + wxLogLastError("CheckMenuItem"); } */ + wxMenuItemBase::Check(check); } -void wxMenuItem::SetName(const wxString& strName) +void wxMenuItem::SetText(const wxString& text) { // don't do anything if label didn't change - if ( m_strName == strName ) + if ( m_text == text ) return; - m_strName = strName; + wxMenuItemBase::SetText(text); + OWNER_DRAWN_ONLY( wxOwnerDrawn::SetName(text) ); +/* + HMENU hMenu = GetHMenuOf(m_parentMenu); + wxCHECK_RET( hMenu, wxT("menuitem without menu") ); - HMENU hMenu = GetHMenuOf(m_pParentMenu); +#if wxUSE_ACCEL + m_parentMenu->UpdateAccel(this); +#endif // wxUSE_ACCEL UINT id = GetRealId(); - - // TODO: -/* UINT flagsOld = ::GetMenuState(hMenu, id, MF_BYCOMMAND); if ( flagsOld == 0xFFFFFFFF ) { @@ -190,6 +223,7 @@ void wxMenuItem::SetName(const wxString& strName) } LPCTSTR data; + #if wxUSE_OWNER_DRAWN if ( IsOwnerDrawn() ) { @@ -200,12 +234,12 @@ void wxMenuItem::SetName(const wxString& strName) #endif //owner drawn { flagsOld |= MF_STRING; - data = strName; + data = (char*) text.c_str(); } if ( ::ModifyMenu(hMenu, id, MF_BYCOMMAND | flagsOld, - id, data) == 0xFFFFFFFF ) + id, data) == (int)0xFFFFFFFF ) { wxLogLastError(wxT("ModifyMenu")); } @@ -213,3 +247,22 @@ void wxMenuItem::SetName(const wxString& strName) */ } +void wxMenuItem::SetCheckable(bool checkable) +{ + wxMenuItemBase::SetCheckable(checkable); + OWNER_DRAWN_ONLY( wxOwnerDrawn::SetCheckable(checkable) ); +} + +// ---------------------------------------------------------------------------- +// wxMenuItemBase +// ---------------------------------------------------------------------------- + +wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu, + int id, + const wxString& name, + const wxString& help, + bool isCheckable, + wxMenu *subMenu) +{ + return new wxMenuItem(parentMenu, id, name, help, isCheckable, subMenu); +} diff --git a/src/os2/thread.cpp b/src/os2/thread.cpp index c636e6e9ae..a2b1004172 100644 --- a/src/os2/thread.cpp +++ b/src/os2/thread.cpp @@ -20,12 +20,15 @@ #include -#define INCL_DOS -#include - #include "wx/module.h" #include "wx/thread.h" +#define INCL_DOSSEMAPHORES +#define INCL_DOSPROCESS +#define INCL_ERRORS +#include +#include + // the possible states of the thread ("=>" shows all possible transitions from // this state) enum wxThreadState @@ -41,12 +44,13 @@ enum wxThreadState // static variables // ---------------------------------------------------------------------------- -// TLS index of the slot where we store the pointer to the current thread -static DWORD s_tlsThisThread = 0xFFFFFFFF; - // id of the main thread - the one which can call GUI functions without first // calling wxMutexGuiEnter() -static DWORD s_idMainThread = 0; +static ULONG s_ulIdMainThread = 0; +wxMutex* p_wxMainMutex; + +// OS2 substitute for Tls pointer the current parent thread object +wxThread* m_pThread; // pointer to the wxWindows thread object // if it's FALSE, some secondary thread is holding the GUI lock static bool s_bGuiOwnedByMainThread = TRUE; @@ -54,19 +58,19 @@ static bool s_bGuiOwnedByMainThread = TRUE; // critical section which controls access to all GUI functions: any secondary // thread (i.e. except the main one) must enter this crit section before doing // any GUI calls -static wxCriticalSection *s_critsectGui = NULL; +static wxCriticalSection *s_pCritsectGui = NULL; // critical section which protects s_nWaitingForGui variable -static wxCriticalSection *s_critsectWaitingForGui = NULL; +static wxCriticalSection *s_pCritsectWaitingForGui = NULL; // number of threads waiting for GUI in wxMutexGuiEnter() static size_t s_nWaitingForGui = 0; // are we waiting for a thread termination? -static bool s_waitingForThread = FALSE; +static bool s_bWaitingForThread = FALSE; // ============================================================================ -// Windows implementation of thread classes +// OS/2 implementation of thread classes // ============================================================================ // ---------------------------------------------------------------------------- @@ -75,18 +79,19 @@ static bool s_waitingForThread = FALSE; class wxMutexInternal { public: - HANDLE p_mutex; + HMTX m_vMutex; }; wxMutex::wxMutex() { + APIRET ulrc; + p_internal = new wxMutexInternal; -// p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL); - if ( !p_internal->p_mutex ) + ulrc = ::DosCreateMutexSem(NULL, &p_internal->m_vMutex, 0L, FALSE); + if (ulrc != 0) { wxLogSysError(_("Can not create mutex.")); } - m_locked = 0; } @@ -94,66 +99,65 @@ wxMutex::~wxMutex() { if (m_locked > 0) wxLogDebug(wxT("Warning: freeing a locked mutex (%d locks)."), m_locked); -// CloseHandle(p_internal->p_mutex); + ::DosCloseMutexSem(p_internal->m_vMutex); + delete p_internal; + p_internal = NULL; } wxMutexError wxMutex::Lock() { - DWORD ret; + APIRET ulrc; + + ulrc = ::DosRequestMutexSem(p_internal->m_vMutex, SEM_INDEFINITE_WAIT); -// TODO: -/* - ret = WaitForSingleObject(p_internal->p_mutex, INFINITE); - switch ( ret ) + switch (ulrc) { - case WAIT_ABANDONED: + case ERROR_TOO_MANY_SEM_REQUESTS: return wxMUTEX_BUSY; - case WAIT_OBJECT_0: + case NO_ERROR: // ok break; - case WAIT_FAILED: + case ERROR_INVALID_HANDLE: + case ERROR_INTERRUPT: + case ERROR_SEM_OWNER_DIED: wxLogSysError(_("Couldn't acquire a mutex lock")); return wxMUTEX_MISC_ERROR; - case WAIT_TIMEOUT: + case ERROR_TIMEOUT: default: wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock")); } - m_locked++; -*/ return wxMUTEX_NO_ERROR; } wxMutexError wxMutex::TryLock() { - DWORD ret; + ULONG ulrc; -// TODO: -/* - ret = WaitForSingleObject(p_internal->p_mutex, 0); - if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED) + ulrc = ::DosRequestMutexSem(p_internal->m_vMutex, SEM_IMMEDIATE_RETURN /*0L*/); + if (ulrc == ERROR_TIMEOUT || ulrc == ERROR_TOO_MANY_SEM_REQUESTS) return wxMUTEX_BUSY; m_locked++; -*/ return wxMUTEX_NO_ERROR; } wxMutexError wxMutex::Unlock() { + APIRET ulrc; + if (m_locked > 0) m_locked--; - BOOL ret = 0; // TODO: ReleaseMutex(p_internal->p_mutex); - if ( ret == 0 ) + ulrc = ::DosReleaseMutexSem(p_internal->m_vMutex); + if (ulrc != 0) { wxLogSysError(_("Couldn't release a mutex")); return wxMUTEX_MISC_ERROR; } - return wxMUTEX_NO_ERROR; } @@ -164,117 +168,90 @@ wxMutexError wxMutex::Unlock() class wxConditionInternal { public: - HANDLE event; - int waiters; + HEV m_vEvent; + int m_nWaiters; }; wxCondition::wxCondition() { + APIRET ulrc; + ULONG ulCount; + p_internal = new wxConditionInternal; -// TODO: -/* - p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL); - if ( !p_internal->event ) + ulrc = ::DosCreateEventSem(NULL, &p_internal->m_vEvent, 0L, FALSE); + if (ulrc != 0) { wxLogSysError(_("Can not create event object.")); } -*/ - p_internal->waiters = 0; + p_internal->m_nWaiters = 0; + // ?? just for good measure? + ::DosResetEventSem(p_internal->m_vEvent, &ulCount); } wxCondition::~wxCondition() { -// CloseHandle(p_internal->event); + ::DosCloseEventSem(p_internal->m_vEvent); + delete p_internal; + p_internal = NULL; } -void wxCondition::Wait(wxMutex& mutex) +void wxCondition::Wait( + wxMutex& rMutex +) { - mutex.Unlock(); - p_internal->waiters++; -// WaitForSingleObject(p_internal->event, INFINITE); - p_internal->waiters--; - mutex.Lock(); + rMutex.Unlock(); + p_internal->m_nWaiters++; + ::DosWaitEventSem(p_internal->m_vEvent, SEM_INDEFINITE_WAIT); + p_internal->m_nWaiters--; + rMutex.Lock(); } -bool wxCondition::Wait(wxMutex& mutex, - unsigned long sec, - unsigned long nsec) +bool wxCondition::Wait( + wxMutex& rMutex +, unsigned long ulSec +, unsigned long ulMillisec) { - DWORD ret; + APIRET ulrc; - mutex.Unlock(); - p_internal->waiters++; -// ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000)); - p_internal->waiters--; - mutex.Lock(); + rMutex.Unlock(); + p_internal->m_nWaiters++; + ulrc = ::DosWaitEventSem(p_internal->m_vEvent, ULONG((ulSec * 1000L) + ulMillisec)); + p_internal->m_nWaiters--; + rMutex.Lock(); -// return (ret != WAIT_TIMEOUT); - return FALSE; + return (ulrc != ERROR_TIMEOUT); } void wxCondition::Signal() { -// SetEvent(p_internal->event); + ::DosPostEventSem(p_internal->m_vEvent); } void wxCondition::Broadcast() { - int i; + int i; -// TODO: -/* - for (i=0;iwaiters;i++) + for (i = 0; i < p_internal->m_nWaiters; i++) { - if ( SetEvent(p_internal->event) == 0 ) + if (::DosPostEventSem(p_internal->m_vEvent) != 0) { wxLogSysError(_("Couldn't change the state of event object.")); } } -*/ } // ---------------------------------------------------------------------------- // wxCriticalSection implementation // ---------------------------------------------------------------------------- -#define CRITICAL_SECTION ULONG -class wxCriticalSectionInternal -{ -public: - // init the critical section object - wxCriticalSectionInternal() - { //::InitializeCriticalSection(&m_data); - } - - // implicit cast to the associated data - operator CRITICAL_SECTION *() { return &m_data; } - - // free the associated ressources - ~wxCriticalSectionInternal() - { //::DeleteCriticalSection(&m_data); - } - -private: - CRITICAL_SECTION m_data; -}; - -wxCriticalSection::wxCriticalSection() -{ - m_critsect = new wxCriticalSectionInternal; -} - -wxCriticalSection::~wxCriticalSection() -{ - delete m_critsect; -} void wxCriticalSection::Enter() { -//TODO: ::EnterCriticalSection(*m_critsect); + ::DosEnterCritSec(); } void wxCriticalSection::Leave() { -// TODO: ::LeaveCriticalSection(*m_critsect); + ::DosExitCritSec(); } // ---------------------------------------------------------------------------- @@ -287,144 +264,134 @@ void wxCriticalSection::Leave() class wxThreadInternal { public: - wxThreadInternal() + inline wxThreadInternal() { m_hThread = 0; - m_state = STATE_NEW; - m_priority = 0; // TODO: WXTHREAD_DEFAULT_PRIORITY; + m_eState = STATE_NEW; + m_nPriority = 0; } // create a new (suspended) thread (for the given thread object) - bool Create(wxThread *thread); + bool Create(wxThread* pThread); // suspend/resume/terminate bool Suspend(); bool Resume(); - void Cancel() { m_state = STATE_CANCELED; } + inline void Cancel() { m_eState = STATE_CANCELED; } // thread state - void SetState(wxThreadState state) { m_state = state; } - wxThreadState GetState() const { return m_state; } + inline void SetState(wxThreadState eState) { m_eState = eState; } + inline wxThreadState GetState() const { return m_eState; } // thread priority - void SetPriority(unsigned int priority) { m_priority = priority; } - unsigned int GetPriority() const { return m_priority; } + inline void SetPriority(unsigned int nPriority) { m_nPriority = nPriority; } + inline unsigned int GetPriority() const { return m_nPriority; } // thread handle and id - HANDLE GetHandle() const { return m_hThread; } - DWORD GetId() const { return m_tid; } + inline TID GetHandle() const { return m_hThread; } + TID GetId() const { return m_hThread; } // thread function static DWORD OS2ThreadStart(wxThread *thread); private: - HANDLE m_hThread; // handle of the thread - wxThreadState m_state; // state, see wxThreadState enum - unsigned int m_priority; // thread priority in "wx" units - DWORD m_tid; // thread id + // Threads in OS/2 have only an ID, so m_hThread is both it's handle and ID + // PM also has no real Tls mechanism to index pointers by so we'll just + // keep track of the wxWindows parent object here. + TID m_hThread; // handle and ID of the thread + wxThreadState m_eState; // state, see wxThreadState enum + unsigned int m_nPriority; // thread priority in "wx" units }; -DWORD wxThreadInternal::OS2ThreadStart(wxThread *thread) +ULONG wxThreadInternal::OS2ThreadStart( + wxThread* pThread +) { - // store the thread object in the TLS -// TODO: -/* - if ( !::TlsSetValue(s_tlsThisThread, thread) ) - { - wxLogSysError(_("Can not start thread: error writing TLS.")); + m_pThread = pThread; - return (DWORD)-1; - } -*/ - DWORD ret = (DWORD)thread->Entry(); - thread->p_internal->SetState(STATE_EXITED); - thread->OnExit(); + DWORD dwRet = (DWORD)pThread->Entry(); - delete thread; + pThread->p_internal->SetState(STATE_EXITED); + pThread->OnExit(); - return ret; + delete pThread; + m_pThread = NULL; + return dwRet; } -bool wxThreadInternal::Create(wxThread *thread) +bool wxThreadInternal::Create( + wxThread* pThread +) { -// TODO: -/* - m_hThread = ::CreateThread - ( - NULL, // default security - 0, // default stack size - (LPTHREAD_START_ROUTINE) // thread entry point - wxThreadInternal::OS2ThreadStart, // - (LPVOID)thread, // parameter - CREATE_SUSPENDED, // flags - &m_tid // [out] thread id - ); + APIRET ulrc; - if ( m_hThread == NULL ) + ulrc = ::DosCreateThread( &m_hThread + ,(PFNTHREAD)wxThreadInternal::OS2ThreadStart + ,(ULONG)pThread + ,CREATE_SUSPENDED | STACK_SPARSE + ,8192L + ); + if(ulrc != 0) { wxLogSysError(_("Can't create thread")); return FALSE; } - // translate wxWindows priority to the Windows one - int win_priority; - if (m_priority <= 20) - win_priority = THREAD_PRIORITY_LOWEST; - else if (m_priority <= 40) - win_priority = THREAD_PRIORITY_BELOW_NORMAL; - else if (m_priority <= 60) - win_priority = THREAD_PRIORITY_NORMAL; - else if (m_priority <= 80) - win_priority = THREAD_PRIORITY_ABOVE_NORMAL; - else if (m_priority <= 100) - win_priority = THREAD_PRIORITY_HIGHEST; + // translate wxWindows priority to the PM one + ULONG ulOS2_Priority; + + if (m_nPriority <= 20) + ulOS2_Priority = PRTYC_NOCHANGE; + else if (m_nPriority <= 40) + ulOS2_Priority = PRTYC_IDLETIME; + else if (m_nPriority <= 60) + ulOS2_Priority = PRTYC_REGULAR; + else if (m_nPriority <= 80) + ulOS2_Priority = PRTYC_TIMECRITICAL; + else if (m_nPriority <= 100) + ulOS2_Priority = PRTYC_FOREGROUNDSERVER; else { wxFAIL_MSG(wxT("invalid value of thread priority parameter")); - win_priority = THREAD_PRIORITY_NORMAL; + ulOS2_Priority = PRTYC_REGULAR; } - - if ( ::SetThreadPriority(m_hThread, win_priority) == 0 ) + ulrc = ::DosSetPriority( PRTYS_THREAD + ,ulOS2_Priority + ,0 + ,(ULONG)m_hThread + ); + if (ulrc != 0) { wxLogSysError(_("Can't set thread priority")); } -*/ - return FALSE; + return TRUE; } bool wxThreadInternal::Suspend() { -// TODO: -/* - DWORD nSuspendCount = ::SuspendThread(m_hThread); - if ( nSuspendCount == (DWORD)-1 ) - { - wxLogSysError(_("Can not suspend thread %x"), m_hThread); + ULONG ulrc = ::DosSuspendThread(m_hThread); + if (ulrc != 0) + { + wxLogSysError(_("Can not suspend thread %lu"), m_hThread); return FALSE; } - - m_state = STATE_PAUSED; -*/ - return FALSE; + m_eState = STATE_PAUSED; + return TRUE; } bool wxThreadInternal::Resume() { -// TODO: -/* - DWORD nSuspendCount = ::ResumeThread(m_hThread); - if ( nSuspendCount == (DWORD)-1 ) - { - wxLogSysError(_("Can not resume thread %x"), m_hThread); + ULONG ulrc = ::DosResumeThread(m_hThread); + if (ulrc != 0) + { + wxLogSysError(_("Can not suspend thread %lu"), m_hThread); return FALSE; } - - m_state = STATE_RUNNING; -*/ - return FALSE; + m_eState = STATE_PAUSED; + return TRUE; } // static functions @@ -432,24 +399,19 @@ bool wxThreadInternal::Resume() wxThread *wxThread::This() { - wxThread *thread = NULL; // TODO (wxThread *)::TlsGetValue(s_tlsThisThread); - -// TODO: -/* - // be careful, 0 may be a valid return value as well - if ( !thread && (::GetLastError() != NO_ERROR) ) - { - wxLogSysError(_("Couldn't get the current thread pointer")); - - // return NULL... - } -*/ - return thread; + wxThread* pThread = m_pThread; + return pThread; } bool wxThread::IsMain() { -// TODO: return ::GetCurrentThreadId() == s_idMainThread; + PTIB ptib; + PPIB ppib; + + ::DosGetInfoBlocks(&ptib, &ppib); + + if (ptib->tib_ptib2->tib2_ultid == s_ulIdMainThread) + return TRUE; return FALSE; } @@ -459,13 +421,14 @@ bool wxThread::IsMain() void wxThread::Yield() { - // 0 argument to Sleep() is special ::DosSleep(0); } -void wxThread::Sleep(unsigned long milliseconds) +void wxThread::Sleep( + unsigned long ulMilliseconds +) { - ::DosSleep(milliseconds); + ::DosSleep(ulMilliseconds); } // create/start thread @@ -481,14 +444,13 @@ wxThreadError wxThread::Create() wxThreadError wxThread::Run() { - wxCriticalSectionLocker lock(m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); if ( p_internal->GetState() != STATE_NEW ) { // actually, it may be almost any state at all, not only STATE_RUNNING return wxTHREAD_RUNNING; } - return Resume(); } @@ -497,14 +459,14 @@ wxThreadError wxThread::Run() wxThreadError wxThread::Pause() { - wxCriticalSectionLocker lock(m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); return p_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR; } wxThreadError wxThread::Resume() { - wxCriticalSectionLocker lock(m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); return p_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR; } @@ -514,25 +476,26 @@ wxThreadError wxThread::Resume() wxThread::ExitCode wxThread::Delete() { - ExitCode rc = 0; + ExitCode rc = 0; + ULONG ulrc; // Delete() is always safe to call, so consider all possible states - if ( IsPaused() ) + if (IsPaused()) Resume(); - if ( IsRunning() ) + if (IsRunning()) { - if ( IsMain() ) + if (IsMain()) { // set flag for wxIsWaitingForThread() - s_waitingForThread = TRUE; - + s_bWaitingForThread = TRUE; wxBeginBusyCursor(); } - HANDLE hThread; + TID hThread; + { - wxCriticalSectionLocker lock(m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); p_internal->Cancel(); hThread = p_internal->GetHandle(); @@ -541,144 +504,113 @@ wxThread::ExitCode wxThread::Delete() // we can't just wait for the thread to terminate because it might be // calling some GUI functions and so it will never terminate before we // process the Windows messages that result from these functions - DWORD result; -// TODO: -/* + do { - result = ::MsgWaitForMultipleObjects - ( - 1, // number of objects to wait for - &hThread, // the objects - FALSE, // don't wait for all objects - INFINITE, // no timeout - QS_ALLEVENTS // return as soon as there are any events - ); - - switch ( result ) + ulrc = ::DosWaitThread( &hThread + ,DCWW_NOWAIT + ); + switch (ulrc) { - case 0xFFFFFFFF: + case ERROR_INTERRUPT: + case ERROR_INVALID_THREADID: // error wxLogSysError(_("Can not wait for thread termination")); Kill(); return (ExitCode)-1; - case WAIT_OBJECT_0: + case 0: // thread we're waiting for terminated break; - case WAIT_OBJECT_0 + 1: + case ERROR_THREAD_NOT_TERMINATED: // new message arrived, process it - if ( !wxTheApp->DoMessage() ) + if (!wxTheApp->DoMessage()) { // WM_QUIT received: kill the thread Kill(); - return (ExitCode)-1; } - - if ( IsMain() ) + if (IsMain()) { // give the thread we're waiting for chance to exit // from the GUI call it might have been in - if ( (s_nWaitingForGui > 0) && wxGuiOwnedByMainThread() ) + if ((s_nWaitingForGui > 0) && wxGuiOwnedByMainThread()) { wxMutexGuiLeave(); } } - break; default: - wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject")); + wxFAIL_MSG(wxT("unexpected result of DosWatiThread")); } - } while ( result != WAIT_OBJECT_0 ); -*/ - if ( IsMain() ) - { - s_waitingForThread = FALSE; - - wxEndBusyCursor(); - } + } while (ulrc != 0); -// TODO: -/* - if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) ) + if (IsMain()) { - wxLogLastError("GetExitCodeThread"); - - rc = (ExitCode)-1; + s_bWaitingForThread = FALSE; + wxEndBusyCursor(); } - wxASSERT_MSG( (LPVOID)rc != (LPVOID)STILL_ACTIVE, - wxT("thread must be already terminated.") ); - - ::CloseHandle(hThread); -*/ + ::DosExit(EXIT_THREAD, ulrc); } - + rc = (ExitCode)ulrc; return rc; } wxThreadError wxThread::Kill() { - if ( !IsRunning() ) + if (!IsRunning()) return wxTHREAD_NOT_RUNNING; -// TODO: -/* - if ( !::TerminateThread(p_internal->GetHandle(), (DWORD)-1) ) - { - wxLogSysError(_("Couldn't terminate thread")); - - return wxTHREAD_MISC_ERROR; - } -*/ + ::DosKillThread(p_internal->GetHandle()); delete this; - return wxTHREAD_NO_ERROR; } -void wxThread::Exit(void *status) +void wxThread::Exit( + void* pStatus +) { delete this; - -// TODO: ::ExitThread((DWORD)status); - - wxFAIL_MSG(wxT("Couldn't return from ExitThread()!")); + ::DosExit(EXIT_THREAD, ULONG(pStatus)); + wxFAIL_MSG(wxT("Couldn't return from DosExit()!")); } -void wxThread::SetPriority(unsigned int prio) +void wxThread::SetPriority( + unsigned int nPrio +) { - wxCriticalSectionLocker lock(m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - p_internal->SetPriority(prio); + p_internal->SetPriority(nPrio); } unsigned int wxThread::GetPriority() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); return p_internal->GetPriority(); } unsigned long wxThread::GetID() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); return (unsigned long)p_internal->GetId(); } bool wxThread::IsRunning() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); return p_internal->GetState() == STATE_RUNNING; } bool wxThread::IsAlive() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); return (p_internal->GetState() == STATE_RUNNING) || (p_internal->GetState() == STATE_PAUSED); @@ -686,14 +618,14 @@ bool wxThread::IsAlive() const bool wxThread::IsPaused() const { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); return (p_internal->GetState() == STATE_PAUSED); } bool wxThread::TestDestroy() { - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); + wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); return p_internal->GetState() == STATE_CANCELED; } @@ -726,98 +658,44 @@ IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) bool wxThreadModule::OnInit() { - // allocate TLS index for storing the pointer to the current thread -// TODO: -/* - s_tlsThisThread = ::TlsAlloc(); - if ( s_tlsThisThread == 0xFFFFFFFF ) - { - // in normal circumstances it will only happen if all other - // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other - // words, this should never happen - wxLogSysError(_("Thread module initialization failed: " - "impossible to allocate index in thread " - "local storage")); + s_pCritsectWaitingForGui = new wxCriticalSection(); - return FALSE; - } -*/ - // main thread doesn't have associated wxThread object, so store 0 in the - // TLS instead + s_pCritsectGui = new wxCriticalSection(); + s_pCritsectGui->Enter(); -// TODO: -/* - if ( !::TlsSetValue(s_tlsThisThread, (LPVOID)0) ) - { - ::TlsFree(s_tlsThisThread); - s_tlsThisThread = 0xFFFFFFFF; + PTIB ptib; + PPIB ppib; - wxLogSysError(_("Thread module initialization failed: " - "can not store value in thread local storage")); - - return FALSE; - } -*/ - s_critsectWaitingForGui = new wxCriticalSection(); - - s_critsectGui = new wxCriticalSection(); - s_critsectGui->Enter(); - - // no error return for GetCurrentThreadId() -// s_idMainThread = ::GetCurrentThreadId(); + ::DosGetInfoBlocks(&ptib, &ppib); + s_ulIdMainThread = ptib->tib_ptib2->tib2_ultid; return TRUE; } void wxThreadModule::OnExit() { -// TODO: -/* - if ( !::TlsFree(s_tlsThisThread) ) - { - wxLogLastError("TlsFree failed."); - } -*/ - if ( s_critsectGui ) + if (s_pCritsectGui) { - s_critsectGui->Leave(); - delete s_critsectGui; - s_critsectGui = NULL; + s_pCritsectGui->Leave(); + delete s_pCritsectGui; + s_pCritsectGui = NULL; } - wxDELETE(s_critsectWaitingForGui); + wxDELETE(s_pCritsectWaitingForGui); } // ---------------------------------------------------------------------------- -// under Windows, these functions are implemented usign a critical section and -// not a mutex, so the names are a bit confusing +// Helper functions // ---------------------------------------------------------------------------- -void WXDLLEXPORT wxMutexGuiEnter() +// Does nothing under OS/2 [for now] +void WXDLLEXPORT wxWakeUpMainThread() { - // this would dead lock everything... - wxASSERT_MSG( !wxThread::IsMain(), - wxT("main thread doesn't want to block in wxMutexGuiEnter()!") ); - - // the order in which we enter the critical sections here is crucial!! - - // set the flag telling to the main thread that we want to do some GUI - { - wxCriticalSectionLocker enter(*s_critsectWaitingForGui); - - s_nWaitingForGui++; - } - - wxWakeUpMainThread(); - - // now we may block here because the main thread will soon let us in - // (during the next iteration of OnIdle()) - s_critsectGui->Enter(); } void WXDLLEXPORT wxMutexGuiLeave() { - wxCriticalSectionLocker enter(*s_critsectWaitingForGui); + wxCriticalSectionLocker enter(*s_pCritsectWaitingForGui); if ( wxThread::IsMain() ) { @@ -834,7 +712,7 @@ void WXDLLEXPORT wxMutexGuiLeave() wxWakeUpMainThread(); } - s_critsectGui->Leave(); + s_pCritsectGui->Leave(); } void WXDLLEXPORT wxMutexGuiLeaveOrEnter() @@ -842,15 +720,15 @@ void WXDLLEXPORT wxMutexGuiLeaveOrEnter() wxASSERT_MSG( wxThread::IsMain(), wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") ); - wxCriticalSectionLocker enter(*s_critsectWaitingForGui); + wxCriticalSectionLocker enter(*s_pCritsectWaitingForGui); if ( s_nWaitingForGui == 0 ) { // no threads are waiting for GUI - so we may acquire the lock without // any danger (but only if we don't already have it) - if ( !wxGuiOwnedByMainThread() ) + if (!wxGuiOwnedByMainThread()) { - s_critsectGui->Enter(); + s_pCritsectGui->Enter(); s_bGuiOwnedByMainThread = TRUE; } @@ -859,7 +737,7 @@ void WXDLLEXPORT wxMutexGuiLeaveOrEnter() else { // some threads are waiting, release the GUI lock if we have it - if ( wxGuiOwnedByMainThread() ) + if (wxGuiOwnedByMainThread()) { wxMutexGuiLeave(); } @@ -872,25 +750,5 @@ bool WXDLLEXPORT wxGuiOwnedByMainThread() return s_bGuiOwnedByMainThread; } -// wake up the main thread if it's in ::GetMessage() -void WXDLLEXPORT wxWakeUpMainThread() -{ - // sending any message would do - hopefully WM_NULL is harmless enough -// TODO: -/* - if ( !::PostThreadMessage(s_idMainThread, WM_NULL, 0, 0) ) - { - // should never happen - wxLogLastError("PostThreadMessage(WM_NULL)"); - } -*/ -} - -bool WXDLLEXPORT wxIsWaitingForThread() -{ - return s_waitingForThread; -} - - #endif // wxUSE_THREADS diff --git a/src/os2/utils.cpp b/src/os2/utils.cpp index 2e8d254f13..1b441d1cef 100644 --- a/src/os2/utils.cpp +++ b/src/os2/utils.cpp @@ -142,23 +142,57 @@ bool wxShell( const wxString& rCommand ) { - wxChar* zShell; - - if ((zShell = wxGetenv(_T("COMSPEC"))) == NULL) - zShell = _T("\\CMD.EXE"); - + wxChar* zShell = _T("CMD.EXE"); + wxString sInputs; wxChar zTmp[255]; + STARTDATA SData = {0}; + PSZ PgmTitle = "Command Shell"; + APIRET rc; + PID vPid = 0; + ULONG ulSessID = 0; + UCHAR achObjBuf[256] = {0}; //error data if DosStart fails + RESULTCODES vResult; + + SData.Length = sizeof(STARTDATA); + SData.Related = SSF_RELATED_INDEPENDENT; + SData.FgBg = SSF_FGBG_FORE; + SData.TraceOpt = SSF_TRACEOPT_NONE; + SData.PgmTitle = PgmTitle; + SData.PgmName = zShell; + +// sInputs = "/C " + rCommand; + SData.PgmInputs = NULL; //(BYTE*)sInputs.c_str(); + SData.TermQ = 0; + SData.Environment = 0; + SData.InheritOpt = SSF_INHERTOPT_SHELL; + SData.SessionType = SSF_TYPE_WINDOWABLEVIO; + SData.IconFile = 0; + SData.PgmHandle = 0; + SData.PgmControl = SSF_CONTROL_VISIBLE | SSF_CONTROL_MAXIMIZE; + SData.InitXPos = 30; + SData.InitYPos = 40; + SData.InitXSize = 200; + SData.InitYSize = 140; + SData.Reserved = 0; + SData.ObjectBuffer = (char*)achObjBuf; + SData.ObjectBuffLen = (ULONG)sizeof(achObjBuf); + + rc = ::DosStartSession(&SData, &ulSessID, &vPid); + if (rc == 0) + { + PTIB ptib; + PPIB ppib; - if (rCommand != "") - wxSprintf( zTmp - ,"%s /c %s" - ,zShell - ,WXSTRINGCAST rCommand - ); - else - wxStrcpy(zTmp, zShell); + ::DosGetInfoBlocks(&ptib, &ppib); - return (wxExecute((wxChar*)zTmp, FALSE) != 0); + ::DosWaitChild( DCWA_PROCESS + ,DCWW_WAIT + ,&vResult + ,&ppib->pib_ulpid + ,vPid + ); + } + return (rc != 0); } // Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX) diff --git a/src/os2/utilsexc.cpp b/src/os2/utilsexc.cpp index cc19f5cad2..03e82eb1d8 100644 --- a/src/os2/utilsexc.cpp +++ b/src/os2/utilsexc.cpp @@ -25,6 +25,11 @@ #include "wx/os2/private.h" +#define INCL_DOSPROCESS +#define INCL_DOSERRORS +#define INCL_DOS +#include + #include #include @@ -50,6 +55,7 @@ struct wxExecuteData public: ~wxExecuteData() { + cout << "Closing thread: " << endl; DosExit(EXIT_PROCESS, 0); } @@ -67,8 +73,10 @@ static ULONG wxExecuteThread( ULONG ulRc; PID vPidChild; - ulRc = ::DosWaitChild( DCWA_PROCESSTREE - ,DCWW_WAIT + cout << "Executing thread: " << endl; + + ulRc = ::DosWaitChild( DCWA_PROCESSTREE + ,DCWW_NOWAIT ,&pData->vResultCodes ,&vPidChild ,pData->vResultCodes.codeTerminate // process PID to look at @@ -78,14 +86,11 @@ static ULONG wxExecuteThread( wxLogLastError("DosWaitChild"); } delete pData; - - -// ::WinSendMsg(pData->hWnd, (ULONG)wxWM_PROC_TERMINATED, 0, (MPARAM)pData); return 0; } -// Unlike windows where everything needs a window, console apps in OS/2 -// need no windows so this is not ever used +// window procedure of a hidden window which is created just to receive +// the notification message when a process exits MRESULT APIENTRY wxExecuteWindowCbk( HWND hWnd , ULONG ulMessage @@ -128,7 +133,11 @@ long wxExecute( , wxProcess* pHandler ) { - wxCHECK_MSG(!!rCommand, 0, wxT("empty command in wxExecute")); + if (rCommand.IsEmpty()) + { + cout << "empty command in wxExecute." << endl; + return 0; + } // create the process UCHAR vLoadError[CCHMAXPATH] = {0}; @@ -146,39 +155,20 @@ long wxExecute( else ulExecFlag = EXEC_ASYNCRESULT; - if (::DosExecPgm( (PCHAR)vLoadError - ,sizeof(vLoadError) - ,ulExecFlag - ,zArgs - ,zEnvs - ,&vResultCodes - ,rCommand - )) + rc = ::DosExecPgm( (PCHAR)vLoadError + ,sizeof(vLoadError) + ,ulExecFlag + ,zArgs + ,zEnvs + ,&vResultCodes + ,(PSZ)rCommand.c_str() + ); + if (rc != NO_ERROR) { - wxLogSysError(_("Execution of command '%s' failed"), rCommand.c_str()); + wxLogSysError(_("Execution of command '%s' failed with error: %ul"), rCommand.c_str(), rc); return 0; } - - // PM does not need non visible object windows to run console child processes -/* - HWND hwnd = ::WinCreateWindow( HWND_DESKTOP - ,wxPanelClassName - ,NULL - ,0 - ,0 - ,0 - ,0 - ,0 - ,NULLHANDLE - ,NULLHANDLE - ,ulWindowId - ,NULL - ,NULL - ); - wxASSERT_MSG( hwnd, wxT("can't create a hidden window for wxExecute") ); - pOldProc = ::WinSubclassWindow(hwnd, (PFNWP)&wxExecuteWindowCbk); - -*/ + cout << "Executing: " << rCommand.c_str() << endl; // Alloc data wxExecuteData* pData = new wxExecuteData; @@ -205,8 +195,6 @@ long wxExecute( if (rc != NO_ERROR) { wxLogLastError("CreateThread in wxExecute"); - -// ::WinDestroyWindow(hwnd); delete pData; // the process still started up successfully... @@ -214,11 +202,15 @@ long wxExecute( } if (!bSync) { - // clean up will be done when the process terminates - // return the pid + // warning: don't exit your app unless you actively + // kill and cleanup you child processes + // Maybe detach the process here??? + // If cmd.exe need to pass DETACH to detach the process here return vResultCodes.codeTerminate; } + + // waiting until command executed ::DosWaitThread(&vTID, DCWW_WAIT); ULONG ulExitCode = pData->vResultCodes.codeResult; -- 2.45.2