/*
* Copyright © 2006 Christian Persch
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Some code taken from mozilla/embedding/components/windowwatcher/src/nsPromptService.cpp
* which was under MPL/LGPL/GPL tri-licence and is here being used under the licence above.
* Original notice:
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*/
#include <xpcom-config.h>
#include <config.h>
struct JSContext; /* Just so we don't need to include a bunch of JS headers */
#include <nsIDOMDocumentEvent.h>
#include <nsIDOMDocument.h>
#include <nsIDOMEvent.h>
#include <nsIDOMEventTarget.h>
#include <nsIJSContextStack.h>
#include <nsIPrivateDOMEvent.h>
#include <nsPIDOMWindow.h>
#include <nsServiceManagerUtils.h>
#include <nsThreadUtils.h>
#include <gtk/gtkdialog.h>
#include "ggeAutoModalDialog.h"
ggeAutoModalDialog::ggeAutoModalDialog (nsIDOMWindow *aWindow,
PRBool aNotifyDOM)
: mWindow (aWindow),
mPWindow (do_QueryInterface (aWindow)),
mStack (do_GetService ("@mozilla.org/js/xpc/ContextStack;1")),
mDefaultEnabled (DispatchEvent ("DOMWillOpenModalDialog", aNotifyDOM)),
mContextPushed (PR_FALSE),
mModalStateSet (PR_FALSE)
{
/* First we check whether we should show the dialogue at all */
if (aNotifyDOM) {
if (!mDefaultEnabled) {
return;
}
}
if (mStack) {
mContextPushed = NS_SUCCEEDED (mStack->Push (nsnull));
}
if (mWindow) {
NS_ASSERTION (mPWindow, "Should have a window here!");
mPWindow->EnterModalState ();
mModalStateSet = PR_TRUE;
}
}
ggeAutoModalDialog::~ggeAutoModalDialog ()
{
if (mModalStateSet) {
NS_ASSERTION (mPWindow, "Should have a window here!");
mPWindow->LeaveModalState ();
}
if (mContextPushed) {
NS_ASSERTION (mStack, "Should have a stack!");
JSContext* cx;
mStack->Pop (&cx);
NS_ASSERTION(cx == nsnull, "We pushed a null context but popped a non-null context!?");
}
}
/* static */ void PR_CALLBACK
ggeAutoModalDialog::ResponseCallback (GtkWidget *aDialog,
int aResponse,
void *aData)
{
ggeAutoModalDialog *obj = reinterpret_cast<ggeAutoModalDialog*>(aData);
gtk_widget_hide (aDialog);
obj->mResponse = aResponse;
obj->mContinueModalLoop = PR_FALSE;
}
/* static */ gboolean PR_CALLBACK
ggeAutoModalDialog::DeleteCallback (GtkWidget *aDialog,
void *aEvent,
void *aData)
{
gtk_dialog_response (GTK_DIALOG (aDialog), GTK_RESPONSE_DELETE_EVENT);
return TRUE;
}
void
ggeAutoModalDialog::Run (GtkWidget *aDialog)
{
NS_ASSERTION (ShouldShow(), "Calling ::Run on a prevented dialogue!");
/* Do NOT use gtk_dialog_run here, since it blocks the network thread!
* See https://bugzilla.mozilla.org/show_bug.cgi?id=338225
*/
// Reset popup state while opening a modal dialog, and firing
// events about the dialog, to prevent the current state from
// being active the whole time a modal dialog is open.
nsAutoPopupStatePusher popupStatePusher (mPWindow, openAbused);
mDialog = aDialog;
g_object_ref_sink (mDialog);
mResponse = GTK_RESPONSE_DELETE_EVENT;
gulong responseHandler = g_signal_connect (mDialog, "response",
G_CALLBACK (ResponseCallback),
reinterpret_cast<void*>(this));
gulong deleteHandler = g_signal_connect (mDialog, "delete-event",
G_CALLBACK (DeleteCallback),
reinterpret_cast<void*>(this));
nsCOMPtr<nsIThread> thread (do_GetCurrentThread ());
NS_ASSERTION (thread, "No UI thread?");
mContinueModalLoop = PR_TRUE;
while (mContinueModalLoop) {
if (!NS_ProcessNextEvent (thread))
break;
}
g_signal_handler_disconnect (mDialog, responseHandler);
g_signal_handler_disconnect (mDialog, deleteHandler);
/* FIXME */
g_object_unref (mDialog);
mDialog = NULL;
}
PRBool
ggeAutoModalDialog::DispatchEvent (const char *aEventName,
PRBool aDoNotify)
{
if (!mWindow || !aDoNotify) {
return PR_TRUE;
}
nsCOMPtr<nsIDOMDocument> domdoc;
mWindow->GetDocument (getter_AddRefs (domdoc));
nsCOMPtr<nsIDOMDocumentEvent> docevent (do_QueryInterface (domdoc));
nsCOMPtr<nsIDOMEvent> event;
PRBool defaultActionEnabled = PR_TRUE;
if (docevent) {
docevent->CreateEvent (NS_LITERAL_STRING ("Events"), getter_AddRefs (event));
nsCOMPtr<nsIPrivateDOMEvent> privateEvent (do_QueryInterface (event));
if (privateEvent) {
event->InitEvent (NS_ConvertASCIItoUTF16 (aEventName), PR_TRUE, PR_TRUE);
privateEvent->SetTrusted(PR_TRUE);
nsCOMPtr<nsIDOMEventTarget> target (do_QueryInterface (mWindow));
target->DispatchEvent (event, &defaultActionEnabled);
}
}
return defaultActionEnabled;
}