From f38c620e2825a88bf808df62995287f394bd20bd Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Fri, 23 Jan 2015 20:03:47 +0000 Subject: [PATCH] cefclient: Linux: Move GTK dialog handlers from ClientHandler into a separate class (issue #1500). git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1991 5089003a-bbd8-11dd-ad1f-f1f9622dbc98 --- cef_paths2.gypi | 2 + tests/cefclient/client_handler.cc | 67 ++--- tests/cefclient/client_handler.h | 42 +-- tests/cefclient/client_handler_gtk.cc | 380 ------------------------ tests/cefclient/dialog_handler_gtk.cc | 402 ++++++++++++++++++++++++++ tests/cefclient/dialog_handler_gtk.h | 65 +++++ tests/cefclient/print_handler_gtk.h | 17 +- 7 files changed, 501 insertions(+), 474 deletions(-) create mode 100644 tests/cefclient/dialog_handler_gtk.cc create mode 100644 tests/cefclient/dialog_handler_gtk.h diff --git a/cef_paths2.gypi b/cef_paths2.gypi index fcd9af987..0d538bf65 100644 --- a/cef_paths2.gypi +++ b/cef_paths2.gypi @@ -261,6 +261,8 @@ 'cefclient_sources_linux': [ 'tests/cefclient/cefclient_gtk.cc', 'tests/cefclient/client_handler_gtk.cc', + 'tests/cefclient/dialog_handler_gtk.cc', + 'tests/cefclient/dialog_handler_gtk.h', 'tests/cefclient/main_context_impl_posix.cc', 'tests/cefclient/osr_widget_gtk.h', 'tests/cefclient/osr_widget_gtk.cc', diff --git a/tests/cefclient/client_handler.cc b/tests/cefclient/client_handler.cc index 914f41944..2861dd6da 100644 --- a/tests/cefclient/client_handler.cc +++ b/tests/cefclient/client_handler.cc @@ -26,6 +26,10 @@ #include "cefclient/resource_util.h" #include "cefclient/test_runner.h" +#if defined(OS_LINUX) +#include "cefclient/dialog_handler_gtk.h" +#endif + namespace client { #if defined(OS_WIN) @@ -65,12 +69,16 @@ ClientHandler::ClientHandler() console_log_file_(MainContext::Get()->GetConsoleLogPath()), first_console_message_(true), focus_on_editable_field_(false) { -#if defined(OS_LINUX) - gtk_dialog_ = NULL; -#endif - DCHECK(!console_log_file_.empty()); +#if defined(OS_LINUX) + // Provide the GTK-based dialog implementation on Linux. + CefRefPtr dialog_handler = + new ClientDialogHandlerGtk(); + dialog_handler_ = dialog_handler.get(); + jsdialog_handler_ = dialog_handler.get(); +#endif + // Read command line settings. CefRefPtr command_line = CefCommandLine::GetGlobalCommandLine(); @@ -152,22 +160,6 @@ bool ClientHandler::OnContextMenuCommand( } } -#if !defined(OS_LINUX) - -bool ClientHandler::OnFileDialog(CefRefPtr browser, - FileDialogMode mode, - const CefString& title, - const CefString& default_file_path, - const std::vector& accept_filters, - int selected_accept_filter, - CefRefPtr callback) { - CEF_REQUIRE_UI_THREAD(); - - return false; -} - -#endif // !defined(OS_LINUX) - bool ClientHandler::OnConsoleMessage(CefRefPtr browser, const CefString& message, const CefString& source, @@ -243,35 +235,6 @@ 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) { - CEF_REQUIRE_UI_THREAD(); - return false; -} - -bool ClientHandler::OnBeforeUnloadDialog( - CefRefPtr browser, - const CefString& message_text, - bool is_reload, - CefRefPtr callback) { - CEF_REQUIRE_UI_THREAD(); - return false; -} - -void ClientHandler::OnResetDialogState(CefRefPtr browser) { - CEF_REQUIRE_UI_THREAD(); -} - -#endif // !defined(OS_LINUX) - bool ClientHandler::OnPreKeyEvent(CefRefPtr browser, const CefKeyEvent& event, CefEventHandle os_event, @@ -607,6 +570,12 @@ void ClientHandler::SetMainWindowHandle(ClientWindowHandle handle) { } main_handle_ = handle; + +#if defined(OS_LINUX) + // Associate |handle| with the GTK dialog handler. + static_cast(dialog_handler_.get())->set_parent( + handle); +#endif } ClientWindowHandle ClientHandler::GetMainWindowHandle() const { diff --git a/tests/cefclient/client_handler.h b/tests/cefclient/client_handler.h index ee9132841..901b39a01 100644 --- a/tests/cefclient/client_handler.h +++ b/tests/cefclient/client_handler.h @@ -33,12 +33,10 @@ namespace client { // ClientHandler implementation. class ClientHandler : public CefClient, public CefContextMenuHandler, - public CefDialogHandler, public CefDisplayHandler, public CefDownloadHandler, public CefDragHandler, public CefGeolocationHandler, - public CefJSDialogHandler, public CefKeyboardHandler, public CefLifeSpanHandler, public CefLoadHandler, @@ -61,7 +59,7 @@ class ClientHandler : public CefClient, return this; } CefRefPtr GetDialogHandler() OVERRIDE { - return this; + return dialog_handler_; } CefRefPtr GetDisplayHandler() OVERRIDE { return this; @@ -76,7 +74,7 @@ class ClientHandler : public CefClient, return this; } CefRefPtr GetJSDialogHandler() OVERRIDE { - return this; + return jsdialog_handler_; } CefRefPtr GetKeyboardHandler() OVERRIDE { return this; @@ -108,15 +106,6 @@ class ClientHandler : public CefClient, int command_id, EventFlags event_flags) OVERRIDE; - // CefDialogHandler methods - bool OnFileDialog(CefRefPtr browser, - FileDialogMode mode, - const CefString& title, - const CefString& default_file_path, - const std::vector& accept_filters, - int selected_accept_filter, - CefRefPtr callback) OVERRIDE; - // CefDisplayHandler methods void OnAddressChange(CefRefPtr browser, CefRefPtr frame, @@ -151,22 +140,6 @@ class ClientHandler : public CefClient, int request_id, CefRefPtr callback) OVERRIDE; - // CefJSDialogHandler methods - 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; - bool OnBeforeUnloadDialog( - CefRefPtr browser, - const CefString& message_text, - bool is_reload, - CefRefPtr callback) OVERRIDE; - void OnResetDialogState(CefRefPtr browser) OVERRIDE; - // CefKeyboardHandler methods bool OnPreKeyEvent(CefRefPtr browser, const CefKeyEvent& event, @@ -302,6 +275,9 @@ class ClientHandler : public CefClient, // True if mouse cursor change is disabled. bool mouse_cursor_change_disabled_; + + CefRefPtr dialog_handler_; + CefRefPtr jsdialog_handler_; // END THREAD SAFE MEMBERS // Lock used to protect members accessed on multiple threads. Make it mutable @@ -362,14 +338,6 @@ class ClientHandler : public CefClient, // when the number of windows reaches 0. static int browser_count_; -#if defined(OS_LINUX) - // Linux-only implementation of GTK-based dialog boxes. - static void OnDialogResponse(GtkDialog *dialog, - gint response_id, - ClientHandler* handler); - GtkWidget* gtk_dialog_; - CefRefPtr js_dialog_callback_; -#endif // END UI THREAD ACCESS ONLY MEMBERS // Include the default reference counting implementation. diff --git a/tests/cefclient/client_handler_gtk.cc b/tests/cefclient/client_handler_gtk.cc index b1718f070..ec447a1a9 100644 --- a/tests/cefclient/client_handler_gtk.cc +++ b/tests/cefclient/client_handler_gtk.cc @@ -13,261 +13,9 @@ #include "cefclient/client_handler.h" #include "include/cef_browser.h" #include "include/cef_frame.h" -#include "include/cef_url.h" namespace client { -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(); -} - -std::string GetDescriptionFromMimeType(const std::string& mime_type) { - // Check for wild card mime types and return an appropriate description. - static const struct { - const char* mime_type; - const char* label; - } kWildCardMimeTypes[] = { - { "audio", "Audio Files" }, - { "image", "Image Files" }, - { "text", "Text Files" }, - { "video", "Video Files" }, - }; - - for (size_t i = 0; - i < sizeof(kWildCardMimeTypes) / sizeof(kWildCardMimeTypes[0]); ++i) { - if (mime_type == std::string(kWildCardMimeTypes[i].mime_type) + "/*") - return std::string(kWildCardMimeTypes[i].label); - } - - return std::string(); -} - -void AddFilters(GtkFileChooser* chooser, - const std::vector& accept_filters, - bool include_all_files, - std::vector* filters) { - bool has_filter = false; - - for (size_t i = 0; i < accept_filters.size(); ++i) { - const std::string& filter = accept_filters[i]; - if (filter.empty()) - continue; - - std::vector extensions; - std::string description; - - size_t sep_index = filter.find('|'); - if (sep_index != std::string::npos) { - // Treat as a filter of the form "Filter Name|.ext1;.ext2;.ext3". - description = filter.substr(0, sep_index); - - const std::string& exts = filter.substr(sep_index + 1); - size_t last = 0; - size_t size = exts.size(); - for (size_t i = 0; i <= size; ++i) { - if (i == size || exts[i] == ';') { - std::string ext(exts, last, i - last); - if (!ext.empty() && ext[0] == '.') - extensions.push_back(ext); - last = i + 1; - } - } - } else if (filter[0] == '.') { - // Treat as an extension beginning with the '.' character. - extensions.push_back(filter); - } else { - // Otherwise convert mime type to one or more extensions. - description = GetDescriptionFromMimeType(filter); - - std::vector ext; - CefGetExtensionsForMimeType(filter, ext); - for (size_t x = 0; x < ext.size(); ++x) - extensions.push_back("." + ext[x].ToString()); - } - - if (extensions.empty()) - continue; - - GtkFileFilter* gtk_filter = gtk_file_filter_new(); - - std::string ext_str; - for (size_t x = 0; x < extensions.size(); ++x) { - const std::string& pattern = "*" + extensions[x]; - if (x != 0) - ext_str += ";"; - ext_str += pattern; - gtk_file_filter_add_pattern(gtk_filter, pattern.c_str()); - } - - if (description.empty()) - description = ext_str; - else - description += " (" + ext_str + ")"; - - gtk_file_filter_set_name(gtk_filter, description.c_str()); - gtk_file_chooser_add_filter(chooser, gtk_filter); - if (!has_filter) - has_filter = true; - - filters->push_back(gtk_filter); - } - - // Add the *.* filter, but only if we have added other filters (otherwise it - // is implied). - if (include_all_files && has_filter) { - GtkFileFilter* filter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(filter, "*"); - gtk_file_filter_set_name(filter, "All Files (*)"); - gtk_file_chooser_add_filter(chooser, filter); - } -} - -} // namespace - -bool ClientHandler::OnFileDialog(CefRefPtr browser, - FileDialogMode mode, - const CefString& title, - const CefString& default_file_path, - const std::vector& accept_filters, - int selected_accept_filter, - CefRefPtr callback) { - std::vector files; - - GtkFileChooserAction action; - const gchar* accept_button; - - // Remove any modifier flags. - FileDialogMode mode_type = - static_cast(mode & FILE_DIALOG_TYPE_MASK); - - if (mode_type == FILE_DIALOG_OPEN || mode_type == FILE_DIALOG_OPEN_MULTIPLE) { - action = GTK_FILE_CHOOSER_ACTION_OPEN; - accept_button = GTK_STOCK_OPEN; - } else if (mode_type == FILE_DIALOG_OPEN_FOLDER) { - action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; - accept_button = GTK_STOCK_OPEN; - } else if (mode_type == FILE_DIALOG_SAVE) { - action = GTK_FILE_CHOOSER_ACTION_SAVE; - accept_button = GTK_STOCK_SAVE; - } else { - NOTREACHED(); - return false; - } - - std::string title_str; - if (!title.empty()) { - title_str = title; - } else { - switch (mode) { - case FILE_DIALOG_OPEN: - title_str = "Open File"; - break; - case FILE_DIALOG_OPEN_MULTIPLE: - title_str = "Open Files"; - break; - case FILE_DIALOG_OPEN_FOLDER: - title_str = "Open Folder"; - break; - case FILE_DIALOG_SAVE: - title_str = "Save File"; - break; - default: - break; - } - } - - GtkWidget* window = gtk_widget_get_ancestor( - GTK_WIDGET(GetMainWindowHandle()), GTK_TYPE_WINDOW); - GtkWidget* dialog = gtk_file_chooser_dialog_new( - title_str.c_str(), - GTK_WINDOW(window), - action, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - accept_button, GTK_RESPONSE_ACCEPT, - NULL); - - if (mode_type == FILE_DIALOG_OPEN_MULTIPLE) - gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE); - - if (mode_type == FILE_DIALOG_SAVE) { - gtk_file_chooser_set_do_overwrite_confirmation( - GTK_FILE_CHOOSER(dialog), - !!(mode & FILE_DIALOG_OVERWRITEPROMPT_FLAG)); - } - - gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog), - !(mode & FILE_DIALOG_HIDEREADONLY_FLAG)); - - if (!default_file_path.empty()) { - gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), - default_file_path.ToString().c_str()); - } - - std::vector filters; - AddFilters(GTK_FILE_CHOOSER(dialog), accept_filters, true, &filters); - if (selected_accept_filter < static_cast(filters.size())) { - gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), - filters[selected_accept_filter]); - } - - bool success = false; - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - if (mode_type == FILE_DIALOG_OPEN || mode_type == FILE_DIALOG_OPEN_FOLDER || - mode_type == FILE_DIALOG_SAVE) { - char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - files.push_back(std::string(filename)); - success = true; - } else if (mode_type == FILE_DIALOG_OPEN_MULTIPLE) { - GSList* filenames = - gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); - if (filenames) { - for (GSList* iter = filenames; iter != NULL; - iter = g_slist_next(iter)) { - std::string path(static_cast(iter->data)); - g_free(iter->data); - files.push_back(path); - } - g_slist_free(filenames); - success = true; - } - } - } - - int filter_index = selected_accept_filter; - if (success) { - GtkFileFilter* selected_filter = - gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog)); - if (selected_filter != NULL) { - for (size_t x = 0; x < filters.size(); ++x) { - if (filters[x] == selected_filter) { - filter_index = x; - break; - } - } - } - } - - gtk_widget_destroy(dialog); - - if (success) - callback->Continue(filter_index, files); - else - callback->Cancel(); - - return true; -} - void ClientHandler::OnAddressChange(CefRefPtr browser, CefRefPtr frame, const CefString& url) { @@ -330,134 +78,6 @@ 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) { - CEF_REQUIRE_UI_THREAD(); - - 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(GetMainWindowHandle()), 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) { - CEF_REQUIRE_UI_THREAD(); - - 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) { - CEF_REQUIRE_UI_THREAD(); - - 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) { - CEF_REQUIRE_UI_THREAD(); - - DCHECK_EQ(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: - NOTREACHED(); - } - - handler->OnResetDialogState(NULL); -} - void ClientHandler::SetLoading(bool isLoading) { CEF_REQUIRE_UI_THREAD(); diff --git a/tests/cefclient/dialog_handler_gtk.cc b/tests/cefclient/dialog_handler_gtk.cc new file mode 100644 index 000000000..e99591a85 --- /dev/null +++ b/tests/cefclient/dialog_handler_gtk.cc @@ -0,0 +1,402 @@ +// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "cefclient/dialog_handler_gtk.h" +#include "include/cef_browser.h" +#include "include/cef_url.h" +#include "include/wrapper/cef_helpers.h" + +namespace client { + +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(); +} + +std::string GetDescriptionFromMimeType(const std::string& mime_type) { + // Check for wild card mime types and return an appropriate description. + static const struct { + const char* mime_type; + const char* label; + } kWildCardMimeTypes[] = { + { "audio", "Audio Files" }, + { "image", "Image Files" }, + { "text", "Text Files" }, + { "video", "Video Files" }, + }; + + for (size_t i = 0; + i < sizeof(kWildCardMimeTypes) / sizeof(kWildCardMimeTypes[0]); ++i) { + if (mime_type == std::string(kWildCardMimeTypes[i].mime_type) + "/*") + return std::string(kWildCardMimeTypes[i].label); + } + + return std::string(); +} + +void AddFilters(GtkFileChooser* chooser, + const std::vector& accept_filters, + bool include_all_files, + std::vector* filters) { + bool has_filter = false; + + for (size_t i = 0; i < accept_filters.size(); ++i) { + const std::string& filter = accept_filters[i]; + if (filter.empty()) + continue; + + std::vector extensions; + std::string description; + + size_t sep_index = filter.find('|'); + if (sep_index != std::string::npos) { + // Treat as a filter of the form "Filter Name|.ext1;.ext2;.ext3". + description = filter.substr(0, sep_index); + + const std::string& exts = filter.substr(sep_index + 1); + size_t last = 0; + size_t size = exts.size(); + for (size_t i = 0; i <= size; ++i) { + if (i == size || exts[i] == ';') { + std::string ext(exts, last, i - last); + if (!ext.empty() && ext[0] == '.') + extensions.push_back(ext); + last = i + 1; + } + } + } else if (filter[0] == '.') { + // Treat as an extension beginning with the '.' character. + extensions.push_back(filter); + } else { + // Otherwise convert mime type to one or more extensions. + description = GetDescriptionFromMimeType(filter); + + std::vector ext; + CefGetExtensionsForMimeType(filter, ext); + for (size_t x = 0; x < ext.size(); ++x) + extensions.push_back("." + ext[x].ToString()); + } + + if (extensions.empty()) + continue; + + GtkFileFilter* gtk_filter = gtk_file_filter_new(); + + std::string ext_str; + for (size_t x = 0; x < extensions.size(); ++x) { + const std::string& pattern = "*" + extensions[x]; + if (x != 0) + ext_str += ";"; + ext_str += pattern; + gtk_file_filter_add_pattern(gtk_filter, pattern.c_str()); + } + + if (description.empty()) + description = ext_str; + else + description += " (" + ext_str + ")"; + + gtk_file_filter_set_name(gtk_filter, description.c_str()); + gtk_file_chooser_add_filter(chooser, gtk_filter); + if (!has_filter) + has_filter = true; + + filters->push_back(gtk_filter); + } + + // Add the *.* filter, but only if we have added other filters (otherwise it + // is implied). + if (include_all_files && has_filter) { + GtkFileFilter* filter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(filter, "*"); + gtk_file_filter_set_name(filter, "All Files (*)"); + gtk_file_chooser_add_filter(chooser, filter); + } +} + +} // namespace + + +ClientDialogHandlerGtk::ClientDialogHandlerGtk() + : gtk_parent_(NULL), + gtk_dialog_(NULL) { +} + +bool ClientDialogHandlerGtk::OnFileDialog( + CefRefPtr browser, + FileDialogMode mode, + const CefString& title, + const CefString& default_file_path, + const std::vector& accept_filters, + int selected_accept_filter, + CefRefPtr callback) { + std::vector files; + + GtkFileChooserAction action; + const gchar* accept_button; + + // Remove any modifier flags. + FileDialogMode mode_type = + static_cast(mode & FILE_DIALOG_TYPE_MASK); + + if (mode_type == FILE_DIALOG_OPEN || mode_type == FILE_DIALOG_OPEN_MULTIPLE) { + action = GTK_FILE_CHOOSER_ACTION_OPEN; + accept_button = GTK_STOCK_OPEN; + } else if (mode_type == FILE_DIALOG_OPEN_FOLDER) { + action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; + accept_button = GTK_STOCK_OPEN; + } else if (mode_type == FILE_DIALOG_SAVE) { + action = GTK_FILE_CHOOSER_ACTION_SAVE; + accept_button = GTK_STOCK_SAVE; + } else { + NOTREACHED(); + return false; + } + + std::string title_str; + if (!title.empty()) { + title_str = title; + } else { + switch (mode) { + case FILE_DIALOG_OPEN: + title_str = "Open File"; + break; + case FILE_DIALOG_OPEN_MULTIPLE: + title_str = "Open Files"; + break; + case FILE_DIALOG_OPEN_FOLDER: + title_str = "Open Folder"; + break; + case FILE_DIALOG_SAVE: + title_str = "Save File"; + break; + default: + break; + } + } + + DCHECK(gtk_parent_); + GtkWidget* window = gtk_widget_get_ancestor( + GTK_WIDGET(gtk_parent_), GTK_TYPE_WINDOW); + GtkWidget* dialog = gtk_file_chooser_dialog_new( + title_str.c_str(), + GTK_WINDOW(window), + action, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + accept_button, GTK_RESPONSE_ACCEPT, + NULL); + + if (mode_type == FILE_DIALOG_OPEN_MULTIPLE) + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE); + + if (mode_type == FILE_DIALOG_SAVE) { + gtk_file_chooser_set_do_overwrite_confirmation( + GTK_FILE_CHOOSER(dialog), + !!(mode & FILE_DIALOG_OVERWRITEPROMPT_FLAG)); + } + + gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog), + !(mode & FILE_DIALOG_HIDEREADONLY_FLAG)); + + if (!default_file_path.empty()) { + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), + default_file_path.ToString().c_str()); + } + + std::vector filters; + AddFilters(GTK_FILE_CHOOSER(dialog), accept_filters, true, &filters); + if (selected_accept_filter < static_cast(filters.size())) { + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), + filters[selected_accept_filter]); + } + + bool success = false; + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + if (mode_type == FILE_DIALOG_OPEN || mode_type == FILE_DIALOG_OPEN_FOLDER || + mode_type == FILE_DIALOG_SAVE) { + char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + files.push_back(std::string(filename)); + success = true; + } else if (mode_type == FILE_DIALOG_OPEN_MULTIPLE) { + GSList* filenames = + gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); + if (filenames) { + for (GSList* iter = filenames; iter != NULL; + iter = g_slist_next(iter)) { + std::string path(static_cast(iter->data)); + g_free(iter->data); + files.push_back(path); + } + g_slist_free(filenames); + success = true; + } + } + } + + int filter_index = selected_accept_filter; + if (success) { + GtkFileFilter* selected_filter = + gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog)); + if (selected_filter != NULL) { + for (size_t x = 0; x < filters.size(); ++x) { + if (filters[x] == selected_filter) { + filter_index = x; + break; + } + } + } + } + + gtk_widget_destroy(dialog); + + if (success) + callback->Continue(filter_index, files); + else + callback->Cancel(); + + return true; +} + +bool ClientDialogHandlerGtk::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) { + CEF_REQUIRE_UI_THREAD(); + + 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(); + } + + DCHECK(gtk_parent_); + GtkWidget* window = gtk_widget_get_ancestor( + GTK_WIDGET(gtk_parent_), 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 ClientDialogHandlerGtk::OnBeforeUnloadDialog( + CefRefPtr browser, + const CefString& message_text, + bool is_reload, + CefRefPtr callback) { + CEF_REQUIRE_UI_THREAD(); + + 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 ClientDialogHandlerGtk::OnResetDialogState(CefRefPtr browser) { + CEF_REQUIRE_UI_THREAD(); + + if (!gtk_dialog_) + return; + gtk_widget_destroy(gtk_dialog_); + gtk_dialog_ = NULL; + js_dialog_callback_ = NULL; +} + +// static +void ClientDialogHandlerGtk::OnDialogResponse(GtkDialog* dialog, + gint response_id, + ClientDialogHandlerGtk* handler) { + CEF_REQUIRE_UI_THREAD(); + + DCHECK_EQ(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: + NOTREACHED(); + } + + handler->OnResetDialogState(NULL); +} + +} // namespace client + diff --git a/tests/cefclient/dialog_handler_gtk.h b/tests/cefclient/dialog_handler_gtk.h new file mode 100644 index 000000000..fa772c299 --- /dev/null +++ b/tests/cefclient/dialog_handler_gtk.h @@ -0,0 +1,65 @@ +// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#ifndef CEF_TESTS_CEFCLIENT_DIALOG_HANDLER_GTK_H_ +#define CEF_TESTS_CEFCLIENT_DIALOG_HANDLER_GTK_H_ +#pragma once + +#include + +#include "include/cef_dialog_handler.h" +#include "include/cef_jsdialog_handler.h" + +namespace client { + +class ClientDialogHandlerGtk : public CefDialogHandler, + public CefJSDialogHandler { + public: + ClientDialogHandlerGtk(); + + // CefDialogHandler methods. + bool OnFileDialog(CefRefPtr browser, + FileDialogMode mode, + const CefString& title, + const CefString& default_file_path, + const std::vector& accept_filters, + int selected_accept_filter, + CefRefPtr callback) OVERRIDE; + + // CefJSDialogHandler methods. + 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; + bool OnBeforeUnloadDialog( + CefRefPtr browser, + const CefString& message_text, + bool is_reload, + CefRefPtr callback) OVERRIDE; + void OnResetDialogState(CefRefPtr browser) OVERRIDE; + + void set_parent(GtkWidget* parent) { + gtk_parent_ = parent; + } + + private: + static void OnDialogResponse(GtkDialog *dialog, + gint response_id, + ClientDialogHandlerGtk* handler); + + GtkWidget* gtk_parent_; + GtkWidget* gtk_dialog_; + CefRefPtr js_dialog_callback_; + + IMPLEMENT_REFCOUNTING(ClientDialogHandlerGtk); + DISALLOW_COPY_AND_ASSIGN(ClientDialogHandlerGtk); +}; + +} // namespace client + +#endif // CEF_TESTS_CEFCLIENT_DIALOG_HANDLER_GTK_H_ diff --git a/tests/cefclient/print_handler_gtk.h b/tests/cefclient/print_handler_gtk.h index 0949e3b23..4ac163dcf 100644 --- a/tests/cefclient/print_handler_gtk.h +++ b/tests/cefclient/print_handler_gtk.h @@ -18,16 +18,16 @@ class ClientPrintHandlerGtk : public CefPrintHandler { public: ClientPrintHandlerGtk(); - // CefPrintHandler methods - virtual void OnPrintSettings(CefRefPtr settings, - bool get_defaults) OVERRIDE; - virtual bool OnPrintDialog( + // CefPrintHandler methods. + void OnPrintSettings(CefRefPtr settings, + bool get_defaults) OVERRIDE; + bool OnPrintDialog( bool has_selection, CefRefPtr callback) OVERRIDE; - virtual bool OnPrintJob(const CefString& document_name, - const CefString& pdf_file_path, - CefRefPtr callback) OVERRIDE; - virtual void OnPrintReset() OVERRIDE; + bool OnPrintJob(const CefString& document_name, + const CefString& pdf_file_path, + CefRefPtr callback) OVERRIDE; + void OnPrintReset() OVERRIDE; private: void OnDialogResponse(GtkDialog *dialog, @@ -58,6 +58,7 @@ class ClientPrintHandlerGtk : public CefPrintHandler { CefRefPtr job_callback_; IMPLEMENT_REFCOUNTING(ClientPrintHandlerGtk); + DISALLOW_COPY_AND_ASSIGN(ClientPrintHandlerGtk); }; } // namespace client