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
This commit is contained in:
Marshall Greenblatt 2015-01-23 20:03:47 +00:00
parent dfc2dfb0f5
commit f38c620e28
7 changed files with 501 additions and 474 deletions

View File

@ -261,6 +261,8 @@
'cefclient_sources_linux': [ 'cefclient_sources_linux': [
'tests/cefclient/cefclient_gtk.cc', 'tests/cefclient/cefclient_gtk.cc',
'tests/cefclient/client_handler_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/main_context_impl_posix.cc',
'tests/cefclient/osr_widget_gtk.h', 'tests/cefclient/osr_widget_gtk.h',
'tests/cefclient/osr_widget_gtk.cc', 'tests/cefclient/osr_widget_gtk.cc',

View File

@ -26,6 +26,10 @@
#include "cefclient/resource_util.h" #include "cefclient/resource_util.h"
#include "cefclient/test_runner.h" #include "cefclient/test_runner.h"
#if defined(OS_LINUX)
#include "cefclient/dialog_handler_gtk.h"
#endif
namespace client { namespace client {
#if defined(OS_WIN) #if defined(OS_WIN)
@ -65,12 +69,16 @@ ClientHandler::ClientHandler()
console_log_file_(MainContext::Get()->GetConsoleLogPath()), console_log_file_(MainContext::Get()->GetConsoleLogPath()),
first_console_message_(true), first_console_message_(true),
focus_on_editable_field_(false) { focus_on_editable_field_(false) {
#if defined(OS_LINUX)
gtk_dialog_ = NULL;
#endif
DCHECK(!console_log_file_.empty()); DCHECK(!console_log_file_.empty());
#if defined(OS_LINUX)
// Provide the GTK-based dialog implementation on Linux.
CefRefPtr<ClientDialogHandlerGtk> dialog_handler =
new ClientDialogHandlerGtk();
dialog_handler_ = dialog_handler.get();
jsdialog_handler_ = dialog_handler.get();
#endif
// Read command line settings. // Read command line settings.
CefRefPtr<CefCommandLine> command_line = CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine(); CefCommandLine::GetGlobalCommandLine();
@ -152,22 +160,6 @@ bool ClientHandler::OnContextMenuCommand(
} }
} }
#if !defined(OS_LINUX)
bool ClientHandler::OnFileDialog(CefRefPtr<CefBrowser> browser,
FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefFileDialogCallback> callback) {
CEF_REQUIRE_UI_THREAD();
return false;
}
#endif // !defined(OS_LINUX)
bool ClientHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser, bool ClientHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser,
const CefString& message, const CefString& message,
const CefString& source, const CefString& source,
@ -243,35 +235,6 @@ bool ClientHandler::OnRequestGeolocationPermission(
return true; return true;
} }
#if !defined(OS_LINUX)
bool ClientHandler::OnJSDialog(CefRefPtr<CefBrowser> browser,
const CefString& origin_url,
const CefString& accept_lang,
JSDialogType dialog_type,
const CefString& message_text,
const CefString& default_prompt_text,
CefRefPtr<CefJSDialogCallback> callback,
bool& suppress_message) {
CEF_REQUIRE_UI_THREAD();
return false;
}
bool ClientHandler::OnBeforeUnloadDialog(
CefRefPtr<CefBrowser> browser,
const CefString& message_text,
bool is_reload,
CefRefPtr<CefJSDialogCallback> callback) {
CEF_REQUIRE_UI_THREAD();
return false;
}
void ClientHandler::OnResetDialogState(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
}
#endif // !defined(OS_LINUX)
bool ClientHandler::OnPreKeyEvent(CefRefPtr<CefBrowser> browser, bool ClientHandler::OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
const CefKeyEvent& event, const CefKeyEvent& event,
CefEventHandle os_event, CefEventHandle os_event,
@ -607,6 +570,12 @@ void ClientHandler::SetMainWindowHandle(ClientWindowHandle handle) {
} }
main_handle_ = handle; main_handle_ = handle;
#if defined(OS_LINUX)
// Associate |handle| with the GTK dialog handler.
static_cast<ClientDialogHandlerGtk*>(dialog_handler_.get())->set_parent(
handle);
#endif
} }
ClientWindowHandle ClientHandler::GetMainWindowHandle() const { ClientWindowHandle ClientHandler::GetMainWindowHandle() const {

View File

@ -33,12 +33,10 @@ namespace client {
// ClientHandler implementation. // ClientHandler implementation.
class ClientHandler : public CefClient, class ClientHandler : public CefClient,
public CefContextMenuHandler, public CefContextMenuHandler,
public CefDialogHandler,
public CefDisplayHandler, public CefDisplayHandler,
public CefDownloadHandler, public CefDownloadHandler,
public CefDragHandler, public CefDragHandler,
public CefGeolocationHandler, public CefGeolocationHandler,
public CefJSDialogHandler,
public CefKeyboardHandler, public CefKeyboardHandler,
public CefLifeSpanHandler, public CefLifeSpanHandler,
public CefLoadHandler, public CefLoadHandler,
@ -61,7 +59,7 @@ class ClientHandler : public CefClient,
return this; return this;
} }
CefRefPtr<CefDialogHandler> GetDialogHandler() OVERRIDE { CefRefPtr<CefDialogHandler> GetDialogHandler() OVERRIDE {
return this; return dialog_handler_;
} }
CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE { CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE {
return this; return this;
@ -76,7 +74,7 @@ class ClientHandler : public CefClient,
return this; return this;
} }
CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() OVERRIDE { CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() OVERRIDE {
return this; return jsdialog_handler_;
} }
CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() OVERRIDE { CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() OVERRIDE {
return this; return this;
@ -108,15 +106,6 @@ class ClientHandler : public CefClient,
int command_id, int command_id,
EventFlags event_flags) OVERRIDE; EventFlags event_flags) OVERRIDE;
// CefDialogHandler methods
bool OnFileDialog(CefRefPtr<CefBrowser> browser,
FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefFileDialogCallback> callback) OVERRIDE;
// CefDisplayHandler methods // CefDisplayHandler methods
void OnAddressChange(CefRefPtr<CefBrowser> browser, void OnAddressChange(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, CefRefPtr<CefFrame> frame,
@ -151,22 +140,6 @@ class ClientHandler : public CefClient,
int request_id, int request_id,
CefRefPtr<CefGeolocationCallback> callback) OVERRIDE; CefRefPtr<CefGeolocationCallback> callback) OVERRIDE;
// CefJSDialogHandler methods
bool OnJSDialog(CefRefPtr<CefBrowser> browser,
const CefString& origin_url,
const CefString& accept_lang,
JSDialogType dialog_type,
const CefString& message_text,
const CefString& default_prompt_text,
CefRefPtr<CefJSDialogCallback> callback,
bool& suppress_message) OVERRIDE;
bool OnBeforeUnloadDialog(
CefRefPtr<CefBrowser> browser,
const CefString& message_text,
bool is_reload,
CefRefPtr<CefJSDialogCallback> callback) OVERRIDE;
void OnResetDialogState(CefRefPtr<CefBrowser> browser) OVERRIDE;
// CefKeyboardHandler methods // CefKeyboardHandler methods
bool OnPreKeyEvent(CefRefPtr<CefBrowser> browser, bool OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
const CefKeyEvent& event, const CefKeyEvent& event,
@ -302,6 +275,9 @@ class ClientHandler : public CefClient,
// True if mouse cursor change is disabled. // True if mouse cursor change is disabled.
bool mouse_cursor_change_disabled_; bool mouse_cursor_change_disabled_;
CefRefPtr<CefDialogHandler> dialog_handler_;
CefRefPtr<CefJSDialogHandler> jsdialog_handler_;
// END THREAD SAFE MEMBERS // END THREAD SAFE MEMBERS
// Lock used to protect members accessed on multiple threads. Make it mutable // 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. // when the number of windows reaches 0.
static int browser_count_; 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<CefJSDialogCallback> js_dialog_callback_;
#endif
// END UI THREAD ACCESS ONLY MEMBERS // END UI THREAD ACCESS ONLY MEMBERS
// Include the default reference counting implementation. // Include the default reference counting implementation.

View File

@ -13,261 +13,9 @@
#include "cefclient/client_handler.h" #include "cefclient/client_handler.h"
#include "include/cef_browser.h" #include "include/cef_browser.h"
#include "include/cef_frame.h" #include "include/cef_frame.h"
#include "include/cef_url.h"
namespace client { 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<GtkWidget*>(
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<CefString>& accept_filters,
bool include_all_files,
std::vector<GtkFileFilter*>* 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<std::string> 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<CefString> 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<CefBrowser> browser,
FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefFileDialogCallback> callback) {
std::vector<CefString> files;
GtkFileChooserAction action;
const gchar* accept_button;
// Remove any modifier flags.
FileDialogMode mode_type =
static_cast<FileDialogMode>(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<GtkFileFilter*> filters;
AddFilters(GTK_FILE_CHOOSER(dialog), accept_filters, true, &filters);
if (selected_accept_filter < static_cast<int>(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<char*>(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<CefBrowser> browser, void ClientHandler::OnAddressChange(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, CefRefPtr<CefFrame> frame,
const CefString& url) { const CefString& url) {
@ -330,134 +78,6 @@ void ClientHandler::OnTitleChange(CefRefPtr<CefBrowser> browser,
} }
} }
bool ClientHandler::OnJSDialog(CefRefPtr<CefBrowser> browser,
const CefString& origin_url,
const CefString& accept_lang,
JSDialogType dialog_type,
const CefString& message_text,
const CefString& default_prompt_text,
CefRefPtr<CefJSDialogCallback> 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<CefBrowser> browser,
const CefString& message_text,
bool is_reload,
CefRefPtr<CefJSDialogCallback> 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<CefBrowser> 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) { void ClientHandler::SetLoading(bool isLoading) {
CEF_REQUIRE_UI_THREAD(); CEF_REQUIRE_UI_THREAD();

View File

@ -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<GtkWidget*>(
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<CefString>& accept_filters,
bool include_all_files,
std::vector<GtkFileFilter*>* 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<std::string> 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<CefString> 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<CefBrowser> browser,
FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefFileDialogCallback> callback) {
std::vector<CefString> files;
GtkFileChooserAction action;
const gchar* accept_button;
// Remove any modifier flags.
FileDialogMode mode_type =
static_cast<FileDialogMode>(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<GtkFileFilter*> filters;
AddFilters(GTK_FILE_CHOOSER(dialog), accept_filters, true, &filters);
if (selected_accept_filter < static_cast<int>(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<char*>(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<CefBrowser> browser,
const CefString& origin_url,
const CefString& accept_lang,
JSDialogType dialog_type,
const CefString& message_text,
const CefString& default_prompt_text,
CefRefPtr<CefJSDialogCallback> 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<CefBrowser> browser,
const CefString& message_text,
bool is_reload,
CefRefPtr<CefJSDialogCallback> 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<CefBrowser> 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

View File

@ -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 <gtk/gtk.h>
#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<CefBrowser> browser,
FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
const std::vector<CefString>& accept_filters,
int selected_accept_filter,
CefRefPtr<CefFileDialogCallback> callback) OVERRIDE;
// CefJSDialogHandler methods.
bool OnJSDialog(CefRefPtr<CefBrowser> browser,
const CefString& origin_url,
const CefString& accept_lang,
JSDialogType dialog_type,
const CefString& message_text,
const CefString& default_prompt_text,
CefRefPtr<CefJSDialogCallback> callback,
bool& suppress_message) OVERRIDE;
bool OnBeforeUnloadDialog(
CefRefPtr<CefBrowser> browser,
const CefString& message_text,
bool is_reload,
CefRefPtr<CefJSDialogCallback> callback) OVERRIDE;
void OnResetDialogState(CefRefPtr<CefBrowser> 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<CefJSDialogCallback> js_dialog_callback_;
IMPLEMENT_REFCOUNTING(ClientDialogHandlerGtk);
DISALLOW_COPY_AND_ASSIGN(ClientDialogHandlerGtk);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_DIALOG_HANDLER_GTK_H_

View File

@ -18,16 +18,16 @@ class ClientPrintHandlerGtk : public CefPrintHandler {
public: public:
ClientPrintHandlerGtk(); ClientPrintHandlerGtk();
// CefPrintHandler methods // CefPrintHandler methods.
virtual void OnPrintSettings(CefRefPtr<CefPrintSettings> settings, void OnPrintSettings(CefRefPtr<CefPrintSettings> settings,
bool get_defaults) OVERRIDE; bool get_defaults) OVERRIDE;
virtual bool OnPrintDialog( bool OnPrintDialog(
bool has_selection, bool has_selection,
CefRefPtr<CefPrintDialogCallback> callback) OVERRIDE; CefRefPtr<CefPrintDialogCallback> callback) OVERRIDE;
virtual bool OnPrintJob(const CefString& document_name, bool OnPrintJob(const CefString& document_name,
const CefString& pdf_file_path, const CefString& pdf_file_path,
CefRefPtr<CefPrintJobCallback> callback) OVERRIDE; CefRefPtr<CefPrintJobCallback> callback) OVERRIDE;
virtual void OnPrintReset() OVERRIDE; void OnPrintReset() OVERRIDE;
private: private:
void OnDialogResponse(GtkDialog *dialog, void OnDialogResponse(GtkDialog *dialog,
@ -58,6 +58,7 @@ class ClientPrintHandlerGtk : public CefPrintHandler {
CefRefPtr<CefPrintJobCallback> job_callback_; CefRefPtr<CefPrintJobCallback> job_callback_;
IMPLEMENT_REFCOUNTING(ClientPrintHandlerGtk); IMPLEMENT_REFCOUNTING(ClientPrintHandlerGtk);
DISALLOW_COPY_AND_ASSIGN(ClientPrintHandlerGtk);
}; };
} // namespace client } // namespace client