Back to index

lightning-sunbird  0.9+nobinonly
nsAppShell.cpp
Go to the documentation of this file.
00001 /* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
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  *   Peter Hartshorn <peter@igelaus.com.au>
00024  *   Ken Faulkner <faulkner@igelaus.com.au>
00025  *   Tony Tsui <tony@igelaus.com.au>
00026  *   Caspian Maclean <caspian@igelaus.com.au>
00027  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either the GNU General Public License Version 2 or later (the "GPL"), or
00031  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 
00043 #include <stdlib.h>
00044 #include <sys/time.h>
00045 #include <unistd.h>
00046 #include <ctype.h>
00047 #include <errno.h>
00048 #include <X11/keysym.h>
00049 #include <X11/keysymdef.h>
00050 #include <X11/Xlocale.h>
00051 
00052 #include "nsWindow.h"
00053 #include "nsWidget.h"
00054 #include "nsAppShell.h"
00055 #include "nsKeyCode.h"
00056 #include "nsWidgetsCID.h"
00057 
00058 #include "nsIWidget.h"
00059 #include "nsIEventQueueService.h"
00060 #include "nsIServiceManager.h"
00061 #include "nsIDragService.h"
00062 #include "nsIDragSessionXlib.h"
00063 #include "nsITimer.h"
00064 
00065 #include "xlibrgb.h"
00066 
00067 #define CHAR_BUF_SIZE 80
00068 
00069 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00070 static NS_DEFINE_IID(kCDragServiceCID,  NS_DRAGSERVICE_CID);
00071 
00072 /* nsAppShell static members */
00073 Display *nsAppShell::mDisplay = nsnull;
00074 XlibRgbHandle *nsAppShell::mXlib_rgb_handle = nsnull;
00075 XtAppContext nsAppShell::mAppContext;
00076 PRTime nsAppShell::mClickTime = 0;
00077 PRInt16 nsAppShell::mClicks = 1;
00078 PRUint16 nsAppShell::mClickedButton = 0;
00079 PRPackedBool nsAppShell::mClicked = PR_FALSE;
00080 PRPackedBool nsAppShell::mDragging  = PR_FALSE;
00081 PRPackedBool nsAppShell::mAltDown   = PR_FALSE;
00082 PRPackedBool nsAppShell::mShiftDown = PR_FALSE;
00083 PRPackedBool nsAppShell::mCtrlDown  = PR_FALSE;
00084 PRPackedBool nsAppShell::mMetaDown  = PR_FALSE;
00085 PRPackedBool nsAppShell::DieAppShellDie = PR_FALSE;
00086 
00087 static PLHashTable *sQueueHashTable = nsnull;
00088 static PLHashTable *sCountHashTable = nsnull;
00089 static nsVoidArray *sEventQueueList = nsnull;
00090 
00091 
00092 // For debugging.
00093 static const char *event_names[] = 
00094 {
00095   "",
00096   "",
00097   "KeyPress",
00098   "KeyRelease",
00099   "ButtonPress",
00100   "ButtonRelease",
00101   "MotionNotify",
00102   "EnterNotify",
00103   "LeaveNotify",
00104   "FocusIn",
00105   "FocusOut",
00106   "KeymapNotify",
00107   "Expose",
00108   "GraphicsExpose",
00109   "NoExpose",
00110   "VisibilityNotify",
00111   "CreateNotify",
00112   "DestroyNotify",
00113   "UnmapNotify",
00114   "MapNotify",
00115   "MapRequest",
00116   "ReparentNotify",
00117   "ConfigureNotify",
00118   "ConfigureRequest",
00119   "GravityNotify",
00120   "ResizeRequest",
00121   "CirculateNotify",
00122   "CirculateRequest",
00123   "PropertyNotify",
00124   "SelectionClear",
00125   "SelectionRequest",
00126   "SelectionNotify",
00127   "ColormapNotify",
00128   "ClientMessage",
00129   "MappingNotify"
00130 };
00131 
00132 #define COMPARE_FLAG1( a,b) ((b)[0]=='-' && !strcmp((a), &(b)[1]))
00133 #define COMPARE_FLAG2( a,b) ((b)[0]=='-' && (b)[1]=='-' && !strcmp((a), &(b)[2]))
00134 #define COMPARE_FLAG12(a,b) ((b)[0]=='-' && !strcmp((a), (b)[1]=='-'?&(b)[2]:&(b)[1]))
00135 
00136 #define ALL_EVENTS ( KeyPressMask | KeyReleaseMask | ButtonPressMask | \
00137                      ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | \
00138                      PointerMotionMask | PointerMotionHintMask | Button1MotionMask | \
00139                      Button2MotionMask | Button3MotionMask | \
00140                      Button4MotionMask | Button5MotionMask | ButtonMotionMask | \
00141                      KeymapStateMask | ExposureMask | VisibilityChangeMask | \
00142                      StructureNotifyMask | ResizeRedirectMask | \
00143                      SubstructureNotifyMask | SubstructureRedirectMask | \
00144                      FocusChangeMask | PropertyChangeMask | \
00145                      ColormapChangeMask | OwnerGrabButtonMask )
00146 
00147 nsAppShell::nsAppShell()  
00148 { 
00149   if (!sEventQueueList)
00150     sEventQueueList = new nsVoidArray();
00151 
00152   mEventQueue = nsnull;
00153 }
00154 
00155 NS_IMPL_ISUPPORTS1(nsAppShell, nsIAppShell)
00156 
00157 PR_BEGIN_EXTERN_C
00158 static 
00159 int xerror_handler( Display *display, XErrorEvent *ev )
00160 {
00161   /* this should _never_ be happen... but if this happens - debug mode or not - scream !!! */
00162   char errmsg[80];
00163   XGetErrorText(display, ev->error_code, errmsg, sizeof(errmsg));
00164   fprintf(stderr, "nsAppShellXlib: Warning (X Error) -  %s\n", errmsg);
00165   abort(); // die !!
00166   
00167   return 0;
00168 }
00169 PR_END_EXTERN_C
00170 
00171 NS_METHOD nsAppShell::Create(int* bac, char ** bav)
00172 {
00173   /* Create the Xt Application context... */
00174   if (mAppContext == nsnull) {
00175     int      argc = bac ? *bac : 0;
00176     char   **argv = bav;
00177     nsresult rv;
00178 
00179     char        *displayName    = nsnull;
00180     Bool         synchronize    = False;
00181     int          i;
00182     XlibRgbArgs  xargs;
00183     memset(&xargs, 0, sizeof(xargs));
00184     /* Use a "well-known" name that other modules can "look-up" this handle
00185      * via |xxlib_find_handle| ... */
00186     xargs.handle_name = XXLIBRGB_DEFAULT_HANDLE;
00187 
00188     for (i = 0; ++i < argc-1; ) {
00189       /* allow both --display and -display */
00190       if (COMPARE_FLAG12 ("display", argv[i])) {
00191         displayName=argv[i+1];
00192         break;
00193       }
00194     }
00195     for (i = 0; ++i < argc-1; ) {
00196       if (COMPARE_FLAG1 ("visual", argv[i])) {
00197         xargs.xtemplate_mask |= VisualIDMask;
00198         xargs.xtemplate.visualid = strtol(argv[i+1], NULL, 0);
00199         break;
00200       }
00201     }   
00202     for (i = 0; ++i < argc; ) {
00203       if (COMPARE_FLAG1 ("sync", argv[i])) {
00204         synchronize = True;
00205         break;
00206       }
00207     }
00208     for (i = 0; ++i < argc; ) {
00209       /* allow both --no-xshm and -no-xshm */
00210       if (COMPARE_FLAG12 ("no-xshm", argv[i])) {
00211         xargs.disallow_mit_shmem = True;
00212         break;
00213       }
00214     }    
00215     for (i = 0; ++i < argc; ) {
00216       if (COMPARE_FLAG1 ("install_colormap", argv[i])) {
00217         xargs.install_colormap = True;
00218         break;
00219       }
00220     }
00221     
00222     /* setup locale */
00223     if (!setlocale (LC_ALL,""))
00224       NS_WARNING("locale not supported by C library");
00225   
00226     if (!XSupportsLocale ()) {
00227       NS_WARNING("locale not supported by Xlib, locale set to C");
00228       setlocale (LC_ALL, "C");
00229     }
00230   
00231     if (!XSetLocaleModifiers (""))
00232       NS_WARNING("can not set locale modifiers");
00233 
00234     XtToolkitInitialize();
00235     mAppContext = XtCreateApplicationContext();
00236 
00237     if (!(mDisplay = XtOpenDisplay (mAppContext, displayName, 
00238                                     "Mozilla5", "Mozilla5", nsnull, 0, 
00239                                     &argc, argv))) 
00240     {
00241       fprintf (stderr, "%s:  unable to open display \"%s\"\n", argv[0], XDisplayName(displayName));
00242       exit (EXIT_FAILURE);
00243     }
00244     
00245     // Requires XSynchronize(mDisplay, True); To stop X buffering. Use this
00246     // to make debugging easier. KenF
00247     if (synchronize)
00248     {
00249       /* Set error handler which calls abort() - only usefull with an 
00250        * unbuffered X connection */
00251       (void)XSetErrorHandler(xerror_handler);
00252       
00253       NS_WARNING("running via unbuffered X connection.");
00254       XSynchronize(mDisplay, True);
00255     }
00256        
00257     mXlib_rgb_handle = xxlib_rgb_create_handle(mDisplay, XDefaultScreenOfDisplay(mDisplay),
00258                                                &xargs);
00259     if (!mXlib_rgb_handle)
00260     {
00261       fprintf (stderr, "%s:  unable to create Xlib context\n", argv[0]);
00262       exit (EXIT_FAILURE);
00263     }
00264   }
00265 
00266   PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("nsAppShell::Create(dpy=%p)\n",
00267          mDisplay));
00268 
00269   return NS_OK;
00270 }
00271 
00272 NS_IMETHODIMP nsAppShell::Spinup()
00273 {
00274   nsresult rv = NS_OK;
00275 
00276 #ifdef DEBUG_APPSHELL
00277   printf("nsAppShell::Spinup()\n");
00278 #endif
00279 
00280   /* Get the event queue service */
00281   nsCOMPtr<nsIEventQueueService> eventQService = do_GetService(kEventQueueServiceCID, &rv);
00282 
00283   if (NS_FAILED(rv)) {
00284     NS_WARNING("Could not obtain event queue service");
00285     return rv;
00286   }
00287 
00288   /* Get the event queue for the thread.*/
00289   rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQueue));
00290   
00291   /* If we got an event queue, use it. */
00292   if (!mEventQueue) {
00293     /* otherwise create a new event queue for the thread */
00294     rv = eventQService->CreateThreadEventQueue();
00295     if (NS_FAILED(rv)) {
00296       NS_WARNING("Could not create the thread event queue");
00297       return rv;
00298     }
00299 
00300     /* Ask again nicely for the event queue now that we have created one. */
00301     rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQueue));
00302     if (NS_FAILED(rv)) {
00303       NS_WARNING("Could not get the thread event queue");
00304       return rv;
00305     }
00306   }
00307 
00308   ListenToEventQueue(mEventQueue, PR_TRUE);
00309 
00310   return rv;
00311 }
00312 
00313 /* must be a |XtInputCallbackProc| !! */
00314 PR_BEGIN_EXTERN_C
00315 static
00316 void HandleQueueXtProc(XtPointer ptr, int *source_fd, XtInputId* id)
00317 {
00318   nsIEventQueue *queue = (nsIEventQueue *)ptr;
00319   queue->ProcessPendingEvents();
00320 }
00321 PR_END_EXTERN_C
00322 
00323 nsresult nsAppShell::Run()
00324 {
00325   if (mEventQueue == nsnull)
00326     Spinup();
00327 
00328   if (mEventQueue == nsnull) {
00329     NS_WARNING("Cannot initialize the Event Queue");
00330     return NS_ERROR_NOT_INITIALIZED;
00331   }
00332                
00333   XEvent xevent;
00334   
00335   /* process events. */
00336   while (!DieAppShellDie) 
00337   {   
00338     XtAppNextEvent(mAppContext, &xevent);
00339   
00340     if (XtDispatchEvent(&xevent) == False)
00341       DispatchXEvent(&xevent);
00342     
00343     if (XEventsQueued(mDisplay, QueuedAlready) == 0)
00344     {
00345       /* Flush the nsWindow's drawing queue */
00346       nsWindow::UpdateIdle(nsnull);
00347     }
00348   }
00349   
00350   Spindown();
00351   return NS_OK;
00352 }
00353 
00354 NS_METHOD nsAppShell::Spindown()
00355 {
00356   if (mEventQueue) {
00357     ListenToEventQueue(mEventQueue, PR_FALSE);
00358     mEventQueue->ProcessPendingEvents();
00359     mEventQueue = nsnull;
00360   }
00361 
00362   return NS_OK;
00363 }
00364 
00365 #define NUMBER_HASH_KEY(_num) ((PLHashNumber) _num)
00366 
00367 static PLHashNumber
00368 IntHashKey(PRInt32 key)
00369 {
00370   return NUMBER_HASH_KEY(key);
00371 }
00372 // wrapper so we can call a macro
00373 PR_BEGIN_EXTERN_C
00374 static unsigned long getNextRequest (void *aClosure) {
00375   return XNextRequest(nsAppShell::mDisplay);
00376 }
00377 PR_END_EXTERN_C
00378 
00379 NS_IMETHODIMP nsAppShell::ListenToEventQueue(nsIEventQueue *aQueue,
00380                                              PRBool aListen)
00381 {
00382   if (!mEventQueue) {
00383     NS_WARNING("nsAppShell::ListenToEventQueue(): No event queue available.");
00384     return NS_ERROR_NOT_INITIALIZED;
00385   }
00386   
00387 #ifdef DEBUG_APPSHELL
00388   printf("ListenToEventQueue(%p, %d) this=%p\n", aQueue, aListen, this);
00389 #endif
00390   if (!sQueueHashTable) {
00391     sQueueHashTable = PL_NewHashTable(3, (PLHashFunction)IntHashKey,
00392                                       PL_CompareValues, PL_CompareValues, 0, 0);
00393   }
00394   if (!sCountHashTable) {
00395     sCountHashTable = PL_NewHashTable(3, (PLHashFunction)IntHashKey,
00396                                       PL_CompareValues, PL_CompareValues, 0, 0);
00397   }    
00398 
00399   int   queue_fd = aQueue->GetEventQueueSelectFD();
00400   void *key      = aQueue;
00401   if (aListen) {
00402     /* Add listener -
00403      * but only if we arn't already in the table... */
00404     if (!PL_HashTableLookup(sQueueHashTable, key)) {
00405       long tag;
00406         
00407       /* set up our fds callbacks */
00408       tag = (long)XtAppAddInput(mAppContext,
00409                                 queue_fd,
00410                                 (XtPointer)(long)(XtInputReadMask),
00411                                 HandleQueueXtProc,
00412                                 (XtPointer)mEventQueue);
00413 
00414 /* This hack would not be neccesary if we would have a hashtable function
00415  * which returns success/failure in a separate var ...
00416  */
00417 #define NEVER_BE_ZERO_MAGIC (54321) 
00418       tag += NEVER_BE_ZERO_MAGIC; /* be sure that |tag| is _never_ 0 */
00419       NS_ASSERTION(tag!=0, "tag is 0 while adding");
00420       
00421       if (tag) {
00422         PL_HashTableAdd(sQueueHashTable, key, (void *)tag);
00423       }
00424       
00425       PLEventQueue *plqueue;
00426       aQueue->GetPLEventQueue(&plqueue);
00427       PL_RegisterEventIDFunc(plqueue, getNextRequest, 0);
00428       sEventQueueList->AppendElement(plqueue);
00429     }
00430   } else {
00431     /* Remove listener... */   
00432     PLEventQueue *plqueue;
00433     aQueue->GetPLEventQueue(&plqueue);
00434     PL_UnregisterEventIDFunc(plqueue);
00435     sEventQueueList->RemoveElement(plqueue);
00436 
00437     int tag = long(PL_HashTableLookup(sQueueHashTable, key));
00438     if (tag) {
00439       tag -= NEVER_BE_ZERO_MAGIC;
00440       XtRemoveInput((XtInputId)tag);
00441       PL_HashTableRemove(sQueueHashTable, key);
00442     }  
00443   }
00444 
00445   return NS_OK;
00446 }
00447 
00448 /* Does nothing. Used by xp code with non-gtk expectations.
00449  * this method will be removed once xp eventloops are working.
00450  */
00451 NS_METHOD
00452 nsAppShell::GetNativeEvent(PRBool &aRealEvent, void *&aEvent)
00453 {
00454   aRealEvent = PR_FALSE;
00455   aEvent     = nsnull;
00456 
00457   return NS_OK;
00458 }
00459 
00460 nsresult nsAppShell::DispatchNativeEvent(PRBool aRealEvent, void *aEvent)
00461 {
00462   XEvent xevent;
00463   
00464   if (!mEventQueue)
00465     return NS_ERROR_NOT_INITIALIZED;
00466 
00467 #if 1
00468   /* gisburn: Why do we have to call this explicitly ?
00469    * I have registered a callback via XtAddAppInput() above... 
00470    */  
00471   mEventQueue->ProcessPendingEvents();  
00472 #endif
00473 
00474   XtAppNextEvent(mAppContext, &xevent);
00475     
00476   if (XtDispatchEvent(&xevent) == False)
00477     DispatchXEvent(&xevent);
00478    
00479   if (XEventsQueued(mDisplay, QueuedAlready) == 0)
00480   {
00481     /* Flush the nsWindow's drawing queue */
00482     nsWindow::UpdateIdle(nsnull);
00483   }
00484     
00485   return NS_OK;
00486 }
00487 
00488 NS_METHOD nsAppShell::Exit()
00489 {
00490   DieAppShellDie = PR_TRUE;
00491   return NS_OK;
00492 }
00493 
00494 nsAppShell::~nsAppShell()
00495 {
00496 }
00497 
00498 void* nsAppShell::GetNativeData(PRUint32 aDataType)
00499 {
00500   return nsnull;
00501 }
00502 
00503 void
00504 nsAppShell::DispatchXEvent(XEvent *event)
00505 {
00506   nsWidget *widget;
00507   widget = nsWidget::GetWidgetForWindow(event->xany.window);
00508 
00509   // did someone pass us an x event for a window we don't own?
00510   // bad! bad!
00511   if (widget == nsnull)
00512     return;
00513 
00514   // switch on the type of event
00515   switch (event->type) 
00516   {
00517   case Expose:
00518     HandleExposeEvent(event, widget);
00519     break;
00520 
00521   case ConfigureNotify:
00522     // we need to make sure that this is the LAST of the
00523     // config events.
00524     PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("DispatchEvent: ConfigureNotify event for window 0x%lx %d %d %d %d\n",
00525                                          event->xconfigure.window,
00526                                          event->xconfigure.x, 
00527                                          event->xconfigure.y,
00528                                          event->xconfigure.width, 
00529                                          event->xconfigure.height));
00530 
00531     HandleConfigureNotifyEvent(event, widget);
00532 
00533     break;
00534 
00535   case ButtonPress:
00536   case ButtonRelease:
00537     HandleFocusInEvent(event, widget);
00538     HandleButtonEvent(event, widget);
00539     break;
00540 
00541   case MotionNotify:
00542     HandleMotionNotifyEvent(event, widget);
00543     break;
00544 
00545   case KeyPress:
00546     HandleKeyPressEvent(event, widget);
00547     break;
00548   case KeyRelease:
00549     HandleKeyReleaseEvent(event, widget);
00550     break;
00551 
00552   case FocusIn:
00553     HandleFocusInEvent(event, widget);
00554     break;
00555 
00556   case FocusOut:
00557     HandleFocusOutEvent(event, widget);
00558     break;
00559 
00560   case EnterNotify:
00561     HandleEnterEvent(event, widget);
00562     break;
00563 
00564   case LeaveNotify:
00565     HandleLeaveEvent(event, widget);
00566     break;
00567 
00568   case NoExpose:
00569     // these annoy me.
00570     break;
00571   case VisibilityNotify:
00572     HandleVisibilityNotifyEvent(event, widget);
00573     break;
00574   case ClientMessage:
00575     HandleClientMessageEvent(event, widget);
00576     break;
00577   case SelectionRequest:
00578     HandleSelectionRequestEvent(event, widget);
00579     break;
00580   default:
00581     PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Unhandled window event: Window 0x%lx Got a %s event\n",
00582                                          event->xany.window, event_names[event->type]));
00583 
00584     break;
00585   }
00586 }
00587 
00588 void
00589 nsAppShell::HandleMotionNotifyEvent(XEvent *event, nsWidget *aWidget)
00590 {
00591   if (mDragging) {
00592     HandleDragMotionEvent(event, aWidget);
00593   }
00594 
00595   nsMouseEvent mevent(PR_TRUE, NS_MOUSE_MOVE, aWidget, nsMouseEvent::eReal);
00596   XEvent aEvent;
00597 
00598   mevent.point.x = event->xmotion.x;
00599   mevent.point.y = event->xmotion.y;
00600 
00601   mevent.isShift = mShiftDown;
00602   mevent.isControl = mCtrlDown;
00603   mevent.isAlt = mAltDown;
00604   mevent.isMeta = mMetaDown;
00605   
00606   Display * dpy = (Display *)aWidget->GetNativeData(NS_NATIVE_DISPLAY);
00607   Window win = (Window)aWidget->GetNativeData(NS_NATIVE_WINDOW);
00608   // We are only interested in the LAST (newest) location of the pointer
00609   while(XCheckWindowEvent(dpy,
00610                           win,
00611                           ButtonMotionMask,
00612                           &aEvent)) {
00613     mevent.point.x = aEvent.xmotion.x;
00614     mevent.point.y = aEvent.xmotion.y;
00615   }
00616   NS_ADDREF(aWidget);
00617   aWidget->DispatchMouseEvent(mevent);
00618   NS_RELEASE(aWidget);
00619 }
00620 
00621 void
00622 nsAppShell::HandleButtonEvent(XEvent *event, nsWidget *aWidget)
00623 {
00624   PRUint32 eventType = 0;
00625   PRBool currentlyDragging = mDragging;
00626   nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, aWidget);
00627 
00628   PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Button event for window 0x%lx button %d type %s\n",
00629                                        event->xany.window,
00630                                        event->xbutton.button,
00631                                        (event->type == ButtonPress ? "ButtonPress" : "ButtonRelease")));
00632   switch(event->type) {
00633   case ButtonPress:
00634     switch(event->xbutton.button) {
00635     case 1:
00636       eventType = NS_MOUSE_LEFT_BUTTON_DOWN;
00637       mDragging = PR_TRUE;
00638       break;
00639     case 2:
00640       eventType = NS_MOUSE_MIDDLE_BUTTON_DOWN;
00641       break;
00642     case 3:
00643       /* look back into this in case anything actually needs a
00644        * NS_MOUSE_RIGHT_BUTTON_DOWN */
00645       eventType = NS_CONTEXTMENU;
00646       break;
00647     case 4:
00648     case 5:
00649       scrollEvent.delta = (event->xbutton.button == 4) ? -3 : 3;
00650       scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
00651 
00652       scrollEvent.point.x = event->xbutton.x;
00653       scrollEvent.point.y = event->xbutton.y;
00654 
00655       scrollEvent.isShift = mShiftDown;
00656       scrollEvent.isControl = mCtrlDown;
00657       scrollEvent.isAlt = mAltDown;
00658       scrollEvent.isMeta = mMetaDown;
00659       scrollEvent.time = PR_Now();
00660       NS_IF_ADDREF(aWidget);
00661       aWidget->DispatchWindowEvent(scrollEvent);
00662       NS_IF_RELEASE(aWidget);
00663       return;
00664     }
00665     break;
00666   case ButtonRelease:
00667     switch(event->xbutton.button) {
00668     case 1:
00669       eventType = NS_MOUSE_LEFT_BUTTON_UP;
00670       mDragging = PR_FALSE;
00671       break;
00672     case 2:
00673       eventType = NS_MOUSE_MIDDLE_BUTTON_UP;
00674       break;
00675     case 3:
00676       eventType = NS_MOUSE_RIGHT_BUTTON_UP;
00677       break;
00678     case 4:
00679     case 5:
00680       return;
00681     }
00682     break;
00683   }
00684 
00685   nsMouseEvent mevent(PR_TRUE, eventType, aWidget, nsMouseEvent::eReal);
00686   mevent.isShift = mShiftDown;
00687   mevent.isControl = mCtrlDown;
00688   mevent.isAlt = mAltDown;
00689   mevent.isMeta = mMetaDown;
00690   mevent.point.x = event->xbutton.x;
00691   mevent.point.y = event->xbutton.y;
00692   mevent.time = PR_Now();
00693   
00694   // If we are waiting longer than 1 sec for the second click, this is not a
00695   // double click.
00696   if (PR_Now() - mClickTime > 1000000)
00697     mClicked = PR_FALSE;               
00698 
00699   if (event->type == ButtonPress) {
00700     if (!mClicked) {
00701       mClicked = PR_TRUE;
00702       mClickTime = PR_Now();
00703       mClicks = 1;
00704       mClickedButton = event->xbutton.button;
00705     } else {
00706       mClickTime = PR_Now() - mClickTime;
00707       if ((mClickTime < 500000) && (mClickedButton == event->xbutton.button))
00708         mClicks = 2;
00709       else
00710         mClicks = 1;
00711       mClicked = PR_FALSE;
00712     }
00713   }
00714 
00715   if (currentlyDragging && !mDragging)
00716     HandleDragDropEvent(event, aWidget);
00717 
00718   mevent.clickCount = mClicks;
00719   NS_IF_ADDREF(aWidget);
00720   aWidget->DispatchMouseEvent(mevent);
00721   NS_IF_RELEASE(aWidget);
00722 }
00723 
00724 void
00725 nsAppShell::HandleExposeEvent(XEvent *event, nsWidget *aWidget)
00726 {
00727   PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Expose event for window 0x%lx %d %d %d %d\n", event->xany.window,
00728                                        event->xexpose.x, event->xexpose.y, event->xexpose.width, event->xexpose.height));
00729 
00730   nsRect dirtyRect(event->xexpose.x, event->xexpose.y, 
00731                    event->xexpose.width, event->xexpose.height);
00732 
00733   /* compress expose events...
00734    */
00735   if (event->xexpose.count!=0) {
00736      XEvent txe;
00737      do {
00738         XWindowEvent(event->xany.display, event->xany.window, ExposureMask, (XEvent *)&txe);
00739         dirtyRect.UnionRect(dirtyRect, nsRect(txe.xexpose.x, txe.xexpose.y, 
00740                                               txe.xexpose.width, txe.xexpose.height));
00741      } while (txe.xexpose.count>0);
00742   }
00743 
00744   aWidget->Invalidate(dirtyRect, PR_FALSE);
00745 }
00746 
00747 void
00748 nsAppShell::HandleConfigureNotifyEvent(XEvent *event, nsWidget *aWidget)
00749 {
00750   PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("ConfigureNotify event for window 0x%lx %d %d %d %d\n",
00751                                        event->xconfigure.window,
00752                                        event->xconfigure.x, event->xconfigure.y,
00753                                        event->xconfigure.width, event->xconfigure.height));
00754 
00755   XEvent    config_event;
00756   while (XCheckTypedWindowEvent(event->xany.display, 
00757                                 event->xany.window, 
00758                                 ConfigureNotify,
00759                                 &config_event) == True) {
00760     // make sure that we don't get other types of events.  
00761     // StructureNotifyMask includes other kinds of events, too.
00762     if (config_event.type == ConfigureNotify) 
00763       {
00764         *event = config_event;
00765         
00766         PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("DispatchEvent: Extra ConfigureNotify event for window 0x%lx %d %d %d %d\n",
00767                                              event->xconfigure.window,
00768                                              event->xconfigure.x, 
00769                                              event->xconfigure.y,
00770                                              event->xconfigure.width, 
00771                                              event->xconfigure.height));
00772       }
00773     else {
00774       PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("EVENT LOSSAGE\n"));
00775     }
00776   }
00777 
00778   nsSizeEvent sevent(PR_TRUE, NS_SIZE, aWidget);
00779   sevent.windowSize = new nsRect (event->xconfigure.x, event->xconfigure.y,
00780                                   event->xconfigure.width, event->xconfigure.height);
00781   sevent.point.x = event->xconfigure.x;
00782   sevent.point.y = event->xconfigure.y;
00783   sevent.mWinWidth = event->xconfigure.width;
00784   sevent.mWinHeight = event->xconfigure.height;
00785   // XXX fix sevent.time
00786   NS_ADDREF(aWidget);
00787   aWidget->OnResize(sevent);
00788   NS_RELEASE(aWidget);
00789   delete sevent.windowSize;
00790 }
00791 
00792 PRUint32 nsConvertCharCodeToUnicode(XKeyEvent* xkey)
00793 {
00794   // The only Unicode specific at the moment is casting to PRUint32.
00795 
00796   // For control characters convert from the event ascii code (e.g. 1 for
00797   // control-a) to the ascii code for the key, e.g., 'a' for
00798   // control-a.
00799 
00800   KeySym         keysym;
00801   XComposeStatus compose;
00802   unsigned char  string_buf[CHAR_BUF_SIZE];
00803   int            len = 0;
00804 
00805   len = XLookupString(xkey, (char *)string_buf, CHAR_BUF_SIZE-1, &keysym, &compose);
00806   if (0 == len)
00807     return 0;
00808 
00809   if (xkey->state & ControlMask) {
00810     if (xkey->state & ShiftMask) {
00811       return (PRUint32)(string_buf[0] + 'A' - 1);
00812     }
00813     else {
00814       return (PRUint32)(string_buf[0] + 'a' - 1);
00815     }
00816   }
00817   if (!isprint(string_buf[0])) {
00818     return 0;
00819   }
00820   else {
00821     return (PRUint32)(string_buf[0]);
00822   }
00823 }
00824 
00825 void
00826 nsAppShell::HandleKeyPressEvent(XEvent *event, nsWidget *aWidget)
00827 {
00828   char      string_buf[CHAR_BUF_SIZE];
00829   int       len = 0;
00830   Window    focusWindow = None;
00831   nsWidget *focusWidget = 0;
00832 
00833   // figure out where the real focus should go...
00834   focusWindow = nsWidget::GetFocusWindow();
00835   if (focusWindow != None) {
00836     focusWidget = nsWidget::GetWidgetForWindow(focusWindow);
00837   }
00838 
00839   PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("KeyPress event for window 0x%lx ( 0x%lx focus window )\n",
00840                                        event->xkey.window,
00841                                        focusWindow));
00842 
00843   // don't even bother...
00844   if (focusWidget == 0) {
00845     return;
00846   }
00847 
00848   KeySym     keysym = nsKeyCode::ConvertKeyCodeToKeySym(event->xkey.display,
00849                                                         event->xkey.keycode);
00850 
00851   switch (keysym) {
00852     case XK_Alt_L:
00853     case XK_Alt_R:
00854       mAltDown = PR_TRUE;
00855       break;
00856     case XK_Control_L:
00857     case XK_Control_R:
00858       mCtrlDown = PR_TRUE;
00859       break;
00860     case XK_Shift_L:
00861     case XK_Shift_R:
00862       mShiftDown = PR_TRUE;
00863       break;
00864     case XK_Meta_L:
00865     case XK_Meta_R:
00866       mMetaDown = PR_TRUE;
00867       break;
00868     default:
00869       break;
00870   }
00871 
00872   // Dont dispatch events for modifier keys pressed ALONE
00873   if (nsKeyCode::KeyCodeIsModifier(event->xkey.keycode))
00874   {
00875     return;
00876   }
00877 
00878   nsKeyEvent keyEvent(PR_TRUE, NS_KEY_DOWN, focusWidget);
00879 
00880   XComposeStatus compose;
00881 
00882   len = XLookupString(&event->xkey, string_buf, CHAR_BUF_SIZE-1, &keysym, &compose);
00883   string_buf[len] = '\0';
00884 
00885   keyEvent.keyCode = nsKeyCode::ConvertKeySymToVirtualKey(keysym);
00886   keyEvent.time = event->xkey.time;
00887   keyEvent.isShift = (event->xkey.state & ShiftMask) ? PR_TRUE : PR_FALSE;
00888   keyEvent.isControl = (event->xkey.state & ControlMask) ? 1 : 0;
00889   keyEvent.isAlt = (event->xkey.state & Mod1Mask) ? 1 : 0;
00890   // I think 'meta' is the same as 'alt' in X11. Is this OK for other systems?
00891   keyEvent.isMeta = (event->xkey.state & Mod1Mask) ? 1 : 0;
00892 
00893   //  printf("keysym = %x, keycode = %x, vk = %x\n",
00894   //         keysym,
00895   //         event->xkey.keycode,
00896   //         keyEvent.keyCode);
00897 
00898   PRBool noDefault = focusWidget->DispatchKeyEvent(keyEvent);
00899 
00900   nsKeyEvent pressEvent(PR_TRUE, NS_KEY_PRESS, focusWidget);
00901   pressEvent.keyCode = nsKeyCode::ConvertKeySymToVirtualKey(keysym);
00902   pressEvent.charCode = nsConvertCharCodeToUnicode(&event->xkey);
00903   pressEvent.time = event->xkey.time;
00904   pressEvent.isShift = (event->xkey.state & ShiftMask) ? PR_TRUE : PR_FALSE;
00905   pressEvent.isControl = (event->xkey.state & ControlMask) ? 1 : 0;
00906   pressEvent.isAlt = (event->xkey.state & Mod1Mask) ? 1 : 0;
00907   pressEvent.isMeta = (event->xkey.state & Mod1Mask) ? 1 : 0;
00908   if (noDefault) {   // If default prevented on keydown, do same for keypress
00909     pressEvent.flags |= NS_EVENT_FLAG_NO_DEFAULT;
00910   }
00911 
00912   focusWidget->DispatchKeyEvent(pressEvent);
00913 }
00914 
00915 void
00916 nsAppShell::HandleKeyReleaseEvent(XEvent *event, nsWidget *aWidget)
00917 {
00918   PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("KeyRelease event for window 0x%lx\n",
00919                                        event->xkey.window));
00920 
00921   KeySym     keysym = nsKeyCode::ConvertKeyCodeToKeySym(event->xkey.display,
00922                                                         event->xkey.keycode);
00923 
00924   switch (keysym) {
00925     case XK_Alt_L:
00926     case XK_Alt_R:
00927       mAltDown = PR_FALSE;
00928       break;
00929     case XK_Control_L:
00930     case XK_Control_R:
00931       mCtrlDown = PR_FALSE;
00932       break;
00933     case XK_Shift_L:
00934     case XK_Shift_R:
00935       mShiftDown = PR_FALSE;
00936       break;
00937     case XK_Meta_L:
00938     case XK_Meta_R:
00939       mMetaDown = PR_FALSE;
00940       break;
00941     default:
00942       break;
00943   }
00944 
00945   // Dont dispatch events for modifier keys pressed ALONE
00946   if (nsKeyCode::KeyCodeIsModifier(event->xkey.keycode))
00947   {
00948     return;
00949   }
00950 
00951   nsKeyEvent keyEvent(PR_TRUE, NS_KEY_UP, aWidget);
00952 
00953   keyEvent.keyCode = nsKeyCode::ConvertKeySymToVirtualKey(keysym);
00954   keyEvent.time = event->xkey.time;
00955   keyEvent.isShift = event->xkey.state & ShiftMask;
00956   keyEvent.isControl = (event->xkey.state & ControlMask) ? 1 : 0;
00957   keyEvent.isAlt = (event->xkey.state & Mod1Mask) ? 1 : 0;
00958   keyEvent.isMeta = (event->xkey.state & Mod1Mask) ? 1 : 0;
00959   keyEvent.point.x = event->xkey.x;
00960   keyEvent.point.y = event->xkey.y;
00961 
00962   NS_ADDREF(aWidget);
00963 
00964   aWidget->DispatchKeyEvent(keyEvent);
00965 
00966   NS_RELEASE(aWidget);
00967 }
00968 
00969 void
00970 nsAppShell::HandleFocusInEvent(XEvent *event, nsWidget *aWidget)
00971 {
00972   PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("FocusIn event for window 0x%lx\n",
00973                                        event->xfocus.window));
00974   nsFocusEvent focusEvent(PR_TRUE, NS_GOTFOCUS, aWidget);
00975   
00976   NS_ADDREF(aWidget);
00977   aWidget->DispatchWindowEvent(focusEvent);
00978   NS_RELEASE(aWidget);
00979 }
00980 
00981 void
00982 nsAppShell::HandleFocusOutEvent(XEvent *event, nsWidget *aWidget)
00983 {
00984   PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("FocusOut event for window 0x%lx\n",
00985                                        event->xfocus.window));
00986   nsFocusEvent focusEvent(PR_TRUE, NS_LOSTFOCUS, aWidget);
00987 
00988   NS_ADDREF(aWidget);
00989   aWidget->DispatchWindowEvent(focusEvent);
00990   NS_RELEASE(aWidget);
00991 }
00992 
00993 /* Identify pointer grab/ungrab events due to window manager activity */
00994 static inline int
00995 is_wm_ungrab_enter(XCrossingEvent *event)
00996 {
00997   return (NotifyGrab == event->mode) &&
00998     ((NotifyAncestor == event->detail) ||
00999      (NotifyVirtual == event->detail));
01000 }
01001 
01002 static inline int
01003 is_wm_grab_leave(XCrossingEvent *event)
01004 {
01005   return (NotifyGrab == event->mode) &&
01006     ((NotifyAncestor == event->detail) ||
01007      (NotifyVirtual == event->detail));
01008 }
01009 
01010 void
01011 nsAppShell::HandleEnterEvent(XEvent *event, nsWidget *aWidget)
01012 {
01013   PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Enter event for window 0x%lx\n",
01014                                        event->xcrossing.window));
01015 
01016   if (event->xcrossing.subwindow != None)
01017     return;
01018 
01019   if(is_wm_ungrab_enter(&event->xcrossing))
01020     return;
01021 
01022   if (mDragging) {
01023     HandleDragEnterEvent(event, aWidget);
01024   }
01025 
01026   nsMouseEvent enterEvent(PR_TRUE, NS_MOUSE_ENTER, aWidget,
01027                           nsMouseEvent::eReal);
01028 
01029   enterEvent.time = event->xcrossing.time;
01030   enterEvent.point.x = nscoord(event->xcrossing.x);
01031   enterEvent.point.y = nscoord(event->xcrossing.y);
01032   
01033   // make sure this is in focus. This will do until I rewrite all the 
01034   // focus routines. KenF
01035   aWidget->SetFocus();
01036 
01037   NS_ADDREF(aWidget);
01038   aWidget->DispatchWindowEvent(enterEvent);
01039   NS_RELEASE(aWidget);
01040 }
01041 
01042 void
01043 nsAppShell::HandleLeaveEvent(XEvent *event, nsWidget *aWidget)
01044 {
01045   PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Leave event for window 0x%lx\n",
01046                                        event->xcrossing.window));
01047 
01048   if (event->xcrossing.subwindow != None)
01049     return;
01050 
01051   if(is_wm_grab_leave(&event->xcrossing))
01052     return;
01053 
01054   if (mDragging) {
01055     HandleDragLeaveEvent(event, aWidget);
01056   }
01057 
01058   nsMouseEvent leaveEvent(PR_TRUE, NS_MOUSE_EXIT, aWidget,
01059                           nsMouseEvent::eReal);
01060 
01061   leaveEvent.time = event->xcrossing.time;
01062   leaveEvent.point.x = nscoord(event->xcrossing.x);
01063   leaveEvent.point.y = nscoord(event->xcrossing.y);
01064   
01065   NS_ADDREF(aWidget);
01066   aWidget->DispatchWindowEvent(leaveEvent);
01067   NS_RELEASE(aWidget);
01068 }
01069 
01070 void nsAppShell::HandleVisibilityNotifyEvent(XEvent *event, nsWidget *aWidget)
01071 {
01072 #ifdef DEBUG
01073   PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("VisibilityNotify event for window 0x%lx ",
01074                                        event->xfocus.window));
01075   switch(event->xvisibility.state) {
01076   case VisibilityFullyObscured:
01077     PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Fully Obscured\n"));
01078     break;
01079   case VisibilityPartiallyObscured:
01080     PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Partially Obscured\n"));
01081     break;
01082   case VisibilityUnobscured:
01083     PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("Unobscured\n"));
01084   }
01085 #endif
01086   aWidget->SetVisibility(event->xvisibility.state);
01087 }
01088 
01089 void nsAppShell::HandleMapNotifyEvent(XEvent *event, nsWidget *aWidget)
01090 {
01091   PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("MapNotify event for window 0x%lx\n",
01092                                        event->xmap.window));
01093   // XXX set map status is gone now..
01094   //  aWidget->SetMapStatus(PR_TRUE);
01095 }
01096 
01097 void nsAppShell::HandleUnmapNotifyEvent(XEvent *event, nsWidget *aWidget)
01098 {
01099   PR_LOG(XlibWidgetsLM, PR_LOG_DEBUG, ("UnmapNotifyEvent for window 0x%lx\n",
01100                                        event->xunmap.window));
01101   // XXX set map status is gone now..
01102   //aWidget->SetMapStatus(PR_FALSE);
01103 }
01104 
01105 void nsAppShell::HandleClientMessageEvent(XEvent *event, nsWidget *aWidget)
01106 {
01107   // check to see if it's a WM_DELETE message
01108 #if defined(DEBUG_warren) || defined(DEBUG_quy)
01109   printf("handling client message\n");
01110 #endif
01111   if (nsWidget::WMProtocolsInitialized) {
01112     if ((Atom)event->xclient.data.l[0] == nsWidget::WMDeleteWindow) {
01113 #ifdef DEBUG
01114       printf("got a delete window event\n");
01115 #endif /* DEBUG */      
01116       aWidget->OnDeleteWindow();
01117     }
01118   }
01119 }
01120 
01121 void nsAppShell::HandleSelectionRequestEvent(XEvent *event, nsWidget *aWidget)
01122 {
01123   nsGUIEvent ev(PR_TRUE, 0, aWidget);
01124 
01125   ev.nativeMsg = (void *)event;
01126 
01127   aWidget->DispatchWindowEvent(ev);
01128 }
01129 
01130 void nsAppShell::HandleDragMotionEvent(XEvent *event, nsWidget *aWidget) {
01131   PRBool currentlyDragging = PR_FALSE;
01132 
01133   nsresult rv;
01134   nsCOMPtr<nsIDragService> dragService( do_GetService(kCDragServiceCID, &rv) );
01135   nsCOMPtr<nsIDragSessionXlib> dragServiceXlib;
01136   if (NS_SUCCEEDED(rv)) {
01137     dragServiceXlib = do_QueryInterface(dragService);
01138     if (dragServiceXlib) {
01139       dragServiceXlib->IsDragging(&currentlyDragging);
01140     }
01141   }
01142 
01143   if (currentlyDragging) {
01144     dragServiceXlib->UpdatePosition(event->xmotion.x, event->xmotion.y);
01145 
01146     nsMouseEvent mevent(PR_TRUE, NS_DRAGDROP_OVER, aWidget,
01147                         nsMouseEvent::eReal);
01148     mevent.point.x = event->xmotion.x;
01149     mevent.point.y = event->xmotion.y;
01150 
01151     NS_ADDREF(aWidget);
01152     aWidget->DispatchMouseEvent(mevent);
01153     NS_RELEASE(aWidget);
01154   }
01155 }
01156 
01157 void nsAppShell::HandleDragEnterEvent(XEvent *event, nsWidget *aWidget) {
01158   PRBool currentlyDragging = PR_FALSE;
01159 
01160   nsresult rv;
01161   nsCOMPtr<nsIDragService> dragService( do_GetService(kCDragServiceCID, &rv) );
01162   if (NS_SUCCEEDED(rv)) {
01163     nsCOMPtr<nsIDragSessionXlib> dragServiceXlib;
01164     dragServiceXlib = do_QueryInterface(dragService);
01165     if (dragServiceXlib) {
01166       dragServiceXlib->IsDragging(&currentlyDragging);
01167     }
01168   }
01169 
01170   if (currentlyDragging) {
01171     nsMouseEvent enterEvent(PR_TRUE, NS_DRAGDROP_ENTER, aWidget,
01172                             nsMouseEvent::eReal);
01173   
01174     enterEvent.point.x = event->xcrossing.x;
01175     enterEvent.point.y = event->xcrossing.y;
01176   
01177     NS_ADDREF(aWidget);
01178     aWidget->DispatchWindowEvent(enterEvent);
01179     NS_RELEASE(aWidget);
01180   }
01181 }
01182 
01183 void nsAppShell::HandleDragLeaveEvent(XEvent *event, nsWidget *aWidget) {
01184   PRBool currentlyDragging = PR_FALSE;
01185   
01186   nsresult rv;
01187   nsCOMPtr<nsIDragService> dragService( do_GetService(kCDragServiceCID, &rv) );
01188 
01189   // FIXME: Not sure if currentlyDragging is required. KenF
01190   if (NS_SUCCEEDED(rv)) {
01191     nsCOMPtr<nsIDragSessionXlib> dragServiceXlib;
01192     dragServiceXlib = do_QueryInterface(dragService);
01193     if (dragServiceXlib) {
01194       dragServiceXlib->IsDragging(&currentlyDragging);
01195     }
01196   }
01197 
01198   if (currentlyDragging) {
01199     nsMouseEvent leaveEvent(PR_TRUE, NS_DRAGDROP_EXIT, aWidget,
01200                             nsMouseEvent::eReal);
01201   
01202     leaveEvent.point.x = event->xcrossing.x;
01203     leaveEvent.point.y = event->xcrossing.y;
01204   
01205     NS_ADDREF(aWidget);
01206     aWidget->DispatchWindowEvent(leaveEvent);
01207     NS_RELEASE(aWidget);
01208   }
01209 }
01210 
01211 void nsAppShell::HandleDragDropEvent(XEvent *event, nsWidget *aWidget) {
01212   PRBool currentlyDragging = PR_FALSE;
01213 
01214   nsresult rv;
01215   nsCOMPtr<nsIDragService> dragService( do_GetService(kCDragServiceCID, &rv) );
01216 
01217   // FIXME: Dont think the currentlyDragging check is required. KenF
01218   if (NS_SUCCEEDED(rv)) {
01219     nsCOMPtr<nsIDragSessionXlib> dragServiceXlib;
01220     dragServiceXlib = do_QueryInterface(dragService);
01221     if (dragServiceXlib) {
01222       dragServiceXlib->IsDragging(&currentlyDragging);
01223     }
01224   }
01225 
01226   if (currentlyDragging) {
01227     nsMouseEvent mevent(PR_TRUE, NS_DRAGDROP_DROP, aWidget,
01228                         nsMouseEvent::eReal);
01229     mevent.point.x = event->xbutton.x;
01230     mevent.point.y = event->xbutton.y;
01231   
01232     NS_IF_ADDREF(aWidget);
01233     aWidget->DispatchMouseEvent(mevent);
01234     NS_IF_RELEASE(aWidget);
01235 
01236     dragService->EndDragSession();
01237   }
01238 }
01239 
01240 void nsAppShell::ForwardEvent(XEvent *event, nsWidget *aWidget)
01241 {
01242   nsGUIEvent ev(PR_TRUE, 0, aWidget);
01243   ev.nativeMsg = (void *)event;
01244 
01245   aWidget->DispatchWindowEvent(ev);
01246 }
01247