1 /*
2 * This file is part of the LibreOffice project.
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 *
8 * This file incorporates work covered by the following license notice:
9 *
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
17 */
18
19 #include <sal/macros.h>
20 #include <sal/log.hxx>
21
22 #include <unotools/moduleoptions.hxx>
23 #include <unotools/dynamicmenuoptions.hxx>
24
25 #undef WB_LEFT
26 #undef WB_RIGHT
27
28 #include "shutdownicon.hxx"
29 #include <sfx2/sfxresid.hxx>
30 #include <sfx2/strings.hrc>
31 #include <shlobj.h>
32 #include <objidl.h>
33 #include <osl/thread.h>
34 #include <systools/win32/qswin32.h>
35 #include <comphelper/sequenceashashmap.hxx>
36 #include <o3tl/char16_t2wchar_t.hxx>
37
38 #include <set>
39
40 using namespace ::osl;
41
42 using ::com::sun::star::uno::Sequence;
43 using ::com::sun::star::beans::PropertyValue;
44
45
46 #define EXECUTER_WINDOWCLASS L"SO Executer Class"
47 #define EXECUTER_WINDOWNAME L"SO Executer Window"
48
49
50 #define ID_QUICKSTART 1
51 #define IDM_EXIT 2
52 #define IDM_OPEN 3
53 #define IDM_WRITER 4
54 #define IDM_CALC 5
55 #define IDM_IMPRESS 6
56 #define IDM_DRAW 7
57 #define IDM_BASE 8
58 #define IDM_TEMPLATE 9
59 #define IDM_MATH 12
60 #define IDM_INSTALL 10
61 #define IDM_STARTCENTER 14
62
63
64 #define ICON_LO_DEFAULT 1
65 #define ICON_TEXT_DOCUMENT 2
66 #define ICON_SPREADSHEET_DOCUMENT 4
67 #define ICON_DRAWING_DOCUMENT 6
68 #define ICON_PRESENTATION_DOCUMENT 8
69 #define ICON_TEMPLATE 11
70 #define ICON_DATABASE_DOCUMENT 12
71 #define ICON_MATH_DOCUMENT 13
72 #define ICON_OPEN 5 // See index of open folder icon in shell32.dll
73
74 #define SFX_TASKBAR_NOTIFICATION WM_USER+1
75
76 static HWND aListenerWindow = nullptr;
77 static HWND aExecuterWindow = nullptr;
78 static HMENU popupMenu = nullptr;
79
80 static void OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmis);
81 static void OnDrawItem(HWND hwnd, LPDRAWITEMSTRUCT lpdis);
82
83 typedef struct tagMYITEM
84 {
85 OUString text;
86 OUString module;
87 UINT iconId;
88 } MYITEM;
89
90
addMenuItem(HMENU hMenu,UINT id,UINT iconId,const OUString & text,int & pos,bool bOwnerdraw,const OUString & module)91 static void addMenuItem( HMENU hMenu, UINT id, UINT iconId, const OUString& text, int& pos, bool bOwnerdraw, const OUString& module )
92 {
93 MENUITEMINFOW mi = {};
94
95 mi.cbSize = sizeof( mi );
96 if( id == static_cast<UINT>( -1 ) )
97 {
98 mi.fMask=MIIM_TYPE;
99 mi.fType=MFT_SEPARATOR;
100 }
101 else
102 {
103 if( bOwnerdraw )
104 {
105 mi.fMask=MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
106 mi.fType=MFT_OWNERDRAW;
107 mi.fState=MFS_ENABLED;
108 mi.wID = id;
109
110 MYITEM *pMyItem = new MYITEM;
111 pMyItem->text = text;
112 pMyItem->iconId = iconId;
113 pMyItem->module = module;
114 mi.dwItemData = reinterpret_cast<DWORD_PTR>(pMyItem);
115 }
116 else
117 {
118 mi.fMask=MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
119 mi.fType=MFT_STRING;
120 mi.fState=MFS_ENABLED;
121 mi.wID = id;
122 mi.dwTypeData = o3tl::toW(
123 const_cast<sal_Unicode *>(text.getStr()));
124 mi.cch = text.getLength();
125 }
126
127 if ( IDM_TEMPLATE == id )
128 mi.fState |= MFS_DEFAULT;
129 }
130
131 InsertMenuItemW( hMenu, pos++, TRUE, &mi );
132 }
133
134
createSystrayMenu()135 static HMENU createSystrayMenu( )
136 {
137 SvtModuleOptions aModuleOptions;
138
139 HMENU hMenu = CreatePopupMenu();
140 int pos=0;
141
142 ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
143 OSL_ENSURE( pShutdownIcon, "ShutdownIcon instance empty!");
144
145 if( !pShutdownIcon )
146 return nullptr;
147
148 // collect the URLs of the entries in the File/New menu
149 ::std::set< OUString > aFileNewAppsAvailable;
150 SvtDynamicMenuOptions aOpt;
151 Sequence < Sequence < PropertyValue > > const aNewMenu = aOpt.GetMenu( EDynamicMenuType::NewMenu );
152 const OUString sURLKey( "URL" );
153
154 for ( auto const & newMenuProp : aNewMenu )
155 {
156 ::comphelper::SequenceAsHashMap aEntryItems( newMenuProp );
157 OUString sURL( aEntryItems.getUnpackedValueOrDefault( sURLKey, OUString() ) );
158 if ( sURL.getLength() )
159 aFileNewAppsAvailable.insert( sURL );
160 }
161
162 // describe the menu entries for launching the applications
163 struct MenuEntryDescriptor
164 {
165 SvtModuleOptions::EModule eModuleIdentifier;
166 UINT nMenuItemID;
167 UINT nMenuIconID;
168 const char* pAsciiURLDescription;
169 } aMenuItems[] =
170 {
171 { SvtModuleOptions::EModule::WRITER, IDM_WRITER, ICON_TEXT_DOCUMENT, WRITER_URL },
172 { SvtModuleOptions::EModule::CALC, IDM_CALC, ICON_SPREADSHEET_DOCUMENT, CALC_URL },
173 { SvtModuleOptions::EModule::IMPRESS, IDM_IMPRESS,ICON_PRESENTATION_DOCUMENT, IMPRESS_WIZARD_URL },
174 { SvtModuleOptions::EModule::DRAW, IDM_DRAW, ICON_DRAWING_DOCUMENT, DRAW_URL },
175 { SvtModuleOptions::EModule::DATABASE, IDM_BASE, ICON_DATABASE_DOCUMENT, BASE_URL },
176 { SvtModuleOptions::EModule::MATH, IDM_MATH, ICON_MATH_DOCUMENT, MATH_URL },
177 };
178
179 // insert the menu entries for launching the applications
180 for ( size_t i = 0; i < SAL_N_ELEMENTS(aMenuItems); ++i )
181 {
182 if ( !aModuleOptions.IsModuleInstalled( aMenuItems[i].eModuleIdentifier ) )
183 // the complete application is not even installed
184 continue;
185
186 OUString sURL( OUString::createFromAscii( aMenuItems[i].pAsciiURLDescription ) );
187
188 if ( aFileNewAppsAvailable.find( sURL ) == aFileNewAppsAvailable.end() )
189 // the application is installed, but the entry has been configured to *not* appear in the File/New
190 // menu => also let not appear it in the quickstarter
191 continue;
192
193 addMenuItem( hMenu, aMenuItems[i].nMenuItemID, aMenuItems[i].nMenuIconID,
194 ShutdownIcon::GetUrlDescription( sURL ), pos, true, "" );
195 }
196
197
198 // insert the remaining menu entries
199 addMenuItem( hMenu, IDM_TEMPLATE, ICON_TEMPLATE,
200 SfxResId( STR_QUICKSTART_FROMTEMPLATE ), pos, true, "");
201 addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, "" );
202 addMenuItem( hMenu, IDM_OPEN, ICON_OPEN, SfxResId(STR_QUICKSTART_FILEOPEN), pos, true, "SHELL32");
203 addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, "" );
204 addMenuItem( hMenu, IDM_INSTALL,0, SfxResId(STR_QUICKSTART_PRELAUNCH), pos, false, "" );
205 addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, "" );
206 addMenuItem( hMenu, IDM_EXIT, 0, SfxResId(STR_QUICKSTART_EXIT), pos, false, "" );
207
208 // indicate status of autostart folder
209 CheckMenuItem( hMenu, IDM_INSTALL, MF_BYCOMMAND | (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
210
211 return hMenu;
212 }
213
214
deleteSystrayMenu(HMENU hMenu)215 static void deleteSystrayMenu( HMENU hMenu )
216 {
217 if( !hMenu || !IsMenu( hMenu ))
218 return;
219
220 MENUITEMINFOW mi = {};
221 int pos=0;
222 mi.cbSize = sizeof( mi );
223 mi.fMask = MIIM_DATA;
224
225 while( GetMenuItemInfoW( hMenu, pos++, true, &mi ) )
226 {
227 MYITEM *pMyItem = reinterpret_cast<MYITEM*>(mi.dwItemData);
228 if( pMyItem )
229 {
230 pMyItem->text.clear();
231 delete pMyItem;
232 }
233 mi.fMask = MIIM_DATA;
234 }
235 }
236
237
addTaskbarIcon(HWND hWnd)238 static void addTaskbarIcon( HWND hWnd )
239 {
240 OUString strTip = SfxResId(STR_QUICKSTART_TIP);
241
242 // add taskbar icon
243 NOTIFYICONDATAW nid;
244 nid.hIcon = static_cast<HICON>(LoadImageW( GetModuleHandleW( nullptr ), MAKEINTRESOURCEW( ICON_LO_DEFAULT ),
245 IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ),
246 LR_DEFAULTCOLOR | LR_SHARED ));
247
248 wcsncpy( nid.szTip, o3tl::toW(strTip.getStr()), 64 );
249
250 nid.cbSize = sizeof(nid);
251 nid.hWnd = hWnd;
252 nid.uID = ID_QUICKSTART;
253 nid.uCallbackMessage = SFX_TASKBAR_NOTIFICATION;
254 nid.uFlags = NIF_MESSAGE|NIF_TIP|NIF_ICON;
255
256 Shell_NotifyIconW(NIM_ADD, &nid);
257 }
258
259
listenerWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)260 static LRESULT CALLBACK listenerWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
261 {
262 static UINT s_uTaskbarRestart = 0;
263 static UINT s_uMsgKillTray = 0;
264
265 switch (uMsg)
266 {
267 case WM_NCCREATE:
268 return TRUE;
269 case WM_CREATE:
270 {
271 // request notification when taskbar is recreated
272 // we then have to add our icon again
273 s_uTaskbarRestart = RegisterWindowMessageW(L"TaskbarCreated");
274 s_uMsgKillTray = RegisterWindowMessageW( SHUTDOWN_QUICKSTART_MESSAGE );
275
276 // create the menu
277 if( !popupMenu )
278 if( (popupMenu = createSystrayMenu( )) == nullptr )
279 return -1;
280
281 // and the icon
282 addTaskbarIcon( hWnd );
283
284 // disable shutdown
285 ShutdownIcon::getInstance()->SetVeto( true );
286 ShutdownIcon::addTerminateListener();
287 }
288 return 0;
289
290 case WM_MEASUREITEM:
291 OnMeasureItem(hWnd, reinterpret_cast<LPMEASUREITEMSTRUCT>(lParam));
292 return TRUE;
293
294 case WM_DRAWITEM:
295 OnDrawItem(hWnd, reinterpret_cast<LPDRAWITEMSTRUCT>(lParam));
296 return TRUE;
297
298 case SFX_TASKBAR_NOTIFICATION:
299 switch( lParam )
300 {
301 case WM_LBUTTONDOWN:
302 {
303 BOOL const ret = PostMessageW(aExecuterWindow, WM_COMMAND, IDM_STARTCENTER, reinterpret_cast<LPARAM>(hWnd));
304 SAL_WARN_IF(0 == ret, "sfx.appl", "ERROR: PostMessage() failed!");
305 break;
306 }
307
308 case WM_RBUTTONDOWN:
309 {
310 POINT pt;
311 GetCursorPos(&pt);
312 SetForegroundWindow( hWnd );
313
314 // update status before showing menu, could have been changed from option page
315 CheckMenuItem( popupMenu, IDM_INSTALL, MF_BYCOMMAND| (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
316
317 EnableMenuItem( popupMenu, IDM_EXIT, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
318 EnableMenuItem( popupMenu, IDM_OPEN, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
319 EnableMenuItem( popupMenu, IDM_TEMPLATE, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
320 int m = TrackPopupMenuEx( popupMenu, TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON,
321 pt.x, pt.y, hWnd, nullptr );
322 BOOL const ret = PostMessageW( hWnd, 0, 0, 0 );
323 SAL_WARN_IF(0 == ret, "sfx.appl", "ERROR: PostMessage() failed!");
324 switch( m )
325 {
326 case IDM_OPEN:
327 case IDM_WRITER:
328 case IDM_CALC:
329 case IDM_IMPRESS:
330 case IDM_DRAW:
331 case IDM_TEMPLATE:
332 case IDM_BASE:
333 case IDM_MATH:
334 break;
335 case IDM_INSTALL:
336 CheckMenuItem( popupMenu, IDM_INSTALL, MF_BYCOMMAND| (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
337 break;
338 case IDM_EXIT:
339 // delete taskbar icon
340 NOTIFYICONDATAW nid;
341 nid.cbSize=sizeof(nid);
342 nid.hWnd = hWnd;
343 nid.uID = ID_QUICKSTART;
344 Shell_NotifyIconW(NIM_DELETE, &nid);
345 break;
346 }
347
348 BOOL const ret2 = PostMessageW(aExecuterWindow, WM_COMMAND, m, reinterpret_cast<LPARAM>(hWnd));
349 SAL_WARN_IF(0 == ret2, "sfx.appl", "ERROR: PostMessage() failed!");
350 }
351 break;
352 }
353 break;
354 case WM_DESTROY:
355 deleteSystrayMenu( popupMenu );
356 // We don't need the Systray Thread anymore
357 PostQuitMessage( 0 );
358 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
359 default:
360 if( uMsg == s_uTaskbarRestart )
361 {
362 // re-create taskbar icon
363 addTaskbarIcon( hWnd );
364 }
365 else if ( uMsg == s_uMsgKillTray )
366 {
367 // delete taskbar icon
368 NOTIFYICONDATAW nid;
369 nid.cbSize=sizeof(nid);
370 nid.hWnd = hWnd;
371 nid.uID = ID_QUICKSTART;
372 Shell_NotifyIconW(NIM_DELETE, &nid);
373
374 BOOL const ret = PostMessageW(aExecuterWindow, WM_COMMAND, IDM_EXIT, reinterpret_cast<LPARAM>(hWnd));
375 SAL_WARN_IF(0 == ret, "sfx.appl", "ERROR: PostMessage() failed!");
376 }
377 else
378 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
379 }
380 return 0;
381 }
382
383
executerWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)384 static LRESULT CALLBACK executerWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
385 {
386 switch (uMsg)
387 {
388 case WM_NCCREATE:
389 return TRUE;
390 case WM_CREATE:
391 return 0;
392
393 case WM_COMMAND:
394 switch( LOWORD(wParam) )
395 {
396 case IDM_OPEN:
397 if ( !ShutdownIcon::bModalMode )
398 ShutdownIcon::FileOpen();
399 break;
400 case IDM_WRITER:
401 ShutdownIcon::OpenURL( WRITER_URL, "_default" );
402 break;
403 case IDM_CALC:
404 ShutdownIcon::OpenURL( CALC_URL, "_default" );
405 break;
406 case IDM_IMPRESS:
407 ShutdownIcon::OpenURL( IMPRESS_WIZARD_URL, "_default" );
408 break;
409 case IDM_DRAW:
410 ShutdownIcon::OpenURL( DRAW_URL, "_default" );
411 break;
412 case IDM_BASE:
413 ShutdownIcon::OpenURL( BASE_URL, "_default" );
414 break;
415 case IDM_MATH:
416 ShutdownIcon::OpenURL( MATH_URL, "_default" );
417 break;
418 case IDM_STARTCENTER:
419 ShutdownIcon::OpenURL( STARTMODULE_URL, "_default" );
420 break;
421 case IDM_TEMPLATE:
422 if ( !ShutdownIcon::bModalMode )
423 ShutdownIcon::FromTemplate();
424 break;
425 case IDM_INSTALL:
426 ShutdownIcon::SetAutostart( !ShutdownIcon::GetAutostart() );
427 break;
428 case IDM_EXIT:
429 // remove listener and
430 // terminate office if running in background
431 if ( !ShutdownIcon::bModalMode )
432 ShutdownIcon::terminateDesktop();
433 break;
434 }
435 break;
436 case WM_DESTROY:
437 default:
438 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
439 }
440 return 0;
441 }
442
443
SystrayThread(LPVOID)444 static DWORD WINAPI SystrayThread( LPVOID /*lpParam*/ )
445 {
446 osl_setThreadName("SystrayThread");
447
448 aListenerWindow = CreateWindowExW(0,
449 QUICKSTART_CLASSNAME, // registered class name
450 QUICKSTART_WINDOWNAME, // window name
451 0, // window style
452 CW_USEDEFAULT, // horizontal position of window
453 CW_USEDEFAULT, // vertical position of window
454 CW_USEDEFAULT, // window width
455 CW_USEDEFAULT, // window height
456 nullptr, // handle to parent or owner window
457 nullptr, // menu handle or child identifier
458 GetModuleHandleW( nullptr ), // handle to application instance
459 nullptr // window-creation data
460 );
461
462 MSG msg;
463
464 while ( GetMessageW( &msg, nullptr, 0, 0 ) )
465 {
466 TranslateMessage( &msg );
467 DispatchMessageW( &msg );
468 }
469
470 return msg.wParam; // Exit code of WM_QUIT
471 }
472
473
win32_init_sys_tray()474 void win32_init_sys_tray()
475 {
476 if ( ShutdownIcon::IsQuickstarterInstalled() )
477 {
478 WNDCLASSEXW listenerClass;
479 listenerClass.cbSize = sizeof(listenerClass);
480 listenerClass.style = 0;
481 listenerClass.lpfnWndProc = listenerWndProc;
482 listenerClass.cbClsExtra = 0;
483 listenerClass.cbWndExtra = 0;
484 listenerClass.hInstance = GetModuleHandleW( nullptr );
485 listenerClass.hIcon = nullptr;
486 listenerClass.hCursor = nullptr;
487 listenerClass.hbrBackground = nullptr;
488 listenerClass.lpszMenuName = nullptr;
489 listenerClass.lpszClassName = QUICKSTART_CLASSNAME;
490 listenerClass.hIconSm = nullptr;
491
492 RegisterClassExW(&listenerClass);
493
494 WNDCLASSEXW executerClass;
495 executerClass.cbSize = sizeof(executerClass);
496 executerClass.style = 0;
497 executerClass.lpfnWndProc = executerWndProc;
498 executerClass.cbClsExtra = 0;
499 executerClass.cbWndExtra = 0;
500 executerClass.hInstance = GetModuleHandleW( nullptr );
501 executerClass.hIcon = nullptr;
502 executerClass.hCursor = nullptr;
503 executerClass.hbrBackground = nullptr;
504 executerClass.lpszMenuName = nullptr;
505 executerClass.lpszClassName = EXECUTER_WINDOWCLASS;
506 executerClass.hIconSm = nullptr;
507
508 RegisterClassExW( &executerClass );
509
510 aExecuterWindow = CreateWindowExW(0,
511 EXECUTER_WINDOWCLASS, // registered class name
512 EXECUTER_WINDOWNAME, // window name
513 0, // window style
514 CW_USEDEFAULT, // horizontal position of window
515 CW_USEDEFAULT, // vertical position of window
516 CW_USEDEFAULT, // window width
517 CW_USEDEFAULT, // window height
518 nullptr, // handle to parent or owner window
519 nullptr, // menu handle or child identifier
520 GetModuleHandleW( nullptr ), // handle to application instance
521 nullptr // window-creation data
522 );
523
524 DWORD dwThreadId;
525 CloseHandle(CreateThread(nullptr, 0, SystrayThread, nullptr, 0, &dwThreadId));
526 }
527 }
528
529
win32_shutdown_sys_tray()530 void win32_shutdown_sys_tray()
531 {
532 if ( ShutdownIcon::IsQuickstarterInstalled() )
533 {
534 if( IsWindow( aListenerWindow ) )
535 {
536 DestroyWindow( aListenerWindow );
537 aListenerWindow = nullptr;
538 DestroyWindow( aExecuterWindow );
539 aExecuterWindow = nullptr;
540 }
541 UnregisterClassW( QUICKSTART_CLASSNAME, GetModuleHandleW( nullptr ) );
542 UnregisterClassW( EXECUTER_WINDOWCLASS, GetModuleHandleW( nullptr ) );
543 }
544 }
545
546
OnMeasureItem(HWND hwnd,LPMEASUREITEMSTRUCT lpmis)547 void OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmis)
548 {
549 MYITEM *pMyItem = reinterpret_cast<MYITEM *>(lpmis->itemData);
550 HDC hdc = GetDC(hwnd);
551 SIZE size;
552
553 NONCLIENTMETRICSW ncm = {};
554 ncm.cbSize = sizeof(ncm);
555
556 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
557
558 // Assume every menu item can be default and printed bold
559 ncm.lfMenuFont.lfWeight = FW_BOLD;
560
561 HFONT hfntOld = static_cast<HFONT>(SelectObject(hdc, CreateFontIndirectW( &ncm.lfMenuFont )));
562
563 GetTextExtentPoint32W(hdc, o3tl::toW(pMyItem->text.getStr()),
564 pMyItem->text.getLength(), &size);
565
566 lpmis->itemWidth = size.cx + 4 + GetSystemMetrics( SM_CXSMICON );
567 lpmis->itemHeight = std::max<int>(size.cy, GetSystemMetrics( SM_CYSMICON ));
568 lpmis->itemHeight += 4;
569
570 DeleteObject( SelectObject(hdc, hfntOld) );
571 ReleaseDC(hwnd, hdc);
572 }
573
OnDrawItem(HWND,LPDRAWITEMSTRUCT lpdis)574 void OnDrawItem(HWND /*hwnd*/, LPDRAWITEMSTRUCT lpdis)
575 {
576 MYITEM *pMyItem = reinterpret_cast<MYITEM *>(lpdis->itemData);
577 COLORREF clrPrevText, clrPrevBkgnd;
578 HFONT hfntOld;
579 HBRUSH hbrOld;
580 int x, y;
581 BOOL fSelected = lpdis->itemState & ODS_SELECTED;
582 BOOL fDisabled = lpdis->itemState & (ODS_DISABLED | ODS_GRAYED);
583
584 // Set the appropriate foreground and background colors.
585
586 RECT aRect = lpdis->rcItem;
587
588 clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_MENU) );
589
590 if ( fDisabled )
591 clrPrevText = SetTextColor( lpdis->hDC, GetSysColor( COLOR_GRAYTEXT ) );
592 else
593 clrPrevText = SetTextColor( lpdis->hDC, GetSysColor( fSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT ) );
594
595 if ( fSelected )
596 clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT) );
597 else
598 clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_MENU) );
599
600 hbrOld = static_cast<HBRUSH>(SelectObject( lpdis->hDC, CreateSolidBrush( GetBkColor( lpdis->hDC ) ) ));
601
602 // Fill background
603 PatBlt(lpdis->hDC, aRect.left, aRect.top, aRect.right-aRect.left, aRect.bottom-aRect.top, PATCOPY);
604
605 int height = aRect.bottom-aRect.top;
606
607 x = aRect.left;
608 y = aRect.top;
609
610 int cx = GetSystemMetrics( SM_CXSMICON );
611 int cy = GetSystemMetrics( SM_CYSMICON );
612 HICON hIcon( nullptr );
613 HMODULE hModule( GetModuleHandleW( nullptr ) );
614
615 if ( pMyItem->module.getLength() > 0 )
616 {
617 LPCWSTR pModuleName = o3tl::toW( pMyItem->module.getStr() );
618 hModule = GetModuleHandleW( pModuleName );
619 if ( hModule == nullptr )
620 {
621 hModule = LoadLibraryW(pModuleName);
622 }
623 }
624
625 hIcon = static_cast<HICON>(LoadImageW( hModule, MAKEINTRESOURCEW( pMyItem->iconId ),
626 IMAGE_ICON, cx, cy,
627 LR_DEFAULTCOLOR | LR_SHARED ));
628
629
630 HBRUSH hbrIcon = CreateSolidBrush( GetSysColor( COLOR_GRAYTEXT ) );
631
632 DrawStateW( lpdis->hDC, hbrIcon, nullptr, reinterpret_cast<LPARAM>(hIcon), WPARAM(0), x, y+(height-cy)/2, 0, 0, DST_ICON | (fDisabled ? (fSelected ? DSS_MONO : DSS_DISABLED) : DSS_NORMAL) );
633
634 DeleteObject( hbrIcon );
635
636 x += cx + 4; // space for icon
637 aRect.left = x;
638
639 NONCLIENTMETRICSW ncm = {};
640 ncm.cbSize = sizeof(ncm);
641
642 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
643
644 // Print default menu entry with bold font
645 if ( lpdis->itemState & ODS_DEFAULT )
646 ncm.lfMenuFont.lfWeight = FW_BOLD;
647
648 hfntOld = static_cast<HFONT>(SelectObject(lpdis->hDC, CreateFontIndirectW( &ncm.lfMenuFont )));
649
650
651 SIZE size;
652 GetTextExtentPointW( lpdis->hDC, o3tl::toW(pMyItem->text.getStr()), pMyItem->text.getLength(), &size );
653
654 DrawStateW( lpdis->hDC, nullptr, nullptr, reinterpret_cast<LPARAM>(pMyItem->text.getStr()), WPARAM(0), aRect.left, aRect.top + (height - size.cy)/2, 0, 0, DST_TEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) );
655
656 // Restore the original font and colors.
657 DeleteObject( SelectObject( lpdis->hDC, hbrOld ) );
658 DeleteObject( SelectObject( lpdis->hDC, hfntOld) );
659 SetTextColor(lpdis->hDC, clrPrevText);
660 SetBkColor(lpdis->hDC, clrPrevBkgnd);
661 }
662
663
664 // code from setup2 project
665
666
SHFree_(void * pv)667 static void SHFree_( void *pv )
668 {
669 IMalloc *pMalloc;
670 if( NOERROR == SHGetMalloc(&pMalloc) )
671 {
672 pMalloc->Free( pv );
673 pMalloc->Release();
674 }
675 }
676
677 #define ALLOC(type, n) static_cast<type *>(HeapAlloc(GetProcessHeap(), 0, sizeof(type) * n ))
678 #define FREE(p) HeapFree(GetProcessHeap(), 0, p)
679
SHGetSpecialFolder(int nFolderID)680 static OUString SHGetSpecialFolder( int nFolderID )
681 {
682
683 LPITEMIDLIST pidl;
684 HRESULT hHdl = SHGetSpecialFolderLocation( nullptr, nFolderID, &pidl );
685 OUString aFolder;
686
687 if( hHdl == NOERROR )
688 {
689 WCHAR *lpFolderA;
690 lpFolderA = ALLOC( WCHAR, 16000 );
691
692 SHGetPathFromIDListW( pidl, lpFolderA );
693 aFolder = o3tl::toU( lpFolderA );
694
695 FREE( lpFolderA );
696 SHFree_( pidl );
697 }
698 return aFolder;
699 }
700
GetAutostartFolderNameW32()701 OUString ShutdownIcon::GetAutostartFolderNameW32()
702 {
703 return SHGetSpecialFolder(CSIDL_STARTUP);
704 }
705
SHCoCreateInstance(LPVOID lpszReserved,REFCLSID clsid,LPUNKNOWN pUnkUnknown,REFIID iid,LPVOID * ppv)706 static HRESULT WINAPI SHCoCreateInstance( LPVOID lpszReserved, REFCLSID clsid, LPUNKNOWN pUnkUnknown, REFIID iid, LPVOID *ppv )
707 {
708 HRESULT hResult = E_NOTIMPL;
709 HMODULE hModShell = GetModuleHandleW( L"SHELL32" );
710
711 if ( hModShell != nullptr )
712 {
713 typedef HRESULT (WINAPI *SHCoCreateInstance_PROC)( LPVOID lpszReserved, REFCLSID clsid, LPUNKNOWN pUnkUnknwon, REFIID iid, LPVOID *ppv );
714
715 SHCoCreateInstance_PROC lpfnSHCoCreateInstance = reinterpret_cast<SHCoCreateInstance_PROC>(GetProcAddress( hModShell, MAKEINTRESOURCEA(102) ));
716
717 if ( lpfnSHCoCreateInstance )
718 hResult = lpfnSHCoCreateInstance( lpszReserved, clsid, pUnkUnknown, iid, ppv );
719 }
720 return hResult;
721 }
722
CreateShortcut(const OUString & rAbsObject,const OUString & rAbsObjectPath,const OUString & rAbsShortcut,const OUString & rDescription,const OUString & rParameter)723 static BOOL CreateShortcut( const OUString& rAbsObject, const OUString& rAbsObjectPath,
724 const OUString& rAbsShortcut, const OUString& rDescription, const OUString& rParameter )
725 {
726 HRESULT hres;
727 IShellLinkW* psl;
728 CLSID clsid_ShellLink = CLSID_ShellLink;
729 CLSID clsid_IShellLink = IID_IShellLinkW;
730
731 hres = CoCreateInstance( clsid_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
732 clsid_IShellLink, reinterpret_cast<void**>(&psl) );
733 if( FAILED(hres) )
734 hres = SHCoCreateInstance( nullptr, clsid_ShellLink, nullptr, clsid_IShellLink, reinterpret_cast<void**>(&psl) );
735
736 if( SUCCEEDED(hres) )
737 {
738 IPersistFile* ppf;
739 psl->SetPath( o3tl::toW(rAbsObject.getStr()) );
740 psl->SetWorkingDirectory( o3tl::toW(rAbsObjectPath.getStr()) );
741 psl->SetDescription( o3tl::toW(rDescription.getStr()) );
742 if( rParameter.getLength() )
743 psl->SetArguments( o3tl::toW(rParameter.getStr()) );
744
745 CLSID clsid_IPersistFile = IID_IPersistFile;
746 hres = psl->QueryInterface( clsid_IPersistFile, reinterpret_cast<void**>(&ppf) );
747
748 if( SUCCEEDED(hres) )
749 {
750 hres = ppf->Save( o3tl::toW(rAbsShortcut.getStr()), TRUE );
751 ppf->Release();
752 } else return FALSE;
753 psl->Release();
754 } else return FALSE;
755 return TRUE;
756 }
757
758
759 // install/uninstall
760
FileExistsW(LPCWSTR lpPath)761 static bool FileExistsW( LPCWSTR lpPath )
762 {
763 bool bExists = false;
764 WIN32_FIND_DATAW aFindData;
765
766 HANDLE hFind = FindFirstFileW( lpPath, &aFindData );
767
768 if ( INVALID_HANDLE_VALUE != hFind )
769 {
770 bExists = true;
771 FindClose( hFind );
772 }
773
774 return bExists;
775 }
776
IsQuickstarterInstalled()777 bool ShutdownIcon::IsQuickstarterInstalled()
778 {
779 wchar_t aPath[_MAX_PATH];
780 GetModuleFileNameW( nullptr, aPath, _MAX_PATH-1);
781
782 OUString aOfficepath( o3tl::toU(aPath) );
783 int i = aOfficepath.lastIndexOf('\\');
784 if( i != -1 )
785 aOfficepath = aOfficepath.copy(0, i);
786
787 OUString quickstartExe(aOfficepath + "\\quickstart.exe");
788
789 return FileExistsW( o3tl::toW(quickstartExe.getStr()) );
790 }
791
EnableAutostartW32(const OUString & aShortcut)792 void ShutdownIcon::EnableAutostartW32( const OUString &aShortcut )
793 {
794 wchar_t aPath[_MAX_PATH];
795 GetModuleFileNameW( nullptr, aPath, _MAX_PATH-1);
796
797 OUString aOfficepath( o3tl::toU(aPath) );
798 int i = aOfficepath.lastIndexOf('\\');
799 if( i != -1 )
800 aOfficepath = aOfficepath.copy(0, i);
801
802 OUString quickstartExe(aOfficepath + "\\quickstart.exe");
803
804 CreateShortcut( quickstartExe, aOfficepath, aShortcut, OUString(), OUString() );
805 }
806
807
808 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
809