1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 #include <tools/svwin.h> 32 33 #include <vcl/menu.hxx> 34 #include <vcl/sysdata.hxx> 35 36 #include <win/wincomp.hxx> 37 #include <win/saldata.hxx> 38 #include <win/salinst.h> 39 #include <win/salframe.h> 40 #include <win/salmenu.h> 41 42 #include <impbmp.hxx> 43 #include <salgdi.hxx> 44 45 // uncomment the following line to have ownerdrawn menues, ie, with bitmaps 46 // however, this is incompatible with OLE inplace editing 47 // so it is not activated by default 48 //#define OWNERDRAW 49 50 static DWORD myerr=0; 51 52 // ======================================================================= 53 54 sal_Bool SalData::IsKnownMenuHandle( HMENU hMenu ) 55 { 56 if( mhMenuSet.find( hMenu ) == mhMenuSet.end() ) 57 return FALSE; 58 else 59 return TRUE; 60 } 61 62 // ======================================================================= 63 64 // WinSalInst factory methods 65 66 SalMenu* WinSalInstance::CreateMenu( sal_Bool bMenuBar, Menu* ) 67 { 68 WinSalMenu *pSalMenu = new WinSalMenu(); 69 70 pSalMenu->mbMenuBar = bMenuBar; 71 pSalMenu->mhWnd = NULL; 72 if( bMenuBar ) 73 pSalMenu->mhMenu = ::CreateMenu(); 74 else 75 pSalMenu->mhMenu = ::CreatePopupMenu(); 76 77 if( pSalMenu->mhMenu ) 78 GetSalData()->mhMenuSet.insert( pSalMenu->mhMenu ); 79 80 return pSalMenu; 81 } 82 83 void WinSalInstance::DestroyMenu( SalMenu* pSalMenu ) 84 { 85 delete pSalMenu; 86 } 87 88 89 SalMenuItem* WinSalInstance::CreateMenuItem( const SalItemParams* pItemData ) 90 { 91 if( !pItemData ) 92 return NULL; 93 94 WinSalMenuItem *pSalMenuItem = new WinSalMenuItem(); 95 memset( &pSalMenuItem->mInfo, 0, sizeof( MENUITEMINFOW ) ); 96 pSalMenuItem->mInfo.cbSize = sizeof( MENUITEMINFOW ); 97 98 if( pItemData->eType == MENUITEM_SEPARATOR ) 99 { 100 // separator 101 pSalMenuItem->mInfo.fMask = MIIM_TYPE; 102 pSalMenuItem->mInfo.fType = MFT_SEPARATOR; 103 } 104 else 105 { 106 // item 107 pSalMenuItem->mText = pItemData->aText; 108 pSalMenuItem->mpMenu = pItemData->pMenu; 109 pSalMenuItem->maBitmap= !!pItemData->aImage ? pItemData->aImage.GetBitmapEx().GetBitmap() : Bitmap(); 110 pSalMenuItem->mnId = pItemData->nId; 111 112 // 'translate' mnemonics 113 pSalMenuItem->mText.SearchAndReplace( '~', '&' ); 114 115 pSalMenuItem->mInfo.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA; 116 pSalMenuItem->mInfo.fType = MFT_STRING; 117 #ifdef OWNERDRAW 118 if( pItemData->pMenu && !pItemData->pMenu->IsMenuBar() ) 119 pSalMenuItem->mInfo.fType |= MFT_OWNERDRAW; 120 pSalMenuItem->mInfo.fState = MFS_ENABLED; 121 #endif 122 pSalMenuItem->mInfo.dwTypeData = (LPWSTR) pSalMenuItem->mText.GetBuffer(); 123 pSalMenuItem->mInfo.cch = pSalMenuItem->mText.Len(); 124 125 pSalMenuItem->mInfo.wID = pItemData->nId; 126 pSalMenuItem->mInfo.dwItemData = (ULONG_PTR) pSalMenuItem; // user data 127 } 128 129 return pSalMenuItem; 130 } 131 132 void WinSalInstance::DestroyMenuItem( SalMenuItem* pSalMenuItem ) 133 { 134 delete pSalMenuItem; 135 } 136 137 138 // ======================================================================= 139 140 static void ImplDrawMenuBar( SalMenu *pMenu ) 141 { 142 if( pMenu->VisibleMenuBar() ) 143 { 144 // redrawing the menubar all the time actually seems to be unnecessary (it just flickers) 145 /* 146 WinSalMenu *pMenuBar = ImplFindMenuBar( pMenu ); 147 if( pMenuBar && pMenuBar->mhWnd ) 148 ::DrawMenuBar( pMenuBar->mhWnd ); 149 */ 150 } 151 } 152 153 // ======================================================================= 154 155 156 /* 157 * WinSalMenu 158 */ 159 160 WinSalMenu::WinSalMenu() 161 { 162 mhMenu = NULL; 163 mbMenuBar = FALSE; 164 mhWnd = NULL; 165 mpParentMenu = NULL; 166 } 167 168 WinSalMenu::~WinSalMenu() 169 { 170 // only required if not associated to a window... 171 GetSalData()->mhMenuSet.erase( mhMenu ); 172 ::DestroyMenu( mhMenu ); 173 } 174 175 sal_Bool WinSalMenu::VisibleMenuBar() 176 { 177 // The Win32 implementation never shows a native 178 // menubar. Thus, native menues are only visible 179 // when the menu is merged with an OLE container. 180 // The reason are missing tooltips, ownerdraw 181 // issues and accessibility which are better supported 182 // by VCL menues. 183 // Nevertheless, the native menues are always created 184 // and the application will properly react to all native 185 // menu messages. 186 187 return FALSE; 188 } 189 190 void WinSalMenu::SetFrame( const SalFrame *pFrame ) 191 { 192 if( pFrame ) 193 mhWnd = static_cast<const WinSalFrame*>(pFrame)->mhWnd; 194 else 195 mhWnd = NULL; 196 } 197 198 void WinSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos ) 199 { 200 if( pSalMenuItem ) 201 { 202 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem); 203 if( nPos == MENU_APPEND ) 204 { 205 nPos = ::GetMenuItemCount( mhMenu ); 206 if( nPos == -1 ) 207 return; 208 } 209 210 if(!::InsertMenuItemW( mhMenu, nPos, TRUE, &pWItem->mInfo )) 211 myerr = GetLastError(); 212 else 213 { 214 pWItem->mpSalMenu = this; 215 ImplDrawMenuBar( this ); 216 } 217 } 218 } 219 220 void WinSalMenu::RemoveItem( unsigned nPos ) 221 { 222 int num = ::GetMenuItemCount( mhMenu ); 223 if( num != -1 && nPos < (unsigned)num ) 224 { 225 WinSalMenuItem *pSalMenuItem = NULL; 226 227 MENUITEMINFOW mi; 228 memset( &mi, 0, sizeof(mi) ); 229 mi.cbSize = sizeof( mi ); 230 mi.fMask = MIIM_DATA; 231 if( !GetMenuItemInfoW( mhMenu, nPos, TRUE, &mi) ) 232 myerr = GetLastError(); 233 else 234 pSalMenuItem = (WinSalMenuItem *) mi.dwItemData; 235 236 if( !::RemoveMenu( mhMenu, nPos, MF_BYPOSITION ) ) 237 myerr = GetLastError(); 238 else 239 { 240 if( pSalMenuItem ) 241 pSalMenuItem->mpSalMenu = NULL; 242 ImplDrawMenuBar( this ); 243 } 244 } 245 } 246 247 void ImplRemoveItemById( WinSalMenu *pSalMenu, unsigned nItemId ) 248 { 249 if( !pSalMenu ) 250 return; 251 252 WinSalMenuItem *pSalMenuItem = NULL; 253 254 MENUITEMINFOW mi; 255 memset( &mi, 0, sizeof(mi) ); 256 mi.cbSize = sizeof( mi ); 257 mi.fMask = MIIM_DATA; 258 if( !GetMenuItemInfoW( pSalMenu->mhMenu, nItemId, FALSE, &mi) ) 259 myerr = GetLastError(); 260 else 261 pSalMenuItem = (WinSalMenuItem *) mi.dwItemData; 262 263 if( !::RemoveMenu( pSalMenu->mhMenu, nItemId, MF_BYCOMMAND ) ) 264 myerr = GetLastError(); 265 else 266 { 267 if( pSalMenuItem ) 268 pSalMenuItem->mpSalMenu = NULL; 269 ImplDrawMenuBar( pSalMenu ); 270 } 271 } 272 273 void WinSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos ) 274 { 275 if( pSalMenuItem ) 276 { 277 WinSalMenuItem* pWMenuItem = static_cast<WinSalMenuItem*>(pSalMenuItem); 278 WinSalMenu* pWSubMenu = static_cast<WinSalMenu*>(pSubMenu); 279 if( pWMenuItem->mInfo.hSubMenu ) 280 { 281 GetSalData()->mhMenuSet.erase( pWMenuItem->mInfo.hSubMenu ); 282 ::DestroyMenu( pWMenuItem->mInfo.hSubMenu ); 283 } 284 285 pWMenuItem->mInfo.fMask |= MIIM_SUBMENU; 286 if( !pSubMenu ) 287 pWMenuItem->mInfo.hSubMenu = NULL; 288 else 289 { 290 pWMenuItem->mInfo.hSubMenu = pWSubMenu->mhMenu; 291 pWSubMenu->mpParentMenu = this; 292 } 293 294 if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWMenuItem->mInfo ) ) 295 myerr = GetLastError(); 296 else 297 ImplDrawMenuBar( this ); 298 } 299 } 300 301 void WinSalMenu::CheckItem( unsigned nPos, sal_Bool bCheck ) 302 { 303 if( -1 != ::CheckMenuItem( mhMenu, nPos, MF_BYPOSITION|(bCheck ? MF_CHECKED : MF_UNCHECKED) ) ) 304 ImplDrawMenuBar( this ); 305 } 306 307 void WinSalMenu::EnableItem( unsigned nPos, sal_Bool bEnable ) 308 { 309 if( -1 != ::EnableMenuItem( mhMenu, nPos, MF_BYPOSITION|(bEnable ? MF_ENABLED : (MF_DISABLED|MF_GRAYED) ) ) ) 310 ImplDrawMenuBar( this ); 311 } 312 313 void WinSalMenu::SetItemImage( unsigned /*nPos*/, SalMenuItem* pSalMenuItem, const Image& rImage ) 314 { 315 if( pSalMenuItem ) 316 { 317 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem); 318 if( !!rImage ) 319 pWItem->maBitmap = rImage.GetBitmapEx().GetBitmap(); 320 else 321 pWItem->maBitmap = Bitmap(); 322 } 323 } 324 325 void WinSalMenu::SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const XubString& rText ) 326 { 327 if( pSalMenuItem ) 328 { 329 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem); 330 pWItem->mText = rText; 331 // 'translate' mnemonics 332 pWItem->mText.SearchAndReplace( '~', '&' ); 333 pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA; 334 pWItem->mInfo.fType = MFT_STRING; 335 #ifdef OWNERDRAW 336 if( pWItem->mpMenu && !((Menu*) pWItem->mpMenu)->IsMenuBar() ) 337 pWItem->mInfo.fType |= MFT_OWNERDRAW; 338 #endif 339 340 // combine text and accelerator text 341 XubString aStr( pWItem->mText ); 342 if( pWItem->mAccelText.Len() ) 343 { 344 aStr.AppendAscii("\t"); 345 aStr.Append( pWItem->mAccelText ); 346 } 347 pWItem->mInfo.dwTypeData = (LPWSTR) aStr.GetBuffer(); 348 pWItem->mInfo.cch = aStr.Len(); 349 350 if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo )) 351 myerr = GetLastError(); 352 else 353 ImplDrawMenuBar( this ); 354 } 355 } 356 357 void WinSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode&, const XubString& rKeyName ) 358 { 359 if( pSalMenuItem ) 360 { 361 WinSalMenuItem* pWItem = static_cast<WinSalMenuItem*>(pSalMenuItem); 362 pWItem->mAccelText = rKeyName; 363 pWItem->mInfo.fMask = MIIM_TYPE | MIIM_DATA; 364 pWItem->mInfo.fType = MFT_STRING; 365 #ifdef OWNERDRAW 366 if( pWItem->mpMenu && !((Menu*)pWItem->mpMenu)->IsMenuBar() ) 367 pWItem->mInfo.fType |= MFT_OWNERDRAW; 368 #endif 369 // combine text and accelerator text 370 XubString aStr( pWItem->mText ); 371 if( pWItem->mAccelText.Len() ) 372 { 373 aStr.AppendAscii("\t"); 374 aStr.Append( pWItem->mAccelText ); 375 } 376 pWItem->mInfo.dwTypeData = (LPWSTR) aStr.GetBuffer(); 377 pWItem->mInfo.cch = aStr.Len(); 378 379 if(!::SetMenuItemInfoW( mhMenu, nPos, TRUE, &pWItem->mInfo )) 380 myerr = GetLastError(); 381 else 382 ImplDrawMenuBar( this ); 383 } 384 } 385 386 void WinSalMenu::GetSystemMenuData( SystemMenuData* pData ) 387 { 388 if( pData ) 389 pData->hMenu = mhMenu; 390 } 391 392 // ======================================================================= 393 394 /* 395 * SalMenuItem 396 */ 397 398 399 WinSalMenuItem::WinSalMenuItem() 400 { 401 memset( &mInfo, 0, sizeof( MENUITEMINFOW ) ); 402 mpMenu = NULL; 403 mnId = 0xFFFF; 404 mpSalMenu = NULL; 405 } 406 407 WinSalMenuItem::~WinSalMenuItem() 408 { 409 if( mpSalMenu ) 410 ImplRemoveItemById( mpSalMenu, mnId ); 411 } 412 413 // ------------------------------------------------------------------- 414 415