Back to index

lightning-sunbird  0.9+nobinonly
nsAppShell.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* vim:expandtab:shiftwidth=4:tabstop=4:
00003  */
00004 /* ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is mozilla.org code.
00018  *
00019  * The Initial Developer of the Original Code is Christopher Blizzard
00020  * <blizzard@mozilla.org>.  Portions created by the Initial Developer
00021  * are Copyright (C) 2001 the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsAppShell.h"
00040 #include "nsIEventQueueService.h"
00041 #include "nsServiceManagerUtils.h"
00042 #include "plhash.h"
00043 #include "prenv.h"
00044 
00045 // to get the logging stuff
00046 #include "nsCommonWidget.h"
00047 
00048 #include <gtk/gtkmain.h>
00049 
00050 static PRBool sInitialized = PR_FALSE;
00051 static PLHashTable *sQueueHashTable = nsnull;
00052 static PLHashTable *sCountHashTable = nsnull;
00053 
00054 #ifdef PR_LOGGING
00055 PRLogModuleInfo *gWidgetLog = nsnull;
00056 PRLogModuleInfo *gWidgetFocusLog = nsnull;
00057 PRLogModuleInfo *gWidgetIMLog = nsnull;
00058 PRLogModuleInfo *gWidgetDrawLog = nsnull;
00059 #endif
00060 
00061 static gboolean event_processor_callback (GIOChannel *source,
00062                                           GIOCondition condition,
00063                                           gpointer data)
00064 {
00065     nsIEventQueue *eventQueue = (nsIEventQueue *)data;
00066     if (eventQueue)
00067         eventQueue->ProcessPendingEvents();
00068 
00069     // always remove the source event
00070     return TRUE;
00071 }
00072 
00073 #define NUMBER_HASH_KEY(_num) ((PLHashNumber) _num)
00074 
00075 static PLHashNumber
00076 IntHashKey(PRInt32 key)
00077 {
00078     return NUMBER_HASH_KEY(key);
00079 }
00080 
00081 nsAppShell::nsAppShell(void)
00082 {
00083 #ifdef PR_LOGGING
00084     if (!gWidgetLog)
00085         gWidgetLog = PR_NewLogModule("Widget");
00086     if (!gWidgetFocusLog)
00087         gWidgetFocusLog = PR_NewLogModule("WidgetFocus");
00088     if (!gWidgetIMLog)
00089         gWidgetIMLog = PR_NewLogModule("WidgetIM");
00090     if (!gWidgetDrawLog)
00091         gWidgetDrawLog = PR_NewLogModule("WidgetDraw");
00092 #endif
00093 }
00094 
00095 nsAppShell::~nsAppShell(void)
00096 {
00097 }
00098 
00099 /* static */ void
00100 nsAppShell::ReleaseGlobals()
00101 {
00102   if (sQueueHashTable) {
00103     PL_HashTableDestroy(sQueueHashTable);
00104     sQueueHashTable = nsnull;
00105   }
00106   if (sCountHashTable) {
00107     PL_HashTableDestroy(sCountHashTable);
00108     sCountHashTable = nsnull;
00109   }
00110 }
00111 
00112 NS_IMPL_ISUPPORTS1(nsAppShell, nsIAppShell)
00113 
00114 NS_IMETHODIMP
00115 nsAppShell::Create(int *argc, char **argv)
00116 {
00117     if (sInitialized)
00118         return NS_OK;
00119 
00120     sInitialized = PR_TRUE;
00121 
00122     if (PR_GetEnv("MOZ_DEBUG_PAINTS")) {
00123         gdk_window_set_debug_updates(TRUE);
00124     }
00125 
00126     return NS_OK;
00127 }
00128 
00129 NS_IMETHODIMP
00130 nsAppShell::Run(void)
00131 {
00132     if (!mEventQueue)
00133         Spinup();
00134 
00135     if (!mEventQueue)
00136         return NS_ERROR_NOT_INITIALIZED;
00137 
00138     // go go gadget gtk2!
00139     gtk_main();
00140 
00141     Spindown();
00142 
00143     return NS_OK;
00144 }
00145 
00146 NS_IMETHODIMP
00147 nsAppShell::Spinup(void)
00148 {
00149     nsresult rv = NS_OK;
00150 
00151     // get the event queue service
00152     nsCOMPtr <nsIEventQueueService> eventQService = 
00153         do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
00154 
00155     if (NS_FAILED(rv)) {
00156         NS_WARNING("Failed to get event queue service");
00157         return rv;
00158     }
00159 
00160     // get the event queue for this thread
00161     rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD,
00162                                             getter_AddRefs(mEventQueue));
00163 
00164     // if we got an event queue, just use it
00165     if (mEventQueue)
00166         goto done;
00167 
00168     // otherwise creaet a new event queue for the thread
00169     rv = eventQService->CreateThreadEventQueue();
00170     if (NS_FAILED(rv)) {
00171         NS_WARNING("Could not create the thread event queue");
00172         return rv;
00173     }
00174 
00175     // ask again for the event queue now that we have create one.
00176     rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD,
00177                                             getter_AddRefs(mEventQueue));
00178 
00179  done:
00180     ListenToEventQueue(mEventQueue, PR_TRUE);
00181 
00182     return rv;
00183 }
00184 
00185 NS_IMETHODIMP
00186 nsAppShell::Spindown(void)
00187 {
00188     // stop listening to the event queue
00189     if (mEventQueue) {
00190         ListenToEventQueue(mEventQueue, PR_FALSE);
00191         mEventQueue->ProcessPendingEvents();
00192         mEventQueue = nsnull;
00193     }
00194     return NS_OK;
00195 }
00196 
00197 NS_IMETHODIMP
00198 nsAppShell::ListenToEventQueue(nsIEventQueue *aQueue, PRBool aListen)
00199 {
00200     LOG(("ListenToEventQueue %p %d\n", (void *)aQueue, aListen));
00201     // initialize our hash tables if we have to
00202     if (!sQueueHashTable)
00203         sQueueHashTable = PL_NewHashTable(3, (PLHashFunction)IntHashKey,
00204                                           PL_CompareValues,
00205                                           PL_CompareValues, 0, 0);
00206     if (!sCountHashTable)
00207         sCountHashTable = PL_NewHashTable(3, (PLHashFunction)IntHashKey,
00208                                           PL_CompareValues, 
00209                                           PL_CompareValues, 0, 0);
00210 
00211     PRInt32 key = aQueue->GetEventQueueSelectFD();
00212 
00213     /* add a listener */
00214     if (aListen) {
00215         /* only add if we arn't already in the table */
00216         if (!PL_HashTableLookup(sQueueHashTable, GINT_TO_POINTER(key))) {
00217             GIOChannel *ioc;
00218             guint       tag;
00219             ioc = g_io_channel_unix_new(key);
00220             tag = g_io_add_watch_full (ioc, G_PRIORITY_DEFAULT_IDLE,
00221                                        G_IO_IN,
00222                                        event_processor_callback, aQueue, NULL);
00223             // it's owned by the mainloop now
00224             g_io_channel_unref(ioc);
00225             PL_HashTableAdd(sQueueHashTable, GINT_TO_POINTER(key),
00226                             GUINT_TO_POINTER(tag));
00227             LOG(("created tag %d from key %d\n", tag, key));
00228         }
00229         /* bump up the count */
00230         gint count = GPOINTER_TO_INT(PL_HashTableLookup(sCountHashTable, 
00231                                                         GINT_TO_POINTER(key)));
00232         PL_HashTableAdd(sCountHashTable, GINT_TO_POINTER(key), 
00233                         GINT_TO_POINTER(count+1));
00234         LOG(("key %d now has count %d\n", key, count+1));
00235     } else {
00236         /* remove listener */
00237         gint count = GPOINTER_TO_INT(PL_HashTableLookup(sCountHashTable,
00238                                                         GINT_TO_POINTER(key)));
00239         LOG(("key %d will have count %d\n", key, count-1));
00240         if (count - 1 == 0) {
00241             guint tag;
00242             tag = GPOINTER_TO_UINT(PL_HashTableLookup(sQueueHashTable,
00243                                                       GINT_TO_POINTER(key)));
00244             LOG(("shutting down tag %d\n", tag));
00245             g_source_remove(tag);
00246             PL_HashTableRemove(sQueueHashTable, GINT_TO_POINTER(key));
00247             PL_HashTableRemove(sCountHashTable, GINT_TO_POINTER(key));
00248         }
00249         else {
00250             // update the count for this key
00251             PL_HashTableAdd(sCountHashTable, GINT_TO_POINTER(key),
00252                             GINT_TO_POINTER(count-1));
00253         }
00254     }
00255 
00256     return NS_OK;
00257 }
00258 
00259 NS_IMETHODIMP
00260 nsAppShell::GetNativeEvent(PRBool &aRealEvent, void * &aEvent)
00261 {
00262     aRealEvent = PR_FALSE;
00263     aEvent = 0;
00264 
00265     return NS_OK;
00266 }
00267 
00268 NS_IMETHODIMP
00269 nsAppShell::DispatchNativeEvent(PRBool aRealEvent, void *aEvent)
00270 {
00271     if (!mEventQueue)
00272         return NS_ERROR_NOT_INITIALIZED;
00273 
00274     g_main_context_iteration(NULL, TRUE);
00275 
00276     return NS_OK;
00277 }
00278 
00279 NS_IMETHODIMP
00280 nsAppShell::Exit(void)
00281 {
00282     gtk_main_quit();
00283     return NS_OK;
00284 }