Back to index

lightning-sunbird  0.9+nobinonly
EventFilter.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or 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 /*
00039        EventFilter.cpp
00040        
00041        Provides a generalized event filtering service.
00042        
00043        Patches WaitNextEvent for events, and MenuSelect for menus.
00044        
00045        by Patrick C. Beard.
00046  */
00047 
00048 #include "EventFilter.h"
00049 
00050 #include <MixedMode.h>
00051 #include <Memory.h>
00052 #include <LowMem.h>
00053 #include <Menus.h>
00054 #include <Patches.h>
00055 #include <Traps.h>
00056 
00057 enum {
00058        uppWaitNextEventProcInfo = kPascalStackBased
00059               | RESULT_SIZE(SIZE_CODE(sizeof(Boolean)))
00060               | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(EventMask)))
00061               | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(EventRecord*)))
00062               | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(UInt32)))
00063               | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(RgnHandle))),
00064        uppMenuSelectProcInfo = kPascalStackBased
00065               | RESULT_SIZE(SIZE_CODE(sizeof(long)))
00066               | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(Point)))
00067 };
00068 
00069 static pascal Boolean NewWaitNextEvent(EventMask eventMask, EventRecord* event, UInt32 sleep, RgnHandle mouseRgn);
00070 static pascal long NewMenuSelect(Point where);
00071 
00072 enum {
00073        kIsToolboxTrap = (1 << 11)
00074 };
00075 
00076 inline TrapType getTrapType(UInt16 trapNum)
00077 {
00078        return ((trapNum & kIsToolboxTrap) != 0 ? kToolboxTrapType : kOSTrapType);
00079 }
00080 
00081 static UniversalProcPtr SwapTrapAddress(UInt16 trapNum, UniversalProcPtr newTrapAddress)
00082 {
00083        TrapType type = getTrapType(trapNum);
00084        UniversalProcPtr oldTrapAddress = NGetTrapAddress(trapNum, type);
00085        NSetTrapAddress(newTrapAddress, trapNum, type);
00086        return oldTrapAddress;
00087 }
00088 
00089 struct Patch {
00090        UInt16 trap;
00091        RoutineDescriptor descriptor;
00092        UniversalProcPtr original;
00093 
00094        void Install() { original = SwapTrapAddress(trap, &descriptor); }
00095        void Remove() { SwapTrapAddress(trap, original); original = NULL; }
00096 };
00097 
00098 static Patch WaitNextEventPatch = {
00099        _WaitNextEvent,
00100        BUILD_ROUTINE_DESCRIPTOR(uppWaitNextEventProcInfo, NewWaitNextEvent),
00101        NULL
00102 };
00103 
00104 static Patch MenuSelectPatch = {
00105        _MenuSelect,
00106        BUILD_ROUTINE_DESCRIPTOR(uppMenuSelectProcInfo, NewMenuSelect),
00107        NULL
00108 };
00109 
00110 static EventFilterProcPtr theEventFilter;
00111 static MenuFilterProcPtr theMenuFilter;
00112 
00113 OSStatus InstallEventFilters(EventFilterProcPtr eventFilter, MenuFilterProcPtr menuFilter)
00114 {
00115        if (theEventFilter == NULL) {
00116               theEventFilter = eventFilter;
00117               theMenuFilter = menuFilter;
00118 
00119               // Patch WNE, which will be used to filter events.
00120               WaitNextEventPatch.Install();
00121               
00122               // Patch MenuSelect, which will be used to filter menu selections.
00123               MenuSelectPatch.Install();
00124 
00125               return noErr;
00126        }
00127        return paramErr;
00128 }
00129 
00130 OSStatus RemoveEventFilters()
00131 {
00132        if (theEventFilter != NULL) {
00133               WaitNextEventPatch.Remove();
00134               MenuSelectPatch.Remove();
00135               
00136               theEventFilter = NULL;
00137               theMenuFilter = NULL;
00138               
00139               return noErr;
00140        }
00141        return paramErr;
00142 }
00143 
00144 static pascal Boolean NewWaitNextEvent(EventMask eventMask, EventRecord* event, UInt32 sleep, RgnHandle mouseRgn)
00145 {
00146        Boolean gotEvent = CALL_FOUR_PARAMETER_UPP(WaitNextEventPatch.original, uppWaitNextEventProcInfo, eventMask, event, sleep, mouseRgn);
00147        if (true) {
00148               // prevent recursive calls to the filter.
00149               static Boolean inFilter = false;
00150               if (! inFilter) {
00151                      inFilter = true;
00152                      Boolean filteredEvent = theEventFilter(event);
00153                      if (filteredEvent) {
00154                             // consume the event by making it a nullEvent.
00155                             event->what = nullEvent;
00156                             gotEvent = false;
00157                      }
00158                      inFilter = false;
00159               }
00160        }
00161        return gotEvent;
00162 }
00163 
00164 static pascal long NewMenuSelect(Point where)
00165 {
00166        long menuSelection = CALL_ONE_PARAMETER_UPP(MenuSelectPatch.original, uppMenuSelectProcInfo, where);
00167        if (menuSelection != 0) {
00168               Boolean filteredEvent = theMenuFilter(menuSelection);
00169               if (filteredEvent) {
00170                      // consume the menu selection by zeroing it out.
00171                      menuSelection = 0;
00172               }
00173        }
00174        return menuSelection;
00175 }