File: remote_open_url_client_delegate_linux.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (163 lines) | stat: -rw-r--r-- 5,935 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/host/remote_open_url/remote_open_url_client_delegate_linux.h"

#include <gtk/gtk.h>

#include <string_view>

#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/containers/fixed_flat_set.h"
#include "base/environment.h"
#include "base/logging.h"
#include "base/process/launch.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "remoting/base/host_settings.h"
#include "remoting/base/logging.h"
#include "remoting/base/string_resources.h"
#include "remoting/host/host_setting_keys.h"
#include "remoting/host/resources.h"
#include "ui/base/l10n/l10n_util.h"

namespace remoting {

namespace {

constexpr char kXdgCurrentDesktopEnvVar[] = "XDG_CURRENT_DESKTOP";

void ShowMessageDialog(const std::string& message) {
  // IDS_URL_FORWARDER_NAME's placeholder is in the printf format (%s) since
  // it's used in Jinja.
  std::string dialog_title = l10n_util::GetStringUTF8(IDS_URL_FORWARDER_NAME);
  base::ReplaceFirstSubstringAfterOffset(
      &dialog_title, /* start_offset= */ 0, "%s",
      l10n_util::GetStringUTF8(IDS_PRODUCT_NAME));
  GtkWidget* dialog =
      gtk_message_dialog_new(nullptr, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO,
                             GTK_BUTTONS_OK, "%s", dialog_title.c_str());
  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s",
                                           message.c_str());
  gtk_dialog_run(GTK_DIALOG(dialog));
  gtk_widget_destroy(dialog);
}

bool IsBrowserValid(const std::string& browser) {
  static constexpr auto invalid_browsers =
      base::MakeFixedFlatSet<std::string_view>({
          // This is the chromoting forwarder itself.
          "crd-url-forwarder.desktop",

          // XFCE's forwarder. May potentially launch the chromoting forwarder
          // recursively.
          "xfce4-web-browser.desktop",
      });
  if (browser.empty()) {
    return false;
  }
  return !invalid_browsers.contains(browser);
}

// Shows a window for the user to choose the fallback browser then sets it on
// the host settings with |host_setting_key|. Returns the chosen browser's
// desktop entry ID, e.g. google-chrome.desktop. Returns empty string if the
// user cancels the dialog.
std::string ChooseFallbackBrowser(const HostSettingKey host_setting_key) {
  std::string browser_chooser_heading =
      l10n_util::GetStringUTF8(IDS_CHOOSE_FALLBACK_BROWSER);
  std::string invalid_browser_message =
      l10n_util::GetStringUTF8(IDS_BROWSER_IS_INVALID);

  while (true) {
    GtkWidget* dialog = gtk_app_chooser_dialog_new_for_content_type(
        nullptr, GTK_DIALOG_MODAL, "x-scheme-handler/http");
    gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
    gtk_app_chooser_dialog_set_heading(GTK_APP_CHOOSER_DIALOG(dialog),
                                       browser_chooser_heading.c_str());
    int result = gtk_dialog_run(GTK_DIALOG(dialog));
    if (result != GTK_RESPONSE_OK) {
      HOST_LOG << "User canceled choosing the fallback browser.";
      gtk_widget_destroy(dialog);
      return std::string();
    }

    GAppInfo* app_info = gtk_app_chooser_get_app_info(GTK_APP_CHOOSER(dialog));
    std::string app_id = g_app_info_get_id(app_info);
    g_object_unref(app_info);
    gtk_widget_destroy(dialog);

    if (IsBrowserValid(app_id)) {
      HOST_LOG << "Setting " << host_setting_key << " to " << app_id;
      HostSettings::GetInstance()->SetString(host_setting_key, app_id);
      return app_id;
    }

    ShowMessageDialog(invalid_browser_message);
  }
}

}  // namespace

RemoteOpenUrlClientDelegateLinux::RemoteOpenUrlClientDelegateLinux()
    : environment_(base::Environment::Create()) {
#if GTK_CHECK_VERSION(3, 90, 0)
  gtk_init();
#else
  gtk_init(nullptr, nullptr);
#endif
}

RemoteOpenUrlClientDelegateLinux::~RemoteOpenUrlClientDelegateLinux() = default;

void RemoteOpenUrlClientDelegateLinux::OpenUrlOnFallbackBrowser(
    const GURL& url) {
  std::string current_desktop =
      environment_->GetVar(kXdgCurrentDesktopEnvVar).value_or(std::string());

  const char* host_setting_key = kLinuxPreviousDefaultWebBrowserGeneric;
  if (base::Contains(current_desktop, "Cinnamon")) {
    host_setting_key = kLinuxPreviousDefaultWebBrowserCinnamon;
  } else if (base::Contains(current_desktop, "XFCE")) {
    host_setting_key = kLinuxPreviousDefaultWebBrowserXfce;
  } else if (base::Contains(current_desktop, "GNOME")) {
    host_setting_key = kLinuxPreviousDefaultWebBrowserGnome;
  } else {
    LOG(WARNING) << "Unknown desktop environment: " << current_desktop
                 << ", X-Generic will be used.";
  }

  std::string previous_default_browser =
      HostSettings::GetInstance()->GetString(host_setting_key);
  if (!IsBrowserValid(previous_default_browser)) {
    LOG(WARNING)
        << "Fallback browser is invalid. Showing the browser chooser...";
    previous_default_browser = ChooseFallbackBrowser(host_setting_key);
    if (previous_default_browser.empty()) {
      // User canceled the dialog.
      return;
    }
  }
  // gtk-launch DESKTOP_ENTRY [URL...]
  base::CommandLine gtk_launch_command(
      {"gtk-launch", previous_default_browser});
  if (!url.is_empty()) {
    gtk_launch_command.AppendArg(url.spec());
  }
  base::LaunchOptions options;
  // Some browsers require privileges that can't be granted with the
  // PR_SET_NO_NEW_PRIVS bit set.
  options.allow_new_privs = true;
  base::LaunchProcess(gtk_launch_command, options);
}

void RemoteOpenUrlClientDelegateLinux::ShowOpenUrlError(const GURL& url) {
  std::string message = l10n_util::GetStringFUTF8(
      IDS_REMOTE_OPEN_URL_FAILED, base::UTF8ToUTF16(url.spec()));
  LOG(ERROR) << "Failed to open URL remotely: " << url.spec();
  ShowMessageDialog(message);
}

}  // namespace remoting