1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/fullscreen.h" 6 7 #include <gdk/gdk.h> 8 #include <gdk/gdkx.h> 9 10 #include <algorithm> 11 #include <vector> 12 13 #include "base/basictypes.h" 14 #include "chrome/browser/ui/gtk/gtk_util.h" 15 #include "ui/base/x/x11_util.h" 16 #include "ui/gfx/rect.h" 17 18 namespace { 19 20 // TODO (jianli): Merge with gtk_util::EnumerateTopLevelWindows. 21 void EnumerateAllChildWindows(ui::EnumerateWindowsDelegate* delegate, 22 XID window) { 23 std::vector<XID> windows; 24 25 if (!ui::GetXWindowStack(window, &windows)) { 26 // Window Manager doesn't support _NET_CLIENT_LIST_STACKING, so fall back 27 // to old school enumeration of all X windows. 28 XID root, parent, *children; 29 unsigned int num_children; 30 int status = XQueryTree(ui::GetXDisplay(), window, &root, &parent, 31 &children, &num_children); 32 if (status) { 33 for (long i = static_cast<long>(num_children) - 1; i >= 0; i--) 34 windows.push_back(children[i]); 35 XFree(children); 36 } 37 } 38 39 std::vector<XID>::iterator iter; 40 for (iter = windows.begin(); iter != windows.end(); iter++) { 41 if (delegate->ShouldStopIterating(*iter)) 42 return; 43 } 44 } 45 46 // To find the top-most window: 47 // 1) Enumerate all top-level windows from the top to the bottom. 48 // 2) For each window: 49 // 2.1) If it is hidden, continue the iteration. 50 // 2.2) If it is managed by the Window Manager (has a WM_STATE property). 51 // Return this window as the top-most window. 52 // 2.3) Enumerate all its child windows. If there is a child window that is 53 // managed by the Window Manager (has a WM_STATE property). Return this 54 // child window as the top-most window. 55 // 2.4) Otherwise, continue the iteration. 56 57 class WindowManagerWindowFinder : public ui::EnumerateWindowsDelegate { 58 public: 59 WindowManagerWindowFinder() : window_(None) { } 60 61 XID window() const { return window_; } 62 63 protected: 64 virtual bool ShouldStopIterating(XID window) { 65 if (ui::PropertyExists(window, "WM_STATE")) { 66 window_ = window; 67 return true; 68 } 69 return false; 70 } 71 72 private: 73 XID window_; 74 75 DISALLOW_COPY_AND_ASSIGN(WindowManagerWindowFinder); 76 }; 77 78 class TopMostWindowFinder : public ui::EnumerateWindowsDelegate { 79 public: 80 TopMostWindowFinder() 81 : top_most_window_(None) {} 82 83 XID top_most_window() const { return top_most_window_; } 84 85 protected: 86 virtual bool ShouldStopIterating(XID window) { 87 if (!ui::IsWindowVisible(window)) 88 return false; 89 if (ui::PropertyExists(window, "WM_STATE")) { 90 top_most_window_ = window; 91 return true; 92 } 93 WindowManagerWindowFinder child_finder; 94 EnumerateAllChildWindows(&child_finder, window); 95 XID child_window = child_finder.window(); 96 if (child_window == None) 97 return false; 98 top_most_window_ = child_window; 99 return true; 100 } 101 102 private: 103 XID top_most_window_; 104 105 DISALLOW_COPY_AND_ASSIGN(TopMostWindowFinder); 106 }; 107 108 bool IsTopMostWindowFullScreen() { 109 // Find the topmost window. 110 TopMostWindowFinder finder; 111 EnumerateAllChildWindows(&finder, ui::GetX11RootWindow()); 112 XID window = finder.top_most_window(); 113 if (window == None) 114 return false; 115 116 // Make sure it is not the desktop window. 117 static Atom desktop_atom = gdk_x11_get_xatom_by_name_for_display( 118 gdk_display_get_default(), "_NET_WM_WINDOW_TYPE_DESKTOP"); 119 120 std::vector<Atom> atom_properties; 121 if (ui::GetAtomArrayProperty(window, 122 "_NET_WM_WINDOW_TYPE", 123 &atom_properties) && 124 std::find(atom_properties.begin(), atom_properties.end(), desktop_atom) 125 != atom_properties.end()) 126 return false; 127 128 // If it is a GDK window, check it using gdk function. 129 GdkWindow* gwindow = gdk_window_lookup(window); 130 if (gwindow && window != GDK_ROOT_WINDOW()) 131 return gdk_window_get_state(gwindow) == GDK_WINDOW_STATE_FULLSCREEN; 132 133 // Otherwise, do the check via xlib function. 134 return ui::IsX11WindowFullScreen(window); 135 } 136 137 } 138 139 bool IsFullScreenMode() { 140 gdk_error_trap_push(); 141 bool result = IsTopMostWindowFullScreen(); 142 bool got_error = gdk_error_trap_pop(); 143 return result && !got_error; 144 } 145