diff options
author | mgiuca@chromium.org <mgiuca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-02 05:26:35 +0000 |
---|---|---|
committer | mgiuca@chromium.org <mgiuca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-02 05:26:35 +0000 |
commit | f93a77459eb2fe243f8ed4aefa581fb580100147 (patch) | |
tree | 8b5c018f464d1c4e44a1e06d8e8a02b738cdd6fd | |
parent | 800b0cb4a1e999d61d185d1898946294649037d0 (diff) | |
download | chromium_src-f93a77459eb2fe243f8ed4aefa581fb580100147.zip chromium_src-f93a77459eb2fe243f8ed4aefa581fb580100147.tar.gz chromium_src-f93a77459eb2fe243f8ed4aefa581fb580100147.tar.bz2 |
Set the WM_CLASS property of X11 windows in Linux Aura build.
This sets the WM_CLASS for both browser and app windows, mimicking the
behaviour of the existing GTK implementation. Now app windows have the
correct grouping, icon and title in the Ubuntu Unity window manager.
Also, .desktop shortcut files generated from the Aura build now have the
appropriate StartupWMClass key set (which was previously only set by the
GTK build).
BUG=174743
Review URL: https://chromiumcodereview.appspot.com/23093020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@220801 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/shell_integration_linux.cc | 12 | ||||
-rw-r--r-- | chrome/browser/shell_integration_linux.h | 5 | ||||
-rw-r--r-- | chrome/browser/shell_integration_unittest.cc | 24 | ||||
-rw-r--r-- | chrome/browser/ui/views/apps/native_app_window_views.cc | 22 | ||||
-rw-r--r-- | chrome/browser/ui/views/frame/browser_frame.cc | 30 | ||||
-rw-r--r-- | chrome/browser/web_applications/web_app.cc | 2 | ||||
-rw-r--r-- | chrome/browser/web_applications/web_app.h | 4 | ||||
-rw-r--r-- | ui/base/x/x11_util.cc | 13 | ||||
-rw-r--r-- | ui/base/x/x11_util.h | 6 | ||||
-rw-r--r-- | ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc | 5 | ||||
-rw-r--r-- | ui/views/widget/widget.h | 5 |
11 files changed, 95 insertions, 33 deletions
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc index 8fc4cd6..c7cd4ed 100644 --- a/chrome/browser/shell_integration_linux.cc +++ b/chrome/browser/shell_integration_linux.cc @@ -545,6 +545,16 @@ std::vector<base::FilePath> GetDataSearchLocations(base::Environment* env) { return search_paths; } +std::string GetProgramClassName() { + DCHECK(CommandLine::InitializedForCurrentProcess()); + // Get the res_name component from argv[0]. + const CommandLine* command_line = CommandLine::ForCurrentProcess(); + std::string class_name = command_line->GetProgram().BaseName().value(); + if (!class_name.empty()) + class_name[0] = base::ToUpperASCII(class_name[0]); + return class_name; +} + std::string GetDesktopName(base::Environment* env) { #if defined(GOOGLE_CHROME_BUILD) return "google-chrome.desktop"; @@ -761,11 +771,9 @@ std::string GetDesktopFileContents( if (no_display) g_key_file_set_string(key_file, kDesktopEntry, "NoDisplay", "true"); -#if defined(TOOLKIT_GTK) std::string wmclass = web_app::GetWMClassFromAppName(app_name); g_key_file_set_string(key_file, kDesktopEntry, "StartupWMClass", wmclass.c_str()); -#endif gsize length = 0; gchar* data_dump = g_key_file_to_data(key_file, &length, NULL); diff --git a/chrome/browser/shell_integration_linux.h b/chrome/browser/shell_integration_linux.h index 48414b8..d00dcd5 100644 --- a/chrome/browser/shell_integration_linux.h +++ b/chrome/browser/shell_integration_linux.h @@ -31,6 +31,11 @@ bool GetDataWriteLocation(base::Environment* env, base::FilePath* search_path); // 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(). +std::string GetProgramClassName(); + // Returns filename of the desktop shortcut used to launch the browser. std::string GetDesktopName(base::Environment* env); diff --git a/chrome/browser/shell_integration_unittest.cc b/chrome/browser/shell_integration_unittest.cc index 82a9b6a..e3ab231 100644 --- a/chrome/browser/shell_integration_unittest.cc +++ b/chrome/browser/shell_integration_unittest.cc @@ -460,11 +460,7 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) { "Name=GMail\n" "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n" "Icon=chrome-http__gmail.com\n" -#if !defined(USE_AURA) - // Aura Chrome does not (yet) set WMClass, so we only expect - // StartupWMClass on non-Aura builds. "StartupWMClass=gmail.com\n" -#endif }, // Make sure that empty icons are replaced by the chrome icon. @@ -481,11 +477,7 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) { "Name=GMail\n" "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n" "Icon=chromium-browser\n" -#if !defined(USE_AURA) - // Aura Chrome does not (yet) set WMClass, so we only expect - // StartupWMClass on non-Aura builds. "StartupWMClass=gmail.com\n" -#endif }, // Test adding NoDisplay=true. @@ -503,11 +495,7 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) { "Exec=/opt/google/chrome/google-chrome --app=http://gmail.com/\n" "Icon=chrome-http__gmail.com\n" "NoDisplay=true\n" -#if !defined(USE_AURA) - // Aura Chrome does not (yet) set WMClass, so we only expect - // StartupWMClass on non-Aura builds. "StartupWMClass=gmail.com\n" -#endif }, // Now we're starting to be more evil... @@ -525,11 +513,7 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) { "Exec=/opt/google/chrome/google-chrome " "--app=http://evil.com/evil%20--join-the-b0tnet\n" "Icon=chrome-http__evil.com_evil\n" -#if !defined(USE_AURA) - // Aura Chrome does not (yet) set WMClass, so we only expect - // StartupWMClass on non-Aura builds. "StartupWMClass=evil.com__evil%20--join-the-b0tnet\n" -#endif }, { "http://evil.com/evil; rm -rf /; \"; rm -rf $HOME >ownz0red", "Innocent Title", @@ -549,12 +533,8 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) { // be; finally, \\ becomes \\\\ when represented in a C++ string! "-rf%20\\\\$HOME%20%3Eownz0red\"\n" "Icon=chrome-http__evil.com_evil\n" -#if !defined(USE_AURA) - // Aura Chrome does not (yet) set WMClass, so we only expect - // StartupWMClass on non-Aura builds. "StartupWMClass=evil.com__evil;%20rm%20-rf%20_;%20%22;%20" "rm%20-rf%20$HOME%20%3Eownz0red\n" -#endif }, { "http://evil.com/evil | cat `echo ownz0red` >/dev/null", "Innocent Title", @@ -571,12 +551,8 @@ TEST(ShellIntegrationTest, GetDesktopFileContents) { "--app=http://evil.com/evil%20%7C%20cat%20%60echo%20ownz0red" "%60%20%3E/dev/null\n" "Icon=chrome-http__evil.com_evil\n" -#if !defined(USE_AURA) - // Aura Chrome does not (yet) set WMClass, so we only expect - // StartupWMClass on non-Aura builds. "StartupWMClass=evil.com__evil%20%7C%20cat%20%60echo%20ownz0red" "%60%20%3E_dev_null\n" -#endif }, }; diff --git a/chrome/browser/ui/views/apps/native_app_window_views.cc b/chrome/browser/ui/views/apps/native_app_window_views.cc index 3f97372..a98d7a4 100644 --- a/chrome/browser/ui/views/apps/native_app_window_views.cc +++ b/chrome/browser/ui/views/apps/native_app_window_views.cc @@ -14,6 +14,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h" #include "chrome/browser/ui/views/extensions/shell_window_frame_view.h" +#include "chrome/browser/web_applications/web_app.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" #include "content/public/browser/browser_thread.h" @@ -29,12 +30,15 @@ #if defined(OS_WIN) #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/web_applications/web_app_ui.h" -#include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app_win.h" #include "ui/base/win/shell.h" #include "ui/views/win/hwnd_util.h" #endif +#if defined(OS_LINUX) +#include "chrome/browser/shell_integration_linux.h" +#endif + #if defined(USE_ASH) #include "ash/screen_ash.h" #include "ash/shell.h" @@ -155,6 +159,9 @@ NativeAppWindowViews::~NativeAppWindowViews() { void NativeAppWindowViews::InitializeDefaultWindow( const ShellWindow::CreateParams& create_params) { + std::string app_name = + web_app::GenerateApplicationNameFromExtensionId(extension()->id()); + views::Widget::InitParams init_params(views::Widget::InitParams::TYPE_WINDOW); init_params.delegate = this; init_params.remove_standard_frame = ShouldUseChromeStyleFrame(); @@ -167,6 +174,14 @@ void NativeAppWindowViews::InitializeDefaultWindow( window_bounds.x() != INT_MIN && window_bounds.y() != INT_MIN; if (position_specified && !window_bounds.IsEmpty()) init_params.bounds = window_bounds; + +#if defined(OS_LINUX) + // 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 = ShellIntegrationLinux::GetProgramClassName(); +#endif + window_->Init(init_params); gfx::Rect adjusted_bounds = window_bounds; @@ -190,11 +205,10 @@ void NativeAppWindowViews::InitializeDefaultWindow( } #if defined(OS_WIN) - string16 app_name = UTF8ToWide( - web_app::GenerateApplicationNameFromExtensionId(extension()->id())); + string16 app_name_wide = UTF8ToWide(app_name); HWND hwnd = GetNativeAppWindowHWND(); ui::win::SetAppIdForWindow(ShellIntegration::GetAppModelIdForProfile( - app_name, profile()->GetPath()), hwnd); + app_name_wide, profile()->GetPath()), hwnd); web_app::UpdateShortcutInfoAndIconForApp( *extension(), profile(), diff --git a/chrome/browser/ui/views/frame/browser_frame.cc b/chrome/browser/ui/views/frame/browser_frame.cc index 5b99f02..7c96755 100644 --- a/chrome/browser/ui/views/frame/browser_frame.cc +++ b/chrome/browser/ui/views/frame/browser_frame.cc @@ -5,6 +5,7 @@ #include "chrome/browser/ui/views/frame/browser_frame.h" #include "ash/shell.h" +#include "base/command_line.h" #include "base/i18n/rtl.h" #include "chrome/browser/app_mode/app_mode_utils.h" #include "chrome/browser/themes/theme_service.h" @@ -19,6 +20,7 @@ #include "chrome/browser/ui/views/frame/native_browser_frame.h" #include "chrome/browser/ui/views/frame/system_menu_model_builder.h" #include "chrome/browser/ui/views/frame/top_container_view.h" +#include "chrome/browser/web_applications/web_app.h" #include "chrome/common/chrome_switches.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" @@ -32,6 +34,10 @@ #include "chrome/browser/ui/views/frame/glass_browser_frame_view.h" #endif +#if defined(OS_LINUX) +#include "chrome/browser/shell_integration_linux.h" +#endif + #if defined(USE_ASH) #include "chrome/browser/ui/ash/ash_init.h" #endif @@ -74,6 +80,30 @@ void BrowserFrame::InitBrowserFrame() { params.context = ash::Shell::GetPrimaryRootWindow(); } #endif + +#if defined(OS_LINUX) + // 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 CommandLine& command_line = *CommandLine::ForCurrentProcess(); + const Browser& browser = *browser_view_->browser(); + params.wm_class_class = ShellIntegrationLinux::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 NativeAppWindowViews. + 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 + ")"; + } +#endif // defined(OS_LINUX) + Init(params); if (!native_browser_frame_->UsesNativeSystemMenu()) { diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index 10c2c99..103090d 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc @@ -228,7 +228,7 @@ void GetIconsInfo(const WebApplicationInfo& app_info, } #endif -#if defined(TOOLKIT_GTK) +#if defined(OS_LINUX) std::string GetWMClassFromAppName(std::string app_name) { file_util::ReplaceIllegalCharactersInPath(&app_name, '_'); TrimString(app_name, "_", &app_name); diff --git a/chrome/browser/web_applications/web_app.h b/chrome/browser/web_applications/web_app.h index 6752597..8602cc5 100644 --- a/chrome/browser/web_applications/web_app.h +++ b/chrome/browser/web_applications/web_app.h @@ -97,8 +97,8 @@ void GetIconsInfo(const WebApplicationInfo& app_info, IconInfoList* icons); #endif -#if defined(TOOLKIT_GTK) -// GTK+ windows that correspond to web apps need to have a deterministic (and +#if defined(OS_LINUX) +// Windows that correspond to web apps need to have a deterministic (and // different) WMClass than normal chrome windows so the window manager groups // them as a separate application. std::string GetWMClassFromAppName(std::string app_name); diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc index 3a1ced1..44d8d28 100644 --- a/ui/base/x/x11_util.cc +++ b/ui/base/x/x11_util.cc @@ -1012,6 +1012,19 @@ Atom GetAtom(const char* name) { #endif } +void SetWindowClassHint(Display* display, + XID window, + std::string res_name, + std::string res_class) { + XClassHint class_hints; + // const_cast is safe because XSetClassHint does not modify the strings. + // Just to be safe, the res_name and res_class parameters are local copies, + // not const references. + class_hints.res_name = const_cast<char*>(res_name.c_str()); + class_hints.res_class = const_cast<char*>(res_class.c_str()); + XSetClassHint(display, window, &class_hints); +} + XID GetParentWindow(XID window) { XID root = None; XID parent = None; diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h index f0cf1b7..40eb9c5 100644 --- a/ui/base/x/x11_util.h +++ b/ui/base/x/x11_util.h @@ -211,6 +211,12 @@ UI_EXPORT bool SetAtomArrayProperty(XID window, // Gets the X atom for default display corresponding to atom_name. Atom GetAtom(const char* atom_name); +// Sets the WM_CLASS attribute for a given X11 window. +UI_EXPORT void SetWindowClassHint(Display* display, + XID window, + std::string res_name, + std::string res_class); + // Get |window|'s parent window, or None if |window| is the root window. UI_EXPORT XID GetParentWindow(XID window); diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc index b6a1c13..9fa5a7c 100644 --- a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc +++ b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc @@ -871,6 +871,11 @@ void DesktopRootWindowHostX11::InitX11Window( PropModeAppend, reinterpret_cast<unsigned char*>(&atom), 1); } + + if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) { + ui::SetWindowClassHint( + xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class); + } } // TODO(erg): This method should basically be everything I need form diff --git a/ui/views/widget/widget.h b/ui/views/widget/widget.h index 6623364..d8a3200 100644 --- a/ui/views/widget/widget.h +++ b/ui/views/widget/widget.h @@ -216,6 +216,11 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate, // where it wants your window placed.) NULL is not allowed if you are using // aura. gfx::NativeView context; + // Only used by X11, for root level windows. Specifies the res_name and + // res_class fields, respectively, of the WM_CLASS window property. Controls + // window grouping and desktop file matching in Linux window managers. + std::string wm_class_name; + std::string wm_class_class; }; Widget(); |