mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	API versioning requires that enumerations end with a count value (`*_NUM_VALUES`) and structs begin with a size value (`size_t size`). Wrapper templates are updated to support structs with different size values indicating different versions. To test: Run `ceftests --gtest_filter=ApiVersionTest.StructVersion*`
		
			
				
	
	
		
			481 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			481 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// 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 "tests/cefclient/browser/dialog_handler_gtk.h"
 | 
						|
 | 
						|
#include <libgen.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
 | 
						|
#include "include/base/cef_logging.h"
 | 
						|
#include "include/cef_browser.h"
 | 
						|
#include "include/cef_parser.h"
 | 
						|
#include "include/wrapper/cef_helpers.h"
 | 
						|
#include "tests/cefclient/browser/root_window.h"
 | 
						|
#include "tests/cefclient/browser/util_gtk.h"
 | 
						|
#include "tests/shared/common/string_util.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);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  LOG(WARNING) << "Unrecognized mime type: " << mime_type;
 | 
						|
  return std::string();
 | 
						|
}
 | 
						|
 | 
						|
void AddFilters(GtkFileChooser* chooser,
 | 
						|
                const std::vector<CefString>& accept_filters,
 | 
						|
                const std::vector<CefString>& accept_extensions,
 | 
						|
                const std::vector<CefString>& accept_descriptions,
 | 
						|
                bool include_all_files,
 | 
						|
                std::vector<GtkFileFilter*>* filters) {
 | 
						|
  bool has_filter = false;
 | 
						|
 | 
						|
  for (size_t j = 0; j < accept_filters.size(); ++j) {
 | 
						|
    const std::string& filter = accept_filters[j];
 | 
						|
    if (filter.empty()) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    // Extensions and descriptions may be provided.
 | 
						|
    std::vector<std::string> extensions =
 | 
						|
        AsciiStrSplit(accept_extensions[j], ';');
 | 
						|
    std::string description = accept_descriptions[j];
 | 
						|
 | 
						|
    if (extensions.empty()) {
 | 
						|
      // Try to convert mime type to one or more extensions.
 | 
						|
      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;
 | 
						|
    }
 | 
						|
 | 
						|
    if (description.empty() && filter[0] != '.') {
 | 
						|
      description = GetDescriptionFromMimeType(filter);
 | 
						|
    }
 | 
						|
 | 
						|
    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);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
GtkWindow* GetWindow(CefRefPtr<CefBrowser> browser) {
 | 
						|
  REQUIRE_MAIN_THREAD();
 | 
						|
  scoped_refptr<RootWindow> root_window =
 | 
						|
      RootWindow::GetForBrowser(browser->GetIdentifier());
 | 
						|
  if (root_window) {
 | 
						|
    GtkWidget* window = root_window->GetWindowHandle();
 | 
						|
    DCHECK(window);
 | 
						|
    if (!window) {
 | 
						|
      LOG(ERROR) << "No GtkWindow for browser";
 | 
						|
    }
 | 
						|
    return GTK_WINDOW(window);
 | 
						|
  }
 | 
						|
  return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
// Returns true if |accept_filters| contains a MIME type value without matching
 | 
						|
// extensions in |accept_extensions|.
 | 
						|
bool MissingMimeTypeData(const std::vector<CefString>& accept_filters,
 | 
						|
                         const std::vector<CefString>& accept_extensions) {
 | 
						|
  if (accept_filters.empty()) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  for (size_t i = 0; i < accept_filters.size(); ++i) {
 | 
						|
    const std::string& filter = accept_filters[i];
 | 
						|
    if (filter[0] != '.' && accept_extensions[i].empty()) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
ClientDialogHandlerGtk::ClientDialogHandlerGtk() : gtk_dialog_(nullptr) {}
 | 
						|
 | 
						|
bool ClientDialogHandlerGtk::OnFileDialog(
 | 
						|
    CefRefPtr<CefBrowser> browser,
 | 
						|
    FileDialogMode mode,
 | 
						|
    const CefString& title,
 | 
						|
    const CefString& default_file_path,
 | 
						|
    const std::vector<CefString>& accept_filters,
 | 
						|
    const std::vector<CefString>& accept_extensions,
 | 
						|
    const std::vector<CefString>& accept_descriptions,
 | 
						|
    CefRefPtr<CefFileDialogCallback> callback) {
 | 
						|
  CEF_REQUIRE_UI_THREAD();
 | 
						|
  DCHECK((accept_filters.size() == accept_extensions.size()) ==
 | 
						|
         accept_descriptions.size());
 | 
						|
 | 
						|
  if (MissingMimeTypeData(accept_filters, accept_extensions)) {
 | 
						|
    // Wait for the 2nd call that provides MIME type data.
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  OnFileDialogParams params;
 | 
						|
  params.browser = browser;
 | 
						|
  params.mode = mode;
 | 
						|
  params.title = title;
 | 
						|
  params.default_file_path = default_file_path;
 | 
						|
  params.accept_filters = accept_filters;
 | 
						|
  params.accept_extensions = accept_extensions;
 | 
						|
  params.accept_descriptions = accept_descriptions;
 | 
						|
  params.callback = callback;
 | 
						|
 | 
						|
  GetWindowAndContinue(
 | 
						|
      browser, base::BindOnce(&ClientDialogHandlerGtk::OnFileDialogContinue,
 | 
						|
                              this, params));
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool ClientDialogHandlerGtk::OnJSDialog(CefRefPtr<CefBrowser> browser,
 | 
						|
                                        const CefString& origin_url,
 | 
						|
                                        JSDialogType dialog_type,
 | 
						|
                                        const CefString& message_text,
 | 
						|
                                        const CefString& default_prompt_text,
 | 
						|
                                        CefRefPtr<CefJSDialogCallback> callback,
 | 
						|
                                        bool& suppress_message) {
 | 
						|
  CEF_REQUIRE_UI_THREAD();
 | 
						|
 | 
						|
  OnJSDialogParams params;
 | 
						|
  params.browser = browser;
 | 
						|
  params.origin_url = origin_url;
 | 
						|
  params.dialog_type = dialog_type;
 | 
						|
  params.message_text = message_text;
 | 
						|
  params.default_prompt_text = default_prompt_text;
 | 
						|
  params.callback = callback;
 | 
						|
 | 
						|
  GetWindowAndContinue(
 | 
						|
      browser, base::BindOnce(&ClientDialogHandlerGtk::OnJSDialogContinue, this,
 | 
						|
                              params));
 | 
						|
  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(), 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_ = nullptr;
 | 
						|
  js_dialog_callback_ = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
void ClientDialogHandlerGtk::OnFileDialogContinue(
 | 
						|
    const OnFileDialogParams& params,
 | 
						|
    GtkWindow* window) {
 | 
						|
  REQUIRE_MAIN_THREAD();
 | 
						|
 | 
						|
  ScopedGdkThreadsEnter scoped_gdk_threads;
 | 
						|
 | 
						|
  std::vector<CefString> files;
 | 
						|
 | 
						|
  GtkFileChooserAction action;
 | 
						|
  const gchar* accept_button;
 | 
						|
 | 
						|
  if (params.mode == FILE_DIALOG_OPEN ||
 | 
						|
      params.mode == FILE_DIALOG_OPEN_MULTIPLE) {
 | 
						|
    action = GTK_FILE_CHOOSER_ACTION_OPEN;
 | 
						|
    accept_button = "_Open";
 | 
						|
  } else if (params.mode == FILE_DIALOG_OPEN_FOLDER) {
 | 
						|
    action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
 | 
						|
    accept_button = "_Open";
 | 
						|
  } else if (params.mode == FILE_DIALOG_SAVE) {
 | 
						|
    action = GTK_FILE_CHOOSER_ACTION_SAVE;
 | 
						|
    accept_button = "_Save";
 | 
						|
  } else {
 | 
						|
    NOTREACHED();
 | 
						|
    params.callback->Cancel();
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  std::string title_str;
 | 
						|
  if (!params.title.empty()) {
 | 
						|
    title_str = params.title;
 | 
						|
  } else {
 | 
						|
    switch (params.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* dialog = gtk_file_chooser_dialog_new(
 | 
						|
      title_str.c_str(), GTK_WINDOW(window), action, "_Cancel",
 | 
						|
      GTK_RESPONSE_CANCEL, accept_button, GTK_RESPONSE_ACCEPT, nullptr);
 | 
						|
 | 
						|
  if (params.mode == FILE_DIALOG_OPEN_MULTIPLE) {
 | 
						|
    gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!params.default_file_path.empty() && params.mode == FILE_DIALOG_SAVE) {
 | 
						|
    const std::string& file_path = params.default_file_path;
 | 
						|
    bool exists = false;
 | 
						|
 | 
						|
    struct stat sb;
 | 
						|
    if (stat(file_path.c_str(), &sb) == 0 && S_ISREG(sb.st_mode)) {
 | 
						|
      // Use the directory and name of the existing file.
 | 
						|
      gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), file_path.data());
 | 
						|
      exists = true;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!exists) {
 | 
						|
      // Set the current file name but let the user choose the directory.
 | 
						|
      std::string file_name_str = file_path;
 | 
						|
      const char* file_name = basename(const_cast<char*>(file_name_str.data()));
 | 
						|
      gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), file_name);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  std::vector<GtkFileFilter*> filters;
 | 
						|
  AddFilters(GTK_FILE_CHOOSER(dialog), params.accept_filters,
 | 
						|
             params.accept_extensions, params.accept_descriptions, true,
 | 
						|
             &filters);
 | 
						|
 | 
						|
  bool success = false;
 | 
						|
 | 
						|
  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
 | 
						|
    if (params.mode == FILE_DIALOG_OPEN ||
 | 
						|
        params.mode == FILE_DIALOG_OPEN_FOLDER ||
 | 
						|
        params.mode == FILE_DIALOG_SAVE) {
 | 
						|
      char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
 | 
						|
      files.push_back(std::string(filename));
 | 
						|
      success = true;
 | 
						|
    } else if (params.mode == FILE_DIALOG_OPEN_MULTIPLE) {
 | 
						|
      GSList* filenames =
 | 
						|
          gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
 | 
						|
      if (filenames) {
 | 
						|
        for (GSList* iter = filenames; iter != nullptr;
 | 
						|
             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;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  gtk_widget_destroy(dialog);
 | 
						|
 | 
						|
  if (success) {
 | 
						|
    params.callback->Continue(files);
 | 
						|
  } else {
 | 
						|
    params.callback->Cancel();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ClientDialogHandlerGtk::OnJSDialogContinue(const OnJSDialogParams& params,
 | 
						|
                                                GtkWindow* window) {
 | 
						|
  REQUIRE_MAIN_THREAD();
 | 
						|
 | 
						|
  ScopedGdkThreadsEnter scoped_gdk_threads;
 | 
						|
 | 
						|
  GtkButtonsType buttons = GTK_BUTTONS_NONE;
 | 
						|
  GtkMessageType gtk_message_type = GTK_MESSAGE_OTHER;
 | 
						|
  std::string title;
 | 
						|
 | 
						|
  switch (params.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;
 | 
						|
 | 
						|
    case JSDIALOGTYPE_NUM_VALUES:
 | 
						|
      NOTREACHED();
 | 
						|
      return;
 | 
						|
  }
 | 
						|
 | 
						|
  js_dialog_callback_ = params.callback;
 | 
						|
 | 
						|
  if (!params.origin_url.empty()) {
 | 
						|
    title += " - ";
 | 
						|
    title += CefFormatUrlForSecurityDisplay(params.origin_url).ToString();
 | 
						|
  }
 | 
						|
 | 
						|
  gtk_dialog_ = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL,
 | 
						|
                                       gtk_message_type, buttons, "%s",
 | 
						|
                                       params.message_text.ToString().c_str());
 | 
						|
  g_signal_connect(gtk_dialog_, "delete-event",
 | 
						|
                   G_CALLBACK(gtk_widget_hide_on_delete), nullptr);
 | 
						|
 | 
						|
  gtk_window_set_title(GTK_WINDOW(gtk_dialog_), title.c_str());
 | 
						|
 | 
						|
  GtkWidget* ok_button =
 | 
						|
      gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), "_OK", GTK_RESPONSE_OK);
 | 
						|
 | 
						|
  if (params.dialog_type != JSDIALOGTYPE_PROMPT) {
 | 
						|
    gtk_widget_grab_focus(ok_button);
 | 
						|
  }
 | 
						|
 | 
						|
  if (params.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),
 | 
						|
                       params.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_));
 | 
						|
}
 | 
						|
 | 
						|
void ClientDialogHandlerGtk::GetWindowAndContinue(
 | 
						|
    CefRefPtr<CefBrowser> browser,
 | 
						|
    base::OnceCallback<void(GtkWindow*)> callback) {
 | 
						|
  if (!CURRENTLY_ON_MAIN_THREAD()) {
 | 
						|
    MAIN_POST_CLOSURE(
 | 
						|
        base::BindOnce(&ClientDialogHandlerGtk::GetWindowAndContinue, this,
 | 
						|
                       browser, std::move(callback)));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  GtkWindow* window = GetWindow(browser);
 | 
						|
  if (window) {
 | 
						|
    std::move(callback).Run(window);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// static
 | 
						|
void ClientDialogHandlerGtk::OnDialogResponse(GtkDialog* dialog,
 | 
						|
                                              gint response_id,
 | 
						|
                                              ClientDialogHandlerGtk* handler) {
 | 
						|
  REQUIRE_MAIN_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();
 | 
						|
  }
 | 
						|
 | 
						|
  CefPostTask(TID_UI,
 | 
						|
              base::BindOnce(&ClientDialogHandlerGtk::OnResetDialogState,
 | 
						|
                             handler, nullptr));
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace client
 |