Back to index

lightning-sunbird  0.9+nobinonly
AltWindowHandling.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is mozilla.org code.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1998
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either of the GNU General Public License Version 2 or later (the "GPL"),
00025  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038     AltWindowHandling.cpp
00039     
00040     Due to a hole in the OJI API, 6.x still not able to open a new
00041     window from Java w/o a hack.  thePluginManager2->RegisterWindow
00042     is doing nothing.  Here I add Patrick's workaround used in 4.x.
00043     File will be used from TopLevelFrame::showHide()
00044     This code comes from the CPluginManager class in BackwardAdaptor.cpp.
00045     If the API is fixed, can remove this file and the two calls to it.
00046     
00047  */
00048 
00049 #include <Controls.h>
00050 #include <Events.h>
00051 
00052 #include "nsIPluginManager2.h"
00053 #include "EventFilter.h"
00054 #include "nsIEventHandler.h"
00055 
00056 #include "AltWindowHandling.h"
00057 
00058 RegisteredWindow* theRegisteredWindows = NULL;
00059 RegisteredWindow* theActiveWindow = NULL;
00060 Boolean mEventFiltersInstalled = nil;
00061 
00062 Boolean EventFilter(EventRecord* event);
00063 Boolean MenuFilter(long menuSelection);
00064 RegisteredWindow** GetRegisteredWindow(nsPluginPlatformWindowRef window);
00065 
00066 NS_METHOD
00067 AltRegisterWindow(nsIEventHandler* handler, nsPluginPlatformWindowRef window)
00068 {
00069     theRegisteredWindows = new RegisteredWindow(theRegisteredWindows, handler, window);
00070     
00071 #ifdef XP_MAC
00072     // use jGNE to obtain events for registered windows.
00073     if (!mEventFiltersInstalled) {
00074         ::InstallEventFilters(&EventFilter, &MenuFilter);
00075         mEventFiltersInstalled = true;
00076     }
00077 
00078     // plugin expects the window to be shown and selected at this point.
00079     
00080     SInt16 variant = ::GetWVariant(window);
00081     if (variant == plainDBox) {
00082         ::ShowHide(window, true);
00083         ::BringToFront(window);
00084     } else {
00085         ::ShowWindow(window);
00086         ::SelectWindow(window);
00087     }
00088 #endif
00089 
00090     return NS_OK;
00091 }
00092 
00093 NS_METHOD
00094 AltUnregisterWindow(nsIEventHandler* handler, nsPluginPlatformWindowRef window)
00095 {
00096     RegisteredWindow** link = GetRegisteredWindow(window);
00097     if (link != NULL) {
00098         RegisteredWindow* registeredWindow = *link;
00099         if (registeredWindow == theActiveWindow)
00100             theActiveWindow = NULL;
00101         *link = registeredWindow->mNext;
00102         delete registeredWindow;
00103     }
00104 
00105 #ifdef XP_MAC
00106     ::HideWindow(window);
00107 
00108     // if no windows registered, remove the filter.
00109     if (theRegisteredWindows == NULL) {
00110         ::RemoveEventFilters();
00111         mEventFiltersInstalled = false;
00112     }
00113 #endif
00114 
00115     return NS_OK;
00116 }
00117 
00118 static void sendActivateEvent(nsIEventHandler* handler, WindowRef window, Boolean active)
00119 {
00120     EventRecord event;
00121     ::OSEventAvail(0, &event);
00122     event.what = activateEvt;
00123     event.message = UInt32(window);
00124     if (active)
00125         event.modifiers |= activeFlag;
00126     else
00127         event.modifiers &= ~activeFlag;
00128 
00129     nsPluginEvent pluginEvent = { &event, window };
00130     PRBool handled = PR_FALSE;
00131 
00132     handler->HandleEvent(&pluginEvent, &handled);
00133 }
00134 
00135 RegisteredWindow** GetRegisteredWindow(nsPluginPlatformWindowRef window)
00136 {
00137     RegisteredWindow** link = &theRegisteredWindows;
00138     RegisteredWindow* registeredWindow = *link;
00139     while (registeredWindow != NULL) {
00140         if (registeredWindow->mWindow == window)
00141             return link;
00142         link = &registeredWindow->mNext;
00143         registeredWindow = *link;
00144     }
00145     return NULL;
00146 }
00147 RegisteredWindow* FindRegisteredWindow(nsPluginPlatformWindowRef window);
00148 RegisteredWindow* FindRegisteredWindow(nsPluginPlatformWindowRef window)
00149 {
00150     RegisteredWindow** link = GetRegisteredWindow(window);
00151     return (link != NULL ? *link : NULL);
00152 }
00153 
00161 Boolean EventFilter(EventRecord* event)
00162 {
00163     Boolean filteredEvent = false;
00164 
00165     WindowRef window = WindowRef(event->message);
00166     nsPluginEvent pluginEvent = { event, window };
00167     EventRecord simulatedEvent;
00168 
00169     RegisteredWindow* registeredWindow;
00170     PRBool handled = PR_FALSE;
00171     
00172     // see if this event is for one of our registered windows.
00173     switch (event->what) {
00174     case nullEvent:
00175         // See if the frontmost window is one of our registered windows.
00176         // we want to somehow deliver mouse enter/leave events.
00177         window = ::FrontWindow();
00178         registeredWindow = FindRegisteredWindow(window);
00179         if (registeredWindow != NULL) {
00180             simulatedEvent = *event;
00181             simulatedEvent.what = nsPluginEventType_AdjustCursorEvent;
00182             pluginEvent.event = &simulatedEvent;
00183             pluginEvent.window = registeredWindow->mWindow;
00184             registeredWindow->mHandler->HandleEvent(&pluginEvent, &handled);
00185         }
00186         break;
00187     case keyDown:
00188     case keyUp:
00189     case autoKey:
00190         // See if the frontmost window is one of our registered windows.
00191         window = ::FrontWindow();
00192         registeredWindow = FindRegisteredWindow(window);
00193         if (registeredWindow != NULL) {
00194             pluginEvent.window = window;
00195             registeredWindow->mHandler->HandleEvent(&pluginEvent, &handled);
00196             filteredEvent = true;
00197         }
00198         break;
00199     case mouseDown:
00200         // use FindWindow to see if the click was in one our registered windows.
00201         short partCode = FindWindow(event->where, &window);
00202         switch (partCode) {
00203         case inContent:
00204         case inDrag:
00205         case inGrow:
00206         case inGoAway:
00207         case inZoomIn:
00208         case inZoomOut:
00209         case inCollapseBox:
00210         case inProxyIcon:
00211             registeredWindow = FindRegisteredWindow(window);
00212             if (registeredWindow != NULL) {
00213                 // make sure this window has been activated before passing it the click.
00214                 if (theActiveWindow == NULL) {
00215                     sendActivateEvent(registeredWindow->mHandler, window, true);
00216                     theActiveWindow = registeredWindow;
00217                 }
00218                 pluginEvent.window = window;
00219                 registeredWindow->mHandler->HandleEvent(&pluginEvent, &handled);
00220                 filteredEvent = true;
00221             } else if (theActiveWindow != NULL) {
00222                 // a click is going into an unregistered window, if we are active,
00223                 // the browser doesn't seem to be generating a deactivate event.
00224                 // I think this is because PowerPlant is managing the windows, dang it.
00225                 window = theActiveWindow->mWindow;
00226                 sendActivateEvent(theActiveWindow->mHandler, window, false);
00227                 ::HiliteWindow(window, false);
00228                 theActiveWindow = NULL;
00229             }
00230             break;
00231         }
00232         break;
00233     case activateEvt:
00234         registeredWindow = FindRegisteredWindow(window);
00235         if (registeredWindow != NULL) {
00236             registeredWindow->mHandler->HandleEvent(&pluginEvent, &handled);
00237             filteredEvent = true;
00238             theActiveWindow = registeredWindow;
00239         }
00240         break;
00241     case updateEvt:
00242         registeredWindow = FindRegisteredWindow(window);
00243         if (registeredWindow != NULL) {
00244             GrafPtr port; GetPort(&port); SetPort(window); BeginUpdate(window);
00245                 registeredWindow->mHandler->HandleEvent(&pluginEvent, &handled);
00246             EndUpdate(window); SetPort(port);
00247             filteredEvent = true;
00248         }
00249         break;
00250     case osEvt:
00251         if ((event->message & osEvtMessageMask) == (suspendResumeMessage << 24)) {
00252             registeredWindow = theActiveWindow;
00253             if (registeredWindow != NULL) {
00254                 window = registeredWindow->mWindow;
00255                 Boolean active = (event->message & resumeFlag) != 0;
00256                 sendActivateEvent(registeredWindow->mHandler, window, active);
00257                 pluginEvent.window = window;
00258                 registeredWindow->mHandler->HandleEvent(&pluginEvent, &handled);
00259                 ::HiliteWindow(window, active);
00260             }
00261         }
00262         break;
00263     }
00264     
00265     return filteredEvent;
00266 }
00267 
00268 // TODO:  find out what range of menus Communicator et. al. uses.
00269 enum {
00270     kBaseMenuID = 20000,
00271     kBaseSubMenuID = 200
00272 };
00273 
00274 static PRInt16 nextMenuID = kBaseMenuID;
00275 static PRInt16 nextSubMenuID = kBaseSubMenuID;
00276 
00277 Boolean MenuFilter(long menuSelection)
00278 {
00279     if (theActiveWindow != NULL) {
00280         UInt16 menuID = (menuSelection >> 16);
00281         if ((menuID >= kBaseMenuID && menuID < nextMenuID) || (menuID >= kBaseSubMenuID && menuID < nextSubMenuID)) {
00282             EventRecord menuEvent;
00283             ::OSEventAvail(0, &menuEvent);
00284             menuEvent.what = nsPluginEventType_MenuCommandEvent;
00285             menuEvent.message = menuSelection;
00286 
00287             WindowRef window = theActiveWindow->mWindow;
00288             nsPluginEvent pluginEvent = { &menuEvent, window };
00289             PRBool handled = PR_FALSE;
00290             theActiveWindow->mHandler->HandleEvent(&pluginEvent, &handled);
00291             
00292             return handled;
00293         }
00294     }
00295     return false;
00296 }