/* * 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 #include struct JSContext; /* Just so we don't need to include a bunch of JS headers */ #include #include #include #include #include #include #include #include #include #include #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(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(this)); gulong deleteHandler = g_signal_connect (mDialog, "delete-event", G_CALLBACK (DeleteCallback), reinterpret_cast(this)); nsCOMPtr 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 domdoc; mWindow->GetDocument (getter_AddRefs (domdoc)); nsCOMPtr docevent (do_QueryInterface (domdoc)); nsCOMPtr event; PRBool defaultActionEnabled = PR_TRUE; if (docevent) { docevent->CreateEvent (NS_LITERAL_STRING ("Events"), getter_AddRefs (event)); nsCOMPtr privateEvent (do_QueryInterface (event)); if (privateEvent) { event->InitEvent (NS_ConvertASCIItoUTF16 (aEventName), PR_TRUE, PR_TRUE); privateEvent->SetTrusted(PR_TRUE); nsCOMPtr target (do_QueryInterface (mWindow)); target->DispatchEvent (event, &defaultActionEnabled); } } return defaultActionEnabled; }