147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/* 247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * Copyright 2010 The WebRTC Project Authors. All rights reserved. 347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * 447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * Use of this source code is governed by a BSD-style license 547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * that can be found in the LICENSE file in the root of the source 647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * tree. An additional intellectual property rights grant can be found 747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * in the file PATENTS. All contributing project authors may 847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org * be found in the AUTHORS file in the root of the source tree. 947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */ 1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 11cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.org#include "webrtc/base/x11windowpicker.h" 1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <math.h> 1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <string.h> 1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <algorithm> 1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <string> 1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <X11/Xatom.h> 2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <X11/extensions/Xcomposite.h> 2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <X11/extensions/Xrender.h> 2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <X11/Xutil.h> 2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/logging.h" 2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc { 2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Convenience wrapper for XGetWindowProperty results. 2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgtemplate <class PropertyType> 3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgclass XWindowProperty { 3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org public: 3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XWindowProperty(Display* display, Window window, Atom property) 3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org : data_(NULL) { 3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const int kBitsPerByte = 8; 3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Atom actual_type; 3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int actual_format; 3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned long bytes_after; // NOLINT: type required by XGetWindowProperty 3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int status = XGetWindowProperty(display, window, property, 0L, ~0L, False, 3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AnyPropertyType, &actual_type, 4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &actual_format, &size_, 4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &bytes_after, &data_); 4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org succeeded_ = (status == Success); 4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!succeeded_) { 4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org data_ = NULL; // Ensure nothing is freed. 4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } else if (sizeof(PropertyType) * kBitsPerByte != actual_format) { 4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_WARNING) << "Returned type size differs from " 4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org "requested type size."; 4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org succeeded_ = false; 4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // We still need to call XFree in this case, so leave data_ alone. 5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!succeeded_) { 5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org size_ = 0; 5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ~XWindowProperty() { 5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (data_) { 5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFree(data_); 5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool succeeded() const { return succeeded_; } 6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org size_t size() const { return size_; } 6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org const PropertyType* data() const { 6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return reinterpret_cast<PropertyType*>(data_); 6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org PropertyType* data() { 6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return reinterpret_cast<PropertyType*>(data_); 6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org private: 7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool succeeded_; 7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned long size_; // NOLINT: type required by XGetWindowProperty 7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned char* data_; 7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DISALLOW_COPY_AND_ASSIGN(XWindowProperty); 7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}; 7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Stupid X11. It seems none of the synchronous returns codes from X11 calls 8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// are meaningful unless an asynchronous error handler is configured. This 8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// RAII class registers and unregisters an X11 error handler. 8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgclass XErrorSuppressor { 8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org public: 8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org explicit XErrorSuppressor(Display* display) 8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org : display_(display), original_error_handler_(NULL) { 8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org SuppressX11Errors(); 8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ~XErrorSuppressor() { 8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org UnsuppressX11Errors(); 9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org private: 9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org static int ErrorHandler(Display* display, XErrorEvent* e) { 9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org char buf[256]; 9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XGetErrorText(display, e->error_code, buf, sizeof buf); 9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_WARNING) << "Received X11 error \"" << buf << "\" for request code " 9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << static_cast<unsigned int>(e->request_code); 9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return 0; 9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org void SuppressX11Errors() { 10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFlush(display_); 10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XSync(display_, False); 10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org original_error_handler_ = XSetErrorHandler(&ErrorHandler); 10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org void UnsuppressX11Errors() { 10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFlush(display_); 10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XSync(display_, False); 11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XErrorHandler handler = XSetErrorHandler(original_error_handler_); 11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (handler != &ErrorHandler) { 11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_WARNING) << "Unbalanced XSetErrorHandler() calls detected. " 11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << "Final error handler may not be what you expect!"; 11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org original_error_handler_ = NULL; 11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Display* display_; 11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XErrorHandler original_error_handler_; 12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 12147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DISALLOW_COPY_AND_ASSIGN(XErrorSuppressor); 12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}; 12347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Hiding all X11 specifics inside its own class. This to avoid 12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// conflicts between talk and X11 header declarations. 12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgclass XWindowEnumerator { 12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org public: 12847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XWindowEnumerator() 12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org : display_(NULL), 13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org has_composite_extension_(false), 13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org has_render_extension_(false) { 13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ~XWindowEnumerator() { 13547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (display_ != NULL) { 13647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XCloseDisplay(display_); 13747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool Init() { 14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (display_ != NULL) { 14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Already initialized. 14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return true; 14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org display_ = XOpenDisplay(NULL); 14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (display_ == NULL) { 14747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "Failed to open display."; 14847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 14947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 15047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 15147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 15247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 15347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org wm_state_ = XInternAtom(display_, "WM_STATE", True); 15447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org net_wm_icon_ = XInternAtom(display_, "_NET_WM_ICON", False); 15547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 15647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int event_base, error_base, major_version, minor_version; 15747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (XCompositeQueryExtension(display_, &event_base, &error_base) && 15847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XCompositeQueryVersion(display_, &major_version, &minor_version) && 15947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // XCompositeNameWindowPixmap() requires version 0.2 16047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org (major_version > 0 || minor_version >= 2)) { 16147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org has_composite_extension_ = true; 16247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } else { 16347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_INFO) << "Xcomposite extension not available or too old."; 16447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 16547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 16647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (XRenderQueryExtension(display_, &event_base, &error_base) && 16747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XRenderQueryVersion(display_, &major_version, &minor_version) && 16847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // XRenderSetPictureTransform() requires version 0.6 16947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org (major_version > 0 || minor_version >= 6)) { 17047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org has_render_extension_ = true; 17147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } else { 17247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_INFO) << "Xrender extension not available or too old."; 17347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 17447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return true; 17547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 17647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 17747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool EnumerateWindows(WindowDescriptionList* descriptions) { 17847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!Init()) { 17947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 18047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 18147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 18247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int num_screens = XScreenCount(display_); 18347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool result = false; 18447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org for (int i = 0; i < num_screens; ++i) { 18547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (EnumerateScreenWindows(descriptions, i)) { 18647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // We know we succeded on at least one screen. 18747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org result = true; 18847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 18947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 19047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return result; 19147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 19247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 19347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool EnumerateDesktops(DesktopDescriptionList* descriptions) { 19447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!Init()) { 19547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 19647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 19747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 19847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window default_root_window = XDefaultRootWindow(display_); 19947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int num_screens = XScreenCount(display_); 20047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org for (int i = 0; i < num_screens; ++i) { 20147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window root_window = XRootWindow(display_, i); 20247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DesktopId id(DesktopId(root_window, i)); 20347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // TODO: Figure out an appropriate desktop title. 20447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org DesktopDescription desc(id, ""); 20547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org desc.set_primary(root_window == default_root_window); 20647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org descriptions->push_back(desc); 20747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 20847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return num_screens > 0; 20947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 21047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 21147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool IsVisible(const WindowId& id) { 21247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!Init()) { 21347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 21447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 21547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 21647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XWindowAttributes attr; 21747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!XGetWindowAttributes(display_, id.id(), &attr)) { 21847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "XGetWindowAttributes() failed"; 21947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 22047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 22147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return attr.map_state == IsViewable; 22247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 22347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 22447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool MoveToFront(const WindowId& id) { 22547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!Init()) { 22647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 22747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 22847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 22947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned int num_children; 23047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window* children; 23147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window parent; 23247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window root; 23347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 23447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Find root window to pass event to. 23547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int status = XQueryTree(display_, id.id(), &root, &parent, &children, 23647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &num_children); 23747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (status == 0) { 23847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_WARNING) << "Failed to query for child windows."; 23947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 24047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 24147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (children != NULL) { 24247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFree(children); 24347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 24447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 24547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Move the window to front. 24647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XRaiseWindow(display_, id.id()); 24747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 24847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Some window managers (e.g., metacity in GNOME) consider it illegal to 24947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // raise a window without also giving it input focus with 25047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // _NET_ACTIVE_WINDOW, so XRaiseWindow() on its own isn't enough. 25147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Atom atom = XInternAtom(display_, "_NET_ACTIVE_WINDOW", True); 25247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (atom != None) { 25347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XEvent xev; 25447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org long event_mask; 25547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 25647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org xev.xclient.type = ClientMessage; 25747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org xev.xclient.serial = 0; 25847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org xev.xclient.send_event = True; 25947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org xev.xclient.window = id.id(); 26047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org xev.xclient.message_type = atom; 26147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 26247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // The format member is set to 8, 16, or 32 and specifies whether the 26347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // data should be viewed as a list of bytes, shorts, or longs. 26447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org xev.xclient.format = 32; 26547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 26647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org xev.xclient.data.l[0] = 0; 26747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org xev.xclient.data.l[1] = 0; 26847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org xev.xclient.data.l[2] = 0; 26947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org xev.xclient.data.l[3] = 0; 27047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org xev.xclient.data.l[4] = 0; 27147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 27247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org event_mask = SubstructureRedirectMask | SubstructureNotifyMask; 27347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 27447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XSendEvent(display_, root, False, event_mask, &xev); 27547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 27647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFlush(display_); 27747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return true; 27847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 27947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 28047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint8* GetWindowIcon(const WindowId& id, int* width, int* height) { 28147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!Init()) { 28247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 28347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 28447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 28547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Atom ret_type; 28647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int format; 28747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned long length, bytes_after, size; 28847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned char* data = NULL; 28947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 29047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Find out the size of the icon data. 29147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (XGetWindowProperty( 29247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org display_, id.id(), net_wm_icon_, 0, 0, False, XA_CARDINAL, 29347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &ret_type, &format, &length, &size, &data) == Success && 29447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org data) { 29547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFree(data); 29647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } else { 29747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "Failed to get size of the icon."; 29847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 29947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 30047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Get the icon data, the format is one uint32 each for width and height, 30147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // followed by the actual pixel data. 30247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (size >= 2 && 30347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XGetWindowProperty( 30447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org display_, id.id(), net_wm_icon_, 0, size, False, XA_CARDINAL, 30547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &ret_type, &format, &length, &bytes_after, &data) == Success && 30647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org data) { 30747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint32* data_ptr = reinterpret_cast<uint32*>(data); 30847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int w, h; 30947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org w = data_ptr[0]; 31047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org h = data_ptr[1]; 31147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (size < static_cast<unsigned long>(w * h + 2)) { 31247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFree(data); 31347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "Not a vaild icon."; 31447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 31547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 31647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint8* rgba = 31747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ArgbToRgba(&data_ptr[2], 0, 0, w, h, w, h, true); 31847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFree(data); 31947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *width = w; 32047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *height = h; 32147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return rgba; 32247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } else { 32347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "Failed to get window icon data."; 32447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 32547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 32647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 32747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 32847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint8* GetWindowThumbnail(const WindowId& id, int width, int height) { 32947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!Init()) { 33047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 33147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 33247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 33347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!has_composite_extension_) { 33447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Without the Xcomposite extension we would only get a good thumbnail if 33547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // the whole window is visible on screen and not covered by any 33647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // other window. This is not something we want so instead, just 33747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // bail out. 33847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_INFO) << "No Xcomposite extension detected."; 33947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 34047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 34147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 34247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 34347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window root; 34447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int x; 34547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int y; 34647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned int src_width; 34747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned int src_height; 34847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned int border_width; 34947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned int depth; 35047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 35147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // In addition to needing X11 server-side support for Xcomposite, it 35247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // actually needs to be turned on for this window in order to get a good 35347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // thumbnail. If the user has modern hardware/drivers but isn't using a 35447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // compositing window manager, that won't be the case. Here we 35547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // automatically turn it on for shareable windows so that we can get 35647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // thumbnails. We used to avoid it because the transition is visually ugly, 35747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // but recent window managers don't always redirect windows which led to 35847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // no thumbnails at all, which is a worse experience. 35947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 36047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Redirect drawing to an offscreen buffer (ie, turn on compositing). 36147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // X11 remembers what has requested this and will turn it off for us when 36247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // we exit. 36347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XCompositeRedirectWindow(display_, id.id(), CompositeRedirectAutomatic); 36447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Pixmap src_pixmap = XCompositeNameWindowPixmap(display_, id.id()); 36547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!src_pixmap) { 36647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Even if the backing pixmap doesn't exist, this still should have 36747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // succeeded and returned a valid handle (it just wouldn't be a handle to 36847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // anything). So this is a real error path. 36947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "XCompositeNameWindowPixmap() failed"; 37047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 37147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 37247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!XGetGeometry(display_, src_pixmap, &root, &x, &y, 37347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &src_width, &src_height, &border_width, 37447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &depth)) { 37547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // If the window does not actually have a backing pixmap, this is the path 37647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // that will "fail", so it's a warning rather than an error. 37747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_WARNING) << "XGetGeometry() failed (probably composite is not in " 37847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << "use)"; 37947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFreePixmap(display_, src_pixmap); 38047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 38147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 38247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 38347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // If we get to here, then composite is in use for this window and it has a 38447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // valid backing pixmap. 38547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 38647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XWindowAttributes attr; 38747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!XGetWindowAttributes(display_, id.id(), &attr)) { 38847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "XGetWindowAttributes() failed"; 38947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFreePixmap(display_, src_pixmap); 39047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 39147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 39247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 39347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint8* data = GetDrawableThumbnail(src_pixmap, 39447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org attr.visual, 39547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org src_width, 39647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org src_height, 39747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org width, 39847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org height); 39947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFreePixmap(display_, src_pixmap); 40047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return data; 40147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 40247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 40347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int GetNumDesktops() { 40447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!Init()) { 40547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return -1; 40647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 40747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 40847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return XScreenCount(display_); 40947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 41047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 41147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint8* GetDesktopThumbnail(const DesktopId& id, int width, int height) { 41247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!Init()) { 41347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 41447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 41547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 41647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 41747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window root_window = id.id(); 41847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XWindowAttributes attr; 41947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!XGetWindowAttributes(display_, root_window, &attr)) { 42047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "XGetWindowAttributes() failed"; 42147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 42247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 42347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 42447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return GetDrawableThumbnail(root_window, 42547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org attr.visual, 42647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org attr.width, 42747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org attr.height, 42847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org width, 42947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org height); 43047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 43147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 43247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool GetDesktopDimensions(const DesktopId& id, int* width, int* height) { 43347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!Init()) { 43447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 43547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 43647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XErrorSuppressor error_suppressor(display_); 43747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XWindowAttributes attr; 43847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!XGetWindowAttributes(display_, id.id(), &attr)) { 43947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "XGetWindowAttributes() failed"; 44047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 44147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 44247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *width = attr.width; 44347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *height = attr.height; 44447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return true; 44547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 44647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 44747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org private: 44847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint8* GetDrawableThumbnail(Drawable src_drawable, 44947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Visual* visual, 45047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int src_width, 45147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int src_height, 45247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int dst_width, 45347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int dst_height) { 45447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!has_render_extension_) { 45547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Without the Xrender extension we would have to read the full window and 45647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // scale it down in our process. Xrender is over a decade old so we aren't 45747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // going to expend effort to support that situation. We still need to 45847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // check though because probably some virtual VNC displays are in this 45947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // category. 46047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_INFO) << "No Xrender extension detected."; 46147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 46247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 46347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 46447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XRenderPictFormat* format = XRenderFindVisualFormat(display_, 46547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org visual); 46647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!format) { 46747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "XRenderFindVisualFormat() failed"; 46847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 46947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 47047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 47147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Create a picture to reference the window pixmap. 47247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XRenderPictureAttributes pa; 47347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org pa.subwindow_mode = IncludeInferiors; // Don't clip child widgets 47447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Picture src = XRenderCreatePicture(display_, 47547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org src_drawable, 47647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org format, 47747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org CPSubwindowMode, 47847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &pa); 47947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!src) { 48047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "XRenderCreatePicture() failed"; 48147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 48247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 48347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 48447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Create a picture to reference the destination pixmap. 48547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Pixmap dst_pixmap = XCreatePixmap(display_, 48647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org src_drawable, 48747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org dst_width, 48847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org dst_height, 48947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org format->depth); 49047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!dst_pixmap) { 49147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "XCreatePixmap() failed"; 49247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XRenderFreePicture(display_, src); 49347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 49447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 49547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 49647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Picture dst = XRenderCreatePicture(display_, dst_pixmap, format, 0, NULL); 49747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!dst) { 49847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "XRenderCreatePicture() failed"; 49947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFreePixmap(display_, dst_pixmap); 50047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XRenderFreePicture(display_, src); 50147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return NULL; 50247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 50347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 50447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Clear the background. 50547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XRenderColor transparent = {0}; 50647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XRenderFillRectangle(display_, 50747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org PictOpSrc, 50847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org dst, 50947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &transparent, 51047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 0, 51147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 0, 51247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org dst_width, 51347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org dst_height); 51447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 51547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Calculate how much we need to scale the image. 51647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org double scale_x = static_cast<double>(dst_width) / 51747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org static_cast<double>(src_width); 51847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org double scale_y = static_cast<double>(dst_height) / 51947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org static_cast<double>(src_height); 52047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org double scale = rtc::_min(scale_y, scale_x); 52147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 52247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int scaled_width = round(src_width * scale); 52347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int scaled_height = round(src_height * scale); 52447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 52547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Render the thumbnail centered on both axis. 52647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int centered_x = (dst_width - scaled_width) / 2; 52747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int centered_y = (dst_height - scaled_height) / 2; 52847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 52947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Scaling matrix 53047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XTransform xform = { { 53147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org { XDoubleToFixed(1), XDoubleToFixed(0), XDoubleToFixed(0) }, 53247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org { XDoubleToFixed(0), XDoubleToFixed(1), XDoubleToFixed(0) }, 53347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(scale) } 53447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } }; 53547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XRenderSetPictureTransform(display_, src, &xform); 53647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 53747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Apply filter to smooth out the image. 53847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XRenderSetPictureFilter(display_, src, FilterBest, NULL, 0); 53947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 54047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Render the image to the destination picture. 54147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XRenderComposite(display_, 54247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org PictOpSrc, 54347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org src, 54447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org None, 54547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org dst, 54647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 0, 54747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 0, 54847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 0, 54947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 0, 55047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org centered_x, 55147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org centered_y, 55247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org scaled_width, 55347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org scaled_height); 55447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 55547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Get the pixel data from the X server. TODO: XGetImage 55647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // might be slow here, compare with ShmGetImage. 55747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XImage* image = XGetImage(display_, 55847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org dst_pixmap, 55947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 0, 56047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 0, 56147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org dst_width, 56247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org dst_height, 56347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org AllPlanes, ZPixmap); 56447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint8* data = ArgbToRgba(reinterpret_cast<uint32*>(image->data), 56547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org centered_x, 56647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org centered_y, 56747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org scaled_width, 56847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org scaled_height, 56947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org dst_width, 57047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org dst_height, 57147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org false); 57247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XDestroyImage(image); 57347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XRenderFreePicture(display_, dst); 57447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFreePixmap(display_, dst_pixmap); 57547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XRenderFreePicture(display_, src); 57647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return data; 57747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 57847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 57947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint8* ArgbToRgba(uint32* argb_data, int x, int y, int w, int h, 58047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int stride_x, int stride_y, bool has_alpha) { 58147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint8* p; 58247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int len = stride_x * stride_y * 4; 58347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint8* data = new uint8[len]; 58447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org memset(data, 0, len); 58547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org p = data + 4 * (y * stride_x + x); 58647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org for (int i = 0; i < h; ++i) { 58747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org for (int j = 0; j < w; ++j) { 58847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint32 argb; 58947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint32 rgba; 59047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org argb = argb_data[stride_x * (y + i) + x + j]; 59147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org rgba = (argb << 8) | (argb >> 24); 59247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *p = rgba >> 24; 59347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ++p; 59447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *p = (rgba >> 16) & 0xff; 59547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ++p; 59647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *p = (rgba >> 8) & 0xff; 59747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ++p; 59847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *p = has_alpha ? rgba & 0xFF : 0xFF; 59947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org ++p; 60047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 60147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org p += (stride_x - w) * 4; 60247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 60347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return data; 60447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 60547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 60647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool EnumerateScreenWindows(WindowDescriptionList* descriptions, int screen) { 60747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window parent; 60847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window *children; 60947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int status; 61047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned int num_children; 61147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window root_window = XRootWindow(display_, screen); 61247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org status = XQueryTree(display_, root_window, &root_window, &parent, &children, 61347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &num_children); 61447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (status == 0) { 61547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "Failed to query for child windows."; 61647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 61747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 61847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org for (unsigned int i = 0; i < num_children; ++i) { 61947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Iterate in reverse order to display windows from front to back. 62047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef CHROMEOS 62147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // TODO(jhorwich): Short-term fix for crbug.com/120229: Don't need to 62247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // filter, just return all windows and let the picker scan through them. 62347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window app_window = children[num_children - 1 - i]; 62447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#else 62547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window app_window = GetApplicationWindow(children[num_children - 1 - i]); 62647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif 62747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (app_window && 628cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.org !X11WindowPicker::IsDesktopElement(display_, app_window)) { 62947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org std::string title; 63047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (GetWindowTitle(app_window, &title)) { 63147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org WindowId id(app_window); 63247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org WindowDescription desc(id, title); 63347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org descriptions->push_back(desc); 63447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 63547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 63647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 63747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (children != NULL) { 63847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFree(children); 63947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 64047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return true; 64147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 64247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 64347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool GetWindowTitle(Window window, std::string* title) { 64447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int status; 64547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool result = false; 64647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XTextProperty window_name; 64747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org window_name.value = NULL; 64847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (window) { 64947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org status = XGetWMName(display_, window, &window_name); 65047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (status && window_name.value && window_name.nitems) { 65147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int cnt; 65247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org char **list = NULL; 65347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org status = Xutf8TextPropertyToTextList(display_, &window_name, &list, 65447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &cnt); 65547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (status >= Success && cnt && *list) { 65647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (cnt > 1) { 65747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_INFO) << "Window has " << cnt 65847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << " text properties, only using the first one."; 65947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 66047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *title = *list; 66147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org result = true; 66247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 66347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (list != NULL) { 66447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFreeStringList(list); 66547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 66647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 66747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (window_name.value != NULL) { 66847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFree(window_name.value); 66947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 67047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 67147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return result; 67247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 67347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 67447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window GetApplicationWindow(Window window) { 67547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window root, parent; 67647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window app_window = 0; 67747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Window *children; 67847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned int num_children; 67947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Atom type = None; 68047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int format; 68147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned long nitems, after; 68247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org unsigned char *data; 68347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 68447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int ret = XGetWindowProperty(display_, window, 68547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org wm_state_, 0L, 2, 68647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org False, wm_state_, &type, &format, 68747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &nitems, &after, &data); 68847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (ret != Success) { 68947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "XGetWindowProperty failed with return code " << ret 69047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << " for window " << window << "."; 69147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return 0; 69247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 69347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (type != None) { 69447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int64 state = static_cast<int64>(*data); 69547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFree(data); 69647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return state == NormalState ? window : 0; 69747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 69847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFree(data); 69947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (!XQueryTree(display_, window, &root, &parent, &children, 70047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org &num_children)) { 70147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_ERROR) << "Failed to query for child windows although window" 70247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org << "does not have a valid WM_STATE."; 70347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return 0; 70447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 70547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org for (unsigned int i = 0; i < num_children; ++i) { 70647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org app_window = GetApplicationWindow(children[i]); 70747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (app_window) { 70847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org break; 70947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 71047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 71147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (children != NULL) { 71247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFree(children); 71347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 71447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return app_window; 71547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 71647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 71747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Atom wm_state_; 71847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Atom net_wm_icon_; 71947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Display* display_; 72047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool has_composite_extension_; 72147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool has_render_extension_; 72247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}; 72347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 724cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.orgX11WindowPicker::X11WindowPicker() : enumerator_(new XWindowEnumerator()) { 72547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 72647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 727cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.orgX11WindowPicker::~X11WindowPicker() { 72847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 72947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 730cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.orgbool X11WindowPicker::IsDesktopElement(_XDisplay* display, Window window) { 73147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (window == 0) { 73247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org LOG(LS_WARNING) << "Zero is never a valid window."; 73347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return false; 73447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 73547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 73647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // First look for _NET_WM_WINDOW_TYPE. The standard 73747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // (http://standards.freedesktop.org/wm-spec/latest/ar01s05.html#id2760306) 73847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // says this hint *should* be present on all windows, and we use the existence 73947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // of _NET_WM_WINDOW_TYPE_NORMAL in the property to indicate a window is not 74047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // a desktop element (that is, only "normal" windows should be shareable). 74147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Atom window_type_atom = XInternAtom(display, "_NET_WM_WINDOW_TYPE", True); 74247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XWindowProperty<uint32_t> window_type(display, window, window_type_atom); 74347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (window_type.succeeded() && window_type.size() > 0) { 74447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Atom normal_window_type_atom = XInternAtom( 74547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org display, "_NET_WM_WINDOW_TYPE_NORMAL", True); 74647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org uint32_t* end = window_type.data() + window_type.size(); 74747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool is_normal = (end != std::find( 74847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org window_type.data(), end, normal_window_type_atom)); 74947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return !is_normal; 75047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 75147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 75247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // Fall back on using the hint. 75347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XClassHint class_hint; 75447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org Status s = XGetClassHint(display, window, &class_hint); 75547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org bool result = false; 75647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (s == 0) { 75747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org // No hints, assume this is a normal application window. 75847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return result; 75947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 76047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org static const std::string gnome_panel("gnome-panel"); 76147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org static const std::string desktop_window("desktop_window"); 76247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 76347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org if (gnome_panel.compare(class_hint.res_name) == 0 || 76447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org desktop_window.compare(class_hint.res_name) == 0) { 76547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org result = true; 76647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org } 76747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFree(class_hint.res_name); 76847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org XFree(class_hint.res_class); 76947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return result; 77047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 77147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 772cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.orgbool X11WindowPicker::Init() { 77347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return enumerator_->Init(); 77447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 77547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 776cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.orgbool X11WindowPicker::GetWindowList(WindowDescriptionList* descriptions) { 77747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return enumerator_->EnumerateWindows(descriptions); 77847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 77947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 780cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.orgbool X11WindowPicker::GetDesktopList(DesktopDescriptionList* descriptions) { 78147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return enumerator_->EnumerateDesktops(descriptions); 78247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 78347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 784cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.orgbool X11WindowPicker::IsVisible(const WindowId& id) { 78547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return enumerator_->IsVisible(id); 78647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 78747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 788cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.orgbool X11WindowPicker::MoveToFront(const WindowId& id) { 78947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return enumerator_->MoveToFront(id); 79047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 79147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 79247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 793cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.orguint8* X11WindowPicker::GetWindowIcon(const WindowId& id, int* width, 79447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int* height) { 79547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return enumerator_->GetWindowIcon(id, width, height); 79647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 79747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 798cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.orguint8* X11WindowPicker::GetWindowThumbnail(const WindowId& id, int width, 79947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int height) { 80047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return enumerator_->GetWindowThumbnail(id, width, height); 80147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 80247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 803cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.orgint X11WindowPicker::GetNumDesktops() { 80447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return enumerator_->GetNumDesktops(); 80547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 80647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 807cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.orguint8* X11WindowPicker::GetDesktopThumbnail(const DesktopId& id, 80847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int width, 80947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int height) { 81047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return enumerator_->GetDesktopThumbnail(id, width, height); 81147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 81247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 813cdc312345fcdfc586a7c8cd720407449cc0bdcd2henrike@webrtc.orgbool X11WindowPicker::GetDesktopDimensions(const DesktopId& id, int* width, 81447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org int* height) { 81547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org return enumerator_->GetDesktopDimensions(id, width, height); 81647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} 81747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org 81847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} // namespace rtc 819