Commit b4a38edc authored by thomasanderson's avatar thomasanderson Committed by Commit bot

Linux: Support the --class argument

It appears we lost support for --class when we stopped using gtk for our
windowing.  This CL adds that feature back.

BUG=118613

Review-Url: https://codereview.chromium.org/2186813002
Cr-Commit-Position: refs/heads/master@{#408709}
parent 1f82749d
......@@ -208,6 +208,21 @@ DefaultWebClientState GetIsDefaultWebClient(const std::string& protocol) {
#endif
}
// https://wiki.gnome.org/Projects/GnomeShell/ApplicationBased
// The WM_CLASS property should be set to the same as the *.desktop file without
// the .desktop extension. We cannot simply use argv[0] in this case, because
// on the stable channel, the executable name is google-chrome-stable, but the
// desktop file is google-chrome.desktop.
std::string GetDesktopBaseName(const std::string& desktop_file_name) {
static const char kDesktopExtension[] = ".desktop";
if (base::EndsWith(desktop_file_name, kDesktopExtension,
base::CompareCase::SENSITIVE)) {
return desktop_file_name.substr(
0, desktop_file_name.length() - strlen(kDesktopExtension));
}
return desktop_file_name;
}
} // namespace
bool SetAsDefaultBrowser() {
......@@ -576,13 +591,48 @@ std::vector<base::FilePath> GetDataSearchLocations(base::Environment* env) {
return search_paths;
}
namespace internal {
std::string GetProgramClassName(const base::CommandLine& command_line,
const std::string& desktop_file_name) {
std::string class_name =
shell_integration::GetDesktopBaseName(desktop_file_name);
std::string user_data_dir =
command_line.GetSwitchValueNative(switches::kUserDataDir);
// If the user launches with e.g. --user-data-dir=/tmp/my-user-data, set the
// class name to "Chrome (/tmp/my-user-data)". The class name will show up in
// the alt-tab list in gnome-shell if you're running a binary that doesn't
// have a matching .desktop file.
return user_data_dir.empty()
? class_name
: class_name + " (" + user_data_dir + ")";
}
std::string GetProgramClassClass(const base::CommandLine& command_line,
const std::string& desktop_file_name) {
if (command_line.HasSwitch(switches::kWmClass))
return command_line.GetSwitchValueASCII(switches::kWmClass);
std::string class_class =
shell_integration::GetDesktopBaseName(desktop_file_name);
if (!class_class.empty()) {
// Capitalize the first character like gtk does.
class_class[0] = base::ToUpperASCII(class_class[0]);
}
return class_class;
}
} // namespace internal
std::string GetProgramClassName() {
std::unique_ptr<base::Environment> env(base::Environment::Create());
std::string desktop_file(GetDesktopName(env.get()));
std::size_t last = desktop_file.find(".desktop");
if (last != std::string::npos)
return desktop_file.substr(0, last);
return desktop_file;
return internal::GetProgramClassName(*base::CommandLine::ForCurrentProcess(),
GetDesktopName(env.get()));
}
std::string GetProgramClassClass() {
std::unique_ptr<base::Environment> env(base::Environment::Create());
return internal::GetProgramClassClass(*base::CommandLine::ForCurrentProcess(),
GetDesktopName(env.get()));
}
std::string GetDesktopName(base::Environment* env) {
......
......@@ -30,11 +30,12 @@ base::FilePath GetDataWriteLocation(base::Environment* env);
// Called on the FILE thread.
std::vector<base::FilePath> GetDataSearchLocations(base::Environment* env);
// Gets the name for use as the res_class (and possibly res_name) of the
// window's WM_CLASS property. This is the program name from argv[0], with the
// first letter capitalized. Equivalent to GDK's gdk_get_program_class().
// Gets the name for use as the res_name of the window's WM_CLASS property.
std::string GetProgramClassName();
// Gets the name for use as the res_class of the window's WM_CLASS property.
std::string GetProgramClassClass();
// Returns filename of the desktop shortcut used to launch the browser.
std::string GetDesktopName(base::Environment* env);
......@@ -136,6 +137,17 @@ void DeleteDesktopShortcuts(const base::FilePath& profile_path,
// for the profile in |profile_path|.
void DeleteAllDesktopShortcuts(const base::FilePath& profile_path);
namespace internal {
// Exposed for testing. Clients should use the corresponding functions in
// shell_integration_linux instead.
std::string GetProgramClassName(const base::CommandLine& command_line,
const std::string& desktop_file_name);
std::string GetProgramClassClass(const base::CommandLine& command_line,
const std::string& desktop_file_name);
} // namespace internal
} // namespace shell_integration_linux
#endif // CHROME_BROWSER_SHELL_INTEGRATION_LINUX_H_
......@@ -654,4 +654,20 @@ TEST(ShellIntegrationTest, GetDirectoryFileContents) {
}
}
TEST(ShellIntegrationTest, WmClass) {
base::CommandLine command_line((base::FilePath()));
EXPECT_EQ("foo", internal::GetProgramClassName(command_line, "foo.desktop"));
EXPECT_EQ("Foo", internal::GetProgramClassClass(command_line, "foo.desktop"));
command_line.AppendSwitchASCII("class", "baR");
EXPECT_EQ("foo", internal::GetProgramClassName(command_line, "foo.desktop"));
EXPECT_EQ("baR", internal::GetProgramClassClass(command_line, "foo.desktop"));
command_line = base::CommandLine(base::FilePath());
command_line.AppendSwitchASCII("user-data-dir", "/tmp/baz");
EXPECT_EQ("foo (/tmp/baz)",
internal::GetProgramClassName(command_line, "foo.desktop"));
EXPECT_EQ("Foo", internal::GetProgramClassClass(command_line, "foo.desktop"));
}
} // namespace shell_integration_linux
......@@ -61,7 +61,15 @@ void GtkInitFromCommandLine(const base::CommandLine& command_line) {
// from browser and above.
std::string GetDesktopName(base::Environment* env) {
#if defined(GOOGLE_CHROME_BUILD)
return "google-chrome.desktop";
version_info::Channel product_channel(chrome::GetChannel());
switch (product_channel) {
case version_info::Channel::DEV:
return "google-chrome-unstable.desktop";
case version_info::Channel::BETA:
return "google-chrome-beta.desktop";
default:
return "google-chrome.desktop";
}
#else // CHROMIUM_BUILD
// Allow $CHROME_DESKTOP to override the built-in value, so that development
// versions can set themselves as the default without interfering with
......
......@@ -63,7 +63,7 @@ void ChromeNativeAppWindowViewsAura::OnBeforeWidgetInit(
// Set up a custom WM_CLASS for app windows. This allows task switchers in
// X11 environments to distinguish them from main browser windows.
init_params->wm_class_name = web_app::GetWMClassFromAppName(app_name);
init_params->wm_class_class = shell_integration_linux::GetProgramClassName();
init_params->wm_class_class = shell_integration_linux::GetProgramClassClass();
const char kX11WindowRoleApp[] = "app";
init_params->wm_role_name = std::string(kX11WindowRoleApp);
#endif
......
......@@ -33,28 +33,20 @@ views::Widget::InitParams DesktopBrowserFrameAuraLinux::GetWidgetParams() {
// Set up a custom WM_CLASS for some sorts of window types. This allows
// task switchers in X11 environments to distinguish between main browser
// windows and e.g app windows.
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
const Browser& browser = *browser_view()->browser();
params.wm_class_class = shell_integration_linux::GetProgramClassName();
params.wm_class_name = params.wm_class_class;
if (browser.is_app() && !browser.is_devtools()) {
// This window is a hosted app or v1 packaged app.
// NOTE: v2 packaged app windows are created by ChromeNativeAppWindowViews.
params.wm_class_name = web_app::GetWMClassFromAppName(browser.app_name());
} else if (command_line.HasSwitch(switches::kUserDataDir)) {
// Set the class name to e.g. "Chrome (/tmp/my-user-data)". The
// class name will show up in the alt-tab list in gnome-shell if
// you're running a binary that doesn't have a matching .desktop
// file.
const std::string user_data_dir =
command_line.GetSwitchValueNative(switches::kUserDataDir);
params.wm_class_name += " (" + user_data_dir + ")";
}
params.wm_class_name =
browser.is_app() && !browser.is_devtools()
? web_app::GetWMClassFromAppName(browser.app_name())
// This window is a hosted app or v1 packaged app.
// NOTE: v2 packaged app windows are created by
// ChromeNativeAppWindowViews.
: shell_integration_linux::GetProgramClassName();
params.wm_class_class = shell_integration_linux::GetProgramClassClass();
const char kX11WindowRoleBrowser[] = "browser";
const char kX11WindowRolePopup[] = "pop-up";
params.wm_role_name = browser_view()->browser()->is_type_tabbed() ?
std::string(kX11WindowRoleBrowser) : std::string(kX11WindowRolePopup);
params.wm_role_name = browser_view()->browser()->is_type_tabbed()
? std::string(kX11WindowRoleBrowser)
: std::string(kX11WindowRolePopup);
params.remove_standard_frame = UseCustomFrame();
return params;
......
......@@ -292,7 +292,7 @@ PanelView::PanelView(Panel* panel, const gfx::Rect& bounds, bool always_on_top)
#if defined(USE_X11) && !defined(OS_CHROMEOS)
params.wm_class_name = web_app::GetWMClassFromAppName(panel->app_name());
params.wm_class_class = shell_integration_linux::GetProgramClassName();
params.wm_class_class = shell_integration_linux::GetProgramClassClass();
#endif
window_->Init(params);
......
......@@ -1094,7 +1094,11 @@ const char kHelpShort[] = "h";
// Specifies which password store to use (detect, default, gnome, kwallet).
const char kPasswordStore[] = "password-store";
// Updates X11Desktophandler::wm_user_time_ms with the latest X server time.
// The same as the --class argument in X applications. Overrides the WM_CLASS
// window property with the given value.
const char kWmClass[] = "class";
// Updates X11DesktopHandler::wm_user_time_ms with the latest X server time.
const char kWmUserTimeMs[] = "wm-user-time-ms";
#endif
......
......@@ -315,6 +315,7 @@ extern const char kOpenAsh[];
extern const char kHelp[];
extern const char kHelpShort[];
extern const char kPasswordStore[];
extern const char kWmClass[];
extern const char kWmUserTimeMs[];
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment