1 /* 2 * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * The Toolkit class has two functions: it instantiates the AWT 28 * ToolkitPeer's native methods, and provides the DLL's core functions. 29 * 30 * There are two ways this DLL can be used: either as a dynamically- 31 * loaded Java native library from the interpreter, or by a Windows- 32 * specific app. The first manner requires that the Toolkit provide 33 * all support needed so the app can function as a first-class Windows 34 * app, while the second assumes that the app will provide that 35 * functionality. Which mode this DLL functions in is determined by 36 * which initialization paradigm is used. If the Toolkit is constructed 37 * normally, then the Toolkit will have its own pump. If it is explicitly 38 * initialized for an embedded environment (via a static method on 39 * sun.awt.windows.WToolkit), then it will rely on an external message 40 * pump. 41 * 42 * The most basic functionality needed is a Windows message pump (also 43 * known as a message loop). When an Java app is started as a console 44 * app by the interpreter, the Toolkit needs to provide that message 45 * pump if the AWT is dynamically loaded. 46 */ 47 48 #ifndef AWT_TOOLKIT_H 49 #define AWT_TOOLKIT_H 50 51 #include "awt.h" 52 #include "awtmsg.h" 53 #include "Trace.h" 54 55 #include "sun_awt_windows_WToolkit.h" 56 57 class AwtObject; 58 class AwtDialog; 59 class AwtDropTarget; 60 61 typedef VOID (CALLBACK* IDLEPROC)(VOID); 62 typedef BOOL (CALLBACK* PEEKMESSAGEPROC)(MSG&); 63 64 // Struct for _WInputMethod_enable|disableNativeIME method 65 struct EnableNativeIMEStruct { 66 jobject self; 67 jobject peer; 68 jint context; 69 jboolean useNativeCompWindow; 70 }; 71 72 /* 73 * class JNILocalFrame 74 * Push/PopLocalFrame helper 75 */ 76 class JNILocalFrame { 77 public: 78 INLINE JNILocalFrame(JNIEnv *env, int size) { 79 m_env = env; 80 int result = m_env->PushLocalFrame(size); 81 if (result < 0) { 82 DASSERT(FALSE); 83 throw std::bad_alloc(); 84 } 85 } 86 INLINE ~JNILocalFrame() { m_env->PopLocalFrame(NULL); } 87 private: 88 JNIEnv* m_env; 89 }; 90 91 /* 92 * class CriticalSection 93 * ~~~~~ ~~~~~~~~~~~~~~~~ 94 * Lightweight intra-process thread synchronization. Can only be used with 95 * other critical sections, and only within the same process. 96 */ 97 class CriticalSection { 98 public: 99 INLINE CriticalSection() { ::InitializeCriticalSection(&rep); } 100 INLINE ~CriticalSection() { ::DeleteCriticalSection(&rep); } 101 102 class Lock { 103 public: 104 INLINE Lock(const CriticalSection& cs) : critSec(cs) { 105 (const_cast<CriticalSection &>(critSec)).Enter(); 106 } 107 INLINE ~Lock() { 108 (const_cast<CriticalSection &>(critSec)).Leave(); 109 } 110 private: 111 const CriticalSection& critSec; 112 }; 113 friend class Lock; 114 115 private: 116 CRITICAL_SECTION rep; 117 118 CriticalSection(const CriticalSection&); 119 const CriticalSection& operator =(const CriticalSection&); 120 121 public: 122 virtual void Enter() { 123 ::EnterCriticalSection(&rep); 124 } 125 virtual BOOL TryEnter() { 126 return ::TryEnterCriticalSection(&rep); 127 } 128 virtual void Leave() { 129 ::LeaveCriticalSection(&rep); 130 } 131 }; 132 133 // Macros for using CriticalSection objects that help trace 134 // lock/unlock actions 135 136 #define CRITICAL_SECTION_ENTER(cs) { \ 137 J2dTraceLn4(J2D_TRACE_VERBOSE2, \ 138 "CS.Wait: tid, cs, file, line = 0x%x, 0x%x, %s, %d", \ 139 GetCurrentThreadId(), &(cs), __FILE__, __LINE__); \ 140 (cs).Enter(); \ 141 J2dTraceLn4(J2D_TRACE_VERBOSE2, \ 142 "CS.Enter: tid, cs, file, line = 0x%x, 0x%x, %s, %d", \ 143 GetCurrentThreadId(), &(cs), __FILE__, __LINE__); \ 144 } 145 146 #define CRITICAL_SECTION_LEAVE(cs) { \ 147 J2dTraceLn4(J2D_TRACE_VERBOSE2, \ 148 "CS.Leave: tid, cs, file, line = 0x%x, 0x%x, %s, %d", \ 149 GetCurrentThreadId(), &(cs), __FILE__, __LINE__); \ 150 (cs).Leave(); \ 151 J2dTraceLn4(J2D_TRACE_VERBOSE2, \ 152 "CS.Left: tid, cs, file, line = 0x%x, 0x%x, %s, %d", \ 153 GetCurrentThreadId(), &(cs), __FILE__, __LINE__); \ 154 } 155 156 // Redefine WinAPI values related to touch input, if OS < Windows 7. 157 #if (!defined(WINVER) || ((WINVER) < 0x0601)) 158 /* 159 * RegisterTouchWindow flag values 160 */ 161 #define TWF_FINETOUCH (0x00000001) 162 #define TWF_WANTPALM (0x00000002) 163 164 #define WM_TOUCH 0x0240 165 166 /* 167 * Touch input handle 168 */ 169 typedef HANDLE HTOUCHINPUT; 170 171 typedef struct tagTOUCHINPUT { 172 LONG x; 173 LONG y; 174 HANDLE hSource; 175 DWORD dwID; 176 DWORD dwFlags; 177 DWORD dwMask; 178 DWORD dwTime; 179 ULONG_PTR dwExtraInfo; 180 DWORD cxContact; 181 DWORD cyContact; 182 } TOUCHINPUT, *PTOUCHINPUT; 183 typedef TOUCHINPUT const * PCTOUCHINPUT; 184 185 /* 186 * Touch input flag values (TOUCHINPUT.dwFlags) 187 */ 188 #define TOUCHEVENTF_MOVE 0x0001 189 #define TOUCHEVENTF_DOWN 0x0002 190 #define TOUCHEVENTF_UP 0x0004 191 #define TOUCHEVENTF_INRANGE 0x0008 192 #define TOUCHEVENTF_PRIMARY 0x0010 193 #define TOUCHEVENTF_NOCOALESCE 0x0020 194 #define TOUCHEVENTF_PEN 0x0040 195 #define TOUCHEVENTF_PALM 0x0080 196 #endif 197 198 /************************************************************************ 199 * AwtToolkit class 200 */ 201 202 class AwtToolkit { 203 public: 204 enum { 205 KB_STATE_SIZE = 256 206 }; 207 208 /* java.awt.Toolkit method ids */ 209 static jmethodID getDefaultToolkitMID; 210 static jmethodID getFontMetricsMID; 211 static jmethodID insetsMID; 212 213 /* sun.awt.windows.WToolkit ids */ 214 static jmethodID windowsSettingChangeMID; 215 static jmethodID displayChangeMID; 216 217 static jmethodID userSessionMID; 218 static jmethodID systemSleepMID; 219 220 BOOL m_isDynamicLayoutSet; 221 222 AwtToolkit(); 223 ~AwtToolkit(); 224 225 BOOL Initialize(BOOL localPump); 226 BOOL Dispose(); 227 228 void SetDynamicLayout(BOOL dynamic); 229 BOOL IsDynamicLayoutSet(); 230 BOOL IsDynamicLayoutSupported(); 231 BOOL IsDynamicLayoutActive(); 232 BOOL areExtraMouseButtonsEnabled(); 233 void setExtraMouseButtonsEnabled(BOOL enable); 234 static UINT GetNumberOfButtons(); 235 236 bool IsWin8OrLater(); 237 bool IsTouchKeyboardAutoShowEnabled(); 238 bool IsAnyKeyboardAttached(); 239 bool IsTouchKeyboardAutoShowSystemEnabled(); 240 void ShowTouchKeyboard(); 241 void HideTouchKeyboard(); 242 BOOL TIRegisterTouchWindow(HWND hWnd, ULONG ulFlags); 243 BOOL TIGetTouchInputInfo(HTOUCHINPUT hTouchInput, 244 UINT cInputs, PTOUCHINPUT pInputs, int cbSize); 245 BOOL TICloseTouchInputHandle(HTOUCHINPUT hTouchInput); 246 247 LRESULT InvokeInputMethodFunction(UINT msg, WPARAM wParam=0, LPARAM lParam=0); 248 249 INLINE BOOL localPump() { return m_localPump; } 250 INLINE BOOL VerifyComponents() { return FALSE; } // TODO: Use new DebugHelper class to set this flag 251 INLINE HWND GetHWnd() { return m_toolkitHWnd; } 252 253 INLINE HMODULE GetModuleHandle() { return m_dllHandle; } 254 INLINE void SetModuleHandle(HMODULE h) { m_dllHandle = h; } 255 256 INLINE static DWORD MainThread() { return GetInstance().m_mainThreadId; } 257 INLINE void VerifyActive() throw (awt_toolkit_shutdown) { 258 if (!m_isActive && m_mainThreadId != ::GetCurrentThreadId()) { 259 throw awt_toolkit_shutdown(); 260 } 261 } 262 INLINE BOOL IsDisposed() { return m_isDisposed; } 263 static UINT GetMouseKeyState(); 264 static void GetKeyboardState(PBYTE keyboardState); 265 266 static ATOM RegisterClass(); 267 static void UnregisterClass(); 268 INLINE LRESULT SendMessage(UINT msg, WPARAM wParam=0, LPARAM lParam=0) { 269 if (!m_isDisposed) { 270 return ::SendMessage(GetHWnd(), msg, wParam, lParam); 271 } else { 272 return NULL; 273 } 274 } 275 static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, 276 LPARAM lParam); 277 static LRESULT CALLBACK GetMessageFilter(int code, WPARAM wParam, 278 LPARAM lParam); 279 static LRESULT CALLBACK ForegroundIdleFilter(int code, WPARAM wParam, 280 LPARAM lParam); 281 static LRESULT CALLBACK MouseLowLevelHook(int code, WPARAM wParam, 282 LPARAM lParam); 283 284 INLINE static AwtToolkit& GetInstance() { return theInstance; } 285 INLINE void SetPeer(JNIEnv *env, jobject wToolkit) { 286 AwtToolkit &tk = AwtToolkit::GetInstance(); 287 if (tk.m_peer != NULL) { 288 env->DeleteGlobalRef(tk.m_peer); 289 } 290 tk.m_peer = (wToolkit != NULL) ? env->NewGlobalRef(wToolkit) : NULL; 291 } 292 293 INLINE jobject GetPeer() { 294 return m_peer; 295 } 296 297 // is this thread the main thread? 298 299 INLINE static BOOL IsMainThread() { 300 return GetInstance().m_mainThreadId == ::GetCurrentThreadId(); 301 } 302 303 // post a message to the message pump thread 304 305 INLINE BOOL PostMessage(UINT msg, WPARAM wp=0, LPARAM lp=0) { 306 return ::PostMessage(GetHWnd(), msg, wp, lp); 307 } 308 309 // cause the message pump thread to call the function synchronously now! 310 311 INLINE void * InvokeFunction(void*(*ftn)(void)) { 312 return (void *)SendMessage(WM_AWT_INVOKE_VOID_METHOD, (WPARAM)ftn, 0); 313 } 314 INLINE void InvokeFunction(void (*ftn)(void)) { 315 InvokeFunction((void*(*)(void))ftn); 316 } 317 INLINE void * InvokeFunction(void*(*ftn)(void *), void* param) { 318 return (void *)SendMessage(WM_AWT_INVOKE_METHOD, (WPARAM)ftn, 319 (LPARAM)param); 320 } 321 INLINE void InvokeFunction(void (*ftn)(void *), void* param) { 322 InvokeFunction((void*(*)(void*))ftn, param); 323 } 324 325 INLINE CriticalSection &GetSyncCS() { return m_Sync; } 326 327 void *SyncCall(void*(*ftn)(void *), void* param); 328 void SyncCall(void (*ftn)(void *), void *param); 329 void *SyncCall(void *(*ftn)(void)); 330 void SyncCall(void (*ftn)(void)); 331 332 // cause the message pump thread to call the function later ... 333 334 INLINE void InvokeFunctionLater(void (*ftn)(void *), void* param) { 335 if (!PostMessage(WM_AWT_INVOKE_METHOD, (WPARAM)ftn, (LPARAM)param)) { 336 JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 337 JNU_ThrowInternalError(env, "Message not posted, native event queue may be full."); 338 } 339 } 340 341 // cause the message pump thread to synchronously synchronize on the handle 342 343 INLINE void WaitForSingleObject(HANDLE handle) { 344 SendMessage(WM_AWT_WAIT_FOR_SINGLE_OBJECT, 0, (LPARAM)handle); 345 } 346 347 /* 348 * Create an AwtXxxx C++ component using a given factory 349 */ 350 typedef void (*ComponentFactory)(void*, void*); 351 static void CreateComponent(void* hComponent, void* hParent, 352 ComponentFactory compFactory, BOOL isParentALocalReference=TRUE); 353 354 static void DestroyComponentHWND(HWND hwnd); 355 356 // constants used to PostQuitMessage 357 358 static const int EXIT_ENCLOSING_LOOP; 359 static const int EXIT_ALL_ENCLOSING_LOOPS; 360 361 // ... 362 363 void QuitMessageLoop(int status); 364 365 UINT MessageLoop(IDLEPROC lpIdleFunc, PEEKMESSAGEPROC lpPeekMessageFunc); 366 BOOL PumpWaitingMessages(PEEKMESSAGEPROC lpPeekMessageFunc); 367 void PumpToDestroy(class AwtComponent* p); 368 void ProcessMsg(MSG& msg); 369 BOOL PreProcessMsg(MSG& msg); 370 BOOL PreProcessMouseMsg(class AwtComponent* p, MSG& msg); 371 BOOL PreProcessKeyMsg(class AwtComponent* p, MSG& msg); 372 373 /* Checks that an free ID exists. */ 374 jboolean isFreeIDAvailable(); 375 /* Create an ID which maps to an AwtObject pointer, such as a menu. */ 376 UINT CreateCmdID(AwtObject* object); 377 378 // removes cmd id mapping 379 void RemoveCmdID(UINT id); 380 381 /* Return the AwtObject associated with its ID. */ 382 AwtObject* LookupCmdID(UINT id); 383 384 /* Return the current application icon. */ 385 HICON GetAwtIcon(); 386 HICON GetAwtIconSm(); 387 388 // Calculate a wave-like value out of the integer 'value' and 389 // the specified period. 390 // The argument 'value' is an integer 0, 1, 2, ... *infinity*. 391 // 392 // Examples: 393 // Period == 3 394 // Generated sequence: 0 1 2 1 0 ..... 395 // 396 // Period == 4 397 // Generated sequence: 0 1 2 3 2 1 0 ..... 398 static inline UINT CalculateWave(UINT value, const UINT period) { 399 if (period < 2) { 400 return 0; 401 } 402 // -2 is necessary to avoid repeating extreme values (0 and period-1) 403 value %= period * 2 -2; 404 if (value >= period) { 405 value = period * 2 -2 - value; 406 } 407 return value; 408 } 409 410 HICON GetSecurityWarningIcon(UINT index, UINT w, UINT h); 411 412 /* Turns on/off dialog modality for the system. */ 413 INLINE AwtDialog* SetModal(AwtDialog* frame) { 414 AwtDialog* previousDialog = m_pModalDialog; 415 m_pModalDialog = frame; 416 return previousDialog; 417 }; 418 INLINE void ResetModal(AwtDialog* oldFrame) { m_pModalDialog = oldFrame; }; 419 INLINE BOOL IsModal() { return (m_pModalDialog != NULL); }; 420 INLINE AwtDialog* GetModalDialog(void) { return m_pModalDialog; }; 421 422 /* Stops the current message pump (normally a modal dialog pump) */ 423 INLINE void StopMessagePump() { m_breakOnError = TRUE; } 424 425 /* Debug settings */ 426 INLINE void SetVerbose(long flag) { m_verbose = (flag != 0); } 427 INLINE void SetVerify(long flag) { m_verifyComponents = (flag != 0); } 428 INLINE void SetBreak(long flag) { m_breakOnError = (flag != 0); } 429 INLINE void SetHeapCheck(long flag); 430 431 static void SetBusy(BOOL busy); 432 433 /* Set and get the default input method Window handler. */ 434 INLINE void SetInputMethodWindow(HWND inputMethodHWnd) { m_inputMethodHWnd = inputMethodHWnd; } 435 INLINE HWND GetInputMethodWindow() { return m_inputMethodHWnd; } 436 437 static VOID CALLBACK PrimaryIdleFunc(); 438 static VOID CALLBACK SecondaryIdleFunc(); 439 static BOOL CALLBACK CommonPeekMessageFunc(MSG& msg); 440 static BOOL activateKeyboardLayout(HKL hkl); 441 442 HANDLE m_waitEvent; 443 volatile DWORD eventNumber; 444 volatile BOOL isInDoDragDropLoop; 445 private: 446 HWND CreateToolkitWnd(LPCTSTR name); 447 448 void InitTouchKeyboardExeFilePath(); 449 HWND GetTouchKeyboardWindow(); 450 451 BOOL m_localPump; 452 DWORD m_mainThreadId; 453 HWND m_toolkitHWnd; 454 HWND m_inputMethodHWnd; 455 BOOL m_verbose; 456 BOOL m_isActive; // set to FALSE at beginning of Dispose 457 BOOL m_isDisposed; // set to TRUE at end of Dispose 458 BOOL m_areExtraMouseButtonsEnabled; 459 460 typedef BOOL (WINAPI *RegisterTouchWindowFunc)(HWND hWnd, ULONG ulFlags); 461 typedef BOOL (WINAPI *GetTouchInputInfoFunc)(HTOUCHINPUT hTouchInput, 462 UINT cInputs, PTOUCHINPUT pInputs, int cbSize); 463 typedef BOOL (WINAPI *CloseTouchInputHandleFunc)(HTOUCHINPUT hTouchInput); 464 465 BOOL m_isWin8OrLater; 466 BOOL m_touchKbrdAutoShowIsEnabled; 467 TCHAR* m_touchKbrdExeFilePath; 468 RegisterTouchWindowFunc m_pRegisterTouchWindow; 469 GetTouchInputInfoFunc m_pGetTouchInputInfo; 470 CloseTouchInputHandleFunc m_pCloseTouchInputHandle; 471 472 BOOL m_vmSignalled; // set to TRUE if QUERYENDSESSION has successfully 473 // raised SIGTERM 474 475 BOOL m_verifyComponents; 476 BOOL m_breakOnError; 477 478 BOOL m_breakMessageLoop; 479 UINT m_messageLoopResult; 480 481 class AwtComponent* m_lastMouseOver; 482 BOOL m_mouseDown; 483 484 HHOOK m_hGetMessageHook; 485 HHOOK m_hMouseLLHook; 486 UINT_PTR m_timer; 487 488 class AwtCmdIDList* m_cmdIDs; 489 BYTE m_lastKeyboardState[KB_STATE_SIZE]; 490 CriticalSection m_lockKB; 491 492 static AwtToolkit theInstance; 493 494 /* The current modal dialog frame (normally NULL). */ 495 AwtDialog* m_pModalDialog; 496 497 /* The WToolkit peer instance */ 498 jobject m_peer; 499 500 HMODULE m_dllHandle; /* The module handle. */ 501 502 CriticalSection m_Sync; 503 CriticalSection m_inputMethodLock; 504 505 HANDLE m_inputMethodWaitEvent; 506 LRESULT m_inputMethodData; 507 508 /* track display changes - used by palette-updating code. 509 This is a workaround for a windows bug that prevents 510 WM_PALETTECHANGED event from occurring immediately after 511 a WM_DISPLAYCHANGED event. 512 */ 513 private: 514 BOOL m_displayChanged; /* Tracks displayChanged events */ 515 // 0 means we are not embedded. 516 DWORD m_embedderProcessID; 517 518 public: 519 BOOL HasDisplayChanged() { return m_displayChanged; } 520 void ResetDisplayChanged() { m_displayChanged = FALSE; } 521 void RegisterEmbedderProcessId(HWND); 522 BOOL IsEmbedderProcessId(const DWORD processID) const 523 { 524 return m_embedderProcessID && (processID == m_embedderProcessID); 525 } 526 527 private: 528 static JNIEnv *m_env; 529 static DWORD m_threadId; 530 public: 531 static void SetEnv(JNIEnv *env); 532 static JNIEnv* GetEnv(); 533 534 static BOOL GetScreenInsets(int screenNum, RECT * rect); 535 536 // If the DWM is active, this function uses 537 // DwmGetWindowAttribute()/DWMWA_EXTENDED_FRAME_BOUNDS. 538 // Otherwise, fall back to regular ::GetWindowRect(). 539 // See 6711576 for more details. 540 static void GetWindowRect(HWND hWnd, LPRECT lpRect); 541 542 private: 543 // The window handle of a toplevel window last seen under the mouse cursor. 544 // See MouseLowLevelHook() for details. 545 HWND m_lastWindowUnderMouse; 546 public: 547 HWND GetWindowUnderMouse() { return m_lastWindowUnderMouse; } 548 549 void InstallMouseLowLevelHook(); 550 void UninstallMouseLowLevelHook(); 551 552 553 /* AWT preloading (early Toolkit thread start) 554 */ 555 public: 556 /* Toolkit preload action class. 557 * Preload actions should be registered with 558 * AwtToolkit::getInstance().GetPreloadThread().AddAction(). 559 * AwtToolkit thread calls InitImpl method at the beghining 560 * and CleanImpl(false) before exiting for all registered actions. 561 * If an application provides own Toolkit thread 562 * (sun.awt.windows.WToolkit.embeddedInit), the thread calls Clean(true) 563 * for each action. 564 */ 565 class PreloadThread; // forward declaration 566 class PreloadAction { 567 friend class PreloadThread; 568 public: 569 PreloadAction() : initThreadId(0), pNext(NULL) {} 570 virtual ~PreloadAction() {} 571 572 protected: 573 // called by PreloadThread or as result 574 // of EnsureInited() call (on Toolkit thread!). 575 virtual void InitImpl() = 0; 576 577 // called by PreloadThread (before exiting). 578 // reInit == false: normal shutdown; 579 // reInit == true: PreloadThread is shutting down due external 580 // Toolkit thread was provided. 581 virtual void CleanImpl(bool reInit) = 0; 582 583 public: 584 // Initialized the action on the Toolkit thread if not yet initialized. 585 bool EnsureInited(); 586 587 // returns thread ID which the action was inited on (0 if not inited) 588 DWORD GetInitThreadID(); 589 590 // Allows to deinitialize action earlier. 591 // The method must be called on the Toolkit thread only. 592 // returns true on success, 593 // false if the action was inited on other thread. 594 bool Clean(); 595 596 private: 597 unsigned initThreadId; 598 // lock for Init/Clean 599 CriticalSection initLock; 600 601 // Chain support (for PreloadThread) 602 PreloadAction *pNext; // for action chain used by PreloadThread 603 void SetNext(PreloadAction *pNext) { this->pNext = pNext; } 604 PreloadAction *GetNext() { return pNext; } 605 606 // wrapper for AwtToolkit::InvokeFunction 607 static void InitWrapper(void *param); 608 609 void Init(); 610 void Clean(bool reInit); 611 612 }; 613 614 /** Toolkit preload thread class. 615 */ 616 class PreloadThread { 617 public: 618 PreloadThread(); 619 ~PreloadThread(); 620 621 // adds action & start the thread if not yet started 622 bool AddAction(PreloadAction *pAction); 623 624 // sets termination flag; returns true if the thread is running. 625 // wrongThread specifies cause of the termination: 626 // false means termination on the application shutdown; 627 // wrongThread is used as reInit parameter for action cleanup. 628 bool Terminate(bool wrongThread); 629 bool InvokeAndTerminate(void(_cdecl *fn)(void *), void *param); 630 631 // waits for the thread completion; 632 // use the method after Terminate() only if Terminate() returned true 633 INLINE void Wait4Finish() { 634 ::WaitForSingleObject(hFinished, INFINITE); 635 } 636 637 INLINE unsigned GetThreadId() { 638 CriticalSection::Lock lock(threadLock); 639 return threadId; 640 } 641 INLINE bool IsWrongThread() { 642 CriticalSection::Lock lock(threadLock); 643 return wrongThread; 644 } 645 // returns true if the current thread is "preload" thread 646 bool OnPreloadThread(); 647 648 private: 649 // data access lock 650 CriticalSection threadLock; 651 652 // the thread status 653 enum Status { 654 None = -1, // initial 655 Preloading = 0, // preloading in progress 656 RunningToolkit, // Running as Toolkit thread 657 Cleaning, // exited from Toolkit thread proc, cleaning 658 Finished // 659 } status; 660 661 // "wrong thread" flag 662 bool wrongThread; 663 664 // thread proc (calls (this)param->ThreadProc()) 665 static unsigned WINAPI StaticThreadProc(void *param); 666 unsigned ThreadProc(); 667 668 INLINE void AwakeThread() { 669 ::SetEvent(hAwake); 670 } 671 672 // if threadId != 0 -> we are running 673 unsigned threadId; 674 // ThreadProc sets the event on exit 675 HANDLE hFinished; 676 // ThreadProc waits on the event for NewAction/Terminate/InvokeAndTerminate 677 HANDLE hAwake; 678 679 // function/param to invoke (InvokeAndTerminate) 680 // if execFunc == NULL => just terminate 681 void(_cdecl *execFunc)(void *); 682 void *execParam; 683 684 // action chain 685 PreloadAction *pActionChain; 686 PreloadAction *pLastProcessedAction; 687 688 // returns next action in the list (NULL if no more actions) 689 PreloadAction* GetNextAction(); 690 691 }; 692 693 INLINE PreloadThread& GetPreloadThread() { return preloadThread; } 694 695 private: 696 PreloadThread preloadThread; 697 698 }; 699 700 701 /* creates an instance of T and assigns it to the argument, but only if 702 the argument is initially NULL. Supposed to be thread-safe. 703 returns the new value of the argument. I'm not using volatile here 704 as InterlockedCompareExchange ensures volatile semantics 705 and acquire/release. 706 The function is useful when used with static POD NULL-initialized 707 pointers, as they are guaranteed to be NULL before any dynamic 708 initialization takes place. This function turns such a pointer 709 into a thread-safe singleton, working regardless of dynamic 710 initialization order. Destruction problem is not solved, 711 we don't need it here. 712 */ 713 714 template<typename T> inline T* SafeCreate(T* &pArg) { 715 /* this implementation has no locks, it just destroys the object if it 716 fails to be the first to init. another way would be using a special 717 flag pointer value to mark the pointer as "being initialized". */ 718 T* pTemp = (T*)InterlockedCompareExchangePointer((void**)&pArg, NULL, NULL); 719 if (pTemp != NULL) return pTemp; 720 T* pNew = new T; 721 pTemp = (T*)InterlockedCompareExchangePointer((void**)&pArg, pNew, NULL); 722 if (pTemp != NULL) { 723 // we failed it - another thread has already initialized pArg 724 delete pNew; 725 return pTemp; 726 } else { 727 return pNew; 728 } 729 } 730 731 #endif /* AWT_TOOLKIT_H */