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': [
'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',

View File

@ -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<ClientDialogHandlerGtk> dialog_handler =
new ClientDialogHandlerGtk();
dialog_handler_ = dialog_handler.get();
jsdialog_handler_ = dialog_handler.get();
#endif
// Read command line settings.
CefRefPtr<CefCommandLine> command_line =
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,
const CefString& message,
const CefString& source,
@ -243,35 +235,6 @@ bool ClientHandler::OnRequestGeolocationPermission(
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,
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<ClientDialogHandlerGtk*>(dialog_handler_.get())->set_parent(
handle);
#endif
}
ClientWindowHandle ClientHandler::GetMainWindowHandle() const {

View File

@ -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<CefDialogHandler> GetDialogHandler() OVERRIDE {
return this;
return dialog_handler_;
}
CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE {
return this;
@ -76,7 +74,7 @@ class ClientHandler : public CefClient,
return this;
}
CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() OVERRIDE {
return this;
return jsdialog_handler_;
}
CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() OVERRIDE {
return this;
@ -108,15 +106,6 @@ class ClientHandler : public CefClient,
int command_id,
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
void OnAddressChange(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
@ -151,22 +140,6 @@ class ClientHandler : public CefClient,
int request_id,
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
bool OnPreKeyEvent(CefRefPtr<CefBrowser> 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<CefDialogHandler> dialog_handler_;
CefRefPtr<CefJSDialogHandler> 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<CefJSDialogCallback> js_dialog_callback_;
#endif
// END UI THREAD ACCESS ONLY MEMBERS
// Include the default reference counting implementation.

View File

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