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