mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1036653 - X11-specific support, r=rjesup,gcp
This commit is contained in:
parent
0f47b9e917
commit
c3f804451d
283
media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_x11.cc
Normal file → Executable file
283
media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_x11.cc
Normal file → Executable file
@ -9,6 +9,9 @@
|
||||
*/
|
||||
#include "webrtc/modules/desktop_capture/window_capturer.h"
|
||||
#include "webrtc/modules/desktop_capture/app_capturer.h"
|
||||
#include "webrtc/modules/desktop_capture/screen_capturer.h"
|
||||
#include "webrtc/modules/desktop_capture/shared_desktop_frame.h"
|
||||
#include "webrtc/modules/desktop_capture/x11/shared_x_util.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
@ -16,6 +19,7 @@
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
#include <X11/extensions/Xrender.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xregion.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -32,47 +36,115 @@ namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
class WindowsCapturerProxy : DesktopCapturer::Callback {
|
||||
public:
|
||||
WindowsCapturerProxy() : window_capturer_(WindowCapturer::Create()) {
|
||||
window_capturer_->Start(this);
|
||||
}
|
||||
~WindowsCapturerProxy() {}
|
||||
void SelectWindow(WindowId windowId) { window_capturer_->SelectWindow(windowId); }
|
||||
scoped_ptr<DesktopFrame>& GetFrame() { return frame_; }
|
||||
void Capture(const DesktopRegion& region) { window_capturer_->Capture(region); }
|
||||
|
||||
class AppCapturerLinux : public AppCapturer{
|
||||
// Callback interface
|
||||
virtual SharedMemory *CreateSharedMemory(size_t) OVERRIDE { return NULL; }
|
||||
virtual void OnCaptureCompleted(DesktopFrame *frame) OVERRIDE { frame_.reset(frame); }
|
||||
|
||||
private:
|
||||
scoped_ptr<WindowCapturer> window_capturer_;
|
||||
scoped_ptr<DesktopFrame> frame_;
|
||||
};
|
||||
|
||||
class ScreenCapturerProxy : DesktopCapturer::Callback {
|
||||
public:
|
||||
ScreenCapturerProxy() : screen_capturer_(ScreenCapturer::Create()) {
|
||||
screen_capturer_->SelectScreen(kFullDesktopScreenId);
|
||||
screen_capturer_->Start(this);
|
||||
}
|
||||
void Capture(const DesktopRegion& region) { screen_capturer_->Capture(region); }
|
||||
scoped_ptr<DesktopFrame>& GetFrame() { return frame_; }
|
||||
|
||||
// Callback interface
|
||||
virtual SharedMemory *CreateSharedMemory(size_t) OVERRIDE { return NULL; }
|
||||
virtual void OnCaptureCompleted(DesktopFrame *frame) OVERRIDE { frame_.reset(frame); }
|
||||
protected:
|
||||
scoped_ptr<ScreenCapturer> screen_capturer_;
|
||||
scoped_ptr<DesktopFrame> frame_;
|
||||
};
|
||||
|
||||
class AppCapturerLinux : public AppCapturer {
|
||||
public:
|
||||
AppCapturerLinux(const DesktopCaptureOptions& options);
|
||||
virtual ~AppCapturerLinux();
|
||||
|
||||
// AppCapturer interface.
|
||||
virtual bool GetAppList(AppList* apps) OVERRIDE;
|
||||
virtual bool SelectApp(ProcessId id) OVERRIDE;
|
||||
virtual bool SelectApp(ProcessId processId) OVERRIDE;
|
||||
virtual bool BringAppToFront() OVERRIDE;
|
||||
|
||||
// DesktopCapturer interface.
|
||||
virtual void Start(Callback* callback) OVERRIDE;
|
||||
virtual void Capture(const DesktopRegion& region) OVERRIDE;
|
||||
|
||||
protected:
|
||||
Display* GetDisplay() { return x_display_->display(); }
|
||||
bool UpdateRegions();
|
||||
|
||||
void CaptureWebRTC(const DesktopRegion& region);
|
||||
void CaptureSample(const DesktopRegion& region);
|
||||
|
||||
void FillDesktopFrameRegionWithColor(DesktopFrame* pDesktopFrame,Region rgn, uint32_t color);
|
||||
private:
|
||||
Callback* callback_;
|
||||
ProcessId selected_process_;
|
||||
|
||||
// Sample Mode
|
||||
ScreenCapturerProxy screen_capturer_proxy_;
|
||||
// Mask of foreground (non-app windows in front of selected)
|
||||
Region rgn_mask_;
|
||||
// Region of selected windows
|
||||
Region rgn_visual_;
|
||||
// Mask of background (desktop, non-app windows behind selected)
|
||||
Region rgn_background_;
|
||||
|
||||
// WebRtc Window mode
|
||||
WindowsCapturerProxy window_capturer_proxy_;
|
||||
|
||||
scoped_refptr<SharedXDisplay> x_display_;
|
||||
DISALLOW_COPY_AND_ASSIGN(AppCapturerLinux);
|
||||
};
|
||||
|
||||
AppCapturerLinux::AppCapturerLinux(const DesktopCaptureOptions& options)
|
||||
: callback_(NULL),
|
||||
selected_process_(0) {
|
||||
selected_process_(0),
|
||||
x_display_(options.x_display()) {
|
||||
rgn_mask_ = XCreateRegion();
|
||||
rgn_visual_ = XCreateRegion();
|
||||
rgn_background_ = XCreateRegion();
|
||||
}
|
||||
|
||||
AppCapturerLinux::~AppCapturerLinux() {
|
||||
if (rgn_mask_) {
|
||||
XDestroyRegion(rgn_mask_);
|
||||
}
|
||||
if (rgn_visual_) {
|
||||
XDestroyRegion(rgn_visual_);
|
||||
}
|
||||
if (rgn_background_) {
|
||||
XDestroyRegion(rgn_background_);
|
||||
}
|
||||
}
|
||||
|
||||
// AppCapturer interface.
|
||||
bool AppCapturerLinux::GetAppList(AppList* apps){
|
||||
// Not implemented yet: See Bug 1036653
|
||||
bool AppCapturerLinux::GetAppList(AppList* apps) {
|
||||
// Implemented in DesktopDeviceInfo
|
||||
return true;
|
||||
}
|
||||
bool AppCapturerLinux::SelectApp(ProcessId id){
|
||||
// Not implemented yet: See Bug 1036653
|
||||
bool AppCapturerLinux::SelectApp(ProcessId processId) {
|
||||
selected_process_ = processId;
|
||||
return true;
|
||||
}
|
||||
bool AppCapturerLinux::BringAppToFront(){
|
||||
bool AppCapturerLinux::BringAppToFront() {
|
||||
// Not implemented yet: See Bug 1036653
|
||||
return true;
|
||||
}
|
||||
@ -86,7 +158,200 @@ void AppCapturerLinux::Start(Callback* callback) {
|
||||
}
|
||||
|
||||
void AppCapturerLinux::Capture(const DesktopRegion& region) {
|
||||
// Not implemented yet: See Bug 1036653
|
||||
CaptureSample(region);
|
||||
}
|
||||
|
||||
void AppCapturerLinux::CaptureWebRTC(const DesktopRegion& region) {
|
||||
XErrorTrap error_trap(GetDisplay());
|
||||
|
||||
int nScreenWidth = DisplayWidth(GetDisplay(), DefaultScreen(GetDisplay()));
|
||||
int nScreenHeight = DisplayHeight(GetDisplay(), DefaultScreen(GetDisplay()));
|
||||
scoped_ptr<DesktopFrame> frame(new BasicDesktopFrame(DesktopSize(nScreenWidth, nScreenHeight)));
|
||||
|
||||
WindowUtilX11 window_util_x11(x_display_);
|
||||
|
||||
::Window root_window = XRootWindow(GetDisplay(), DefaultScreen(GetDisplay()));
|
||||
::Window parent;
|
||||
::Window root_return;
|
||||
::Window *children;
|
||||
unsigned int num_children;
|
||||
int status = XQueryTree(GetDisplay(), root_window, &root_return, &parent,
|
||||
&children, &num_children);
|
||||
if (status == 0) {
|
||||
LOG(LS_ERROR) << "Failed to query for child windows for screen "
|
||||
<< DefaultScreen(GetDisplay());
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < num_children; ++i) {
|
||||
::Window app_window = window_util_x11.GetApplicationWindow(children[i]);
|
||||
if (!app_window) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int processId = window_util_x11.GetWindowProcessID(app_window);
|
||||
if(processId != 0 && processId == selected_process_) {
|
||||
// capture
|
||||
window_capturer_proxy_.SelectWindow(app_window);
|
||||
window_capturer_proxy_.Capture(region);
|
||||
DesktopFrame* frameWin = window_capturer_proxy_.GetFrame().get();
|
||||
if (frameWin == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
XRectangle win_rect;
|
||||
window_util_x11.GetWindowRect(app_window,win_rect, false);
|
||||
if (win_rect.width <= 0 || win_rect.height <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DesktopSize winFrameSize = frameWin->size();
|
||||
DesktopRect target_rect = DesktopRect::MakeXYWH(win_rect.x,
|
||||
win_rect.y,
|
||||
winFrameSize.width(),
|
||||
winFrameSize.height());
|
||||
|
||||
// bitblt into background frame
|
||||
frame->CopyPixelsFrom(*frameWin, DesktopVector(0, 0), target_rect);
|
||||
}
|
||||
}
|
||||
|
||||
if (children) {
|
||||
XFree(children);
|
||||
}
|
||||
|
||||
// trigger event
|
||||
if (callback_) {
|
||||
callback_->OnCaptureCompleted(error_trap.GetLastErrorAndDisable() != 0 ?
|
||||
NULL :
|
||||
frame.release());
|
||||
}
|
||||
}
|
||||
|
||||
void AppCapturerLinux::CaptureSample(const DesktopRegion& region) {
|
||||
XErrorTrap error_trap(GetDisplay());
|
||||
|
||||
//Capture screen >> set root window as capture window
|
||||
screen_capturer_proxy_.Capture(region);
|
||||
DesktopFrame* frame = screen_capturer_proxy_.GetFrame().get();
|
||||
if (frame) {
|
||||
// calculate app visual/foreground region
|
||||
UpdateRegions();
|
||||
|
||||
// TODO: background/foreground mask colors should be configurable; see Bug 1054503
|
||||
// fill background with black
|
||||
FillDesktopFrameRegionWithColor(frame, rgn_background_, 0xFF000000);
|
||||
|
||||
// fill foreground with yellow
|
||||
FillDesktopFrameRegionWithColor(frame, rgn_mask_, 0xFFFFFF00);
|
||||
}
|
||||
|
||||
// trigger event
|
||||
if (callback_) {
|
||||
callback_->OnCaptureCompleted(error_trap.GetLastErrorAndDisable() != 0 ?
|
||||
NULL :
|
||||
screen_capturer_proxy_.GetFrame().release());
|
||||
}
|
||||
}
|
||||
|
||||
void AppCapturerLinux::FillDesktopFrameRegionWithColor(DesktopFrame* pDesktopFrame, Region rgn, uint32_t color) {
|
||||
XErrorTrap error_trap(GetDisplay());
|
||||
|
||||
if (!pDesktopFrame) {
|
||||
return;
|
||||
}
|
||||
if (XEmptyRegion(rgn)) {
|
||||
return;
|
||||
}
|
||||
|
||||
REGION * st_rgn = (REGION *)rgn;
|
||||
if(st_rgn && st_rgn->numRects > 0) {
|
||||
for (short i = 0; i < st_rgn->numRects; i++) {
|
||||
for (short j = st_rgn->rects[i].y1; j < st_rgn->rects[i].y2; j++) {
|
||||
uint32_t* dst_pos = reinterpret_cast<uint32_t*>(pDesktopFrame->data() + pDesktopFrame->stride() * j);
|
||||
for (short k = st_rgn->rects[i].x1; k < st_rgn->rects[i].x2; k++) {
|
||||
dst_pos[k] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AppCapturerLinux::UpdateRegions() {
|
||||
XErrorTrap error_trap(GetDisplay());
|
||||
|
||||
XSubtractRegion(rgn_visual_, rgn_visual_, rgn_visual_);
|
||||
XSubtractRegion(rgn_mask_, rgn_mask_, rgn_mask_);
|
||||
WindowUtilX11 window_util_x11(x_display_);
|
||||
int num_screens = XScreenCount(GetDisplay());
|
||||
for (int screen = 0; screen < num_screens; ++screen) {
|
||||
int nScreenCX = DisplayWidth(GetDisplay(), screen);
|
||||
int nScreenCY = DisplayHeight(GetDisplay(), screen);
|
||||
|
||||
XRectangle screen_rect;
|
||||
screen_rect.x = 0;
|
||||
screen_rect.y = 0;
|
||||
screen_rect.width = nScreenCX;
|
||||
screen_rect.height = nScreenCY;
|
||||
|
||||
XUnionRectWithRegion(&screen_rect, rgn_background_, rgn_background_);
|
||||
XXorRegion(rgn_mask_, rgn_mask_, rgn_mask_);
|
||||
XXorRegion(rgn_visual_, rgn_visual_, rgn_visual_);
|
||||
|
||||
::Window root_window = XRootWindow(GetDisplay(), screen);
|
||||
::Window parent;
|
||||
::Window root_return;
|
||||
::Window *children;
|
||||
unsigned int num_children;
|
||||
int status = XQueryTree(GetDisplay(), root_window, &root_return, &parent, &children, &num_children);
|
||||
if (status == 0) {
|
||||
LOG(LS_ERROR) << "Failed to query for child windows for screen " << screen;
|
||||
continue;
|
||||
}
|
||||
for (unsigned int i = 0; i < num_children; ++i) {
|
||||
::Window app_window = window_util_x11.GetApplicationWindow(children[i]);
|
||||
if (!app_window) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get window region
|
||||
XRectangle win_rect;
|
||||
window_util_x11.GetWindowRect(app_window, win_rect, true);
|
||||
if (win_rect.width <= 0 || win_rect.height <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Region win_rgn = XCreateRegion();
|
||||
XUnionRectWithRegion(&win_rect, win_rgn, win_rgn);
|
||||
// update rgn_visual_ , rgn_mask_,
|
||||
unsigned int processId = window_util_x11.GetWindowProcessID(app_window);
|
||||
if (processId != 0 && processId == selected_process_) {
|
||||
XUnionRegion(rgn_visual_, win_rgn, rgn_visual_);
|
||||
XSubtractRegion(rgn_mask_, win_rgn, rgn_mask_);
|
||||
} else {
|
||||
Region win_rgn_intersect = XCreateRegion();
|
||||
XIntersectRegion(rgn_visual_, win_rgn, win_rgn_intersect);
|
||||
|
||||
XSubtractRegion(rgn_visual_, win_rgn_intersect, rgn_visual_);
|
||||
XUnionRegion(win_rgn_intersect, rgn_mask_, rgn_mask_);
|
||||
|
||||
if (win_rgn_intersect) {
|
||||
XDestroyRegion(win_rgn_intersect);
|
||||
}
|
||||
}
|
||||
if (win_rgn) {
|
||||
XDestroyRegion(win_rgn);
|
||||
}
|
||||
}
|
||||
|
||||
if (children) {
|
||||
XFree(children);
|
||||
}
|
||||
}
|
||||
|
||||
XSubtractRegion(rgn_background_, rgn_visual_, rgn_background_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -81,6 +81,8 @@
|
||||
"mouse_cursor_monitor_x11.cc",
|
||||
"screen_capturer_x11.cc",
|
||||
"window_capturer_x11.cc",
|
||||
"x11/shared_x_util.h",
|
||||
"x11/shared_x_util.cc",
|
||||
"x11/shared_x_display.h",
|
||||
"x11/shared_x_display.cc",
|
||||
"x11/x_error_trap.cc",
|
||||
|
@ -27,64 +27,12 @@
|
||||
#include "webrtc/system_wrappers/interface/logging.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_refptr.h"
|
||||
#include "webrtc/modules/desktop_capture/x11/shared_x_util.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
// Convenience wrapper for XGetWindowProperty() results.
|
||||
template <class PropertyType>
|
||||
class XWindowProperty {
|
||||
public:
|
||||
XWindowProperty(Display* display, Window window, Atom property)
|
||||
: is_valid_(false),
|
||||
size_(0),
|
||||
data_(NULL) {
|
||||
const int kBitsPerByte = 8;
|
||||
Atom actual_type;
|
||||
int actual_format;
|
||||
unsigned long bytes_after; // NOLINT: type required by XGetWindowProperty
|
||||
int status = XGetWindowProperty(display, window, property, 0L, ~0L, False,
|
||||
AnyPropertyType, &actual_type,
|
||||
&actual_format, &size_,
|
||||
&bytes_after, &data_);
|
||||
if (status != Success) {
|
||||
data_ = NULL;
|
||||
return;
|
||||
}
|
||||
if (sizeof(PropertyType) * kBitsPerByte != actual_format) {
|
||||
size_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
~XWindowProperty() {
|
||||
if (data_)
|
||||
XFree(data_);
|
||||
}
|
||||
|
||||
// True if we got properly value successfully.
|
||||
bool is_valid() const { return is_valid_; }
|
||||
|
||||
// Size and value of the property.
|
||||
size_t size() const { return size_; }
|
||||
const PropertyType* data() const {
|
||||
return reinterpret_cast<PropertyType*>(data_);
|
||||
}
|
||||
PropertyType* data() {
|
||||
return reinterpret_cast<PropertyType*>(data_);
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_valid_;
|
||||
unsigned long size_; // NOLINT: type required by XGetWindowProperty
|
||||
unsigned char* data_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(XWindowProperty);
|
||||
};
|
||||
|
||||
class WindowCapturerLinux : public WindowCapturer,
|
||||
public SharedXDisplay::XEventHandler {
|
||||
public:
|
||||
|
@ -4,6 +4,14 @@
|
||||
|
||||
#include "webrtc/modules/desktop_capture/x11/desktop_device_info_x11.h"
|
||||
#include "webrtc/modules/desktop_capture/window_capturer.h"
|
||||
#include "webrtc/modules/desktop_capture/x11/x_error_trap.h"
|
||||
#include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h"
|
||||
#include "webrtc/system_wrappers/interface/logging.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_refptr.h"
|
||||
#include "webrtc/modules/desktop_capture/x11/shared_x_util.h"
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace webrtc{
|
||||
|
||||
@ -23,7 +31,7 @@ DesktopDeviceInfoX11::~DesktopDeviceInfoX11() {
|
||||
}
|
||||
|
||||
#if !defined(MULTI_MONITOR_SCREENSHARE)
|
||||
int32_t DesktopDeviceInfoX11::MultiMonitorScreenshare()
|
||||
void DesktopDeviceInfoX11::MultiMonitorScreenshare()
|
||||
{
|
||||
DesktopDisplayDevice *pDesktopDeviceInfo = new DesktopDisplayDevice;
|
||||
if (pDesktopDeviceInfo) {
|
||||
@ -33,35 +41,80 @@ int32_t DesktopDeviceInfoX11::MultiMonitorScreenshare()
|
||||
|
||||
desktop_display_list_[pDesktopDeviceInfo->getScreenId()] = pDesktopDeviceInfo;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int32_t DesktopDeviceInfoX11::Init() {
|
||||
void DesktopDeviceInfoX11::InitializeScreenList() {
|
||||
#if !defined(MULTI_MONITOR_SCREENSHARE)
|
||||
MultiMonitorScreenshare();
|
||||
#endif
|
||||
|
||||
initializeWindowList();
|
||||
|
||||
return 0;
|
||||
}
|
||||
void DesktopDeviceInfoX11::InitializeApplicationList() {
|
||||
//List all running applications exclude background process.
|
||||
scoped_refptr<SharedXDisplay> SharedDisplay = SharedXDisplay::CreateDefault();
|
||||
XErrorTrap error_trap(SharedDisplay->display());
|
||||
|
||||
int32_t DesktopDeviceInfoX11::Refresh() {
|
||||
#if !defined(MULTI_MONITOR_SCREENSHARE)
|
||||
std::map<intptr_t,DesktopDisplayDevice*>::iterator iterDevice;
|
||||
for (iterDevice=desktop_display_list_.begin(); iterDevice!=desktop_display_list_.end(); iterDevice++){
|
||||
DesktopDisplayDevice * pDesktopDisplayDevice = iterDevice->second;
|
||||
delete pDesktopDisplayDevice;
|
||||
iterDevice->second = NULL;
|
||||
WindowUtilX11 window_util_x11(SharedDisplay);
|
||||
int num_screens = XScreenCount(SharedDisplay->display());
|
||||
for (int screen = 0; screen < num_screens; ++screen) {
|
||||
::Window root_window = XRootWindow(SharedDisplay->display(), screen);
|
||||
::Window parent;
|
||||
::Window *children;
|
||||
unsigned int num_children;
|
||||
int status = XQueryTree(SharedDisplay->display(), root_window, &root_window, &parent,
|
||||
&children, &num_children);
|
||||
if (status == 0) {
|
||||
LOG(LS_ERROR) << "Failed to query for child windows for screen " << screen;
|
||||
continue;
|
||||
}
|
||||
desktop_display_list_.clear();
|
||||
MultiMonitorScreenshare();
|
||||
#endif
|
||||
|
||||
RefreshWindowList();
|
||||
for (unsigned int i = 0; i < num_children; ++i) {
|
||||
::Window app_window = window_util_x11.GetApplicationWindow(children[num_children - 1 - i]);
|
||||
|
||||
return 0;
|
||||
if (!app_window
|
||||
|| window_util_x11.IsDesktopElement(app_window)
|
||||
|| window_util_x11.GetWindowStatus(app_window) == WithdrawnState) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int processId = window_util_x11.GetWindowProcessID(app_window);
|
||||
// filter out non-process
|
||||
if (processId == 0) {
|
||||
continue;
|
||||
}
|
||||
// filter out current process
|
||||
if (processId == getpid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add one application
|
||||
DesktopApplication *pDesktopApplication = new DesktopApplication;
|
||||
if (!pDesktopApplication) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// process id
|
||||
pDesktopApplication->setProcessId(processId);
|
||||
|
||||
// process path name
|
||||
pDesktopApplication->setProcessPathName("");
|
||||
|
||||
// application name
|
||||
std::string strAppName;
|
||||
window_util_x11.GetWindowTitle(app_window, &strAppName);
|
||||
pDesktopApplication->setProcessAppName(strAppName.c_str());
|
||||
|
||||
// unique id name
|
||||
char idStr[64];
|
||||
snprintf(idStr, sizeof(idStr), "%ld", pDesktopApplication->getProcessId());
|
||||
pDesktopApplication->setUniqueIdName(idStr);
|
||||
desktop_application_list_[processId] = pDesktopApplication;
|
||||
}
|
||||
|
||||
if (children) {
|
||||
XFree(children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace webrtc
|
||||
|
@ -2,6 +2,10 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_X11_DEVICE_INFO_H_
|
||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_X11_DEVICE_INFO_H_
|
||||
|
||||
@ -15,13 +19,14 @@ public:
|
||||
DesktopDeviceInfoX11();
|
||||
~DesktopDeviceInfoX11();
|
||||
|
||||
protected:
|
||||
//DesktopDeviceInfo Interfaces
|
||||
virtual int32_t Init();
|
||||
virtual int32_t Refresh();
|
||||
virtual void InitializeApplicationList() OVERRIDE;
|
||||
virtual void InitializeScreenList() OVERRIDE;
|
||||
|
||||
private:
|
||||
#if !defined(MULTI_MONITOR_SCREENSHARE)
|
||||
int32_t MultiMonitorScreenshare();
|
||||
void MultiMonitorScreenshare();
|
||||
#endif
|
||||
};
|
||||
|
||||
|
304
media/webrtc/trunk/webrtc/modules/desktop_capture/x11/shared_x_util.cc
Executable file
304
media/webrtc/trunk/webrtc/modules/desktop_capture/x11/shared_x_util.cc
Executable file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/desktop_capture/x11/shared_x_util.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
WindowUtilX11::WindowUtilX11(scoped_refptr<SharedXDisplay> x_display) {
|
||||
x_display_ = x_display;
|
||||
wm_state_atom_ = XInternAtom(display(), "WM_STATE", True);
|
||||
window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE", True);
|
||||
normal_window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE_NORMAL", True);
|
||||
process_atom_ = XInternAtom(display(), "_NET_WM_PID", True);
|
||||
frame_extends_atom_ = XInternAtom(display(), "_NET_FRAME_EXTENTS", True);
|
||||
}
|
||||
|
||||
WindowUtilX11::~WindowUtilX11() {
|
||||
}
|
||||
|
||||
::Window WindowUtilX11::GetApplicationWindow(::Window window) {
|
||||
// Get WM_STATE property of the window.
|
||||
XWindowProperty<uint32_t> window_state(display(), window, wm_state_atom_);
|
||||
|
||||
// WM_STATE is considered to be set to WithdrawnState when it missing.
|
||||
int32_t state = window_state.is_valid() ? *window_state.data() : WithdrawnState;
|
||||
|
||||
if (state == NormalState) {
|
||||
// Window has WM_STATE==NormalState. Return it.
|
||||
return window;
|
||||
} else if (state == IconicState) {
|
||||
// Window is in minimized. Skip it.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the window is in WithdrawnState then look at all of its children.
|
||||
::Window root, parent;
|
||||
::Window *children;
|
||||
unsigned int num_children;
|
||||
if (!XQueryTree(display(), window, &root, &parent, &children, &num_children)) {
|
||||
LOG(LS_ERROR) << "Failed to query for child windows although window"
|
||||
<< "does not have a valid WM_STATE.";
|
||||
return 0;
|
||||
}
|
||||
::Window app_window = 0;
|
||||
for (unsigned int i = 0; i < num_children; ++i) {
|
||||
app_window = GetApplicationWindow(children[i]);
|
||||
if (app_window) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (children) {
|
||||
XFree(children);
|
||||
}
|
||||
return app_window;
|
||||
}
|
||||
|
||||
bool WindowUtilX11::IsDesktopElement(::Window window) {
|
||||
if (window == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// First look for _NET_WM_WINDOW_TYPE. The standard
|
||||
// (http://standards.freedesktop.org/wm-spec/latest/ar01s05.html#id2760306)
|
||||
// says this hint *should* be present on all windows, and we use the existence
|
||||
// of _NET_WM_WINDOW_TYPE_NORMAL in the property to indicate a window is not
|
||||
// a desktop element (that is, only "normal" windows should be shareable).
|
||||
XWindowProperty<uint32_t> window_type(display(), window, window_type_atom_);
|
||||
if (window_type.is_valid() && window_type.size() > 0) {
|
||||
uint32_t* end = window_type.data() + window_type.size();
|
||||
bool is_normal = (end != std::find(window_type.data(), end, normal_window_type_atom_));
|
||||
return !is_normal;
|
||||
}
|
||||
|
||||
// Fall back on using the hint.
|
||||
XClassHint class_hint;
|
||||
Status status = XGetClassHint(display(), window, &class_hint);
|
||||
bool result = false;
|
||||
if (status == 0) {
|
||||
// No hints, assume this is a normal application window.
|
||||
return result;
|
||||
}
|
||||
|
||||
if (strcmp("gnome-panel", class_hint.res_name) == 0 ||
|
||||
strcmp("desktop_window", class_hint.res_name) == 0) {
|
||||
result = true;
|
||||
}
|
||||
XFree(class_hint.res_name);
|
||||
XFree(class_hint.res_class);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WindowUtilX11::GetWindowTitle(::Window window, std::string* title) {
|
||||
int status;
|
||||
bool result = false;
|
||||
XTextProperty window_name;
|
||||
window_name.value = NULL;
|
||||
if (window) {
|
||||
char * pWinName = NULL;
|
||||
if(XFetchName(display(), window, &pWinName)){
|
||||
*title = pWinName;
|
||||
XFree(pWinName);
|
||||
result = true;
|
||||
}
|
||||
else{
|
||||
status = XGetWMName(display(), window, &window_name);
|
||||
if (status && window_name.value && window_name.nitems) {
|
||||
int cnt;
|
||||
char **list = NULL;
|
||||
status = Xutf8TextPropertyToTextList(display(), &window_name, &list,
|
||||
&cnt);
|
||||
if (status >= Success && cnt && *list) {
|
||||
if (cnt > 1) {
|
||||
LOG(LS_INFO) << "Window has " << cnt << " text properties, only using the first one.";
|
||||
}
|
||||
*title = *list;
|
||||
result = true;
|
||||
}
|
||||
if (list) {
|
||||
XFreeStringList(list);
|
||||
}
|
||||
}
|
||||
if (window_name.value) {
|
||||
XFree(window_name.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WindowUtilX11::BringWindowToFront(::Window window) {
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int num_children;
|
||||
::Window* children;
|
||||
::Window parent;
|
||||
::Window root;
|
||||
// Find the root window to pass event to.
|
||||
int status = XQueryTree(display(), window, &root, &parent, &children, &num_children);
|
||||
if (status == 0) {
|
||||
LOG(LS_ERROR) << "Failed to query for the root window.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (children) {
|
||||
XFree(children);
|
||||
}
|
||||
|
||||
XRaiseWindow(display(), window);
|
||||
|
||||
// Some window managers (e.g., metacity in GNOME) consider it illegal to
|
||||
// raise a window without also giving it input focus with
|
||||
// _NET_ACTIVE_WINDOW, so XRaiseWindow() on its own isn't enough.
|
||||
Atom atom = XInternAtom(display(), "_NET_ACTIVE_WINDOW", True);
|
||||
if (atom != None) {
|
||||
XEvent xev;
|
||||
xev.xclient.type = ClientMessage;
|
||||
xev.xclient.serial = 0;
|
||||
xev.xclient.send_event = True;
|
||||
xev.xclient.window = window;
|
||||
xev.xclient.message_type = atom;
|
||||
|
||||
// The format member is set to 8, 16, or 32 and specifies whether the
|
||||
// data should be viewed as a list of bytes, shorts, or longs.
|
||||
xev.xclient.format = 32;
|
||||
|
||||
memset(xev.xclient.data.l, 0, sizeof(xev.xclient.data.l));
|
||||
|
||||
XSendEvent(display(),
|
||||
root,
|
||||
False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
&xev);
|
||||
}
|
||||
XFlush(display());
|
||||
return true;
|
||||
}
|
||||
|
||||
int WindowUtilX11::GetWindowProcessID(::Window window) {
|
||||
// Get _NET_WM_PID property of the window.
|
||||
XWindowProperty<uint32_t> process_id(display(), window, process_atom_);
|
||||
|
||||
return process_id.is_valid() ? *process_id.data() : 0;
|
||||
}
|
||||
|
||||
int32_t WindowUtilX11::GetWindowStatus(::Window window) {
|
||||
// Get WM_STATE property of the window.
|
||||
XWindowProperty<uint32_t> window_state(display(), window, wm_state_atom_);
|
||||
|
||||
// WM_STATE is considered to be set to -1 when it missing.
|
||||
int32_t state = window_state.is_valid() ? *window_state.data() : -1;
|
||||
return state;
|
||||
}
|
||||
|
||||
bool WindowUtilX11::GetWindowFrameExtents(::Window window,
|
||||
int32_t &left, int32_t &top,
|
||||
int32_t &right, int32_t &bottom) {
|
||||
//reset it first
|
||||
left = top = right = bottom =0;
|
||||
|
||||
Atom actual_type;
|
||||
int actual_format;
|
||||
unsigned long nitems;
|
||||
unsigned long bytes_remaining;
|
||||
unsigned char *data;
|
||||
int status;
|
||||
|
||||
status = XGetWindowProperty(display(),
|
||||
window,
|
||||
frame_extends_atom_,
|
||||
0, // long_offset
|
||||
4, // long_length - we expect 4 32-bit values for _NET_FRAME_EXTENTS
|
||||
False, // delete
|
||||
AnyPropertyType,
|
||||
&actual_type,
|
||||
&actual_format,
|
||||
&nitems,
|
||||
&bytes_remaining,
|
||||
&data);
|
||||
|
||||
if (status == Success) {
|
||||
if ((nitems == 4) && (bytes_remaining == 0)) {
|
||||
long *data_as_long = (long *)((void *) data);
|
||||
left = (int) *(data_as_long++);
|
||||
right = (int) *(data_as_long++);
|
||||
top = (int) *(data_as_long++);
|
||||
bottom = (int) *(data_as_long++);
|
||||
return true;
|
||||
}
|
||||
XFree (data);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WindowUtilX11::GetWindowRect(::Window window, XRectangle & rcWindow, bool bWithFrame) {
|
||||
// reset
|
||||
rcWindow.x = rcWindow.y = rcWindow.width = rcWindow.height = 0;
|
||||
|
||||
// get window info
|
||||
XWindowAttributes win_info;
|
||||
if (!XGetWindowAttributes(display(), window, &win_info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int absx,absy;
|
||||
::Window temp_win;
|
||||
::Window root_win = DefaultRootWindow(display());
|
||||
if (!XTranslateCoordinates(display(), window, root_win, 0, 0, &absx, &absy, &temp_win)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Adjust to limit in screen
|
||||
XRectangle screen_rect;
|
||||
int nScreenCX = DisplayWidth(display(), DefaultScreen(display()));
|
||||
int nScreenCY = DisplayHeight(display(), DefaultScreen(display()));
|
||||
screen_rect.x = 0;
|
||||
screen_rect.y = 0;
|
||||
screen_rect.width = nScreenCX;
|
||||
screen_rect.height = nScreenCY;
|
||||
|
||||
if (absx < 0) {
|
||||
win_info.width += absx;
|
||||
absx = 0;
|
||||
} else if ((absx + win_info.width) > nScreenCX) {
|
||||
win_info.width = nScreenCX - absx;
|
||||
}
|
||||
if (absy < 0) {
|
||||
win_info.height += absy;
|
||||
absy = 0;
|
||||
} else if ((absy + win_info.height) > nScreenCY) {
|
||||
win_info.height = nScreenCY - absy;
|
||||
}
|
||||
|
||||
// data setting
|
||||
rcWindow.x = absx;
|
||||
rcWindow.y = absy;
|
||||
rcWindow.width = win_info.width;
|
||||
rcWindow.height = win_info.height;
|
||||
|
||||
if (bWithFrame) {
|
||||
int left;
|
||||
int right;
|
||||
int top;
|
||||
int bottom;
|
||||
if (GetWindowFrameExtents(window, left, top, right, bottom)) {
|
||||
rcWindow.x -= left;
|
||||
rcWindow.y -= top;
|
||||
rcWindow.width += (left + right);
|
||||
rcWindow.height += (top + bottom);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}//namespace webrtc
|
119
media/webrtc/trunk/webrtc/modules/desktop_capture/x11/shared_x_util.h
Executable file
119
media/webrtc/trunk/webrtc/modules/desktop_capture/x11/shared_x_util.h
Executable file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_X11_SHARED_X_UTIL_H_
|
||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_X11_SHARED_X_UTIL_H_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <assert.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
#include <X11/extensions/Xrender.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/system_wrappers/interface/atomic32.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_refptr.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
//===============================================================================
|
||||
// Moved common code from window_capture_x11.cc to better reuse throughout module
|
||||
|
||||
// Convenience wrapper for XGetWindowProperty() results.
|
||||
template <class PropertyType>
|
||||
class XWindowProperty {
|
||||
public:
|
||||
XWindowProperty(Display* display, Window window, Atom property) :
|
||||
is_valid_(false),
|
||||
size_(0),
|
||||
data_(NULL) {
|
||||
const int kBitsPerByte = 8;
|
||||
Atom actual_type;
|
||||
int actual_format;
|
||||
unsigned long bytes_after; // NOLINT: type required by XGetWindowProperty
|
||||
int status = XGetWindowProperty(display, window, property, 0L, ~0L, False,
|
||||
AnyPropertyType, &actual_type,
|
||||
&actual_format, &size_,
|
||||
&bytes_after, &data_);
|
||||
if (status != Success) {
|
||||
data_ = NULL;
|
||||
return;
|
||||
}
|
||||
if (sizeof(PropertyType) * kBitsPerByte != actual_format) {
|
||||
size_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
is_valid_ = true;
|
||||
}
|
||||
|
||||
~XWindowProperty() {
|
||||
if (data_) {
|
||||
XFree(data_);
|
||||
}
|
||||
}
|
||||
|
||||
// True if we got properly value successfully.
|
||||
bool is_valid() const { return is_valid_; }
|
||||
|
||||
// Size and value of the property.
|
||||
size_t size() const { return size_; }
|
||||
const PropertyType* data() const {
|
||||
return reinterpret_cast<PropertyType*>(data_);
|
||||
}
|
||||
PropertyType* data() {
|
||||
return reinterpret_cast<PropertyType*>(data_);
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_valid_;
|
||||
unsigned long size_; // NOLINT: type required by XGetWindowProperty
|
||||
unsigned char* data_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(XWindowProperty);
|
||||
};
|
||||
|
||||
class WindowUtilX11 {
|
||||
public:
|
||||
WindowUtilX11(scoped_refptr<SharedXDisplay> x_display);
|
||||
~WindowUtilX11();
|
||||
// Iterates through |window| hierarchy to find first visible window, i.e. one
|
||||
// that has WM_STATE property set to NormalState.
|
||||
// See http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1 .
|
||||
::Window GetApplicationWindow(::Window window);
|
||||
// Returns true if the |window| is a desktop element.
|
||||
bool IsDesktopElement(::Window window);
|
||||
// Returns window title for the specified X |window|.
|
||||
bool GetWindowTitle(::Window window, std::string* title);
|
||||
bool BringWindowToFront(::Window window);
|
||||
int GetWindowProcessID(::Window window);
|
||||
int32_t GetWindowStatus(::Window window);
|
||||
bool GetWindowRect(::Window window, XRectangle &rcWindow,bool bWithFrame);
|
||||
bool GetWindowFrameExtents(::Window window, int32_t &left, int32_t &top, int32_t &right, int32_t &bottom);
|
||||
|
||||
protected:
|
||||
Display* display() { return x_display_->display(); }
|
||||
|
||||
scoped_refptr<SharedXDisplay> x_display_;
|
||||
Atom wm_state_atom_;
|
||||
Atom window_type_atom_;
|
||||
Atom normal_window_type_atom_;
|
||||
Atom process_atom_;
|
||||
Atom frame_extends_atom_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_X11_SHARED_X_UTIL_H_
|
Loading…
Reference in New Issue
Block a user