diff options
-rw-r--r-- | chrome/browser/fullscreen.h | 20 | ||||
-rw-r--r-- | chrome/browser/fullscreen_linux.cc | 144 | ||||
-rw-r--r-- | chrome/browser/fullscreen_mac.mm | 100 | ||||
-rw-r--r-- | chrome/browser/fullscreen_win.cc | 80 | ||||
-rw-r--r-- | chrome/browser/idle.h | 7 | ||||
-rw-r--r-- | chrome/browser/idle_linux.cc | 65 | ||||
-rw-r--r-- | chrome/browser/idle_mac.cc | 16 | ||||
-rw-r--r-- | chrome/browser/idle_mac.mm | 99 | ||||
-rw-r--r-- | chrome/browser/notifications/notification_ui_manager.cc | 40 | ||||
-rw-r--r-- | chrome/browser/notifications/notification_ui_manager.h | 8 | ||||
-rw-r--r-- | chrome/browser/ui/gtk/gtk_util.cc | 2 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 6 | ||||
-rw-r--r-- | ui/base/x/x11_util.cc | 192 | ||||
-rw-r--r-- | ui/base/x/x11_util.h | 15 |
14 files changed, 696 insertions, 98 deletions
diff --git a/chrome/browser/fullscreen.h b/chrome/browser/fullscreen.h new file mode 100644 index 0000000..3ed7ecc --- /dev/null +++ b/chrome/browser/fullscreen.h @@ -0,0 +1,20 @@ +// Copyright (c) 2011 The Chromium 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 CHROME_BROWSER_FULLSCREEN_H_ +#define CHROME_BROWSER_FULLSCREEN_H_ +#pragma once + +#include "build/build_config.h" + +// For MacOSX, InitFullScreenMonitor needs to be called first to setup the +// monitor. StopFullScreenMonitor should be called if it is not needed any more. +#if defined(OS_MACOSX) +void InitFullScreenMonitor(); +void StopFullScreenMonitor(); +#endif + +bool IsFullScreenMode(); + +#endif // CHROME_BROWSER_FULLSCREEN_H_ diff --git a/chrome/browser/fullscreen_linux.cc b/chrome/browser/fullscreen_linux.cc new file mode 100644 index 0000000..599ecdd --- /dev/null +++ b/chrome/browser/fullscreen_linux.cc @@ -0,0 +1,144 @@ +// Copyright (c) 2011 The Chromium 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 "chrome/browser/fullscreen.h" + +#include <gdk/gdk.h> +#include <gdk/gdkx.h> + +#include <algorithm> +#include <vector> + +#include "base/basictypes.h" +#include "chrome/browser/ui/gtk/gtk_util.h" +#include "gfx/rect.h" +#include "ui/base/x/x11_util.h" + +namespace { + +// TODO (jianli): Merge with gtk_util::EnumerateTopLevelWindows. +void EnumerateAllChildWindows(ui::EnumerateWindowsDelegate* delegate, + XID window) { + std::vector<XID> windows; + + if (!ui::GetXWindowStack(window, &windows)) { + // Window Manager doesn't support _NET_CLIENT_LIST_STACKING, so fall back + // to old school enumeration of all X windows. + XID root, parent, *children; + unsigned int num_children; + int status = XQueryTree(ui::GetXDisplay(), window, &root, &parent, + &children, &num_children); + if (status) { + for (long i = static_cast<long>(num_children) - 1; i >= 0; i--) + windows.push_back(children[i]); + XFree(children); + } + } + + std::vector<XID>::iterator iter; + for (iter = windows.begin(); iter != windows.end(); iter++) { + if (delegate->ShouldStopIterating(*iter)) + return; + } +} + +// To find the top-most window: +// 1) Enumerate all top-level windows from the top to the bottom. +// 2) For each window: +// 2.1) If it is hidden, continue the iteration. +// 2.2) If it is managed by the Window Manager (has a WM_STATE property). +// Return this window as the top-most window. +// 2.3) Enumerate all its child windows. If there is a child window that is +// managed by the Window Manager (has a WM_STATE property). Return this +// child window as the top-most window. +// 2.4) Otherwise, continue the iteration. + +class WindowManagerWindowFinder : public ui::EnumerateWindowsDelegate { + public: + WindowManagerWindowFinder() : window_(None) { } + + XID window() const { return window_; } + + protected: + virtual bool ShouldStopIterating(XID window) { + if (ui::PropertyExists(window, "WM_STATE")) { + window_ = window; + return true; + } + return false; + } + + private: + XID window_; + + DISALLOW_COPY_AND_ASSIGN(WindowManagerWindowFinder); +}; + +class TopMostWindowFinder : public ui::EnumerateWindowsDelegate { + public: + TopMostWindowFinder() + : top_most_window_(None) {} + + XID top_most_window() const { return top_most_window_; } + + protected: + virtual bool ShouldStopIterating(XID window) { + if (!ui::IsWindowVisible(window)) + return false; + if (ui::PropertyExists(window, "WM_STATE")) { + top_most_window_ = window; + return true; + } + WindowManagerWindowFinder child_finder; + EnumerateAllChildWindows(&child_finder, window); + XID child_window = child_finder.window(); + if (child_window == None) + return false; + top_most_window_ = child_window; + return true; + } + + private: + XID top_most_window_; + + DISALLOW_COPY_AND_ASSIGN(TopMostWindowFinder); +}; + +bool IsTopMostWindowFullScreen() { + // Find the topmost window. + TopMostWindowFinder finder; + EnumerateAllChildWindows(&finder, ui::GetX11RootWindow()); + XID window = finder.top_most_window(); + if (window == None) + return false; + + // Make sure it is not the desktop window. + static Atom desktop_atom = gdk_x11_get_xatom_by_name_for_display( + gdk_display_get_default(), "_NET_WM_WINDOW_TYPE_DESKTOP"); + + std::vector<Atom> atom_properties; + if (ui::GetAtomArrayProperty(window, + "_NET_WM_WINDOW_TYPE", + &atom_properties) && + std::find(atom_properties.begin(), atom_properties.end(), desktop_atom) + != atom_properties.end()) + return false; + + // If it is a GDK window, check it using gdk function. + GdkWindow* gwindow = gdk_window_lookup(window); + if (gwindow && window != GDK_ROOT_WINDOW()) + return gdk_window_get_state(gwindow) == GDK_WINDOW_STATE_FULLSCREEN; + + // Otherwise, do the check via xlib function. + return ui::IsX11WindowFullScreen(window); +} + +} + +bool IsFullScreenMode() { + gdk_error_trap_push(); + bool result = IsTopMostWindowFullScreen(); + bool got_error = gdk_error_trap_pop(); + return result && !got_error; +} diff --git a/chrome/browser/fullscreen_mac.mm b/chrome/browser/fullscreen_mac.mm new file mode 100644 index 0000000..303f6f2 --- /dev/null +++ b/chrome/browser/fullscreen_mac.mm @@ -0,0 +1,100 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/fullscreen.h" + +#import <Carbon/Carbon.h> +#import <Cocoa/Cocoa.h> + +#import "base/logging.h" + +@interface FullScreenMonitor : NSObject { + @private + BOOL fullScreen_; + EventHandlerRef eventHandler_; +} + +@property (nonatomic, getter=isFullScreen) BOOL fullScreen; + +@end + +static OSStatus handleAppEvent(EventHandlerCallRef myHandler, + EventRef event, + void* userData) { + DCHECK(userData); + + FullScreenMonitor* fullScreenMonitor = + reinterpret_cast<FullScreenMonitor*>(userData); + + UInt32 mode = 0; + OSStatus status = GetEventParameter(event, + kEventParamSystemUIMode, + typeUInt32, + NULL, + sizeof(UInt32), + NULL, + &mode); + if (status != noErr) + return status; + BOOL isFullScreenMode = mode == kUIModeAllHidden; + [fullScreenMonitor setFullScreen:isFullScreenMode]; + return noErr; +} + +@implementation FullScreenMonitor + +@synthesize fullScreen = fullScreen_; + +- (id)init { + if ((self = [super init])) { + // Check if the user is in presentation mode initially. + SystemUIMode currentMode; + GetSystemUIMode(¤tMode, NULL); + fullScreen_ = currentMode == kUIModeAllHidden; + + // Register a Carbon event to receive the notification about the login + // session's UI mode change. + EventTypeSpec events[] = + {{ kEventClassApplication, kEventAppSystemUIModeChanged }}; + OSStatus status = InstallApplicationEventHandler( + NewEventHandlerUPP(handleAppEvent), + GetEventTypeCount(events), + events, + self, + &eventHandler_); + if (status) { + [self release]; + self = nil; + } + } + return self; +} + +- (void)dealloc { + if (eventHandler_) + RemoveEventHandler(eventHandler_); + [super dealloc]; +} + +@end + +static FullScreenMonitor* g_fullScreenMonitor = nil; + +void InitFullScreenMonitor() { + if (!g_fullScreenMonitor) + g_fullScreenMonitor = [[FullScreenMonitor alloc] init]; +} + +void StopFullScreenMonitor() { + [g_fullScreenMonitor release]; + g_fullScreenMonitor = nil; +} + +bool IsFullScreenMode() { + // Check if the main display has been captured (game in particular). + if (CGDisplayIsCaptured(CGMainDisplayID())) + return true; + + return [g_fullScreenMonitor isFullScreen]; +} diff --git a/chrome/browser/fullscreen_win.cc b/chrome/browser/fullscreen_win.cc new file mode 100644 index 0000000..68ddc18 --- /dev/null +++ b/chrome/browser/fullscreen_win.cc @@ -0,0 +1,80 @@ +// Copyright (c) 2011 The Chromium 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 "chrome/browser/fullscreen.h" + +#include <windows.h> +#include <shellapi.h> + +static bool IsPlatformFullScreenMode() { + // SHQueryUserNotificationState is only available for Vista and above. +#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_VISTA) + QUERY_USER_NOTIFICATION_STATE state; + if (FAILED(::SHQueryUserNotificationState(&state))) + return false; + return state == QUNS_RUNNING_D3D_FULL_SCREEN || + state == QUNS_PRESENTATION_MODE; +#else + return false; +#endif +} + +static bool IsFullScreenWindowMode() { + // Get the foreground window which the user is currently working on. + HWND wnd = ::GetForegroundWindow(); + if (!wnd) + return false; + + // Get the monitor where the window is located. + RECT wnd_rect; + if (!::GetWindowRect(wnd, &wnd_rect)) + return false; + HMONITOR monitor = ::MonitorFromRect(&wnd_rect, MONITOR_DEFAULTTONULL); + if (!monitor) + return false; + MONITORINFO monitor_info = { sizeof(monitor_info) }; + if (!::GetMonitorInfo(monitor, &monitor_info)) + return false; + + // It should be the main monitor. + if (!(monitor_info.dwFlags & MONITORINFOF_PRIMARY)) + return false; + + // The window should be at least as large as the monitor. + if (!::IntersectRect(&wnd_rect, &wnd_rect, &monitor_info.rcMonitor)) + return false; + if (!::EqualRect(&wnd_rect, &monitor_info.rcMonitor)) + return false; + + // At last, the window style should not have WS_DLGFRAME and WS_THICKFRAME and + // its extended style should not have WS_EX_WINDOWEDGE and WS_EX_TOOLWINDOW. + LONG style = ::GetWindowLong(wnd, GWL_STYLE); + LONG ext_style = ::GetWindowLong(wnd, GWL_EXSTYLE); + return !((style & (WS_DLGFRAME | WS_THICKFRAME)) || + (ext_style & (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW))); +} + +static bool IsFullScreenConsoleMode() { + // We detect this by attaching the current process to the console of the + // foreground window and then checking if it is in full screen mode. + DWORD pid = 0; + ::GetWindowThreadProcessId(::GetForegroundWindow(), &pid); + if (!pid) + return false; + + if (!::AttachConsole(pid)) + return false; + + DWORD modes = 0; + ::GetConsoleDisplayMode(&modes); + ::FreeConsole(); + + return (modes & (CONSOLE_FULLSCREEN | CONSOLE_FULLSCREEN_HARDWARE)) != 0; +} + +bool IsFullScreenMode() { + return IsPlatformFullScreenMode() || + IsFullScreenWindowMode() || + IsFullScreenConsoleMode(); +} diff --git a/chrome/browser/idle.h b/chrome/browser/idle.h index 3ea8067..4f99bef 100644 --- a/chrome/browser/idle.h +++ b/chrome/browser/idle.h @@ -12,6 +12,13 @@ enum IdleState { IDLE_STATE_LOCKED = 2 // Only available on supported systems. }; +// For MacOSX, InitIdleMonitor needs to be called first to setup the monitor. +// StopIdleMonitor should be called if it is not needed any more. +#if defined(OS_MACOSX) +void InitIdleMonitor(); +void StopIdleMonitor(); +#endif + IdleState CalculateIdleState(unsigned int idle_threshold); #endif // CHROME_BROWSER_IDLE_H_ diff --git a/chrome/browser/idle_linux.cc b/chrome/browser/idle_linux.cc index 0da7f72..e1cdac2 100644 --- a/chrome/browser/idle_linux.cc +++ b/chrome/browser/idle_linux.cc @@ -4,9 +4,74 @@ #include "chrome/browser/idle.h" +#include <gdk/gdk.h> +#include <gdk/gdkx.h> + +#include <vector> + +#include "base/basictypes.h" #include "chrome/browser/sync/engine/idle_query_linux.h" +#include "chrome/browser/ui/gtk/gtk_util.h" +#include "ui/base/x/x11_util.h" + +namespace { + +class ScreensaverWindowFinder : public ui::EnumerateWindowsDelegate { + public: + ScreensaverWindowFinder() + : exists_(false) {} + + bool exists() const { return exists_; } + + protected: + virtual bool ShouldStopIterating(XID window) { + if (!ui::IsWindowVisible(window) || !IsScreensaverWindow(window)) + return false; + exists_ = true; + return true; + } + + private: + bool IsScreensaverWindow(XID window) const { + // It should occupy the full screen. + if (!ui::IsX11WindowFullScreen(window)) + return false; + + // For xscreensaver, the window should have _SCREENSAVER_VERSION property. + if (ui::PropertyExists(window, "_SCREENSAVER_VERSION")) + return true; + + // For all others, like gnome-screensaver, the window's WM_CLASS property + // should contain "screensaver". + std::string value; + if (!ui::GetStringProperty(window, "WM_CLASS", &value)) + return false; + + return value.find("screensaver") != std::string::npos; + } + + bool exists_; + + DISALLOW_COPY_AND_ASSIGN(ScreensaverWindowFinder); +}; + +bool ScreensaverWindowExists() { + ScreensaverWindowFinder finder; + gtk_util::EnumerateTopLevelWindows(&finder); + return finder.exists(); +} + +} IdleState CalculateIdleState(unsigned int idle_threshold) { + // Usually the screensaver is used to lock the screen, so we do not need to + // check if the workstation is locked. + gdk_error_trap_push(); + bool result = ScreensaverWindowExists(); + bool got_error = gdk_error_trap_pop(); + if (result && !got_error) + return IDLE_STATE_LOCKED; + browser_sync::IdleQueryLinux idle_query; unsigned int idle_time = idle_query.IdleTime(); if (idle_time >= idle_threshold) diff --git a/chrome/browser/idle_mac.cc b/chrome/browser/idle_mac.cc deleted file mode 100644 index 383e4c7..0000000 --- a/chrome/browser/idle_mac.cc +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2009 The Chromium 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 "chrome/browser/idle.h" - -#include <CoreGraphics/CGEventSource.h> - -IdleState CalculateIdleState(unsigned int idle_threshold) { - unsigned int idle_time = CGEventSourceSecondsSinceLastEventType( - kCGEventSourceStateCombinedSessionState, - kCGAnyInputEventType); - if (idle_time >= idle_threshold) - return IDLE_STATE_IDLE; - return IDLE_STATE_ACTIVE; -} diff --git a/chrome/browser/idle_mac.mm b/chrome/browser/idle_mac.mm new file mode 100644 index 0000000..4032408 --- /dev/null +++ b/chrome/browser/idle_mac.mm @@ -0,0 +1,99 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "chrome/browser/idle.h" + +#import <Cocoa/Cocoa.h> +#import <CoreGraphics/CGEventSource.h> + +@interface MacScreenMonitor : NSObject { + @private + BOOL screensaverRunning_; + BOOL screenLocked_; +} + +@property (readonly, + nonatomic, + getter=isScreensaverRunning) BOOL screensaverRunning; +@property (readonly, nonatomic, getter=isScreenLocked) BOOL screenLocked; + +@end + +@implementation MacScreenMonitor + +@synthesize screensaverRunning = screensaverRunning_; +@synthesize screenLocked = screenLocked_; + +- (id)init { + if ((self = [super init])) { + NSDistributedNotificationCenter* distCenter = + [NSDistributedNotificationCenter defaultCenter]; + [distCenter addObserver:self + selector:@selector(onScreenSaverStarted:) + name:@"com.apple.screensaver.didstart" + object:nil]; + [distCenter addObserver:self + selector:@selector(onScreenSaverStopped:) + name:@"com.apple.screensaver.didstop" + object:nil]; + [distCenter addObserver:self + selector:@selector(onScreenLocked:) + name:@"com.apple.screenIsLocked" + object:nil]; + [distCenter addObserver:self + selector:@selector(onScreenUnlocked:) + name:@"com.apple.screenIsUnlocked" + object:nil]; + } + return self; +} + +- (void)dealloc { + [[NSDistributedNotificationCenter defaultCenter] removeObject:self]; + [super dealloc]; +} + +- (void)onScreenSaverStarted:(NSNotification*)notification { + screensaverRunning_ = YES; +} + +- (void)onScreenSaverStopped:(NSNotification*)notification { + screensaverRunning_ = NO; +} + +- (void)onScreenLocked:(NSNotification*)notification { + screenLocked_ = YES; +} + +- (void)onScreenUnlocked:(NSNotification*)notification { + screenLocked_ = NO; +} + +@end + +static MacScreenMonitor* g_screenMonitor = nil; + +void InitIdleMonitor() { + if (!g_screenMonitor) + g_screenMonitor = [[MacScreenMonitor alloc] init]; +} + +void StopIdleMonitor() { + [g_screenMonitor release]; + g_screenMonitor = nil; +} + +IdleState CalculateIdleState(unsigned int idle_threshold) { + if ([g_screenMonitor isScreensaverRunning] || + [g_screenMonitor isScreenLocked]) + return IDLE_STATE_LOCKED; + + CFTimeInterval idle_time = CGEventSourceSecondsSinceLastEventType( + kCGEventSourceStateCombinedSessionState, + kCGAnyInputEventType); + if (idle_time >= idle_threshold) + return IDLE_STATE_IDLE; + + return IDLE_STATE_ACTIVE; +} diff --git a/chrome/browser/notifications/notification_ui_manager.cc b/chrome/browser/notifications/notification_ui_manager.cc index 950bd6c..51a2c66 100644 --- a/chrome/browser/notifications/notification_ui_manager.cc +++ b/chrome/browser/notifications/notification_ui_manager.cc @@ -8,6 +8,8 @@ #include "base/scoped_ptr.h" #include "base/stl_util-inl.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/fullscreen.h" +#include "chrome/browser/idle.h" #include "chrome/browser/notifications/balloon_collection.h" #include "chrome/browser/notifications/notification.h" #include "chrome/browser/prefs/pref_service.h" @@ -16,6 +18,10 @@ #include "chrome/common/notification_type.h" #include "chrome/common/pref_names.h" +namespace { +const int kUserStatePollingIntervalSeconds = 1; +} + // A class which represents a notification waiting to be shown. class QueuedNotification { public: @@ -42,14 +48,21 @@ class QueuedNotification { }; NotificationUIManager::NotificationUIManager(PrefService* local_state) - : balloon_collection_(NULL) { + : balloon_collection_(NULL), + is_user_active_(true) { registrar_.Add(this, NotificationType::APP_TERMINATING, NotificationService::AllSources()); position_pref_.Init(prefs::kDesktopNotificationPosition, local_state, this); +#if defined(OS_MACOSX) + InitFullScreenMonitor(); +#endif } NotificationUIManager::~NotificationUIManager() { STLDeleteElements(&show_queue_); +#if defined(OS_MACOSX) + StopFullScreenMonitor(); +#endif } // static @@ -126,8 +139,29 @@ void NotificationUIManager::CancelAll() { } void NotificationUIManager::CheckAndShowNotifications() { - // TODO(johnnyg): http://crbug.com/25061 - Check for user idle/presentation. - ShowNotifications(); + CheckUserState(); + if (is_user_active_) + ShowNotifications(); +} + +void NotificationUIManager::CheckUserState() { + bool is_user_active_previously = is_user_active_; + is_user_active_ = CalculateIdleState(0) != IDLE_STATE_LOCKED && + !IsFullScreenMode(); + if (is_user_active_ == is_user_active_previously) + return; + + if (is_user_active_) { + user_state_check_timer_.Stop(); + // We need to show any postponed nofications when the user becomes active + // again. + ShowNotifications(); + } else if (!user_state_check_timer_.IsRunning()) { + // Start a timer to detect the moment at which the user becomes active. + user_state_check_timer_.Start( + base::TimeDelta::FromSeconds(kUserStatePollingIntervalSeconds), this, + &NotificationUIManager::CheckUserState); + } } void NotificationUIManager::ShowNotifications() { diff --git a/chrome/browser/notifications/notification_ui_manager.h b/chrome/browser/notifications/notification_ui_manager.h index 1b9475d..7ac63a2 100644 --- a/chrome/browser/notifications/notification_ui_manager.h +++ b/chrome/browser/notifications/notification_ui_manager.h @@ -11,6 +11,7 @@ #include "base/id_map.h" #include "base/scoped_ptr.h" +#include "base/timer.h" #include "chrome/browser/notifications/balloon.h" #include "chrome/browser/notifications/balloon_collection.h" #include "chrome/browser/prefs/pref_member.h" @@ -93,6 +94,9 @@ class NotificationUIManager // returns true if the replacement happened. bool TryReplacement(const Notification& notification); + // Checks the user state to decide if we want to show the notification. + void CheckUserState(); + // An owned pointer to the collection of active balloons. scoped_ptr<BalloonCollection> balloon_collection_; @@ -106,6 +110,10 @@ class NotificationUIManager // Prefs listener for the position preference. IntegerPrefMember position_pref_; + // Used by screen-saver and full-screen handling support. + bool is_user_active_; + base::RepeatingTimer<NotificationUIManager> user_state_check_timer_; + DISALLOW_COPY_AND_ASSIGN(NotificationUIManager); }; diff --git a/chrome/browser/ui/gtk/gtk_util.cc b/chrome/browser/ui/gtk/gtk_util.cc index 9ba091b..d377093 100644 --- a/chrome/browser/ui/gtk/gtk_util.cc +++ b/chrome/browser/ui/gtk/gtk_util.cc @@ -548,7 +548,7 @@ bool IsScreenComposited() { void EnumerateTopLevelWindows(ui::EnumerateWindowsDelegate* delegate) { std::vector<XID> stack; - if (!ui::GetXWindowStack(&stack)) { + if (!ui::GetXWindowStack(ui::GetX11RootWindow(), &stack)) { // Window Manager doesn't support _NET_CLIENT_LIST_STACKING, so fall back // to old school enumeration of all X windows. Some WMs parent 'top-level' // windows in unnamed actual top-level windows (ion WM), so extend the diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 081a766..cccf05f 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1253,6 +1253,10 @@ 'browser/first_run/first_run_win.cc', 'browser/first_run/first_run_gtk.cc', 'browser/fonts_languages_window.h', + 'browser/fullscreen.h', + 'browser/fullscreen_linux.cc', + 'browser/fullscreen_mac.mm', + 'browser/fullscreen_win.cc', 'browser/gears_integration.cc', 'browser/gears_integration.h', 'browser/geolocation/access_token_store.cc', @@ -1657,7 +1661,7 @@ 'browser/icon_manager_mac.mm', 'browser/icon_manager_win.cc', 'browser/idle_linux.cc', - 'browser/idle_mac.cc', + 'browser/idle_mac.mm', 'browser/idle_win.cc', 'browser/ime_input.cc', 'browser/ime_input.h', diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc index 2b5863a..fda637c 100644 --- a/ui/base/x/x11_util.cc +++ b/ui/base/x/x11_util.cc @@ -16,7 +16,7 @@ #include <sys/shm.h> #include <list> -#include <set> +#include <vector> #include "base/command_line.h" #include "base/logging.h" @@ -66,6 +66,28 @@ int DefaultX11IOErrorHandler(Display* d) { _exit(1); } +// Note: The caller should free the resulting value data. +bool GetProperty(XID window, const std::string& property_name, long max_length, + Atom* type, int* format, unsigned long* num_items, + unsigned char** property) { + Atom property_atom = gdk_x11_get_xatom_by_name_for_display( + gdk_display_get_default(), property_name.c_str()); + + unsigned long remaining_bytes = 0; + return XGetWindowProperty(GetXDisplay(), + window, + property_atom, + 0, // offset into property data to read + max_length, // max length to get + False, // deleted + AnyPropertyType, + type, + format, + num_items, + &remaining_bytes, + property); +} + } // namespace bool XDisplayExists() { @@ -221,27 +243,29 @@ bool GetWindowRect(XID window, gfx::Rect* rect) { return true; } -bool GetIntProperty(XID window, const std::string& property_name, int* value) { - Atom property_atom = gdk_x11_get_xatom_by_name_for_display( - gdk_display_get_default(), property_name.c_str()); +bool PropertyExists(XID window, const std::string& property_name) { + Atom type = None; + int format = 0; // size in bits of each item in 'property' + long unsigned int num_items = 0; + unsigned char* property = NULL; + + int result = GetProperty(window, property_name, 1, + &type, &format, &num_items, &property); + if (result != Success) + return false; + + XFree(property); + return num_items > 0; +} +bool GetIntProperty(XID window, const std::string& property_name, int* value) { Atom type = None; int format = 0; // size in bits of each item in 'property' - long unsigned int num_items = 0, remaining_bytes = 0; + long unsigned int num_items = 0; unsigned char* property = NULL; - int result = XGetWindowProperty(GetXDisplay(), - window, - property_atom, - 0, // offset into property data to read - 1, // max length to get - False, // deleted - AnyPropertyType, - &type, - &format, - &num_items, - &remaining_bytes, - &property); + int result = GetProperty(window, property_name, 1, + &type, &format, &num_items, &property); if (result != Success) return false; @@ -258,26 +282,14 @@ bool GetIntProperty(XID window, const std::string& property_name, int* value) { bool GetIntArrayProperty(XID window, const std::string& property_name, std::vector<int>* value) { - Atom property_atom = gdk_x11_get_xatom_by_name_for_display( - gdk_display_get_default(), property_name.c_str()); - Atom type = None; int format = 0; // size in bits of each item in 'property' - long unsigned int num_items = 0, remaining_bytes = 0; + long unsigned int num_items = 0; unsigned char* properties = NULL; - int result = XGetWindowProperty(GetXDisplay(), - window, - property_atom, - 0, // offset into property data to read - (~0L), // max length to get (all of them) - False, // deleted - AnyPropertyType, - &type, - &format, - &num_items, - &remaining_bytes, - &properties); + int result = GetProperty(window, property_name, + (~0L), // (all of them) + &type, &format, &num_items, &properties); if (result != Success) return false; @@ -293,28 +305,41 @@ bool GetIntArrayProperty(XID window, return true; } +bool GetAtomArrayProperty(XID window, + const std::string& property_name, + std::vector<Atom>* value) { + Atom type = None; + int format = 0; // size in bits of each item in 'property' + long unsigned int num_items = 0; + unsigned char* properties = NULL; + + int result = GetProperty(window, property_name, + (~0L), // (all of them) + &type, &format, &num_items, &properties); + if (result != Success) + return false; + + if (type != XA_ATOM) { + XFree(properties); + return false; + } + + Atom* atom_properties = reinterpret_cast<Atom*>(properties); + value->clear(); + value->insert(value->begin(), atom_properties, atom_properties + num_items); + XFree(properties); + return true; +} + bool GetStringProperty( XID window, const std::string& property_name, std::string* value) { - Atom property_atom = gdk_x11_get_xatom_by_name_for_display( - gdk_display_get_default(), property_name.c_str()); - Atom type = None; int format = 0; // size in bits of each item in 'property' - long unsigned int num_items = 0, remaining_bytes = 0; + long unsigned int num_items = 0; unsigned char* property = NULL; - int result = XGetWindowProperty(GetXDisplay(), - window, - property_atom, - 0, // offset into property data to read - 1024, // max length to get - False, // deleted - AnyPropertyType, - &type, - &format, - &num_items, - &remaining_bytes, - &property); + int result = GetProperty(window, property_name, 1024, + &type, &format, &num_items, &property); if (result != Success) return false; @@ -376,16 +401,16 @@ bool EnumerateChildren(EnumerateWindowsDelegate* delegate, XID window, if (status == 0) return false; - std::set<XID> windows; - for (unsigned int i = 0; i < num_children; i++) - windows.insert(children[i]); + std::vector<XID> windows; + for (int i = static_cast<int>(num_children) - 1; i >= 0; i--) + windows.push_back(children[i]); XFree(children); // XQueryTree returns the children of |window| in bottom-to-top order, so // reverse-iterate the list to check the windows from top-to-bottom. - std::set<XID>::reverse_iterator iter; - for (iter = windows.rbegin(); iter != windows.rend(); iter++) { + std::vector<XID>::iterator iter; + for (iter = windows.begin(); iter != windows.end(); iter++) { if (IsWindowNamed(*iter) && delegate->ShouldStopIterating(*iter)) return true; } @@ -395,7 +420,7 @@ bool EnumerateChildren(EnumerateWindowsDelegate* delegate, XID window, // loop because the recursion and call to XQueryTree are expensive and is only // needed for a small number of cases. if (++depth <= max_depth) { - for (iter = windows.rbegin(); iter != windows.rend(); iter++) { + for (iter = windows.begin(); iter != windows.end(); iter++) { if (EnumerateChildren(delegate, *iter, max_depth, depth)) return true; } @@ -409,29 +434,20 @@ bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth) { return EnumerateChildren(delegate, root, max_depth, 0); } -bool GetXWindowStack(std::vector<XID>* windows) { +bool GetXWindowStack(Window window, std::vector<XID>* windows) { windows->clear(); - static Atom atom = XInternAtom(GetXDisplay(), - "_NET_CLIENT_LIST_STACKING", False); - Atom type; int format; unsigned long count; - unsigned long bytes_after; unsigned char *data = NULL; - if (XGetWindowProperty(GetXDisplay(), - GetX11RootWindow(), - atom, - 0, // offset - ~0L, // length - False, // delete - AnyPropertyType, // requested type - &type, - &format, - &count, - &bytes_after, - &data) != Success) { + if (!GetProperty(window, + "_NET_CLIENT_LIST_STACKING", + ~0L, + &type, + &format, + &count, + &data)) { return false; } @@ -439,8 +455,8 @@ bool GetXWindowStack(std::vector<XID>* windows) { if (type == XA_WINDOW && format == 32 && data && count > 0) { result = true; XID* stack = reinterpret_cast<XID*>(data); - for (unsigned long i = 0; i < count; i++) - windows->insert(windows->begin(), stack[i]); + for (long i = static_cast<long>(count) - 1; i >= 0; i--) + windows->push_back(stack[i]); } if (data) @@ -752,6 +768,34 @@ void SetDefaultX11ErrorHandlers() { SetX11ErrorHandlers(NULL, NULL); } +bool IsX11WindowFullScreen(XID window) { + // First check if _NET_WM_STATE property contains _NET_WM_STATE_FULLSCREEN. + static Atom atom = gdk_x11_get_xatom_by_name_for_display( + gdk_display_get_default(), "_NET_WM_STATE_FULLSCREEN"); + + std::vector<Atom> atom_properties; + if (GetAtomArrayProperty(window, + "_NET_WM_STATE", + &atom_properties) && + std::find(atom_properties.begin(), atom_properties.end(), atom) + != atom_properties.end()) + return true; + + // As the last resort, check if the window size is as large as the main + // screen. + GdkRectangle monitor_rect; + gdk_screen_get_monitor_geometry(gdk_screen_get_default(), 0, &monitor_rect); + + gfx::Rect window_rect; + if (!ui::GetWindowRect(window, &window_rect)) + return false; + + return monitor_rect.x == window_rect.x() && + monitor_rect.y == window_rect.y() && + monitor_rect.width == window_rect.width() && + monitor_rect.height == window_rect.height(); +} + // ---------------------------------------------------------------------------- // These functions are declared in x11_util_internal.h because they require // XLib.h to be included, and it conflicts with many other headers. diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h index 58f9157..3284fcb 100644 --- a/ui/base/x/x11_util.h +++ b/ui/base/x/x11_util.h @@ -17,6 +17,7 @@ #include "base/basictypes.h" +typedef unsigned long Atom; typedef struct _GdkDrawable GdkWindow; typedef struct _GtkWidget GtkWidget; typedef struct _GtkWindow GtkWindow; @@ -76,11 +77,15 @@ int BitsPerPixelForPixmapDepth(Display* display, int depth); bool IsWindowVisible(XID window); // Returns the bounds of |window|. bool GetWindowRect(XID window, gfx::Rect* rect); -// Get the value of an int, int array, or string property. On +// Return true if |window| has any property with |property_name|. +bool PropertyExists(XID window, const std::string& property_name); +// Get the value of an int, int array, atom array or string property. On // success, true is returned and the value is stored in |value|. bool GetIntProperty(XID window, const std::string& property_name, int* value); bool GetIntArrayProperty(XID window, const std::string& property_name, std::vector<int>* value); +bool GetAtomArrayProperty(XID window, const std::string& property_name, + std::vector<Atom>* value); bool GetStringProperty( XID window, const std::string& property_name, std::string* value); @@ -111,8 +116,9 @@ class EnumerateWindowsDelegate { // windows up to a depth of |max_depth|. bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth); -// Returns a list of top-level windows in top-to-bottom stacking order. -bool GetXWindowStack(std::vector<XID>* windows); +// Returns all children windows of a given window in top-to-bottom stacking +// order. +bool GetXWindowStack(XID window, std::vector<XID>* windows); // Restack a window in relation to one of its siblings. If |above| is true, // |window| will be stacked directly above |sibling|; otherwise it will stacked @@ -178,6 +184,9 @@ bool ChangeWindowDesktop(XID window, XID destination); // to set your own error handlers. void SetDefaultX11ErrorHandlers(); +// Return true if a given window is in full-screen mode. +bool IsX11WindowFullScreen(XID window); + } // namespace ui #endif // UI_BASE_X_X11_UTIL_H_ |