From da1ac7dde56cdccd33b635b8b32181b099ac4cea Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Wed, 9 Jul 2014 17:13:06 +0000 Subject: [PATCH] Linux: cefclient: Add a GTK implementation of CefJSDialogHandler (issue #1258). git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1760 5089003a-bbd8-11dd-ad1f-f1f9622dbc98 --- tests/cefclient/client_handler.cpp | 30 ++++++ tests/cefclient/client_handler.h | 28 +++++ tests/cefclient/client_handler_gtk.cpp | 136 +++++++++++++++++++++++++ 3 files changed, 194 insertions(+) diff --git a/tests/cefclient/client_handler.cpp b/tests/cefclient/client_handler.cpp index c2aea8d0a..64c444088 100644 --- a/tests/cefclient/client_handler.cpp +++ b/tests/cefclient/client_handler.cpp @@ -98,6 +98,10 @@ ClientHandler::ClientHandler() m_StopHwnd(NULL), m_ReloadHwnd(NULL), m_bFocusOnEditableField(false) { +#if defined(OS_LINUX) + gtk_dialog_ = NULL; +#endif + // Read command line settings. CefRefPtr command_line = CefCommandLine::GetGlobalCommandLine(); @@ -260,6 +264,32 @@ bool ClientHandler::OnRequestGeolocationPermission( return true; } +#if !defined(OS_LINUX) + +bool ClientHandler::OnJSDialog(CefRefPtr browser, + const CefString& origin_url, + const CefString& accept_lang, + JSDialogType dialog_type, + const CefString& message_text, + const CefString& default_prompt_text, + CefRefPtr callback, + bool& suppress_message) { + return false; +} + +bool ClientHandler::OnBeforeUnloadDialog( + CefRefPtr browser, + const CefString& message_text, + bool is_reload, + CefRefPtr callback) { + return false; +} + +void ClientHandler::OnResetDialogState(CefRefPtr browser) { +} + +#endif // !defined(OS_LINUX) + bool ClientHandler::OnPreKeyEvent(CefRefPtr browser, const CefKeyEvent& event, CefEventHandle os_event, diff --git a/tests/cefclient/client_handler.h b/tests/cefclient/client_handler.h index e084c45c3..ee2ec7f96 100644 --- a/tests/cefclient/client_handler.h +++ b/tests/cefclient/client_handler.h @@ -33,6 +33,7 @@ class ClientHandler : public CefClient, public CefDownloadHandler, public CefDragHandler, public CefGeolocationHandler, + public CefJSDialogHandler, public CefKeyboardHandler, public CefLifeSpanHandler, public CefLoadHandler, @@ -66,6 +67,9 @@ class ClientHandler : public CefClient, virtual CefRefPtr GetGeolocationHandler() OVERRIDE { return this; } + virtual CefRefPtr GetJSDialogHandler() OVERRIDE { + return this; + } virtual CefRefPtr GetKeyboardHandler() OVERRIDE { return this; } @@ -131,6 +135,22 @@ class ClientHandler : public CefClient, int request_id, CefRefPtr callback) OVERRIDE; + // CefJSDialogHandler methods + virtual bool OnJSDialog(CefRefPtr browser, + const CefString& origin_url, + const CefString& accept_lang, + JSDialogType dialog_type, + const CefString& message_text, + const CefString& default_prompt_text, + CefRefPtr callback, + bool& suppress_message) OVERRIDE; + virtual bool OnBeforeUnloadDialog( + CefRefPtr browser, + const CefString& message_text, + bool is_reload, + CefRefPtr callback) OVERRIDE; + virtual void OnResetDialogState(CefRefPtr browser) OVERRIDE; + // CefKeyboardHandler methods virtual bool OnPreKeyEvent(CefRefPtr browser, const CefKeyEvent& event, @@ -334,6 +354,14 @@ class ClientHandler : public CefClient, // when the number of windows reaches 0. static int m_BrowserCount; +#if defined(OS_LINUX) + static void OnDialogResponse(GtkDialog *dialog, + gint response_id, + ClientHandler* handler); + GtkWidget* gtk_dialog_; + CefRefPtr js_dialog_callback_; +#endif + // Include the default reference counting implementation. IMPLEMENT_REFCOUNTING(ClientHandler); // Include the default locking implementation. diff --git a/tests/cefclient/client_handler_gtk.cpp b/tests/cefclient/client_handler_gtk.cpp index e4782db50..27f0997cf 100644 --- a/tests/cefclient/client_handler_gtk.cpp +++ b/tests/cefclient/client_handler_gtk.cpp @@ -13,6 +13,22 @@ #include "include/cef_browser.h" #include "include/cef_frame.h" +namespace { + +const char kPromptTextId[] = "cef_prompt_text"; + +// If there's a text entry in the dialog, get the text from the first one and +// return it. +std::string GetPromptText(GtkDialog* dialog) { + GtkWidget* widget = static_cast( + g_object_get_data(G_OBJECT(dialog), kPromptTextId)); + if (widget) + return gtk_entry_get_text(GTK_ENTRY(widget)); + return std::string(); +} + +} // namespace + void ClientHandler::OnAddressChange(CefRefPtr browser, CefRefPtr frame, const CefString& url) { @@ -75,6 +91,126 @@ void ClientHandler::OnTitleChange(CefRefPtr browser, } } +bool ClientHandler::OnJSDialog(CefRefPtr browser, + const CefString& origin_url, + const CefString& accept_lang, + JSDialogType dialog_type, + const CefString& message_text, + const CefString& default_prompt_text, + CefRefPtr callback, + bool& suppress_message) { + GtkButtonsType buttons = GTK_BUTTONS_NONE; + GtkMessageType gtk_message_type = GTK_MESSAGE_OTHER; + std::string title; + + switch (dialog_type) { + case JSDIALOGTYPE_ALERT: + buttons = GTK_BUTTONS_NONE; + gtk_message_type = GTK_MESSAGE_WARNING; + title = "JavaScript Alert"; + break; + + case JSDIALOGTYPE_CONFIRM: + buttons = GTK_BUTTONS_CANCEL; + gtk_message_type = GTK_MESSAGE_QUESTION; + title = "JavaScript Confirm"; + break; + + case JSDIALOGTYPE_PROMPT: + buttons = GTK_BUTTONS_CANCEL; + gtk_message_type = GTK_MESSAGE_QUESTION; + title = "JavaScript Prompt"; + break; + } + + js_dialog_callback_ = callback; + + if (!origin_url.empty()) { + title += " - "; + title += origin_url.ToString(); + } + + GtkWidget* window = + gtk_widget_get_ancestor(GTK_WIDGET(GetMainHwnd()), GTK_TYPE_WINDOW); + gtk_dialog_ = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL, + gtk_message_type, + buttons, + "%s", + message_text.ToString().c_str()); + g_signal_connect(gtk_dialog_, + "delete-event", + G_CALLBACK(gtk_widget_hide_on_delete), + NULL); + + gtk_window_set_title(GTK_WINDOW(gtk_dialog_), title.c_str()); + + GtkWidget* ok_button = gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), + GTK_STOCK_OK, + GTK_RESPONSE_OK); + + if (dialog_type != JSDIALOGTYPE_PROMPT) + gtk_widget_grab_focus(ok_button); + + if (dialog_type == JSDIALOGTYPE_PROMPT) { + GtkWidget* content_area = + gtk_dialog_get_content_area(GTK_DIALOG(gtk_dialog_)); + GtkWidget* text_box = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(text_box), + default_prompt_text.ToString().c_str()); + gtk_box_pack_start(GTK_BOX(content_area), text_box, TRUE, TRUE, 0); + g_object_set_data(G_OBJECT(gtk_dialog_), kPromptTextId, text_box); + gtk_entry_set_activates_default(GTK_ENTRY(text_box), TRUE); + } + + gtk_dialog_set_default_response(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_OK); + g_signal_connect(gtk_dialog_, "response", G_CALLBACK(OnDialogResponse), this); + gtk_widget_show_all(GTK_WIDGET(gtk_dialog_)); + + return true; +} + +bool ClientHandler::OnBeforeUnloadDialog( + CefRefPtr browser, + const CefString& message_text, + bool is_reload, + CefRefPtr callback) { + const std::string& new_message_text = + message_text.ToString() + "\n\nIs it OK to leave/reload this page?"; + bool suppress_message = false; + + return OnJSDialog(browser, CefString(), CefString(), JSDIALOGTYPE_CONFIRM, + new_message_text, CefString(), callback, suppress_message); +} + +void ClientHandler::OnResetDialogState(CefRefPtr browser) { + if (!gtk_dialog_) + return; + gtk_widget_destroy(gtk_dialog_); + gtk_dialog_ = NULL; + js_dialog_callback_ = NULL; +} + +// static +void ClientHandler::OnDialogResponse(GtkDialog* dialog, + gint response_id, + ClientHandler* handler) { + ASSERT(dialog == GTK_DIALOG(handler->gtk_dialog_)); + switch (response_id) { + case GTK_RESPONSE_OK: + handler->js_dialog_callback_->Continue(true, GetPromptText(dialog)); + break; + case GTK_RESPONSE_CANCEL: + case GTK_RESPONSE_DELETE_EVENT: + handler->js_dialog_callback_->Continue(false, CefString()); + break; + default: + ASSERT(false); // Not reached + } + + handler->OnResetDialogState(NULL); +} + void ClientHandler::SendNotification(NotificationType type) { // TODO(port): Implement this method. }