1f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org/* 2f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org * Copyright 2010 The WebRTC Project Authors. All rights reserved. 3f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org * 4f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org * Use of this source code is governed by a BSD-style license 5f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org * that can be found in the LICENSE file in the root of the source 6f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org * tree. An additional intellectual property rights grant can be found 7f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org * in the file PATENTS. All contributing project authors may 8f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org * be found in the AUTHORS file in the root of the source tree. 9f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org */ 10f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 11fb1eb43377404ef29c41adff69e0f2ba77df8d63henrike@webrtc.org#include "webrtc/base/x11windowpicker.h" 12f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 13f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <math.h> 14f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <string.h> 15f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 16f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <algorithm> 17f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <string> 18f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 19f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <X11/Xatom.h> 20f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <X11/extensions/Xcomposite.h> 21f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <X11/extensions/Xrender.h> 22f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include <X11/Xutil.h> 23f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 24f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#include "webrtc/base/logging.h" 25f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 26f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgnamespace rtc { 27f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 28f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org// Convenience wrapper for XGetWindowProperty results. 29f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgtemplate <class PropertyType> 30f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgclass XWindowProperty { 31f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org public: 32f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XWindowProperty(Display* display, Window window, Atom property) 33f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org : data_(NULL) { 34f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org const int kBitsPerByte = 8; 35f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Atom actual_type; 36f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int actual_format; 37f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned long bytes_after; // NOLINT: type required by XGetWindowProperty 38f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int status = XGetWindowProperty(display, window, property, 0L, ~0L, False, 39f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org AnyPropertyType, &actual_type, 40f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org &actual_format, &size_, 41f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org &bytes_after, &data_); 42f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org succeeded_ = (status == Success); 43f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!succeeded_) { 44f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org data_ = NULL; // Ensure nothing is freed. 45f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } else if (sizeof(PropertyType) * kBitsPerByte != actual_format) { 46f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_WARNING) << "Returned type size differs from " 47f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org "requested type size."; 48f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org succeeded_ = false; 49f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // We still need to call XFree in this case, so leave data_ alone. 50f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 51f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!succeeded_) { 52f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org size_ = 0; 53f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 54f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 55f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 56f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org ~XWindowProperty() { 57f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (data_) { 58f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFree(data_); 59f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 60f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 61f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 62f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool succeeded() const { return succeeded_; } 63f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org size_t size() const { return size_; } 64f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org const PropertyType* data() const { 65f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return reinterpret_cast<PropertyType*>(data_); 66f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 67f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org PropertyType* data() { 68f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return reinterpret_cast<PropertyType*>(data_); 69f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 70f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 71f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org private: 72f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool succeeded_; 73f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned long size_; // NOLINT: type required by XGetWindowProperty 74f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned char* data_; 75f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 763c089d751ede283e21e186885eaf705c3257ccd2henrikg RTC_DISALLOW_COPY_AND_ASSIGN(XWindowProperty); 77f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}; 78f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 79f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org// Stupid X11. It seems none of the synchronous returns codes from X11 calls 80f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org// are meaningful unless an asynchronous error handler is configured. This 81f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org// RAII class registers and unregisters an X11 error handler. 82f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgclass XErrorSuppressor { 83f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org public: 84f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org explicit XErrorSuppressor(Display* display) 85f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org : display_(display), original_error_handler_(NULL) { 86f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org SuppressX11Errors(); 87f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 88f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org ~XErrorSuppressor() { 89f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org UnsuppressX11Errors(); 90f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 91f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 92f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org private: 93f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org static int ErrorHandler(Display* display, XErrorEvent* e) { 94f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org char buf[256]; 95f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XGetErrorText(display, e->error_code, buf, sizeof buf); 96f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_WARNING) << "Received X11 error \"" << buf << "\" for request code " 97f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org << static_cast<unsigned int>(e->request_code); 98f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return 0; 99f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 100f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 101f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org void SuppressX11Errors() { 102f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFlush(display_); 103f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XSync(display_, False); 104f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org original_error_handler_ = XSetErrorHandler(&ErrorHandler); 105f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 106f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 107f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org void UnsuppressX11Errors() { 108f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFlush(display_); 109f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XSync(display_, False); 110f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XErrorHandler handler = XSetErrorHandler(original_error_handler_); 111f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (handler != &ErrorHandler) { 112f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_WARNING) << "Unbalanced XSetErrorHandler() calls detected. " 113f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org << "Final error handler may not be what you expect!"; 114f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 115f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org original_error_handler_ = NULL; 116f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 117f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 118f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Display* display_; 119f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XErrorHandler original_error_handler_; 120f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 1213c089d751ede283e21e186885eaf705c3257ccd2henrikg RTC_DISALLOW_COPY_AND_ASSIGN(XErrorSuppressor); 122f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}; 123f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 124f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org// Hiding all X11 specifics inside its own class. This to avoid 125f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org// conflicts between talk and X11 header declarations. 126f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.orgclass XWindowEnumerator { 127f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org public: 128f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XWindowEnumerator() 129f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org : display_(NULL), 130f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org has_composite_extension_(false), 131f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org has_render_extension_(false) { 132f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 133f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 134f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org ~XWindowEnumerator() { 135f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (display_ != NULL) { 136f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XCloseDisplay(display_); 137f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 138f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 139f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 140f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool Init() { 141f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (display_ != NULL) { 142f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Already initialized. 143f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return true; 144f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 145f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org display_ = XOpenDisplay(NULL); 146f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (display_ == NULL) { 147f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "Failed to open display."; 148f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return false; 149f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 150f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 151f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 152f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 153f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org wm_state_ = XInternAtom(display_, "WM_STATE", True); 154f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org net_wm_icon_ = XInternAtom(display_, "_NET_WM_ICON", False); 155f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 156f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int event_base, error_base, major_version, minor_version; 157f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (XCompositeQueryExtension(display_, &event_base, &error_base) && 158f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XCompositeQueryVersion(display_, &major_version, &minor_version) && 159f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // XCompositeNameWindowPixmap() requires version 0.2 160f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org (major_version > 0 || minor_version >= 2)) { 161f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org has_composite_extension_ = true; 162f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } else { 163f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_INFO) << "Xcomposite extension not available or too old."; 164f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 165f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 166f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (XRenderQueryExtension(display_, &event_base, &error_base) && 167f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XRenderQueryVersion(display_, &major_version, &minor_version) && 168f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // XRenderSetPictureTransform() requires version 0.6 169f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org (major_version > 0 || minor_version >= 6)) { 170f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org has_render_extension_ = true; 171f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } else { 172f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_INFO) << "Xrender extension not available or too old."; 173f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 174f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return true; 175f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 176f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 177f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool EnumerateWindows(WindowDescriptionList* descriptions) { 178f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!Init()) { 179f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return false; 180f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 181f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 182f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int num_screens = XScreenCount(display_); 183f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool result = false; 184f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org for (int i = 0; i < num_screens; ++i) { 185f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (EnumerateScreenWindows(descriptions, i)) { 186f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // We know we succeded on at least one screen. 187f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org result = true; 188f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 189f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 190f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return result; 191f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 192f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 193f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool EnumerateDesktops(DesktopDescriptionList* descriptions) { 194f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!Init()) { 195f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return false; 196f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 197f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 198f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window default_root_window = XDefaultRootWindow(display_); 199f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int num_screens = XScreenCount(display_); 200f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org for (int i = 0; i < num_screens; ++i) { 201f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window root_window = XRootWindow(display_, i); 202f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org DesktopId id(DesktopId(root_window, i)); 203f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // TODO: Figure out an appropriate desktop title. 204f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org DesktopDescription desc(id, ""); 205f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org desc.set_primary(root_window == default_root_window); 206f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org descriptions->push_back(desc); 207f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 208f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return num_screens > 0; 209f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 210f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 211f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool IsVisible(const WindowId& id) { 212f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!Init()) { 213f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return false; 214f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 215f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 216f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XWindowAttributes attr; 217f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!XGetWindowAttributes(display_, id.id(), &attr)) { 218f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "XGetWindowAttributes() failed"; 219f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return false; 220f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 221f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return attr.map_state == IsViewable; 222f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 223f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 224f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool MoveToFront(const WindowId& id) { 225f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!Init()) { 226f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return false; 227f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 228f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 229f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned int num_children; 230f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window* children; 231f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window parent; 232f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window root; 233f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 234f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Find root window to pass event to. 235f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int status = XQueryTree(display_, id.id(), &root, &parent, &children, 236f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org &num_children); 237f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (status == 0) { 238f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_WARNING) << "Failed to query for child windows."; 239f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return false; 240f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 241f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (children != NULL) { 242f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFree(children); 243f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 244f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 245f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Move the window to front. 246f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XRaiseWindow(display_, id.id()); 247f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 248f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Some window managers (e.g., metacity in GNOME) consider it illegal to 249f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // raise a window without also giving it input focus with 250f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // _NET_ACTIVE_WINDOW, so XRaiseWindow() on its own isn't enough. 251f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Atom atom = XInternAtom(display_, "_NET_ACTIVE_WINDOW", True); 252f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (atom != None) { 253f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XEvent xev; 254f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org long event_mask; 255f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 256f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org xev.xclient.type = ClientMessage; 257f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org xev.xclient.serial = 0; 258f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org xev.xclient.send_event = True; 259f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org xev.xclient.window = id.id(); 260f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org xev.xclient.message_type = atom; 261f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 262f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // The format member is set to 8, 16, or 32 and specifies whether the 263f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // data should be viewed as a list of bytes, shorts, or longs. 264f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org xev.xclient.format = 32; 265f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 266f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org xev.xclient.data.l[0] = 0; 267f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org xev.xclient.data.l[1] = 0; 268f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org xev.xclient.data.l[2] = 0; 269f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org xev.xclient.data.l[3] = 0; 270f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org xev.xclient.data.l[4] = 0; 271f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 272f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org event_mask = SubstructureRedirectMask | SubstructureNotifyMask; 273f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 274f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XSendEvent(display_, root, False, event_mask, &xev); 275f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 276f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFlush(display_); 277f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return true; 278f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 279f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 2800c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström uint8_t* GetWindowIcon(const WindowId& id, int* width, int* height) { 281f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!Init()) { 282f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 283f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 284f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 285f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Atom ret_type; 286f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int format; 287f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned long length, bytes_after, size; 288f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned char* data = NULL; 289f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 290f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Find out the size of the icon data. 291f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (XGetWindowProperty( 292f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org display_, id.id(), net_wm_icon_, 0, 0, False, XA_CARDINAL, 293f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org &ret_type, &format, &length, &size, &data) == Success && 294f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org data) { 295f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFree(data); 296f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } else { 297f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "Failed to get size of the icon."; 298f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 299f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 3000c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström // Get the icon data, the format is one uint32_t each for width and height, 301f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // followed by the actual pixel data. 302f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (size >= 2 && 303f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XGetWindowProperty( 304f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org display_, id.id(), net_wm_icon_, 0, size, False, XA_CARDINAL, 305f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org &ret_type, &format, &length, &bytes_after, &data) == Success && 306f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org data) { 3070c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström uint32_t* data_ptr = reinterpret_cast<uint32_t*>(data); 308f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int w, h; 309f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org w = data_ptr[0]; 310f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org h = data_ptr[1]; 311f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (size < static_cast<unsigned long>(w * h + 2)) { 312f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFree(data); 313f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "Not a vaild icon."; 314f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 315f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 3160c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström uint8_t* rgba = ArgbToRgba(&data_ptr[2], 0, 0, w, h, w, h, true); 317f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFree(data); 318f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *width = w; 319f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *height = h; 320f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return rgba; 321f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } else { 322f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "Failed to get window icon data."; 323f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 324f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 325f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 326f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 3270c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström uint8_t* GetWindowThumbnail(const WindowId& id, int width, int height) { 328f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!Init()) { 329f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 330f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 331f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 332f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!has_composite_extension_) { 333f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Without the Xcomposite extension we would only get a good thumbnail if 334f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // the whole window is visible on screen and not covered by any 335f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // other window. This is not something we want so instead, just 336f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // bail out. 337f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_INFO) << "No Xcomposite extension detected."; 338f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 339f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 340f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 341f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 342f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window root; 343f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int x; 344f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int y; 345f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned int src_width; 346f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned int src_height; 347f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned int border_width; 348f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned int depth; 349f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 350f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // In addition to needing X11 server-side support for Xcomposite, it 351f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // actually needs to be turned on for this window in order to get a good 352f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // thumbnail. If the user has modern hardware/drivers but isn't using a 353f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // compositing window manager, that won't be the case. Here we 354f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // automatically turn it on for shareable windows so that we can get 355f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // thumbnails. We used to avoid it because the transition is visually ugly, 356f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // but recent window managers don't always redirect windows which led to 357f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // no thumbnails at all, which is a worse experience. 358f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 359f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Redirect drawing to an offscreen buffer (ie, turn on compositing). 360f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // X11 remembers what has requested this and will turn it off for us when 361f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // we exit. 362f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XCompositeRedirectWindow(display_, id.id(), CompositeRedirectAutomatic); 363f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Pixmap src_pixmap = XCompositeNameWindowPixmap(display_, id.id()); 364f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!src_pixmap) { 365f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Even if the backing pixmap doesn't exist, this still should have 366f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // succeeded and returned a valid handle (it just wouldn't be a handle to 367f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // anything). So this is a real error path. 368f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "XCompositeNameWindowPixmap() failed"; 369f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 370f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 371f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!XGetGeometry(display_, src_pixmap, &root, &x, &y, 372f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org &src_width, &src_height, &border_width, 373f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org &depth)) { 374f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // If the window does not actually have a backing pixmap, this is the path 375f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // that will "fail", so it's a warning rather than an error. 376f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_WARNING) << "XGetGeometry() failed (probably composite is not in " 377f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org << "use)"; 378f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFreePixmap(display_, src_pixmap); 379f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 380f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 381f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 382f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // If we get to here, then composite is in use for this window and it has a 383f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // valid backing pixmap. 384f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 385f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XWindowAttributes attr; 386f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!XGetWindowAttributes(display_, id.id(), &attr)) { 387f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "XGetWindowAttributes() failed"; 388f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFreePixmap(display_, src_pixmap); 389f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 390f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 391f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 3920c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström uint8_t* data = GetDrawableThumbnail(src_pixmap, attr.visual, src_width, 3930c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström src_height, width, height); 394f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFreePixmap(display_, src_pixmap); 395f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return data; 396f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 397f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 398f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int GetNumDesktops() { 399f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!Init()) { 400f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return -1; 401f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 402f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 403f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return XScreenCount(display_); 404f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 405f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 4060c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström uint8_t* GetDesktopThumbnail(const DesktopId& id, int width, int height) { 407f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!Init()) { 408f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 409f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 410f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 411f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 412f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window root_window = id.id(); 413f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XWindowAttributes attr; 414f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!XGetWindowAttributes(display_, root_window, &attr)) { 415f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "XGetWindowAttributes() failed"; 416f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 417f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 418f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 419f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return GetDrawableThumbnail(root_window, 420f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org attr.visual, 421f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org attr.width, 422f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org attr.height, 423f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org width, 424f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org height); 425f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 426f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 427f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool GetDesktopDimensions(const DesktopId& id, int* width, int* height) { 428f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!Init()) { 429f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return false; 430f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 431f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 432f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XWindowAttributes attr; 433f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!XGetWindowAttributes(display_, id.id(), &attr)) { 434f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "XGetWindowAttributes() failed"; 435f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return false; 436f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 437f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *width = attr.width; 438f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *height = attr.height; 439f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return true; 440f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 441f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 442f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org private: 4430c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström uint8_t* GetDrawableThumbnail(Drawable src_drawable, 4440c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström Visual* visual, 4450c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström int src_width, 4460c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström int src_height, 4470c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström int dst_width, 4480c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström int dst_height) { 449f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!has_render_extension_) { 450f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Without the Xrender extension we would have to read the full window and 451f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // scale it down in our process. Xrender is over a decade old so we aren't 452f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // going to expend effort to support that situation. We still need to 453f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // check though because probably some virtual VNC displays are in this 454f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // category. 455f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_INFO) << "No Xrender extension detected."; 456f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 457f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 458f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 459f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XRenderPictFormat* format = XRenderFindVisualFormat(display_, 460f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org visual); 461f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!format) { 462f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "XRenderFindVisualFormat() failed"; 463f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 464f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 465f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 466f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Create a picture to reference the window pixmap. 467f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XRenderPictureAttributes pa; 468f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org pa.subwindow_mode = IncludeInferiors; // Don't clip child widgets 469f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Picture src = XRenderCreatePicture(display_, 470f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org src_drawable, 471f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org format, 472f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org CPSubwindowMode, 473f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org &pa); 474f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!src) { 475f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "XRenderCreatePicture() failed"; 476f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 477f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 478f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 479f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Create a picture to reference the destination pixmap. 480f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Pixmap dst_pixmap = XCreatePixmap(display_, 481f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org src_drawable, 482f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org dst_width, 483f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org dst_height, 484f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org format->depth); 485f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!dst_pixmap) { 486f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "XCreatePixmap() failed"; 487f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XRenderFreePicture(display_, src); 488f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 489f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 490f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 491f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Picture dst = XRenderCreatePicture(display_, dst_pixmap, format, 0, NULL); 492f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!dst) { 493f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "XRenderCreatePicture() failed"; 494f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFreePixmap(display_, dst_pixmap); 495f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XRenderFreePicture(display_, src); 496f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return NULL; 497f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 498f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 499f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Clear the background. 500f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XRenderColor transparent = {0}; 501f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XRenderFillRectangle(display_, 502f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org PictOpSrc, 503f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org dst, 504f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org &transparent, 505f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 0, 506f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 0, 507f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org dst_width, 508f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org dst_height); 509f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 510f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Calculate how much we need to scale the image. 511f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org double scale_x = static_cast<double>(dst_width) / 512f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org static_cast<double>(src_width); 513f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org double scale_y = static_cast<double>(dst_height) / 514f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org static_cast<double>(src_height); 515ff689be3c0c59c1be29aaa0697aa0f762566d6c6andresp@webrtc.org double scale = std::min(scale_y, scale_x); 516f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 517f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int scaled_width = round(src_width * scale); 518f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int scaled_height = round(src_height * scale); 519f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 520f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Render the thumbnail centered on both axis. 521f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int centered_x = (dst_width - scaled_width) / 2; 522f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int centered_y = (dst_height - scaled_height) / 2; 523f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 524f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Scaling matrix 525f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XTransform xform = { { 526f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org { XDoubleToFixed(1), XDoubleToFixed(0), XDoubleToFixed(0) }, 527f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org { XDoubleToFixed(0), XDoubleToFixed(1), XDoubleToFixed(0) }, 528f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(scale) } 529f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } }; 530f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XRenderSetPictureTransform(display_, src, &xform); 531f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 532f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Apply filter to smooth out the image. 533f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XRenderSetPictureFilter(display_, src, FilterBest, NULL, 0); 534f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 535f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Render the image to the destination picture. 536f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XRenderComposite(display_, 537f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org PictOpSrc, 538f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org src, 539f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org None, 540f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org dst, 541f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 0, 542f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 0, 543f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 0, 544f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 0, 545f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org centered_x, 546f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org centered_y, 547f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org scaled_width, 548f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org scaled_height); 549f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 550f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Get the pixel data from the X server. TODO: XGetImage 551f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // might be slow here, compare with ShmGetImage. 552f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XImage* image = XGetImage(display_, 553f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org dst_pixmap, 554f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 0, 555f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 0, 556f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org dst_width, 557f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org dst_height, 558f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org AllPlanes, ZPixmap); 5590c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström uint8_t* data = ArgbToRgba(reinterpret_cast<uint32_t*>(image->data), 5600c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström centered_x, centered_y, scaled_width, 5610c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström scaled_height, dst_width, dst_height, false); 562f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XDestroyImage(image); 563f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XRenderFreePicture(display_, dst); 564f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFreePixmap(display_, dst_pixmap); 565f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XRenderFreePicture(display_, src); 566f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return data; 567f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 568f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 5690c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström uint8_t* ArgbToRgba(uint32_t* argb_data, 5700c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström int x, 5710c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström int y, 5720c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström int w, 5730c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström int h, 5740c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström int stride_x, 5750c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström int stride_y, 5760c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström bool has_alpha) { 5770c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström uint8_t* p; 578f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int len = stride_x * stride_y * 4; 5790c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström uint8_t* data = new uint8_t[len]; 580f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org memset(data, 0, len); 581f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org p = data + 4 * (y * stride_x + x); 582f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org for (int i = 0; i < h; ++i) { 583f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org for (int j = 0; j < w; ++j) { 5840c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström uint32_t argb; 5850c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström uint32_t rgba; 586f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org argb = argb_data[stride_x * (y + i) + x + j]; 587f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org rgba = (argb << 8) | (argb >> 24); 588f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *p = rgba >> 24; 589f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org ++p; 590f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *p = (rgba >> 16) & 0xff; 591f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org ++p; 592f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *p = (rgba >> 8) & 0xff; 593f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org ++p; 594f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *p = has_alpha ? rgba & 0xFF : 0xFF; 595f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org ++p; 596f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 597f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org p += (stride_x - w) * 4; 598f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 599f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return data; 600f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 601f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 602f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool EnumerateScreenWindows(WindowDescriptionList* descriptions, int screen) { 603f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window parent; 604f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window *children; 605f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int status; 606f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned int num_children; 607f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window root_window = XRootWindow(display_, screen); 608f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org status = XQueryTree(display_, root_window, &root_window, &parent, &children, 609f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org &num_children); 610f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (status == 0) { 611f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "Failed to query for child windows."; 612f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return false; 613f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 614f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org for (unsigned int i = 0; i < num_children; ++i) { 615f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Iterate in reverse order to display windows from front to back. 616f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#ifdef CHROMEOS 617f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // TODO(jhorwich): Short-term fix for crbug.com/120229: Don't need to 618f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // filter, just return all windows and let the picker scan through them. 619f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window app_window = children[num_children - 1 - i]; 620f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#else 621f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window app_window = GetApplicationWindow(children[num_children - 1 - i]); 622f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org#endif 623f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (app_window && 624fb1eb43377404ef29c41adff69e0f2ba77df8d63henrike@webrtc.org !X11WindowPicker::IsDesktopElement(display_, app_window)) { 625f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org std::string title; 626f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (GetWindowTitle(app_window, &title)) { 627f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org WindowId id(app_window); 628f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org WindowDescription desc(id, title); 629f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org descriptions->push_back(desc); 630f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 631f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 632f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 633f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (children != NULL) { 634f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFree(children); 635f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 636f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return true; 637f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 638f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 639f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool GetWindowTitle(Window window, std::string* title) { 640f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int status; 641f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool result = false; 642f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XTextProperty window_name; 643f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org window_name.value = NULL; 644f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (window) { 645f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org status = XGetWMName(display_, window, &window_name); 646f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (status && window_name.value && window_name.nitems) { 647f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int cnt; 648f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org char **list = NULL; 649f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org status = Xutf8TextPropertyToTextList(display_, &window_name, &list, 650f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org &cnt); 651f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (status >= Success && cnt && *list) { 652f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (cnt > 1) { 653f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_INFO) << "Window has " << cnt 654f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org << " text properties, only using the first one."; 655f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 656f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org *title = *list; 657f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org result = true; 658f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 659f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (list != NULL) { 660f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFreeStringList(list); 661f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 662f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 663f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (window_name.value != NULL) { 664f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFree(window_name.value); 665f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 666f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 667f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return result; 668f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 669f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 670f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window GetApplicationWindow(Window window) { 671f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window root, parent; 672f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window app_window = 0; 673f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Window *children; 674f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned int num_children; 675f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Atom type = None; 676f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int format; 677f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned long nitems, after; 678f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org unsigned char *data; 679f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 680f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int ret = XGetWindowProperty(display_, window, 681f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org wm_state_, 0L, 2, 682f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org False, wm_state_, &type, &format, 683f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org &nitems, &after, &data); 684f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (ret != Success) { 685f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "XGetWindowProperty failed with return code " << ret 686f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org << " for window " << window << "."; 687f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return 0; 688f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 689f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (type != None) { 6900c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström int64_t state = static_cast<int64_t>(*data); 691f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFree(data); 692f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return state == NormalState ? window : 0; 693f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 694f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFree(data); 695f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (!XQueryTree(display_, window, &root, &parent, &children, 696f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org &num_children)) { 697f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_ERROR) << "Failed to query for child windows although window" 698f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org << "does not have a valid WM_STATE."; 699f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return 0; 700f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 701f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org for (unsigned int i = 0; i < num_children; ++i) { 702f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org app_window = GetApplicationWindow(children[i]); 703f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (app_window) { 704f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org break; 705f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 706f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 707f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (children != NULL) { 708f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFree(children); 709f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 710f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return app_window; 711f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 712f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 713f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Atom wm_state_; 714f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Atom net_wm_icon_; 715f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Display* display_; 716f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool has_composite_extension_; 717f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool has_render_extension_; 718f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org}; 719f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 720fb1eb43377404ef29c41adff69e0f2ba77df8d63henrike@webrtc.orgX11WindowPicker::X11WindowPicker() : enumerator_(new XWindowEnumerator()) { 721f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} 722f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 723fb1eb43377404ef29c41adff69e0f2ba77df8d63henrike@webrtc.orgX11WindowPicker::~X11WindowPicker() { 724f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} 725f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 726fb1eb43377404ef29c41adff69e0f2ba77df8d63henrike@webrtc.orgbool X11WindowPicker::IsDesktopElement(_XDisplay* display, Window window) { 727f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (window == 0) { 728f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org LOG(LS_WARNING) << "Zero is never a valid window."; 729f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return false; 730f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 731f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 732f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // First look for _NET_WM_WINDOW_TYPE. The standard 733f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // (http://standards.freedesktop.org/wm-spec/latest/ar01s05.html#id2760306) 734f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // says this hint *should* be present on all windows, and we use the existence 735f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // of _NET_WM_WINDOW_TYPE_NORMAL in the property to indicate a window is not 736f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // a desktop element (that is, only "normal" windows should be shareable). 737f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Atom window_type_atom = XInternAtom(display, "_NET_WM_WINDOW_TYPE", True); 738f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XWindowProperty<uint32_t> window_type(display, window, window_type_atom); 739f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (window_type.succeeded() && window_type.size() > 0) { 740f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Atom normal_window_type_atom = XInternAtom( 741f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org display, "_NET_WM_WINDOW_TYPE_NORMAL", True); 742f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org uint32_t* end = window_type.data() + window_type.size(); 743f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool is_normal = (end != std::find( 744f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org window_type.data(), end, normal_window_type_atom)); 745f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return !is_normal; 746f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 747f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 748f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // Fall back on using the hint. 749f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XClassHint class_hint; 750f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org Status s = XGetClassHint(display, window, &class_hint); 751f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org bool result = false; 752f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (s == 0) { 753f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org // No hints, assume this is a normal application window. 754f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return result; 755f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 756f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org static const std::string gnome_panel("gnome-panel"); 757f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org static const std::string desktop_window("desktop_window"); 758f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 759f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org if (gnome_panel.compare(class_hint.res_name) == 0 || 760f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org desktop_window.compare(class_hint.res_name) == 0) { 761f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org result = true; 762f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org } 763f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFree(class_hint.res_name); 764f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org XFree(class_hint.res_class); 765f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return result; 766f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} 767f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 768fb1eb43377404ef29c41adff69e0f2ba77df8d63henrike@webrtc.orgbool X11WindowPicker::Init() { 769f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return enumerator_->Init(); 770f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} 771f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 772fb1eb43377404ef29c41adff69e0f2ba77df8d63henrike@webrtc.orgbool X11WindowPicker::GetWindowList(WindowDescriptionList* descriptions) { 773f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return enumerator_->EnumerateWindows(descriptions); 774f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} 775f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 776fb1eb43377404ef29c41adff69e0f2ba77df8d63henrike@webrtc.orgbool X11WindowPicker::GetDesktopList(DesktopDescriptionList* descriptions) { 777f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return enumerator_->EnumerateDesktops(descriptions); 778f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} 779f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 780fb1eb43377404ef29c41adff69e0f2ba77df8d63henrike@webrtc.orgbool X11WindowPicker::IsVisible(const WindowId& id) { 781f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return enumerator_->IsVisible(id); 782f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} 783f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 784fb1eb43377404ef29c41adff69e0f2ba77df8d63henrike@webrtc.orgbool X11WindowPicker::MoveToFront(const WindowId& id) { 785f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return enumerator_->MoveToFront(id); 786f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} 787f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 7880c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boströmuint8_t* X11WindowPicker::GetWindowIcon(const WindowId& id, 7890c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström int* width, 790f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int* height) { 791f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return enumerator_->GetWindowIcon(id, width, height); 792f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} 793f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 7940c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boströmuint8_t* X11WindowPicker::GetWindowThumbnail(const WindowId& id, 7950c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boström int width, 796f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int height) { 797f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return enumerator_->GetWindowThumbnail(id, width, height); 798f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} 799f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 800fb1eb43377404ef29c41adff69e0f2ba77df8d63henrike@webrtc.orgint X11WindowPicker::GetNumDesktops() { 801f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return enumerator_->GetNumDesktops(); 802f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} 803f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 8040c4e06b4c6107a1b94f764e279e4fb4161e905b0Peter Boströmuint8_t* X11WindowPicker::GetDesktopThumbnail(const DesktopId& id, 805f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int width, 806f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int height) { 807f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return enumerator_->GetDesktopThumbnail(id, width, height); 808f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} 809f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 810fb1eb43377404ef29c41adff69e0f2ba77df8d63henrike@webrtc.orgbool X11WindowPicker::GetDesktopDimensions(const DesktopId& id, int* width, 811f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org int* height) { 812f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org return enumerator_->GetDesktopDimensions(id, width, height); 813f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} 814f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org 815f048872e915a3ee229044ec4bc541f6cbf9e4de1henrike@webrtc.org} // namespace rtc 816