Back to index

lightning-sunbird  0.9+nobinonly
nsToolkit.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsToolkit.h"
00039 #include "nsWindow.h"
00040 #include "prmon.h"
00041 #include "prtime.h"
00042 #include "nsGUIEvent.h"
00043 #include "plevent.h"
00044 #include "nsIServiceManager.h"
00045 #include "nsIEventQueueService.h"
00046 #include "nsIEventQueue.h"
00047 #include "nsComponentManagerUtils.h"
00048 #include "nsNativeCharsetUtils.h"
00049 // objbase.h must be declared before initguid.h to use the |DEFINE_GUID|'s in aimm.h
00050 #include <objbase.h>
00051 #include <initguid.h>
00052 #include "aimm.h"
00053 
00054 #ifdef WINCE
00055 #include "resource.h"
00056 
00057 #include "aygshell.h"
00058 #endif
00059 
00060 // unknwn.h is needed to build with WIN32_LEAN_AND_MEAN
00061 #include <unknwn.h>
00062 
00063 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00064 
00065 // Cached reference to event queue service
00066 static nsCOMPtr<nsIEventQueueService>  gEventQueueService;
00067 
00068 NS_IMPL_ISUPPORTS1(nsToolkit, nsIToolkit)
00069 
00070 // If PR_TRUE the user is currently moving a top level window.
00071 static PRBool gIsMovingWindow = PR_FALSE;
00072 
00073 // Message filter used to determine if the user is currently 
00074 // moving a top-level window.
00075 static HHOOK   nsMsgFilterHook = NULL;
00076 
00077 //
00078 // Static thread local storage index of the Toolkit 
00079 // object associated with a given thread...
00080 //
00081 static PRUintn gToolkitTLSIndex = 0;
00082 
00083 
00084 HINSTANCE nsToolkit::mDllInstance = 0;
00085 PRBool    nsToolkit::mIsNT = PR_FALSE;
00086 PRBool    nsToolkit::mUseImeApiW  = PR_FALSE;
00087 PRBool    nsToolkit::mW2KXP_CP936 = PR_FALSE;
00088 PRBool    nsToolkit::mIsWinXP     = PR_FALSE;
00089 
00090 DEFINE_GUID(IID_IActiveIMMApp, 
00091 0x08c0e040, 0x62d1, 0x11d1, 0x93, 0x26, 0x0, 0x60, 0xb0, 0x67, 0xb8, 0x6e);
00092 
00093 DEFINE_GUID(CLSID_CActiveIMM,
00094 0x4955DD33, 0xB159, 0x11d0, 0x8F, 0xCF, 0x0, 0xAA, 0x00, 0x6B, 0xCC, 0x59);
00095 
00096 DEFINE_GUID(IID_IActiveIMMMessagePumpOwner,
00097 0xb5cf2cfa, 0x8aeb, 0x11d1, 0x93, 0x64, 0x0, 0x60, 0xb0, 0x67, 0xb8, 0x6e);
00098 
00099 IActiveIMMApp* nsToolkit::gAIMMApp   = NULL;
00100 PRInt32        nsToolkit::gAIMMCount = 0;
00101 
00102 MouseTrailer MouseTrailer::mSingleton;
00103 
00104 #if !defined(MOZ_STATIC_COMPONENT_LIBS) && !defined(MOZ_ENABLE_LIBXUL)
00105 //
00106 // Dll entry point. Keep the dll instance
00107 //
00108 
00109 #if defined(__GNUC__)
00110 // If DllMain gets name mangled, it won't be seen.
00111 extern "C" {
00112 #endif
00113 
00114 // Windows CE is created when nsToolkit
00115 // starts up, not when the dll is loaded.
00116 #ifndef WINCE
00117 BOOL APIENTRY DllMain(  HINSTANCE hModule, 
00118                         DWORD reason, 
00119                         LPVOID lpReserved )
00120 {
00121     switch( reason ) {
00122         case DLL_PROCESS_ATTACH:
00123             nsToolkit::Startup(hModule);
00124             break;
00125 
00126         case DLL_THREAD_ATTACH:
00127             break;
00128     
00129         case DLL_THREAD_DETACH:
00130             break;
00131     
00132         case DLL_PROCESS_DETACH:
00133             nsToolkit::Shutdown();
00134             break;
00135 
00136     }
00137 
00138     return TRUE;
00139 }
00140 #endif //#ifndef WINCE
00141 
00142 #if defined(__GNUC__)
00143 } // extern "C"
00144 #endif
00145 
00146 #endif
00147 
00148 //
00149 // main for the message pump thread
00150 //
00151 PRBool gThreadState = PR_FALSE;
00152 
00153 struct ThreadInitInfo {
00154     PRMonitor *monitor;
00155     nsToolkit *toolkit;
00156 };
00157 
00158 /* Detect when the user is moving a top-level window */
00159 
00160 #ifndef WINCE
00161 LRESULT CALLBACK DetectWindowMove(int code, WPARAM wParam, LPARAM lParam)
00162 {
00163     /* This msg filter is required to determine when the user has
00164      * clicked in the window title bar and is moving the window. 
00165      */
00166 
00167     CWPSTRUCT* sysMsg = (CWPSTRUCT*)lParam;
00168     if (sysMsg) {
00169       if (sysMsg->message == WM_ENTERSIZEMOVE) {
00170         gIsMovingWindow = PR_TRUE; 
00171         // Notify xpcom that it should favor interactivity
00172         // over performance because the user is moving a 
00173         // window
00174         PL_FavorPerformanceHint(PR_FALSE, 0);
00175       } else if (sysMsg->message == WM_EXITSIZEMOVE) {
00176         gIsMovingWindow = PR_FALSE;
00177         // Notify xpcom that it should go back to its 
00178         // previous performance setting which may favor
00179         // performance over interactivity
00180         PL_FavorPerformanceHint(PR_TRUE, 0);
00181       }
00182     }
00183     return CallNextHookEx(nsMsgFilterHook, code, wParam, lParam);
00184 }
00185 #endif //#ifndef WINCE
00186 
00187 #include "nsWindowAPI.h"
00188 
00189 #define MAX_CLASS_NAME  128
00190 #define MAX_MENU_NAME   128
00191 #define MAX_FILTER_NAME 256
00192 
00193 BOOL CallOpenSaveFileNameA(LPOPENFILENAMEW aFileNameW, BOOL aOpen)
00194 {
00195   BOOL rtn;
00196   OPENFILENAMEA ofnA;
00197   char filterA[MAX_FILTER_NAME+2];
00198   char customFilterA[MAX_FILTER_NAME+1];
00199   char fileA[FILE_BUFFER_SIZE+1];
00200   char fileTitleA[MAX_PATH+1];
00201   char initDirA[MAX_PATH+1];
00202   char titleA[MAX_PATH+1];
00203   char defExtA[MAX_PATH+1];
00204   char tempNameA[MAX_PATH+1];
00205 
00206   memset(&ofnA, 0, sizeof(OPENFILENAMEA));
00207   ofnA.lStructSize = sizeof(OPENFILENAME); 
00208   ofnA.hwndOwner = aFileNameW->hwndOwner; 
00209   ofnA.hInstance = aFileNameW->hInstance; 
00210   if (aFileNameW->lpstrFilter)  {
00211     // find the true filter length
00212     int len = 0;
00213     while ((aFileNameW->lpstrFilter[len]) ||
00214            (aFileNameW->lpstrFilter[len+1]))
00215     {
00216       ++len;
00217     }
00218 
00219     len = WideCharToMultiByte(CP_ACP, 0,
00220                               aFileNameW->lpstrFilter,
00221                               len,
00222                               filterA,
00223                               MAX_FILTER_NAME, NULL, NULL);
00224     filterA[len] = '\0';
00225     filterA[len+1] = '\0';
00226     ofnA.lpstrFilter = filterA; 
00227   }
00228   if (aFileNameW->lpstrCustomFilter)  {
00229     NS_ConvertWtoA(aFileNameW->lpstrCustomFilter, MAX_FILTER_NAME,
00230                    customFilterA, "?");
00231     ofnA.lpstrCustomFilter = customFilterA; 
00232     ofnA.nMaxCustFilter = MAX_FILTER_NAME;  
00233   }
00234   ofnA.nFilterIndex = aFileNameW->nFilterIndex; // Index of pair of filter strings. Should be ok.
00235   if (aFileNameW->lpstrFile)  {
00236     NS_ConvertWtoA(aFileNameW->lpstrFile, FILE_BUFFER_SIZE, fileA, "?");
00237     ofnA.lpstrFile = fileA;
00238     ofnA.nMaxFile = FILE_BUFFER_SIZE;
00239     if (strlen(fileA))  {
00240       // find last file offset
00241       ofnA.nFileOffset = strrchr(fileA, '\\') - fileA + 1; 
00242       // find last file extension offset
00243       ofnA.nFileExtension = strrchr(fileA, '.') - fileA + 1; 
00244     }
00245   }
00246   if (aFileNameW->lpstrFileTitle) {
00247     NS_ConvertWtoA(aFileNameW->lpstrFileTitle, MAX_PATH, fileTitleA, "?");
00248     ofnA.lpstrFileTitle = fileTitleA;
00249     ofnA.nMaxFileTitle = MAX_PATH;  
00250   }
00251   if (aFileNameW->lpstrInitialDir)  {
00252     NS_ConvertWtoA(aFileNameW->lpstrInitialDir, MAX_PATH, initDirA, "?");
00253     ofnA.lpstrInitialDir = initDirA; 
00254   }
00255   if (aFileNameW->lpstrTitle) {
00256     NS_ConvertWtoA(aFileNameW->lpstrTitle, MAX_PATH, titleA, "?");
00257     ofnA.lpstrTitle = titleA; 
00258   }
00259   ofnA.Flags = aFileNameW->Flags; 
00260   if (aFileNameW->lpstrDefExt)  {
00261     NS_ConvertWtoA(aFileNameW->lpstrDefExt, MAX_PATH, defExtA, "?");
00262     ofnA.lpstrDefExt = defExtA; 
00263   }
00264   // Warning:  No WtoA() is done to application-defined data 
00265   ofnA.lCustData = aFileNameW->lCustData; 
00266   ofnA.lpfnHook = aFileNameW->lpfnHook;   
00267   if (aFileNameW->lpTemplateName) {
00268     NS_ConvertWtoA(aFileNameW->lpTemplateName, MAX_PATH, tempNameA, "?");
00269     ofnA.lpTemplateName = tempNameA; 
00270   }
00271   
00272   if (aOpen)
00273     rtn = GetOpenFileNameA(&ofnA);
00274   else
00275     rtn = GetSaveFileNameA(&ofnA);
00276 
00277   if (!rtn)
00278     return 0;
00279 
00280   if (ofnA.lpstrFile) {
00281     if ((ofnA.Flags & OFN_ALLOWMULTISELECT) && (ofnA.Flags & OFN_EXPLORER)) {
00282       // lpstrFile contains the directory and file name strings 
00283       // which are NULL separated, with an extra NULL character after the last file name. 
00284       int lenA = 0;
00285       while ((ofnA.lpstrFile[lenA]) || (ofnA.lpstrFile[lenA+1]))
00286       {
00287         ++lenA;
00288       }
00289       // get the size of required Wide Char and make sure aFileNameW->lpstrFile has enough space
00290       int lenW = MultiByteToWideChar(CP_ACP, 0, ofnA.lpstrFile, lenA, 0, 0);
00291       if (aFileNameW->nMaxFile < lenW+2)
00292         return 0; // doesn't have enough allocated space
00293       MultiByteToWideChar(CP_ACP, 0, ofnA.lpstrFile, lenA, aFileNameW->lpstrFile, aFileNameW->nMaxFile);
00294       aFileNameW->lpstrFile[lenW] = '\0';
00295       aFileNameW->lpstrFile[lenW+1] = '\0';
00296     }
00297     else  { 
00298       NS_ConvertAtoW(ofnA.lpstrFile, aFileNameW->nMaxFile, aFileNameW->lpstrFile);
00299     }
00300   }
00301 
00302   aFileNameW->nFilterIndex = ofnA.nFilterIndex;
00303 
00304   return rtn;
00305 }
00306 
00307 BOOL WINAPI nsGetOpenFileName(LPOPENFILENAMEW aOpenFileNameW)
00308 {
00309   return CallOpenSaveFileNameA(aOpenFileNameW, TRUE);
00310 }
00311 
00312 BOOL WINAPI nsGetSaveFileName(LPOPENFILENAMEW aSaveFileNameW)
00313 {
00314   return CallOpenSaveFileNameA(aSaveFileNameW, FALSE);
00315 }
00316 
00317 int WINAPI nsGetClassName(HWND aWnd, LPWSTR aClassName, int aMaxCount)
00318 {
00319   char classNameA[MAX_CLASS_NAME];
00320 
00321   if (!GetClassNameA(aWnd, classNameA, MAX_CLASS_NAME))
00322     return 0;
00323 
00324   aMaxCount = NS_ConvertAtoW(classNameA, MAX_CLASS_NAME, aClassName);
00325 
00326   return aMaxCount;
00327 }
00328 
00329 HWND WINAPI nsCreateWindowEx(DWORD aExStyle,      
00330                              LPCWSTR aClassNameW,  
00331                              LPCWSTR aWindowNameW, 
00332                              DWORD aStyle,        
00333                              int aX,                
00334                              int aY,                
00335                              int aWidth,           
00336                              int aHeight,          
00337                              HWND aWndParent,      
00338                              HMENU aMenu,          
00339                              HINSTANCE aInstance,  
00340                              LPVOID aParam)
00341 {
00342   char classNameA [MAX_CLASS_NAME];
00343   char windowNameA[MAX_CLASS_NAME];
00344 
00345   // Convert class name and Window name from Unicode to ANSI
00346   if (aClassNameW)
00347       NS_ConvertWtoA(aClassNameW, MAX_CLASS_NAME, classNameA, "?");
00348   if (aWindowNameW)
00349       NS_ConvertWtoA(aWindowNameW, MAX_CLASS_NAME, windowNameA, "?");
00350   
00351   // so far only NULL is passed
00352   if (aParam != NULL) {
00353     NS_ASSERTION(0 , "non-NULL lParam is provided in CreateWindowExA");
00354     return NULL;
00355   }
00356 
00357   return CreateWindowExA(aExStyle, classNameA, windowNameA,
00358       aStyle, aX, aY, aWidth, aHeight, aWndParent, aMenu, aInstance, aParam) ;
00359 }
00360 
00361 LRESULT WINAPI nsSendMessage(HWND aWnd, UINT aMsg, WPARAM awParam, LPARAM alParam)
00362 {
00363   // ************ Developers **********************************************
00364   // As far as I am aware, WM_SETTEXT is the only text related message 
00365   // we call to SendMessage().  When you need to send other text related message,
00366   // please use appropriate converters.
00367   NS_ASSERTION((WM_SETTEXT == aMsg || WM_SETICON == aMsg || WM_SETFONT == aMsg), 
00368                      "Warning. Make sure sending non-Unicode string to ::SendMessage().");
00369   if (WM_SETTEXT == aMsg)  {
00370     char title[MAX_PATH];
00371     if (alParam) // Note: Window titles are truncated to 159 chars by Windows
00372       NS_ConvertWtoA((LPCWSTR)alParam, MAX_PATH, title, "?");
00373     return SendMessageA(aWnd, aMsg, awParam, (LPARAM)&title);
00374   }
00375 
00376   return SendMessageA(aWnd, aMsg, awParam, alParam);
00377 }
00378 
00379 ATOM WINAPI nsRegisterClass(const WNDCLASSW *aClassW)
00380 {
00381   WNDCLASSA wClass;
00382   char classNameA[MAX_CLASS_NAME];
00383   char menuNameA[MAX_MENU_NAME];
00384 
00385   // Set up ANSI version of class struct
00386   wClass.cbClsExtra   = aClassW->cbClsExtra;
00387   wClass.cbWndExtra   = aClassW->cbWndExtra;
00388   wClass.hbrBackground= aClassW->hbrBackground;
00389   wClass.hCursor      = aClassW->hCursor;
00390   wClass.hIcon        = aClassW->hIcon;
00391   wClass.hInstance    = aClassW->hInstance;
00392   wClass.lpfnWndProc  = aClassW->lpfnWndProc;
00393   wClass.style        = aClassW->style;
00394 
00395   if (NULL == aClassW->lpszClassName)
00396     return 0 ;
00397 
00398   wClass.lpszClassName = classNameA;
00399   if (aClassW->lpszClassName)
00400     NS_ConvertWtoA(aClassW->lpszClassName, MAX_CLASS_NAME, classNameA, "?");
00401   
00402   wClass.lpszMenuName = menuNameA; 
00403   if (aClassW->lpszMenuName)
00404     NS_ConvertWtoA(aClassW->lpszMenuName, MAX_MENU_NAME, menuNameA, "?");
00405 
00406   return RegisterClassA(&wClass);
00407 }
00408 
00409 BOOL WINAPI nsUnregisterClass(LPCWSTR aClassW, HINSTANCE aInst)
00410 {
00411   char classA[MAX_PATH+1];
00412 
00413   if (aClassW)  {
00414     NS_ConvertWtoA(aClassW, MAX_PATH, classA, "?");
00415     return UnregisterClassA((LPCSTR)classA, aInst);
00416   }
00417   return FALSE;
00418 }
00419 
00420 #ifndef WINCE
00421 UINT WINAPI nsDragQueryFile(HDROP aDrop, UINT aCount, LPWSTR aFileW, UINT aLen)
00422 {
00423   char fileA[MAX_PATH+1];
00424 
00425   // query a count of file?
00426   if (aCount == 0xFFFFFFFF)
00427     return DragQueryFileA(aDrop, aCount, NULL, 0);
00428 
00429   aLen = DragQueryFileA(aDrop, aCount, fileA, MAX_PATH);
00430   if (!aLen)
00431     return 0;
00432 
00433   aLen = NS_ConvertAtoW(fileA, aFileW ? MAX_PATH : 0, aFileW);
00434   return aLen ? aLen - 1 : 0;
00435 }
00436 
00437 BOOL WINAPI nsSHGetPathFromIDList(LPCITEMIDLIST aIdList, LPWSTR aPathW)
00438 {
00439   char pathA[MAX_PATH+1];
00440 
00441   if (aPathW)  {
00442     NS_ConvertWtoA(aPathW, MAX_PATH, pathA, "?");
00443     if (SHGetPathFromIDListA(aIdList, pathA)) {
00444       NS_ConvertAtoW(pathA, MAX_PATH, aPathW);
00445       return TRUE;
00446     }
00447   }
00448 
00449   return FALSE;
00450 }
00451 
00452 LPITEMIDLIST WINAPI nsSHBrowseForFolder(LPBROWSEINFOW aBiW)
00453 {
00454   BROWSEINFO biA;
00455   LPITEMIDLIST itemIdList;
00456   char displayNameA[MAX_PATH];
00457   char titleA[MAX_PATH];
00458 
00459   memset(&biA, 0, sizeof(BROWSEINFO));
00460   biA.hwndOwner = aBiW->hwndOwner;
00461   biA.pidlRoot = aBiW->pidlRoot;
00462   if (aBiW->pszDisplayName)  {
00463     NS_ConvertWtoA(aBiW->pszDisplayName, MAX_PATH, displayNameA, "?");
00464     biA.pszDisplayName = displayNameA; 
00465   }
00466   if (aBiW->lpszTitle)  {
00467     NS_ConvertWtoA(aBiW->lpszTitle, MAX_PATH, titleA, "?");
00468     biA.lpszTitle = titleA; 
00469   }
00470   biA.ulFlags = aBiW->ulFlags;
00471   biA.lpfn = aBiW->lpfn;
00472   biA.lParam = aBiW->lParam;
00473   biA.iImage = aBiW->iImage;
00474 
00475   itemIdList = SHBrowseForFolderA(&biA);
00476   if (biA.pszDisplayName)  {
00477     NS_ConvertAtoW(biA.pszDisplayName, MAX_PATH, aBiW->pszDisplayName);
00478   }
00479   return itemIdList;
00480 }
00481 #endif //#ifndef WINCE
00482 
00483 HMODULE             nsToolkit::mShell32Module = NULL;
00484 NS_DefWindowProc    nsToolkit::mDefWindowProc = DefWindowProcA;
00485 NS_CallWindowProc   nsToolkit::mCallWindowProc = CallWindowProcA;
00486 NS_SetWindowLong    nsToolkit::mSetWindowLong = SetWindowLongA;
00487 NS_GetWindowLong    nsToolkit::mGetWindowLong = GetWindowLongA;
00488 NS_SendMessage      nsToolkit::mSendMessage = nsSendMessage;
00489 NS_DispatchMessage  nsToolkit::mDispatchMessage = DispatchMessageA;
00490 NS_GetMessage       nsToolkit::mGetMessage = GetMessageA;
00491 NS_PeekMessage      nsToolkit::mPeekMessage = PeekMessageA;
00492 NS_GetOpenFileName  nsToolkit::mGetOpenFileName = nsGetOpenFileName;
00493 NS_GetSaveFileName  nsToolkit::mGetSaveFileName = nsGetSaveFileName;
00494 NS_GetClassName     nsToolkit::mGetClassName = nsGetClassName;
00495 NS_CreateWindowEx   nsToolkit::mCreateWindowEx = nsCreateWindowEx;
00496 NS_RegisterClass    nsToolkit::mRegisterClass = nsRegisterClass; 
00497 NS_UnregisterClass  nsToolkit::mUnregisterClass = nsUnregisterClass; 
00498 
00499 #ifndef WINCE
00500 NS_DragQueryFile        nsToolkit::mDragQueryFile = nsDragQueryFile;
00501 NS_SHGetPathFromIDList  nsToolkit::mSHGetPathFromIDList = nsSHGetPathFromIDList; 
00502 NS_SHBrowseForFolder    nsToolkit::mSHBrowseForFolder = nsSHBrowseForFolder; 
00503 #endif
00504 
00505 void RunPump(void* arg)
00506 {
00507     ThreadInitInfo *info = (ThreadInitInfo*)arg;
00508     ::PR_EnterMonitor(info->monitor);
00509 
00510     // Start Active Input Method Manager on this thread
00511     if(nsToolkit::gAIMMApp)
00512         nsToolkit::gAIMMApp->Activate(TRUE);
00513 
00514     // do registration and creation in this thread
00515     info->toolkit->CreateInternalWindow(PR_GetCurrentThread());
00516 
00517     gThreadState = PR_TRUE;
00518 
00519     ::PR_Notify(info->monitor);
00520     ::PR_ExitMonitor(info->monitor);
00521 
00522     delete info;
00523 
00524     // Process messages
00525     MSG msg;
00526     while (nsToolkit::mGetMessage(&msg, NULL, 0, 0)) {
00527         TranslateMessage(&msg);
00528         nsToolkit::mDispatchMessage(&msg);
00529     }
00530 }
00531 
00532 //-------------------------------------------------------------------------
00533 //
00534 // constructor
00535 //
00536 //-------------------------------------------------------------------------
00537 nsToolkit::nsToolkit()  
00538 {
00539     mGuiThread  = NULL;
00540     mDispatchWnd = 0;
00541 
00542     //
00543     // Initialize COM since create Active Input Method Manager object
00544     //
00545     if (!nsToolkit::gAIMMCount)
00546       ::CoInitialize(NULL);
00547 
00548     if(!nsToolkit::gAIMMApp)
00549       ::CoCreateInstance(CLSID_CActiveIMM, NULL, CLSCTX_INPROC_SERVER, IID_IActiveIMMApp, (void**) &nsToolkit::gAIMMApp);
00550 
00551     nsToolkit::gAIMMCount++;
00552 
00553 #if defined(MOZ_STATIC_COMPONENT_LIBS) || defined (WINCE)
00554     nsToolkit::Startup(GetModuleHandle(NULL));
00555 #endif
00556 }
00557 
00558 
00559 //-------------------------------------------------------------------------
00560 //
00561 // destructor
00562 //
00563 //-------------------------------------------------------------------------
00564 nsToolkit::~nsToolkit()
00565 {
00566     NS_PRECONDITION(::IsWindow(mDispatchWnd), "Invalid window handle");
00567 
00568     nsToolkit::gAIMMCount--;
00569 
00570     if (!nsToolkit::gAIMMCount) {
00571         if(nsToolkit::gAIMMApp) {
00572             nsToolkit::gAIMMApp->Deactivate();
00573             nsToolkit::gAIMMApp->Release();
00574             nsToolkit::gAIMMApp = NULL;
00575         }
00576         ::CoUninitialize();
00577     }
00578 
00579     // Destroy the Dispatch Window
00580     ::DestroyWindow(mDispatchWnd);
00581     mDispatchWnd = NULL;
00582 
00583     // Remove the TLS reference to the toolkit...
00584     PR_SetThreadPrivate(gToolkitTLSIndex, nsnull);
00585 
00586     // Remove reference to cached event queue
00587     gEventQueueService = nsnull;
00588 
00589     // Unhook the filter used to determine when
00590     // the user is moving a top-level window.
00591 #ifndef WINCE
00592     if (nsMsgFilterHook != NULL) {
00593       UnhookWindowsHookEx(nsMsgFilterHook);
00594       nsMsgFilterHook = NULL;
00595     }
00596 #endif
00597 
00598 #if defined (MOZ_STATIC_COMPONENT_LIBS) || defined(WINCE)
00599     nsToolkit::Shutdown();
00600 #endif
00601 }
00602 
00603 
00604 void
00605 nsToolkit::Startup(HMODULE hModule)
00606 {
00607 #ifndef WINCE
00608     //
00609     // Set flag of nsToolkit::mUseImeApiW due to using Unicode API.
00610     //
00611 
00612     OSVERSIONINFOEX osversion;
00613     BOOL osVersionInfoEx;
00614     
00615     ::ZeroMemory(&osversion, sizeof(OSVERSIONINFOEX));
00616     osversion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
00617 
00618     if (!(osVersionInfoEx = GetVersionEx((OSVERSIONINFO *)&osversion))) {
00619       // if OSVERSIONINFOEX doesn't work, try OSVERSIONINFO.
00620       osversion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
00621       if (!GetVersionEx((OSVERSIONINFO *)&osversion)) {
00622         // maybe we are running on very old Windows OS. Assign FALSE.
00623         nsToolkit::mUseImeApiW = PR_FALSE; 
00624         return;
00625       }
00626     }
00627 
00628     nsToolkit::mIsNT = (osversion.dwPlatformId == VER_PLATFORM_WIN32_NT);
00629     if (nsToolkit::mIsNT)
00630 #endif // #ifndef WINCE
00631 
00632     {
00633       // For Windows 9x base OS nsFoo is already pointing to A functions
00634       // However on NT base OS we should point them to respective W functions
00635       nsToolkit::mDefWindowProc = DefWindowProcW;
00636       nsToolkit::mCallWindowProc = CallWindowProcW;
00637       nsToolkit::mSetWindowLong = SetWindowLongW;
00638       nsToolkit::mGetWindowLong = GetWindowLongW; 
00639       nsToolkit::mSendMessage = SendMessageW;
00640       nsToolkit::mDispatchMessage = DispatchMessageW;
00641       nsToolkit::mGetMessage = GetMessageW;
00642       nsToolkit::mPeekMessage = PeekMessageW;
00643       nsToolkit::mGetOpenFileName = GetOpenFileNameW;
00644       nsToolkit::mGetSaveFileName = GetSaveFileNameW;
00645       nsToolkit::mGetClassName = GetClassNameW;
00646       nsToolkit::mCreateWindowEx = CreateWindowExW;
00647       nsToolkit::mRegisterClass = RegisterClassW; 
00648       nsToolkit::mUnregisterClass = UnregisterClassW; 
00649       // Explicit call of SHxxxW in Win95 makes moz fails to run (170969)
00650       // we use GetProcAddress() to hide
00651 #ifndef WINCE
00652       nsToolkit::mDragQueryFile = DragQueryFileW;
00653       nsToolkit::mShell32Module = ::LoadLibrary("Shell32.dll");
00654       if (nsToolkit::mShell32Module) {
00655         nsToolkit::mSHGetPathFromIDList = (NS_SHGetPathFromIDList)GetProcAddress(nsToolkit::mShell32Module, "SHGetPathFromIDListW"); 
00656         if (!nsToolkit::mSHGetPathFromIDList)
00657           nsToolkit::mSHGetPathFromIDList = &nsSHGetPathFromIDList;
00658         nsToolkit::mSHBrowseForFolder = (NS_SHBrowseForFolder)GetProcAddress(nsToolkit::mShell32Module, "SHBrowseForFolderW"); 
00659         if (!nsToolkit::mSHBrowseForFolder)
00660           nsToolkit::mSHBrowseForFolder = &nsSHBrowseForFolder;
00661       }
00662       nsToolkit::mUseImeApiW = PR_TRUE;
00663       // XXX Hack for stopping the crash (125573)
00664       if (osversion.dwMajorVersion == 5 && (osversion.dwMinorVersion == 0 || osversion.dwMinorVersion == 1))  { 
00665         nsToolkit::mIsWinXP = (osversion.dwMinorVersion == 1);
00666         // "Microsoft Windows 2000 " or "Microsoft Windows XP "
00667         if (936 == ::GetACP())  {  // Chinese (PRC, Singapore)
00668           nsToolkit::mUseImeApiW = PR_FALSE;
00669           nsToolkit::mW2KXP_CP936 = PR_TRUE;
00670         }
00671       }
00672 #endif // #ifndef WINCE
00673     }
00674     nsToolkit::mDllInstance = hModule;
00675 
00676     //
00677     // register the internal window class
00678     //
00679     WNDCLASSW wc;
00680     wc.style            = CS_GLOBALCLASS;
00681     wc.lpfnWndProc      = nsToolkit::WindowProc;
00682     wc.cbClsExtra       = 0;
00683     wc.cbWndExtra       = 0;
00684     wc.hInstance        = nsToolkit::mDllInstance;
00685     wc.hIcon            = NULL;
00686     wc.hCursor          = NULL;
00687     wc.hbrBackground    = NULL;
00688     wc.lpszMenuName     = NULL;
00689     wc.lpszClassName    = L"nsToolkitClass";
00690     VERIFY(nsToolkit::mRegisterClass(&wc));
00691 
00692     // Vista API.  Mozilla is DPI Aware.
00693     typedef BOOL (*SetProcessDPIAwareFunc)(VOID);
00694  
00695     SetProcessDPIAwareFunc setDPIAware = (SetProcessDPIAwareFunc)
00696       GetProcAddress(LoadLibrary("user32.dll"),
00697                      "SetProcessDPIAware");
00698     
00699     if (setDPIAware)
00700       setDPIAware();
00701 
00702 #ifdef WINCE
00703     nsToolkit::mUseImeApiW  = PR_TRUE;
00704 #endif
00705 
00706 }
00707 
00708 
00709 void
00710 nsToolkit::Shutdown()
00711 {
00712     if (nsToolkit::mShell32Module)
00713       ::FreeLibrary(nsToolkit::mShell32Module);
00714 
00715     //VERIFY(::UnregisterClass("nsToolkitClass", nsToolkit::mDllInstance));
00716     nsToolkit::mUnregisterClass(L"nsToolkitClass", nsToolkit::mDllInstance);
00717 }
00718 
00719 nsIEventQueue* 
00720 nsToolkit::GetEventQueue()
00721 {
00722   if (! gEventQueueService) {
00723     gEventQueueService = do_GetService(kEventQueueServiceCID);
00724   }
00725 
00726   if (gEventQueueService) {
00727     nsCOMPtr<nsIEventQueue> eventQueue;
00728     gEventQueueService->GetSpecialEventQueue(
00729       nsIEventQueueService::UI_THREAD_EVENT_QUEUE, 
00730       getter_AddRefs(eventQueue));
00731     return eventQueue;
00732   }
00733   
00734   return nsnull;
00735 }
00736 
00737 //-------------------------------------------------------------------------
00738 //
00739 // Register the window class for the internal window and create the window
00740 //
00741 //-------------------------------------------------------------------------
00742 void nsToolkit::CreateInternalWindow(PRThread *aThread)
00743 {
00744     
00745     NS_PRECONDITION(aThread, "null thread");
00746     mGuiThread  = aThread;
00747 
00748     //
00749     // create the internal window
00750     //
00751 
00752     mDispatchWnd = ::CreateWindow("nsToolkitClass",
00753                                   "NetscapeDispatchWnd",
00754                                   WS_DISABLED,
00755                                   -50, -50,
00756                                   10, 10,
00757                                   NULL,
00758                                   NULL,
00759                                   nsToolkit::mDllInstance,
00760                                   NULL);
00761 
00762     VERIFY(mDispatchWnd);
00763 }
00764 
00765 
00766 //-------------------------------------------------------------------------
00767 //
00768 // Create a new thread and run the message pump in there
00769 //
00770 //-------------------------------------------------------------------------
00771 void nsToolkit::CreateUIThread()
00772 {
00773     PRMonitor *monitor = ::PR_NewMonitor();
00774 
00775     ::PR_EnterMonitor(monitor);
00776 
00777     ThreadInitInfo *ti = new ThreadInitInfo();
00778     ti->monitor = monitor;
00779     ti->toolkit = this;
00780 
00781     // create a gui thread
00782     mGuiThread = ::PR_CreateThread(PR_SYSTEM_THREAD,
00783                                     RunPump,
00784                                     (void*)ti,
00785                                     PR_PRIORITY_NORMAL,
00786                                     PR_LOCAL_THREAD,
00787                                     PR_UNJOINABLE_THREAD,
00788                                     0);
00789 
00790     // wait for the gui thread to start
00791     while(gThreadState == PR_FALSE) {
00792         ::PR_Wait(monitor, PR_INTERVAL_NO_TIMEOUT);
00793     }
00794 
00795     // at this point the thread is running
00796     ::PR_ExitMonitor(monitor);
00797     ::PR_DestroyMonitor(monitor);
00798 }
00799 
00800 
00801 //-------------------------------------------------------------------------
00802 //
00803 //
00804 //-------------------------------------------------------------------------
00805 NS_METHOD nsToolkit::Init(PRThread *aThread)
00806 {
00807     // Store the thread ID of the thread containing the message pump.  
00808     // If no thread is provided create one
00809     if (NULL != aThread) {
00810         // Start Active Input Method Manager on this thread
00811         if(nsToolkit::gAIMMApp)
00812             nsToolkit::gAIMMApp->Activate(TRUE);
00813         CreateInternalWindow(aThread);
00814     } else {
00815         // create a thread where the message pump will run
00816         CreateUIThread();
00817     }
00818 
00819 #ifndef WINCE
00820     // Hook window move messages so the toolkit can report when
00821     // the user is moving a top-level window.
00822     if (nsMsgFilterHook == NULL) {
00823       nsMsgFilterHook = SetWindowsHookEx(WH_CALLWNDPROC, DetectWindowMove, 
00824                                                 NULL, GetCurrentThreadId());
00825     }
00826 #endif
00827 
00828     return NS_OK;
00829 }
00830 
00831 PRBool nsToolkit::UserIsMovingWindow(void)
00832 {
00833     return gIsMovingWindow;
00834 }
00835 
00836 //-------------------------------------------------------------------------
00837 //
00838 // nsToolkit WindowProc. Used to call methods on the "main GUI thread"...
00839 //
00840 //-------------------------------------------------------------------------
00841 LRESULT CALLBACK nsToolkit::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, 
00842                                             LPARAM lParam)
00843 {
00844     switch (msg) {
00845         case WM_CALLMETHOD:
00846         {
00847             MethodInfo *info = (MethodInfo *)lParam;
00848             return info->Invoke();
00849         }
00850 
00851         case WM_SYSCOLORCHANGE:
00852         {
00853           // WM_SYSCOLORCHANGE messages are only dispatched to top
00854           // level windows but NS_SYSCOLORCHANGE messages must be dispatched
00855           // to all windows including child windows. We dispatch these messages 
00856           // from the nsToolkit because if we are running embedded we may not 
00857           // have a top-level nsIWidget window.
00858           
00859           // On WIN32 all windows are automatically invalidated after the 
00860           // WM_SYSCOLORCHANGE is dispatched so the window is drawn using
00861           // the current system colors.
00862           nsWindow::GlobalMsgWindowProc(hWnd, msg, wParam, lParam);
00863         }
00864 
00865     }
00866 
00867     if(nsToolkit::gAIMMApp) {
00868         LRESULT lResult;
00869         if (nsToolkit::gAIMMApp->OnDefWindowProc(hWnd, msg, wParam, lParam, &lResult) == S_OK)
00870             return lResult;
00871     }
00872     return nsToolkit::mDefWindowProc(hWnd, msg, wParam, lParam);
00873 }
00874 
00875 
00876 
00877 //-------------------------------------------------------------------------
00878 //
00879 // Return the nsIToolkit for the current thread.  If a toolkit does not
00880 // yet exist, then one will be created...
00881 //
00882 //-------------------------------------------------------------------------
00883 NS_METHOD NS_GetCurrentToolkit(nsIToolkit* *aResult)
00884 {
00885   nsIToolkit* toolkit = nsnull;
00886   nsresult rv = NS_OK;
00887   PRStatus status;
00888 
00889   // Create the TLS index the first time through...
00890   if (0 == gToolkitTLSIndex) {
00891     status = PR_NewThreadPrivateIndex(&gToolkitTLSIndex, NULL);
00892     if (PR_FAILURE == status) {
00893       rv = NS_ERROR_FAILURE;
00894     }
00895   }
00896 
00897   if (NS_SUCCEEDED(rv)) {
00898     toolkit = (nsIToolkit*)PR_GetThreadPrivate(gToolkitTLSIndex);
00899 
00900     //
00901     // Create a new toolkit for this thread...
00902     //
00903     if (!toolkit) {
00904       toolkit = new nsToolkit();
00905 
00906       if (!toolkit) {
00907         rv = NS_ERROR_OUT_OF_MEMORY;
00908       } else {
00909         NS_ADDREF(toolkit);
00910         toolkit->Init(PR_GetCurrentThread());
00911         //
00912         // The reference stored in the TLS is weak.  It is removed in the
00913         // nsToolkit destructor...
00914         //
00915         PR_SetThreadPrivate(gToolkitTLSIndex, (void*)toolkit);
00916       }
00917     } else {
00918       NS_ADDREF(toolkit);
00919     }
00920     *aResult = toolkit;
00921   }
00922 
00923   return rv;
00924 }
00925 
00926 //-------------------------------------------------------------------------
00927 //
00928 //
00929 //-------------------------------------------------------------------------
00930 MouseTrailer::MouseTrailer() : mHoldMouseWindow(nsnull), mCaptureWindow(nsnull),
00931   mIsInCaptureMode(PR_FALSE), mIgnoreNextCycle(PR_FALSE)
00932 {
00933 }
00934 //-------------------------------------------------------------------------
00935 //
00936 //
00937 //-------------------------------------------------------------------------
00938 MouseTrailer::~MouseTrailer()
00939 {
00940   DestroyTimer();
00941   NS_IF_RELEASE(mHoldMouseWindow);
00942   NS_IF_RELEASE(mCaptureWindow);
00943 }
00944 //-------------------------------------------------------------------------
00945 //
00946 //
00947 //-------------------------------------------------------------------------
00948 void MouseTrailer::SetMouseTrailerWindow(nsWindow * aNSWin) 
00949 {
00950   nsWindow *topWin = aNSWin ? aNSWin->GetTopLevelWindow() : nsnull;
00951   if (mHoldMouseWindow != topWin && mTimer) {
00952     // Make sure TimerProc is fired at least once for the old window
00953     TimerProc(nsnull, nsnull);
00954   }
00955   NS_IF_RELEASE(mHoldMouseWindow);
00956   mHoldMouseWindow = topWin;
00957   CreateTimer();
00958 }
00959 //-------------------------------------------------------------------------
00960 //
00961 //
00962 //-------------------------------------------------------------------------
00963 nsresult MouseTrailer::CreateTimer()
00964 {
00965   if (mTimer) {
00966     return NS_OK;
00967   } 
00968 
00969   nsresult rv;
00970   mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
00971   NS_ENSURE_SUCCESS(rv, rv);
00972 
00973   return mTimer->InitWithFuncCallback(TimerProc, nsnull, 200,
00974                                       nsITimer::TYPE_REPEATING_SLACK);
00975 }
00976 
00977 
00978 //-------------------------------------------------------------------------
00979 //
00980 //
00981 //-------------------------------------------------------------------------
00982 void MouseTrailer::DestroyTimer()
00983 {
00984   if (mTimer) {
00985     mTimer->Cancel();
00986     mTimer = nsnull;
00987   }
00988 }
00989 //-------------------------------------------------------------------------
00990 //
00991 //
00992 //-------------------------------------------------------------------------
00993 void MouseTrailer::SetCaptureWindow(nsWindow * aNSWin) 
00994 { 
00995   NS_IF_RELEASE(mCaptureWindow);
00996   mCaptureWindow = aNSWin ? aNSWin->GetTopLevelWindow() : nsnull;
00997   if (nsnull != mCaptureWindow) {
00998     mIsInCaptureMode = PR_TRUE;
00999   }
01000 }
01001 //-------------------------------------------------------------------------
01002 //
01003 //
01004 //-------------------------------------------------------------------------
01005 void MouseTrailer::TimerProc(nsITimer* aTimer, void* aClosure)
01006 {
01007   // Check to see if we are in mouse capture mode,
01008   // Once capture ends we could still get back one more timer event 
01009   // Capture could end outside our window
01010   // Also, for some reason when the mouse is on the frame it thinks that
01011   // it is inside the window that is being captured.
01012   if (nsnull != mSingleton.mCaptureWindow) {
01013     if (mSingleton.mCaptureWindow != mSingleton.mHoldMouseWindow) {
01014       return;
01015     }
01016   } else {
01017     if (mSingleton.mIsInCaptureMode) {
01018       // The mHoldMouse could be bad from rolling over the frame, so clear 
01019       // it if we were capturing and now this is the first timer call back 
01020       // since we canceled the capture
01021       NS_IF_RELEASE(mSingleton.mHoldMouseWindow);
01022       mSingleton.mIsInCaptureMode = PR_FALSE;
01023       return;
01024     }
01025   }
01026 
01027   if (mSingleton.mHoldMouseWindow && ::IsWindow(mSingleton.mHoldMouseWindow->GetWindowHandle())) {
01028     if (mSingleton.mIgnoreNextCycle) {
01029       mSingleton.mIgnoreNextCycle = PR_FALSE;
01030     }
01031     else {
01032       POINT mp;
01033       DWORD pos = ::GetMessagePos();
01034       mp.x = GET_X_LPARAM(pos);
01035       mp.y = GET_Y_LPARAM(pos);
01036 
01037       // Need to get the top level wnd's here. Although mHoldMouseWindow is top level,
01038       // the actual top level window handle might be something else
01039       HWND mouseWnd = nsWindow::GetTopLevelHWND(::WindowFromPoint(mp), PR_TRUE);
01040       HWND holdWnd = nsWindow::GetTopLevelHWND(mSingleton.mHoldMouseWindow->GetWindowHandle(), PR_TRUE);
01041       if (mouseWnd != holdWnd) {
01042         //notify someone that a mouse exit happened
01043         if (nsnull != mSingleton.mHoldMouseWindow) {
01044           mSingleton.mHoldMouseWindow->DispatchMouseEvent(NS_MOUSE_EXIT, NULL, NULL);
01045         }
01046 
01047         // we are out of this window and of any window, destroy timer
01048         mSingleton.DestroyTimer();
01049         NS_IF_RELEASE(mSingleton.mHoldMouseWindow);
01050       }
01051     }
01052   } else {
01053     mSingleton.DestroyTimer();
01054     NS_IF_RELEASE(mSingleton.mHoldMouseWindow);
01055   }
01056 }
01057