1
/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Netscape Public License
6
* Version 1.1 (the "License"); you may not use this file except in
7
* compliance with the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/NPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is mozilla.org code.
17
* The Initial Developer of the Original Code is
18
* Netscape Communications Corporation.
19
* Portions created by the Initial Developer are Copyright (C) 1998
20
* the Initial Developer. All Rights Reserved.
24
* Alternatively, the contents of this file may be used under the terms of
25
* either the GNU General Public License Version 2 or later (the "GPL"), or
26
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27
* in which case the provisions of the GPL or the LGPL are applicable instead
28
* of those above. If you wish to allow use of your version of this file only
29
* under the terms of either the GPL or the LGPL, and not to allow others to
30
* use your version of this file under the terms of the NPL, indicate your
31
* decision by deleting the provisions above and replace them with the notice
32
* and other provisions required by the GPL or the LGPL. If you do not delete
33
* the provisions above, a recipient may use your version of this file under
34
* the terms of any one of the NPL, the GPL or the LGPL.
36
* ***** END LICENSE BLOCK ***** */
42
#include "nsAppShell.h"
43
#include "nsIAppShell.h"
44
#include "nsIServiceManager.h"
45
#include "nsIEventQueueService.h"
46
#include "nsICmdLineService.h"
47
#include "nsGtkEventHandler.h"
51
#include "nsIWidget.h"
54
#include "nsVoidArray.h"
56
static PRBool sInitialized = PR_FALSE;
57
static PLHashTable *sQueueHashTable = nsnull;
58
static PLHashTable *sCountHashTable = nsnull;
59
static nsVoidArray *sEventQueueList = nsnull;
61
struct OurGdkIOClosure {
62
GdkInputFunction function;
67
our_gdk_io_invoke(GIOChannel* source, GIOCondition condition, gpointer data)
69
OurGdkIOClosure* ioc = (OurGdkIOClosure*) data;
71
(*ioc->function)(ioc->data, g_io_channel_unix_get_fd(source),
78
our_gdk_io_destroy(gpointer data)
81
printf("our_gdk_io_destroy()\n");
83
OurGdkIOClosure* ioc = (OurGdkIOClosure*) data;
90
our_gdk_input_add (gint source,
91
GdkInputFunction function,
96
printf("our_gdk_input_add()\n");
99
OurGdkIOClosure *closure = g_new (OurGdkIOClosure, 1);
102
closure->function = function;
103
closure->data = data;
105
channel = g_io_channel_unix_new (source);
106
result = g_io_add_watch_full (channel, priority, G_IO_IN,
108
closure, our_gdk_io_destroy);
109
g_io_channel_unref (channel);
114
// wrapper so we can call a macro
115
static unsigned long getNextRequest (void *aClosure) {
116
return NextRequest(GDK_DISPLAY());
120
//-------------------------------------------------------------------------
124
//-------------------------------------------------------------------------
125
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
126
static NS_DEFINE_CID(kCmdLineServiceCID, NS_COMMANDLINE_SERVICE_CID);
129
//-------------------------------------------------------------------------
131
// nsAppShell constructor
133
//-------------------------------------------------------------------------
134
nsAppShell::nsAppShell()
136
#ifdef DEBUG_APPSHELL
137
printf("nsAppShell::nsAppShell()\n");
139
if (!sEventQueueList)
140
sEventQueueList = new nsVoidArray();
143
//-------------------------------------------------------------------------
145
// nsAppShell destructor
147
//-------------------------------------------------------------------------
148
nsAppShell::~nsAppShell()
150
#ifdef DEBUG_APPSHELL
151
printf("nsAppShell::~nsAppShell()\n");
156
nsAppShell::ReleaseGlobals()
158
if (sQueueHashTable) {
159
PL_HashTableDestroy(sQueueHashTable);
160
sQueueHashTable = nsnull;
162
if (sCountHashTable) {
163
PL_HashTableDestroy(sCountHashTable);
164
sCountHashTable = nsnull;
166
if (sEventQueueList) {
167
delete sEventQueueList;
168
sEventQueueList = nsnull;
172
//-------------------------------------------------------------------------
174
// nsISupports implementation macro
176
//-------------------------------------------------------------------------
178
NS_IMPL_ISUPPORTS1(nsAppShell, nsIAppShell)
180
static void event_processor_callback(gpointer data,
182
GdkInputCondition condition)
184
nsIEventQueue *eventQueue = (nsIEventQueue*)data;
186
eventQueue->ProcessPendingEvents();
190
//-------------------------------------------------------------------------
192
// Create the application shell
194
//-------------------------------------------------------------------------
196
NS_IMETHODIMP nsAppShell::Create(int *bac, char **bav)
198
#ifdef DEBUG_APPSHELL
199
printf("nsAppShell::Create()\n");
204
sInitialized = PR_TRUE;
206
int argc = bac ? *bac : 0;
211
nsCOMPtr<nsICmdLineService> cmdLineArgs = do_GetService(kCmdLineServiceCID);
213
rv = cmdLineArgs->GetArgc(&argc);
215
argc = bac ? *bac : 0;
217
rv = cmdLineArgs->GetArgv(&argv);
225
//-------------------------------------------------------------------------
227
// Spinup - do any preparation necessary for running a message loop
229
//-------------------------------------------------------------------------
230
NS_IMETHODIMP nsAppShell::Spinup()
234
#ifdef DEBUG_APPSHELL
235
printf("nsAppShell::Spinup()\n");
238
// Get the event queue service
239
nsCOMPtr<nsIEventQueueService> eventQService = do_GetService(kEventQueueServiceCID, &rv);
242
NS_ASSERTION("Could not obtain event queue service", PR_FALSE);
246
//Get the event queue for the thread.
247
rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQueue));
249
// If we got an event queue, use it.
253
// otherwise create a new event queue for the thread
254
rv = eventQService->CreateThreadEventQueue();
256
NS_ASSERTION("Could not create the thread event queue", PR_FALSE);
260
// Ask again nicely for the event queue now that we have created one.
261
rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQueue));
263
// XXX shouldn't this be automatic?
265
ListenToEventQueue(mEventQueue, PR_TRUE);
270
//-------------------------------------------------------------------------
272
// Spindown - do any cleanup necessary for finishing a message loop
274
//-------------------------------------------------------------------------
275
NS_IMETHODIMP nsAppShell::Spindown()
277
#ifdef DEBUG_APPSHELL
278
printf("nsAppShell::Spindown()\n");
281
ListenToEventQueue(mEventQueue, PR_FALSE);
282
mEventQueue->ProcessPendingEvents();
283
mEventQueue = nsnull;
288
#ifdef NS_TRACE_MALLOC
289
#include "nsTraceMalloc.h"
292
tm_flush_logfiles(gpointer data)
294
NS_TraceMallocFlushLogfiles();
299
//-------------------------------------------------------------------------
303
//-------------------------------------------------------------------------
304
NS_IMETHODIMP nsAppShell::Run()
310
return NS_ERROR_NOT_INITIALIZED;
312
#ifdef NS_TRACE_MALLOC
313
gtk_idle_add(tm_flush_logfiles, nsnull);
316
// kick up gtk_main. this won't return until gtk_main_quit is called
324
//-------------------------------------------------------------------------
326
// Exit a message handler loop
328
//-------------------------------------------------------------------------
330
NS_IMETHODIMP nsAppShell::Exit()
336
// does nothing. used by xp code with non-gtk expectations.
337
// this method will be removed once xp eventloops are working.
338
NS_IMETHODIMP nsAppShell::GetNativeEvent(PRBool &aRealEvent, void *& aEvent)
340
aRealEvent = PR_FALSE;
346
// simply executes one iteration of the event loop. used by xp code with
347
// non-gtk expectations.
348
// this method will be removed once xp eventloops are working.
349
NS_IMETHODIMP nsAppShell::DispatchNativeEvent(PRBool aRealEvent, void *aEvent)
352
return NS_ERROR_NOT_INITIALIZED;
354
g_main_iteration(PR_TRUE);
359
#define NUMBER_HASH_KEY(_num) ((PLHashNumber) _num)
362
IntHashKey(PRInt32 key)
364
return NUMBER_HASH_KEY(key);
367
NS_IMETHODIMP nsAppShell::ListenToEventQueue(nsIEventQueue *aQueue,
370
#ifdef DEBUG_APPSHELL
371
printf("ListenToEventQueue(%p, %d) this=%p\n", aQueue, aListen, this);
373
if (!sQueueHashTable) {
374
sQueueHashTable = PL_NewHashTable(3, (PLHashFunction)IntHashKey,
375
PL_CompareValues, PL_CompareValues, 0, 0);
377
if (!sCountHashTable) {
378
sCountHashTable = PL_NewHashTable(3, (PLHashFunction)IntHashKey,
379
PL_CompareValues, PL_CompareValues, 0, 0);
384
PRInt32 key = aQueue->GetEventQueueSelectFD();
386
/* only add if we arn't already in the table */
387
if (!PL_HashTableLookup(sQueueHashTable, GINT_TO_POINTER(key))) {
389
tag = our_gdk_input_add(aQueue->GetEventQueueSelectFD(),
390
event_processor_callback,
392
G_PRIORITY_HIGH_IDLE);
394
PL_HashTableAdd(sQueueHashTable, GINT_TO_POINTER(key), GINT_TO_POINTER(tag));
396
PLEventQueue *plqueue;
397
aQueue->GetPLEventQueue(&plqueue);
398
PL_RegisterEventIDFunc(plqueue, getNextRequest, 0);
399
sEventQueueList->AppendElement(plqueue);
401
/* bump up the count */
402
gint count = GPOINTER_TO_INT(PL_HashTableLookup(sCountHashTable, GINT_TO_POINTER(key)));
403
PL_HashTableAdd(sCountHashTable, GINT_TO_POINTER(key), GINT_TO_POINTER(count+1));
405
/* remove listener */
406
PRInt32 key = aQueue->GetEventQueueSelectFD();
408
PLEventQueue *plqueue;
409
aQueue->GetPLEventQueue(&plqueue);
410
PL_UnregisterEventIDFunc(plqueue);
411
sEventQueueList->RemoveElement(plqueue);
413
gint count = GPOINTER_TO_INT(PL_HashTableLookup(sCountHashTable, GINT_TO_POINTER(key)));
414
if (count - 1 == 0) {
415
gint tag = GPOINTER_TO_INT(PL_HashTableLookup(sQueueHashTable, GINT_TO_POINTER(key)));
417
g_source_remove(tag);
418
PL_HashTableRemove(sQueueHashTable, GINT_TO_POINTER(key));
421
PL_HashTableAdd(sCountHashTable, GINT_TO_POINTER(key), GINT_TO_POINTER(count-1));
428
PRBool processQueue(void *aElement, void *aData)
430
PLEventQueue *queue = (PLEventQueue *) aElement;
431
unsigned int id = NS_PTR_TO_INT32(aData);
432
PL_ProcessEventsBeforeID(queue, id);
437
nsAppShell::ProcessBeforeID(unsigned long aID)
440
sEventQueueList->EnumerateForwards(processQueue, (void *)aID);