Implement GetWindowList() on X11
This change implements GetWindowList() on X11. WindowCapturerLinux and
GetWindowUnderPoint() can share the logic of this function.
Bug: webrtc:7950
Change-Id: Ida746840d6f51d31e0470e5ae4955b6f5a4cfaf2
Reviewed-on: https://chromium-review.googlesource.com/606560
Reviewed-by: Jamie Walch <jamiewalch@chromium.org>
Commit-Queue: Zijie He <zijiehe@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#19314}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: ad501d19881fd06a622980fd1d27f95ba89f3348
diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn
index 3b025c5..019f39d 100644
--- a/modules/desktop_capture/BUILD.gn
+++ b/modules/desktop_capture/BUILD.gn
@@ -264,6 +264,10 @@
"window_capturer_x11.cc",
"x11/shared_x_display.cc",
"x11/shared_x_display.h",
+ "x11/window_list_utils.cc",
+ "x11/window_list_utils.h",
+ "x11/x_atom_cache.cc",
+ "x11/x_atom_cache.h",
"x11/x_error_trap.cc",
"x11/x_error_trap.h",
"x11/x_server_pixel_buffer.cc",
diff --git a/modules/desktop_capture/mac/window_list_utils.h b/modules/desktop_capture/mac/window_list_utils.h
index 6492315..a3cd507 100644
--- a/modules/desktop_capture/mac/window_list_utils.h
+++ b/modules/desktop_capture/mac/window_list_utils.h
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_WINDOW_LIST_UTILS_H_
-#define WEBRTC_MODULES_DESKTOP_CAPTURE_WINDOW_LIST_UTILS_H_
+#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_MAC_WINDOW_LIST_UTILS_H_
+#define WEBRTC_MODULES_DESKTOP_CAPTURE_MAC_WINDOW_LIST_UTILS_H_
#include <ApplicationServices/ApplicationServices.h>
@@ -24,8 +24,8 @@
// Iterates all on-screen windows in decreasing z-order and sends them
// one-by-one to |on_window| function. If |on_window| returns false, this
// function returns immediately. GetWindowList() returns false if native APIs
-// failed. Menus, dock, minimized windows and any windows which do not have a
-// valid window id or title will be ignored.
+// failed. Menus, dock, minimized windows (if |ignore_minimized| is true) and
+// any windows which do not have a valid window id or title will be ignored.
bool GetWindowList(rtc::FunctionView<bool(CFDictionaryRef)> on_window,
bool ignore_minimized);
@@ -56,4 +56,4 @@
} // namespace webrtc
-#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_WINDOW_LIST_UTILS_H_
+#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_MAC_WINDOW_LIST_UTILS_H_
diff --git a/modules/desktop_capture/window_capturer_x11.cc b/modules/desktop_capture/window_capturer_x11.cc
index 28f5b96..eb4ece1 100644
--- a/modules/desktop_capture/window_capturer_x11.cc
+++ b/modules/desktop_capture/window_capturer_x11.cc
@@ -8,21 +8,20 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#include <assert.h>
-#include <string.h>
-#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrender.h>
#include <X11/Xutil.h>
-#include <algorithm>
+#include <utility>
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "webrtc/modules/desktop_capture/desktop_capturer.h"
#include "webrtc/modules/desktop_capture/desktop_frame.h"
#include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
-#include "webrtc/modules/desktop_capture/x11/x_error_trap.h"
+#include "webrtc/modules/desktop_capture/x11/window_list_utils.h"
+#include "webrtc/modules/desktop_capture/x11/x_atom_cache.h"
#include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h"
+#include "webrtc/rtc_base/checks.h"
#include "webrtc/rtc_base/constructormagic.h"
#include "webrtc/rtc_base/logging.h"
#include "webrtc/rtc_base/scoped_ref_ptr.h"
@@ -31,56 +30,6 @@
namespace {
-// Convenience wrapper for XGetWindowProperty() results.
-template <class PropertyType>
-class XWindowProperty {
- public:
- XWindowProperty(Display* display, Window window, Atom property) {
- const int kBitsPerByte = 8;
- Atom actual_type;
- int actual_format;
- unsigned long bytes_after; // NOLINT: type required by XGetWindowProperty
- int status = XGetWindowProperty(display, window, property, 0L, ~0L, False,
- AnyPropertyType, &actual_type,
- &actual_format, &size_,
- &bytes_after, &data_);
- if (status != Success) {
- data_ = nullptr;
- return;
- }
- if (sizeof(PropertyType) * kBitsPerByte != actual_format) {
- size_ = 0;
- return;
- }
-
- is_valid_ = true;
- }
-
- ~XWindowProperty() {
- if (data_)
- XFree(data_);
- }
-
- // True if we got properly value successfully.
- bool is_valid() const { return is_valid_; }
-
- // Size and value of the property.
- size_t size() const { return size_; }
- const PropertyType* data() const {
- return reinterpret_cast<PropertyType*>(data_);
- }
- PropertyType* data() {
- return reinterpret_cast<PropertyType*>(data_);
- }
-
- private:
- bool is_valid_ = false;
- unsigned long size_ = 0; // NOLINT: type required by XGetWindowProperty
- unsigned char* data_ = nullptr;
-
- RTC_DISALLOW_COPY_AND_ASSIGN(XWindowProperty);
-};
-
class WindowCapturerLinux : public DesktopCapturer,
public SharedXDisplay::XEventHandler {
public:
@@ -100,43 +49,25 @@
private:
Display* display() { return x_display_->display(); }
- // Iterates through |window| hierarchy to find first visible window, i.e. one
- // that has WM_STATE property set to NormalState.
- // See http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1 .
- ::Window GetApplicationWindow(::Window window);
-
- // Returns true if the |window| is a desktop element.
- bool IsDesktopElement(::Window window);
-
// Returns window title for the specified X |window|.
bool GetWindowTitle(::Window window, std::string* title);
- // Return WM_STATE property of the |window|.
- int32_t GetWindowState(::Window window);
-
Callback* callback_ = nullptr;
rtc::scoped_refptr<SharedXDisplay> x_display_;
- Atom wm_state_atom_;
- Atom window_type_atom_;
- Atom normal_window_type_atom_;
bool has_composite_extension_ = false;
::Window selected_window_ = 0;
XServerPixelBuffer x_server_pixel_buffer_;
+ XAtomCache atom_cache_;
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux);
};
WindowCapturerLinux::WindowCapturerLinux(const DesktopCaptureOptions& options)
- : x_display_(options.x_display()) {
- // Create Atoms so we don't need to do it every time they are used.
- wm_state_atom_ = XInternAtom(display(), "WM_STATE", True);
- window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE", True);
- normal_window_type_atom_ = XInternAtom(
- display(), "_NET_WM_WINDOW_TYPE_NORMAL", True);
-
+ : x_display_(options.x_display()),
+ atom_cache_(display()) {
int event_base, error_base, major_version, minor_version;
if (XCompositeQueryExtension(display(), &event_base, &error_base) &&
XCompositeQueryVersion(display(), &major_version, &minor_version) &&
@@ -155,43 +86,15 @@
}
bool WindowCapturerLinux::GetSourceList(SourceList* sources) {
- SourceList result;
-
- XErrorTrap error_trap(display());
-
- int num_screens = XScreenCount(display());
- for (int screen = 0; screen < num_screens; ++screen) {
- ::Window root_window = XRootWindow(display(), screen);
- ::Window parent;
- ::Window *children;
- unsigned int num_children;
- int status = XQueryTree(display(), root_window, &root_window, &parent,
- &children, &num_children);
- if (status == 0) {
- LOG(LS_ERROR) << "Failed to query for child windows for screen "
- << screen;
- continue;
- }
-
- for (unsigned int i = 0; i < num_children; ++i) {
- // Iterate in reverse order to return windows from front to back.
- ::Window app_window =
- GetApplicationWindow(children[num_children - 1 - i]);
- if (app_window && !IsDesktopElement(app_window)) {
- Source w;
- w.id = app_window;
- if (GetWindowTitle(app_window, &w.title))
- result.push_back(w);
- }
- }
-
- if (children)
- XFree(children);
- }
-
- sources->swap(result);
-
- return true;
+ return GetWindowList(&atom_cache_,
+ [this, sources](::Window window) {
+ Source w;
+ w.id = window;
+ if (this->GetWindowTitle(window, &w.title)) {
+ sources->push_back(w);
+ }
+ return true;
+ });
}
bool WindowCapturerLinux::SelectSource(SourceId id) {
@@ -265,8 +168,8 @@
}
void WindowCapturerLinux::Start(Callback* callback) {
- assert(!callback_);
- assert(callback);
+ RTC_DCHECK(!callback_);
+ RTC_DCHECK(callback);
callback_ = callback;
}
@@ -289,7 +192,7 @@
return;
}
- if (GetWindowState(selected_window_) == IconicState) {
+ if (GetWindowState(&atom_cache_, selected_window_) == IconicState) {
// Window is in minimized. Return a 1x1 frame as same as OSX/Win does.
std::unique_ptr<DesktopFrame> frame(
new BasicDesktopFrame(DesktopSize(1, 1)));
@@ -327,75 +230,6 @@
return false;
}
-// TODO(zijiehe): This function should return the ancestor window of |window|
-// other than the root_window.
-::Window WindowCapturerLinux::GetApplicationWindow(::Window window) {
- int32_t state = GetWindowState(window);
- if (state == NormalState) {
- // Window has WM_STATE==NormalState. Return it.
- return window;
- } else if (state == IconicState) {
- // Window is in minimized. Skip it.
- return 0;
- }
-
- // If the window is in WithdrawnState then look at all of its children.
- ::Window root, parent;
- ::Window *children;
- unsigned int num_children;
- if (!XQueryTree(display(), window, &root, &parent, &children,
- &num_children)) {
- LOG(LS_ERROR) << "Failed to query for child windows although window"
- << "does not have a valid WM_STATE.";
- return 0;
- }
- ::Window app_window = 0;
- for (unsigned int i = 0; i < num_children; ++i) {
- app_window = GetApplicationWindow(children[i]);
- if (app_window)
- break;
- }
-
- if (children)
- XFree(children);
- return app_window;
-}
-
-bool WindowCapturerLinux::IsDesktopElement(::Window window) {
- if (window == 0)
- return false;
-
- // First look for _NET_WM_WINDOW_TYPE. The standard
- // (http://standards.freedesktop.org/wm-spec/latest/ar01s05.html#id2760306)
- // says this hint *should* be present on all windows, and we use the existence
- // of _NET_WM_WINDOW_TYPE_NORMAL in the property to indicate a window is not
- // a desktop element (that is, only "normal" windows should be shareable).
- XWindowProperty<uint32_t> window_type(display(), window, window_type_atom_);
- if (window_type.is_valid() && window_type.size() > 0) {
- uint32_t* end = window_type.data() + window_type.size();
- bool is_normal = (end != std::find(
- window_type.data(), end, normal_window_type_atom_));
- return !is_normal;
- }
-
- // Fall back on using the hint.
- XClassHint class_hint;
- Status status = XGetClassHint(display(), window, &class_hint);
- bool result = false;
- if (status == 0) {
- // No hints, assume this is a normal application window.
- return result;
- }
-
- if (strcmp("gnome-panel", class_hint.res_name) == 0 ||
- strcmp("desktop_window", class_hint.res_name) == 0) {
- result = true;
- }
- XFree(class_hint.res_name);
- XFree(class_hint.res_class);
- return result;
-}
-
bool WindowCapturerLinux::GetWindowTitle(::Window window, std::string* title) {
int status;
bool result = false;
@@ -425,14 +259,6 @@
return result;
}
-int32_t WindowCapturerLinux::GetWindowState(::Window window) {
- // Get WM_STATE property of the window.
- XWindowProperty<uint32_t> window_state(display(), window, wm_state_atom_);
-
- // WM_STATE is considered to be set to WithdrawnState when it missing.
- return window_state.is_valid() ? *window_state.data() : WithdrawnState;
-}
-
} // namespace
// static
diff --git a/modules/desktop_capture/x11/window_list_utils.cc b/modules/desktop_capture/x11/window_list_utils.cc
new file mode 100644
index 0000000..1148acc
--- /dev/null
+++ b/modules/desktop_capture/x11/window_list_utils.cc
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/desktop_capture/x11/window_list_utils.h"
+
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+
+#include <algorithm>
+
+#include "webrtc/modules/desktop_capture/x11/x_error_trap.h"
+#include "webrtc/rtc_base/checks.h"
+#include "webrtc/rtc_base/constructormagic.h"
+#include "webrtc/rtc_base/logging.h"
+
+namespace webrtc {
+
+namespace {
+
+class DeferXFree {
+ public:
+ explicit DeferXFree(void* data) : data_(data) {}
+ ~DeferXFree();
+
+ private:
+ void* const data_;
+};
+
+DeferXFree::~DeferXFree() {
+ if (data_)
+ XFree(data_);
+}
+
+// Convenience wrapper for XGetWindowProperty() results.
+template <class PropertyType>
+class XWindowProperty {
+ public:
+ XWindowProperty(Display* display, Window window, Atom property) {
+ const int kBitsPerByte = 8;
+ Atom actual_type;
+ int actual_format;
+ unsigned long bytes_after; // NOLINT: type required by XGetWindowProperty
+ int status = XGetWindowProperty(display, window, property, 0L, ~0L, False,
+ AnyPropertyType, &actual_type,
+ &actual_format, &size_,
+ &bytes_after, &data_);
+ if (status != Success) {
+ data_ = nullptr;
+ return;
+ }
+ if (sizeof(PropertyType) * kBitsPerByte != actual_format) {
+ size_ = 0;
+ return;
+ }
+
+ is_valid_ = true;
+ }
+
+ ~XWindowProperty() {
+ if (data_)
+ XFree(data_);
+ }
+
+ // True if we got properly value successfully.
+ bool is_valid() const { return is_valid_; }
+
+ // Size and value of the property.
+ size_t size() const { return size_; }
+ const PropertyType* data() const {
+ return reinterpret_cast<PropertyType*>(data_);
+ }
+ PropertyType* data() {
+ return reinterpret_cast<PropertyType*>(data_);
+ }
+
+ private:
+ bool is_valid_ = false;
+ unsigned long size_ = 0; // NOLINT: type required by XGetWindowProperty
+ unsigned char* data_ = nullptr;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(XWindowProperty);
+};
+
+// Iterates through |window| hierarchy to find first visible window, i.e. one
+// that has WM_STATE property set to NormalState.
+// See http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1 .
+::Window GetApplicationWindow(XAtomCache* cache, ::Window window) {
+ int32_t state = GetWindowState(cache, window);
+ if (state == NormalState) {
+ // Window has WM_STATE==NormalState. Return it.
+ return window;
+ } else if (state == IconicState) {
+ // Window is in minimized. Skip it.
+ return 0;
+ }
+
+ RTC_DCHECK_EQ(state, WithdrawnState);
+ // If the window is in WithdrawnState then look at all of its children.
+ ::Window root, parent;
+ ::Window *children;
+ unsigned int num_children;
+ if (!XQueryTree(cache->display(), window, &root, &parent, &children,
+ &num_children)) {
+ LOG(LS_ERROR) << "Failed to query for child windows although window"
+ << "does not have a valid WM_STATE.";
+ return 0;
+ }
+ ::Window app_window = 0;
+ for (unsigned int i = 0; i < num_children; ++i) {
+ app_window = GetApplicationWindow(cache, children[i]);
+ if (app_window)
+ break;
+ }
+
+ if (children)
+ XFree(children);
+ return app_window;
+}
+
+// Returns true if the |window| is a desktop element.
+bool IsDesktopElement(XAtomCache* cache, ::Window window) {
+ RTC_DCHECK(cache);
+ if (window == 0)
+ return false;
+
+ // First look for _NET_WM_WINDOW_TYPE. The standard
+ // (http://standards.freedesktop.org/wm-spec/latest/ar01s05.html#id2760306)
+ // says this hint *should* be present on all windows, and we use the existence
+ // of _NET_WM_WINDOW_TYPE_NORMAL in the property to indicate a window is not
+ // a desktop element (that is, only "normal" windows should be shareable).
+ XWindowProperty<uint32_t> window_type(
+ cache->display(), window, cache->WindowType());
+ if (window_type.is_valid() && window_type.size() > 0) {
+ uint32_t* end = window_type.data() + window_type.size();
+ bool is_normal = (end != std::find(
+ window_type.data(),
+ end,
+ cache->WindowTypeNormal()));
+ return !is_normal;
+ }
+
+ // Fall back on using the hint.
+ XClassHint class_hint;
+ Status status = XGetClassHint(cache->display(), window, &class_hint);
+ if (status == 0) {
+ // No hints, assume this is a normal application window.
+ return false;
+ }
+
+ DeferXFree free_res_name(class_hint.res_name);
+ DeferXFree free_res_class(class_hint.res_class);
+ return strcmp("gnome-panel", class_hint.res_name) == 0 ||
+ strcmp("desktop_window", class_hint.res_name) == 0;
+}
+
+} // namespace
+
+int32_t GetWindowState(XAtomCache* cache, ::Window window) {
+ // Get WM_STATE property of the window.
+ XWindowProperty<uint32_t> window_state(
+ cache->display(), window, cache->WmState());
+
+ // WM_STATE is considered to be set to WithdrawnState when it missing.
+ return window_state.is_valid() ? *window_state.data() : WithdrawnState;
+}
+
+bool GetWindowList(XAtomCache* cache,
+ rtc::FunctionView<bool(::Window)> on_window) {
+ RTC_DCHECK(cache);
+ RTC_DCHECK(on_window);
+ ::Display* const display = cache->display();
+ XErrorTrap error_trap(display);
+
+ int failed_screens = 0;
+ const int num_screens = XScreenCount(display);
+ for (int screen = 0; screen < num_screens; screen++) {
+ ::Window root_window = XRootWindow(display, screen);
+ ::Window parent;
+ ::Window* children;
+ unsigned int num_children;
+ if (XQueryTree(display,
+ root_window,
+ &root_window,
+ &parent,
+ &children,
+ &num_children) == 0) {
+ failed_screens++;
+ LOG(LS_ERROR) << "Failed to query for child windows for screen "
+ << screen;
+ continue;
+ }
+
+ DeferXFree free_children(children);
+
+ for (unsigned int i = 0; i < num_children; i++) {
+ // Iterates in reverse order to return windows from front to back.
+ ::Window app_window =
+ GetApplicationWindow(cache, children[num_children - 1 - i]);
+ if (app_window && !IsDesktopElement(cache, app_window)) {
+ if (!on_window(app_window)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return failed_screens < num_screens;
+}
+
+} // namespace webrtc
diff --git a/modules/desktop_capture/x11/window_list_utils.h b/modules/desktop_capture/x11/window_list_utils.h
new file mode 100644
index 0000000..8a64594
--- /dev/null
+++ b/modules/desktop_capture/x11/window_list_utils.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_X11_WINDOW_LIST_UTILS_H_
+#define WEBRTC_MODULES_DESKTOP_CAPTURE_X11_WINDOW_LIST_UTILS_H_
+
+#include <X11/Xlib.h>
+
+#include "webrtc/modules/desktop_capture/x11/x_atom_cache.h"
+#include "webrtc/rtc_base/function_view.h"
+
+namespace webrtc {
+
+// Synchronously iterates all on-screen windows in |cache|.display() in
+// decreasing z-order and sends them one-by-one to |on_window| function before
+// GetWindowList() returns. If |on_window| returns false, this function ignores
+// other windows and returns immediately. GetWindowList() returns false if
+// native APIs failed. If multiple screens are attached to the |display|, this
+// function returns false only when native APIs failed on all screens. Menus,
+// panels and minimized windows will be ignored.
+bool GetWindowList(XAtomCache* cache,
+ rtc::FunctionView<bool(::Window)> on_window);
+
+// Returns WM_STATE property of the |window|. This function returns
+// WithdrawnState if the |window| is missing.
+int32_t GetWindowState(XAtomCache* cache, ::Window window);
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_X11_WINDOW_LIST_UTILS_H_
diff --git a/modules/desktop_capture/x11/x_atom_cache.cc b/modules/desktop_capture/x11/x_atom_cache.cc
new file mode 100644
index 0000000..161c8e9
--- /dev/null
+++ b/modules/desktop_capture/x11/x_atom_cache.cc
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/desktop_capture/x11/x_atom_cache.h"
+
+#include "webrtc/rtc_base/checks.h"
+
+namespace webrtc {
+
+XAtomCache::XAtomCache(::Display* display) : display_(display) {
+ RTC_DCHECK(display_);
+}
+
+XAtomCache::~XAtomCache() = default;
+
+::Display* XAtomCache::display() const {
+ return display_;
+}
+
+Atom XAtomCache::WmState() {
+ return CreateIfNotExist(&wm_state_, "WM_STATE");
+}
+
+Atom XAtomCache::WindowType() {
+ return CreateIfNotExist(&window_type_, "_NET_WM_WINDOW_TYPE");
+}
+
+Atom XAtomCache::WindowTypeNormal() {
+ return CreateIfNotExist(&window_type_normal_, "_NET_WM_WINDOW_TYPE_NORMAL");
+}
+
+Atom XAtomCache::CreateIfNotExist(Atom* atom, const char* name) {
+ RTC_DCHECK(atom);
+ if (*atom == None) {
+ *atom = XInternAtom(display(), name, True);
+ }
+ return *atom;
+}
+
+} // namespace webrtc
diff --git a/modules/desktop_capture/x11/x_atom_cache.h b/modules/desktop_capture/x11/x_atom_cache.h
new file mode 100644
index 0000000..8ccf2cb
--- /dev/null
+++ b/modules/desktop_capture/x11/x_atom_cache.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_X11_X_ATOM_CACHE_H_
+#define WEBRTC_MODULES_DESKTOP_CAPTURE_X11_X_ATOM_CACHE_H_
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+namespace webrtc {
+
+// A cache of Atom. Each Atom object is created on demand.
+class XAtomCache final {
+ public:
+ explicit XAtomCache(::Display* display);
+ ~XAtomCache();
+
+ ::Display* display() const;
+
+ Atom WmState();
+ Atom WindowType();
+ Atom WindowTypeNormal();
+
+ private:
+ // If |*atom| is None, this function uses XInternAtom() to retrieve an Atom.
+ Atom CreateIfNotExist(Atom* atom, const char* name);
+
+ ::Display* const display_;
+ Atom wm_state_ = None;
+ Atom window_type_ = None;
+ Atom window_type_normal_ = None;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_X11_X_ATOM_CACHE_H_