c++winapiwxwidgets

How to work with system menu of a window in wxWidgets?


I have implemented a custom titlebar for my window and I want to display the default system (context) menu when right-clicking on it. My current approach is as follows:

auto sysMenu = ctrl_->MSWGetSystemMenu();
if( sysMenu )
{
  //sysMenu->Bind( wxEVT_MENU, &WxWindow::onSystemMenu, this );
  ctrl_->PopupMenu( sysMenu, pos );
}

system menu

It successfully displays the system menu, but clicking on any item doesn't seem to have any effect. I initially thought it would send a relevant message, such as SC_CLOSE, to the window's message handler, but it's not happening. My second assumption was that I might need to create my own handler and handle the message there. So, I created a handler function named onSystemMenu like below:

void onSystemMenu( wxCommandEvent& e )
{
  int id = e.GetId();

  switch( id )
  {
    case wxID_MAXIMIZE_FRAME: // Maximize the window
      ctrl_->Maximize();
      break;

    case wxID_RESTORE_FRAME: // Restore the window to its previous size and position
      ctrl_->Restore();
      break;

    case wxID_ICONIZE_FRAME: // Minimize the window
      ctrl_->Iconize();
      break;

    case wxID_CLOSE_FRAME: // Close the window
      ctrl_->Close();
      break;

  }
}

However, the received ID is always different from those expected values. For instance, I'm receiving values like -4048, which doesn't correspond to any of the IDs I listed. I still believe there should be a way to achieve this without manually creating a handler. Can someone please provide assistance?


Solution

  • It seems the following code works:

        auto pos = wxGetMousePosition();
        auto hwnd = ctrl_->GetHandle();
        auto menu = GetSystemMenu( hwnd, FALSE );
        if( menu )
        {
          MENUITEMINFO mInfo;
          mInfo.cbSize = sizeof( MENUITEMINFO );
          mInfo.fMask = MIIM_STATE;
          mInfo.fType = 0;
    
          // update the options
          mInfo.fState = MF_ENABLED;
          SetMenuItemInfo( menu, SC_RESTORE, FALSE, &mInfo );
          SetMenuItemInfo( menu, SC_SIZE, FALSE, &mInfo );
          SetMenuItemInfo( menu, SC_MOVE, FALSE, &mInfo );
          SetMenuItemInfo( menu, SC_MAXIMIZE, FALSE, &mInfo );
          SetMenuItemInfo( menu, SC_MINIMIZE, FALSE, &mInfo );
    
          mInfo.fState = MF_GRAYED;
    
          WINDOWPLACEMENT wp;
          GetWindowPlacement( hwnd, &wp );
    
          switch( wp.showCmd )
          {
            case SW_SHOWMAXIMIZED:
              SetMenuItemInfo( menu, SC_SIZE, FALSE, &mInfo );
              SetMenuItemInfo( menu, SC_MOVE, FALSE, &mInfo );
              SetMenuItemInfo( menu, SC_MAXIMIZE, FALSE, &mInfo );
              SetMenuDefaultItem( menu, SC_CLOSE, FALSE );
              break;
            case SW_SHOWMINIMIZED:
              SetMenuItemInfo( menu, SC_MINIMIZE, FALSE, &mInfo );
              SetMenuDefaultItem( menu, SC_RESTORE, FALSE );
              break;
            case SW_SHOWNORMAL:
              SetMenuItemInfo( menu, SC_RESTORE, FALSE, &mInfo );
              SetMenuDefaultItem( menu, SC_CLOSE, FALSE );
              break;
          }
    
          auto Selected = TrackPopupMenu(
            menu, TPM_RIGHTBUTTON | TPM_RETURNCMD, pos.x, pos.y, 0, hwnd, NULL );
          if( Selected )
            SendMessage( hwnd, WM_SYSCOMMAND, Selected, 0 );
        }
    

    Maybe a bug in PopupMenu of wxWidgets?!