1 /* 2 * Copyright (c) 1996, 2016, 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 /* Use THIS_FILE when it is available. */ 137 #ifndef THIS_FILE 138 #define THIS_FILE __FILE__ 139 #endif 140 141 #define CRITICAL_SECTION_ENTER(cs) { \ 142 J2dTraceLn4(J2D_TRACE_VERBOSE2, \ 143 "CS.Wait: tid, cs, file, line = 0x%x, 0x%x, %s, %d", \ 144 GetCurrentThreadId(), &(cs), THIS_FILE, __LINE__); \ 145 (cs).Enter(); \ 146 J2dTraceLn4(J2D_TRACE_VERBOSE2, \ 147 "CS.Enter: tid, cs, file, line = 0x%x, 0x%x, %s, %d", \ 148 GetCurrentThreadId(), &(cs), THIS_FILE, __LINE__); \ 149 } 150 151 #define CRITICAL_SECTION_LEAVE(cs) { \ 152 J2dTraceLn4(J2D_TRACE_VERBOSE2, \ 153 "CS.Leave: tid, cs, file, line = 0x%x, 0x%x, %s, %d", \ 154 GetCurrentThreadId(), &(cs), THIS_FILE, __LINE__); \ 155 (cs).Leave(); \ 156 J2dTraceLn4(J2D_TRACE_VERBOSE2, \ 157 "CS.Left: tid, cs, file, line = 0x%x, 0x%x, %s, %d", \ 158 GetCurrentThreadId(), &(cs), THIS_FILE, __LINE__); \ 159 } 160 161 // Redefine WinAPI values related to touch input, if OS < Windows 7. 162 #if (!defined(WINVER) || ((WINVER) < 0x0601)) 163 typedef UINT32 POINTER_FLAGS; 164 typedef UINT32 TOUCH_FLAGS; 165 typedef UINT32 TOUCH_MASK; 166 167 #define GET_POINTERID_WPARAM(wParam) (LOWORD (wParam)) 168 169 #define WM_POINTERENTER 0x0249 170 #define WM_NCPOINTERDOWN 0x0242 171 #define WM_NCPOINTERUP 0x0243 172 #define WM_NCPOINTERUPDATE 0x0241 173 #define WM_POINTERACTIVATE 0x024B 174 #define WM_POINTERCAPTURECHANGED 0x024C 175 #define WM_POINTERDOWN 0x0246 176 #define WM_POINTERLEAVE 0x024A 177 #define WM_POINTERUP 0x0247 178 #define WM_POINTERUPDATE 0x0245 179 180 typedef enum _POINTER_BUTTON_CHANGE_TYPE { 181 POINTER_CHANGE_NONE , 182 POINTER_CHANGE_FIRSTBUTTON_DOWN , 183 POINTER_CHANGE_FIRSTBUTTON_UP , 184 POINTER_CHANGE_SECONDBUTTON_DOWN , 185 POINTER_CHANGE_SECONDBUTTON_UP , 186 POINTER_CHANGE_THIRDBUTTON_DOWN , 187 POINTER_CHANGE_THIRDBUTTON_UP , 188 POINTER_CHANGE_FOURTHBUTTON_DOWN , 189 POINTER_CHANGE_FOURTHBUTTON_UP , 190 POINTER_CHANGE_FIFTHBUTTON_DOWN , 191 POINTER_CHANGE_FIFTHBUTTON_UP , 192 } POINTER_BUTTON_CHANGE_TYPE; 193 194 typedef enum tagPOINTER_INPUT_TYPE { 195 PT_POINTER = 0x00000001, 196 PT_TOUCH = 0x00000002, 197 PT_PEN = 0x00000003, 198 PT_MOUSE = 0x00000004, 199 PT_TOUCHPAD = 0x00000005 200 } POINTER_INPUT_TYPE; 201 202 typedef struct tagPOINTER_INFO { 203 POINTER_INPUT_TYPE pointerType; 204 UINT32 pointerId; 205 UINT32 frameId; 206 POINTER_FLAGS pointerFlags; 207 HANDLE sourceDevice; 208 HWND hwndTarget; 209 POINT ptPixelLocation; 210 POINT ptHimetricLocation; 211 POINT ptPixelLocationRaw; 212 POINT ptHimetricLocationRaw; 213 DWORD dwTime; 214 UINT32 historyCount; 215 INT32 inputData; 216 DWORD dwKeyStates; 217 UINT64 PerformanceCount; 218 POINTER_BUTTON_CHANGE_TYPE ButtonChangeType; 219 } POINTER_INFO; 220 #endif 221 222 /************************************************************************ 223 * AwtToolkit class 224 */ 225 226 class AwtToolkit { 227 public: 228 enum { 229 KB_STATE_SIZE = 256 230 }; 231 232 /* java.awt.Toolkit method ids */ 233 static jmethodID getDefaultToolkitMID; 234 static jmethodID getFontMetricsMID; 235 static jmethodID insetsMID; 236 237 /* sun.awt.windows.WToolkit ids */ 238 static jmethodID windowsSettingChangeMID; 239 static jmethodID displayChangeMID; 240 241 static jmethodID userSessionMID; 242 static jmethodID systemSleepMID; 243 244 BOOL m_isDynamicLayoutSet; 245 246 AwtToolkit(); 247 ~AwtToolkit(); 248 249 BOOL Initialize(BOOL localPump); 250 BOOL Dispose(); 251 252 void SetDynamicLayout(BOOL dynamic); 253 BOOL IsDynamicLayoutSet(); 254 BOOL IsDynamicLayoutSupported(); 255 BOOL IsDynamicLayoutActive(); 256 BOOL areExtraMouseButtonsEnabled(); 257 void setExtraMouseButtonsEnabled(BOOL enable); 258 static UINT GetNumberOfButtons(); 259 260 bool IsWin8OrLater(); 261 BOOL TIEnableMouseInPointer(BOOL enable); 262 BOOL TIGetPointerInfo(UINT32 pointerID, POINTER_INFO *pointerInfo); 263 264 INLINE BOOL localPump() { return m_localPump; } 265 INLINE BOOL VerifyComponents() { return FALSE; } // TODO: Use new DebugHelper class to set this flag 266 INLINE HWND GetHWnd() { return m_toolkitHWnd; } 267 268 INLINE HMODULE GetModuleHandle() { return m_dllHandle; } 269 INLINE void SetModuleHandle(HMODULE h) { m_dllHandle = h; } 270 271 INLINE static DWORD MainThread() { return GetInstance().m_mainThreadId; } 272 INLINE void VerifyActive() throw (awt_toolkit_shutdown) { 273 if (!m_isActive && m_mainThreadId != ::GetCurrentThreadId()) { 274 throw awt_toolkit_shutdown(); 275 } 276 } 277 INLINE BOOL IsDisposed() { return m_isDisposed; } 278 static UINT GetMouseKeyState(); 279 static void GetKeyboardState(PBYTE keyboardState); 280 281 static ATOM RegisterClass(); 282 static void UnregisterClass(); 283 INLINE LRESULT SendMessage(UINT msg, WPARAM wParam=0, LPARAM lParam=0) { 284 if (!m_isDisposed) { 285 return ::SendMessage(GetHWnd(), msg, wParam, lParam); 286 } else { 287 return NULL; 288 } 289 } 290 static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, 291 LPARAM lParam); 292 static LRESULT CALLBACK GetMessageFilter(int code, WPARAM wParam, 293 LPARAM lParam); 294 static LRESULT CALLBACK ForegroundIdleFilter(int code, WPARAM wParam, 295 LPARAM lParam); 296 static LRESULT CALLBACK MouseLowLevelHook(int code, WPARAM wParam, 297 LPARAM lParam); 298 299 INLINE static AwtToolkit& GetInstance() { return theInstance; } 300 INLINE void SetPeer(JNIEnv *env, jobject wToolkit) { 301 AwtToolkit &tk = AwtToolkit::GetInstance(); 302 if (tk.m_peer != NULL) { 303 env->DeleteGlobalRef(tk.m_peer); 304 } 305 tk.m_peer = (wToolkit != NULL) ? env->NewGlobalRef(wToolkit) : NULL; 306 } 307 308 INLINE jobject GetPeer() { 309 return m_peer; 310 } 311 312 // is this thread the main thread? 313 314 INLINE static BOOL IsMainThread() { 315 return GetInstance().m_mainThreadId == ::GetCurrentThreadId(); 316 } 317 318 // post a message to the message pump thread 319 320 INLINE BOOL PostMessage(UINT msg, WPARAM wp=0, LPARAM lp=0) { 321 return ::PostMessage(GetHWnd(), msg, wp, lp); 322 } 323 324 // cause the message pump thread to call the function synchronously now! 325 326 INLINE void * InvokeFunction(void*(*ftn)(void)) { 327 return (void *)SendMessage(WM_AWT_INVOKE_VOID_METHOD, (WPARAM)ftn, 0); 328 } 329 INLINE void InvokeFunction(void (*ftn)(void)) { 330 InvokeFunction((void*(*)(void))ftn); 331 } 332 INLINE void * InvokeFunction(void*(*ftn)(void *), void* param) { 333 return (void *)SendMessage(WM_AWT_INVOKE_METHOD, (WPARAM)ftn, 334 (LPARAM)param); 335 } 336 INLINE void InvokeFunction(void (*ftn)(void *), void* param) { 337 InvokeFunction((void*(*)(void*))ftn, param); 338 } 339 340 INLINE CriticalSection &GetSyncCS() { return m_Sync; } 341 342 void *SyncCall(void*(*ftn)(void *), void* param); 343 void SyncCall(void (*ftn)(void *), void *param); 344 void *SyncCall(void *(*ftn)(void)); 345 void SyncCall(void (*ftn)(void)); 346 347 // cause the message pump thread to call the function later ... 348 349 INLINE void InvokeFunctionLater(void (*ftn)(void *), void* param) { 350 if (!PostMessage(WM_AWT_INVOKE_METHOD, (WPARAM)ftn, (LPARAM)param)) { 351 JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 352 JNU_ThrowInternalError(env, "Message not posted, native event queue may be full."); 353 } 354 } 355 356 // cause the message pump thread to synchronously synchronize on the handle 357 358 INLINE void WaitForSingleObject(HANDLE handle) { 359 SendMessage(WM_AWT_WAIT_FOR_SINGLE_OBJECT, 0, (LPARAM)handle); 360 } 361 362 /* 363 * Create an AwtXxxx C++ component using a given factory 364 */ 365 typedef void (*ComponentFactory)(void*, void*); 366 static void CreateComponent(void* hComponent, void* hParent, 367 ComponentFactory compFactory, BOOL isParentALocalReference=TRUE); 368 369 static void DestroyComponentHWND(HWND hwnd); 370 371 // constants used to PostQuitMessage 372 373 static const int EXIT_ENCLOSING_LOOP; 374 static const int EXIT_ALL_ENCLOSING_LOOPS; 375 376 // ... 377 378 void QuitMessageLoop(int status); 379 380 UINT MessageLoop(IDLEPROC lpIdleFunc, PEEKMESSAGEPROC lpPeekMessageFunc); 381 BOOL PumpWaitingMessages(PEEKMESSAGEPROC lpPeekMessageFunc); 382 void PumpToDestroy(class AwtComponent* p); 383 void ProcessMsg(MSG& msg); 384 BOOL PreProcessMsg(MSG& msg); 385 BOOL PreProcessMouseMsg(class AwtComponent* p, MSG& msg); 386 BOOL PreProcessKeyMsg(class AwtComponent* p, MSG& msg); 387 388 /* Create an ID which maps to an AwtObject pointer, such as a menu. */ 389 UINT CreateCmdID(AwtObject* object); 390 391 // removes cmd id mapping 392 void RemoveCmdID(UINT id); 393 394 /* Return the AwtObject associated with its ID. */ 395 AwtObject* LookupCmdID(UINT id); 396 397 /* Return the current application icon. */ 398 HICON GetAwtIcon(); 399 HICON GetAwtIconSm(); 400 401 // Calculate a wave-like value out of the integer 'value' and 402 // the specified period. 403 // The argument 'value' is an integer 0, 1, 2, ... *infinity*. 404 // 405 // Examples: 406 // Period == 3 407 // Generated sequence: 0 1 2 1 0 ..... 408 // 409 // Period == 4 410 // Generated sequence: 0 1 2 3 2 1 0 ..... 411 static inline UINT CalculateWave(UINT value, const UINT period) { 412 if (period < 2) { 413 return 0; 414 } 415 // -2 is necessary to avoid repeating extreme values (0 and period-1) 416 value %= period * 2 -2; 417 if (value >= period) { 418 value = period * 2 -2 - value; 419 } 420 return value; 421 } 422 423 HICON GetSecurityWarningIcon(UINT index, UINT w, UINT h); 424 425 /* Turns on/off dialog modality for the system. */ 426 INLINE AwtDialog* SetModal(AwtDialog* frame) { 427 AwtDialog* previousDialog = m_pModalDialog; 428 m_pModalDialog = frame; 429 return previousDialog; 430 }; 431 INLINE void ResetModal(AwtDialog* oldFrame) { m_pModalDialog = oldFrame; }; 432 INLINE BOOL IsModal() { return (m_pModalDialog != NULL); }; 433 INLINE AwtDialog* GetModalDialog(void) { return m_pModalDialog; }; 434 435 /* Stops the current message pump (normally a modal dialog pump) */ 436 INLINE void StopMessagePump() { m_breakOnError = TRUE; } 437 438 /* Debug settings */ 439 INLINE void SetVerbose(long flag) { m_verbose = (flag != 0); } 440 INLINE void SetVerify(long flag) { m_verifyComponents = (flag != 0); } 441 INLINE void SetBreak(long flag) { m_breakOnError = (flag != 0); } 442 INLINE void SetHeapCheck(long flag); 443 444 static void SetBusy(BOOL busy); 445 446 /* Set and get the default input method Window handler. */ 447 INLINE void SetInputMethodWindow(HWND inputMethodHWnd) { m_inputMethodHWnd = inputMethodHWnd; } 448 INLINE HWND GetInputMethodWindow() { return m_inputMethodHWnd; } 449 450 static VOID CALLBACK PrimaryIdleFunc(); 451 static VOID CALLBACK SecondaryIdleFunc(); 452 static BOOL CALLBACK CommonPeekMessageFunc(MSG& msg); 453 static BOOL activateKeyboardLayout(HKL hkl); 454 455 HANDLE m_waitEvent; 456 volatile DWORD eventNumber; 457 volatile BOOL isInDoDragDropLoop; 458 private: 459 HWND CreateToolkitWnd(LPCTSTR name); 460 461 BOOL m_localPump; 462 DWORD m_mainThreadId; 463 HWND m_toolkitHWnd; 464 HWND m_inputMethodHWnd; 465 BOOL m_verbose; 466 BOOL m_isActive; // set to FALSE at beginning of Dispose 467 BOOL m_isDisposed; // set to TRUE at end of Dispose 468 BOOL m_areExtraMouseButtonsEnabled; 469 470 typedef BOOL (WINAPI *EnableMouseInPointerHandleFunc)(BOOL enable); 471 typedef BOOL (WINAPI *GetPointerInfoHandleFunc)(UINT32 pointerID, POINTER_INFO *pointerInfo); 472 473 BOOL m_isWin8OrLater; 474 EnableMouseInPointerHandleFunc m_pEnableMouseInPointerHandle; 475 GetPointerInfoHandleFunc m_pGetPointerInfoHandle; 476 477 BOOL m_vmSignalled; // set to TRUE if QUERYENDSESSION has successfully 478 // raised SIGTERM 479 480 BOOL m_verifyComponents; 481 BOOL m_breakOnError; 482 483 BOOL m_breakMessageLoop; 484 UINT m_messageLoopResult; 485 486 class AwtComponent* m_lastMouseOver; 487 BOOL m_mouseDown; 488 489 HHOOK m_hGetMessageHook; 490 HHOOK m_hMouseLLHook; 491 UINT_PTR m_timer; 492 493 class AwtCmdIDList* m_cmdIDs; 494 BYTE m_lastKeyboardState[KB_STATE_SIZE]; 495 CriticalSection m_lockKB; 496 497 static AwtToolkit theInstance; 498 499 /* The current modal dialog frame (normally NULL). */ 500 AwtDialog* m_pModalDialog; 501 502 /* The WToolkit peer instance */ 503 jobject m_peer; 504 505 HMODULE m_dllHandle; /* The module handle. */ 506 507 CriticalSection m_Sync; 508 509 /* track display changes - used by palette-updating code. 510 This is a workaround for a windows bug that prevents 511 WM_PALETTECHANGED event from occurring immediately after 512 a WM_DISPLAYCHANGED event. 513 */ 514 private: 515 BOOL m_displayChanged; /* Tracks displayChanged events */ 516 // 0 means we are not embedded. 517 DWORD m_embedderProcessID; 518 519 public: 520 BOOL HasDisplayChanged() { return m_displayChanged; } 521 void ResetDisplayChanged() { m_displayChanged = FALSE; } 522 void RegisterEmbedderProcessId(HWND); 523 BOOL IsEmbedderProcessId(const DWORD processID) const 524 { 525 return m_embedderProcessID && (processID == m_embedderProcessID); 526 } 527 528 private: 529 static JNIEnv *m_env; 530 static DWORD m_threadId; 531 public: 532 static void SetEnv(JNIEnv *env); 533 static JNIEnv* GetEnv(); 534 535 static BOOL GetScreenInsets(int screenNum, RECT * rect); 536 537 // If the DWM is active, this function uses 538 // DwmGetWindowAttribute()/DWMWA_EXTENDED_FRAME_BOUNDS. 539 // Otherwise, fall back to regular ::GetWindowRect(). 540 // See 6711576 for more details. 541 static void GetWindowRect(HWND hWnd, LPRECT lpRect); 542 543 private: 544 // The window handle of a toplevel window last seen under the mouse cursor. 545 // See MouseLowLevelHook() for details. 546 HWND m_lastWindowUnderMouse; 547 public: 548 HWND GetWindowUnderMouse() { return m_lastWindowUnderMouse; } 549 550 void InstallMouseLowLevelHook(); 551 void UninstallMouseLowLevelHook(); 552 553 554 /* AWT preloading (early Toolkit thread start) 555 */ 556 public: 557 /* Toolkit preload action class. 558 * Preload actions should be registered with 559 * AwtToolkit::getInstance().GetPreloadThread().AddAction(). 560 * AwtToolkit thread calls InitImpl method at the beghining 561 * and CleanImpl(false) before exiting for all registered actions. 562 * If an application provides own Toolkit thread 563 * (sun.awt.windows.WToolkit.embeddedInit), the thread calls Clean(true) 564 * for each action. 565 */ 566 class PreloadThread; // forward declaration 567 class PreloadAction { 568 friend class PreloadThread; 569 public: 570 PreloadAction() : initThreadId(0), pNext(NULL) {} 571 virtual ~PreloadAction() {} 572 573 protected: 574 // called by PreloadThread or as result 575 // of EnsureInited() call (on Toolkit thread!). 576 virtual void InitImpl() = 0; 577 578 // called by PreloadThread (before exiting). 579 // reInit == false: normal shutdown; 580 // reInit == true: PreloadThread is shutting down due external 581 // Toolkit thread was provided. 582 virtual void CleanImpl(bool reInit) = 0; 583 584 public: 585 // Initialized the action on the Toolkit thread if not yet initialized. 586 bool EnsureInited(); 587 588 // returns thread ID which the action was inited on (0 if not inited) 589 DWORD GetInitThreadID(); 590 591 // Allows to deinitialize action earlier. 592 // The method must be called on the Toolkit thread only. 593 // returns true on success, 594 // false if the action was inited on other thread. 595 bool Clean(); 596 597 private: 598 unsigned initThreadId; 599 // lock for Init/Clean 600 CriticalSection initLock; 601 602 // Chain support (for PreloadThread) 603 PreloadAction *pNext; // for action chain used by PreloadThread 604 void SetNext(PreloadAction *pNext) { this->pNext = pNext; } 605 PreloadAction *GetNext() { return pNext; } 606 607 // wrapper for AwtToolkit::InvokeFunction 608 static void InitWrapper(void *param); 609 610 void Init(); 611 void Clean(bool reInit); 612 613 }; 614 615 /** Toolkit preload thread class. 616 */ 617 class PreloadThread { 618 public: 619 PreloadThread(); 620 ~PreloadThread(); 621 622 // adds action & start the thread if not yet started 623 bool AddAction(PreloadAction *pAction); 624 625 // sets termination flag; returns true if the thread is running. 626 // wrongThread specifies cause of the termination: 627 // false means termination on the application shutdown; 628 // wrongThread is used as reInit parameter for action cleanup. 629 bool Terminate(bool wrongThread); 630 bool InvokeAndTerminate(void(_cdecl *fn)(void *), void *param); 631 632 // waits for the thread completion; 633 // use the method after Terminate() only if Terminate() returned true 634 INLINE void Wait4Finish() { 635 ::WaitForSingleObject(hFinished, INFINITE); 636 } 637 638 INLINE unsigned GetThreadId() { 639 CriticalSection::Lock lock(threadLock); 640 return threadId; 641 } 642 INLINE bool IsWrongThread() { 643 CriticalSection::Lock lock(threadLock); 644 return wrongThread; 645 } 646 // returns true if the current thread is "preload" thread 647 bool OnPreloadThread(); 648 649 private: 650 // data access lock 651 CriticalSection threadLock; 652 653 // the thread status 654 enum Status { 655 None = -1, // initial 656 Preloading = 0, // preloading in progress 657 RunningToolkit, // Running as Toolkit thread 658 Cleaning, // exited from Toolkit thread proc, cleaning 659 Finished // 660 } status; 661 662 // "wrong thread" flag 663 bool wrongThread; 664 665 // thread proc (calls (this)param->ThreadProc()) 666 static unsigned WINAPI StaticThreadProc(void *param); 667 unsigned ThreadProc(); 668 669 INLINE void AwakeThread() { 670 ::SetEvent(hAwake); 671 } 672 673 // if threadId != 0 -> we are running 674 unsigned threadId; 675 // ThreadProc sets the event on exit 676 HANDLE hFinished; 677 // ThreadProc waits on the event for NewAction/Terminate/InvokeAndTerminate 678 HANDLE hAwake; 679 680 // function/param to invoke (InvokeAndTerminate) 681 // if execFunc == NULL => just terminate 682 void(_cdecl *execFunc)(void *); 683 void *execParam; 684 685 // action chain 686 PreloadAction *pActionChain; 687 PreloadAction *pLastProcessedAction; 688 689 // returns next action in the list (NULL if no more actions) 690 PreloadAction* GetNextAction(); 691 692 }; 693 694 INLINE PreloadThread& GetPreloadThread() { return preloadThread; } 695 696 private: 697 PreloadThread preloadThread; 698 699 }; 700 701 702 /* creates an instance of T and assigns it to the argument, but only if 703 the argument is initially NULL. Supposed to be thread-safe. 704 returns the new value of the argument. I'm not using volatile here 705 as InterlockedCompareExchange ensures volatile semantics 706 and acquire/release. 707 The function is useful when used with static POD NULL-initialized 708 pointers, as they are guaranteed to be NULL before any dynamic 709 initialization takes place. This function turns such a pointer 710 into a thread-safe singleton, working regardless of dynamic 711 initialization order. Destruction problem is not solved, 712 we don't need it here. 713 */ 714 715 template<typename T> inline T* SafeCreate(T* &pArg) { 716 /* this implementation has no locks, it just destroys the object if it 717 fails to be the first to init. another way would be using a special 718 flag pointer value to mark the pointer as "being initialized". */ 719 T* pTemp = (T*)InterlockedCompareExchangePointer((void**)&pArg, NULL, NULL); 720 if (pTemp != NULL) return pTemp; 721 T* pNew = new T; 722 pTemp = (T*)InterlockedCompareExchangePointer((void**)&pArg, pNew, NULL); 723 if (pTemp != NULL) { 724 // we failed it - another thread has already initialized pArg 725 delete pNew; 726 return pTemp; 727 } else { 728 return pNew; 729 } 730 } 731 732 #endif /* AWT_TOOLKIT_H */