shared_x_display.cc (3399B)
1 /* 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "modules/desktop_capture/linux/x11/shared_x_display.h" 12 13 #include <X11/Xlib.h> 14 #if !defined(WEBRTC_MOZILLA_BUILD) 15 #include <X11/extensions/XTest.h> 16 #endif 17 18 #include <algorithm> 19 #include <cstddef> 20 #include <string> 21 #include <vector> 22 23 #include "absl/strings/string_view.h" 24 #include "api/scoped_refptr.h" 25 #include "rtc_base/checks.h" 26 #include "rtc_base/logging.h" 27 #include "rtc_base/synchronization/mutex.h" 28 29 namespace webrtc { 30 31 SharedXDisplay::SharedXDisplay(Display* display) : display_(display) { 32 RTC_DCHECK(display_); 33 } 34 35 SharedXDisplay::~SharedXDisplay() { 36 RTC_DCHECK(event_handlers_.empty()); 37 XCloseDisplay(display_); 38 } 39 40 // static 41 scoped_refptr<SharedXDisplay> SharedXDisplay::Create( 42 absl::string_view display_name) { 43 Display* display = XOpenDisplay( 44 display_name.empty() ? nullptr : std::string(display_name).c_str()); 45 if (!display) { 46 RTC_LOG(LS_ERROR) << "Unable to open display"; 47 return nullptr; 48 } 49 return scoped_refptr<SharedXDisplay>(new SharedXDisplay(display)); 50 } 51 52 // static 53 scoped_refptr<SharedXDisplay> SharedXDisplay::CreateDefault() { 54 return Create(std::string()); 55 } 56 57 void SharedXDisplay::AddEventHandler(int type, XEventHandler* handler) { 58 MutexLock lock(&mutex_); 59 event_handlers_[type].push_back(handler); 60 } 61 62 void SharedXDisplay::RemoveEventHandler(int type, XEventHandler* handler) { 63 MutexLock lock(&mutex_); 64 EventHandlersMap::iterator handlers = event_handlers_.find(type); 65 if (handlers == event_handlers_.end()) 66 return; 67 68 std::erase(handlers->second, handler); 69 70 // Check if no handlers left for this event. 71 if (handlers->second.empty()) 72 event_handlers_.erase(handlers); 73 } 74 75 void SharedXDisplay::ProcessPendingXEvents() { 76 // Hold reference to `this` to prevent it from being destroyed while 77 // processing events. 78 scoped_refptr<SharedXDisplay> self(this); 79 80 // Protect access to `event_handlers_` after incrementing the refcount for 81 // `this` to ensure the instance is still valid when the lock is acquired. 82 MutexLock lock(&mutex_); 83 84 // Find the number of events that are outstanding "now." We don't just loop 85 // on XPending because we want to guarantee this terminates. 86 int events_to_process = XPending(display()); 87 XEvent e; 88 89 for (int i = 0; i < events_to_process; i++) { 90 XNextEvent(display(), &e); 91 EventHandlersMap::iterator handlers = event_handlers_.find(e.type); 92 if (handlers == event_handlers_.end()) 93 continue; 94 for (std::vector<XEventHandler*>::iterator it = handlers->second.begin(); 95 it != handlers->second.end(); ++it) { 96 if ((*it)->HandleXEvent(e)) 97 break; 98 } 99 } 100 } 101 102 void SharedXDisplay::IgnoreXServerGrabs() { 103 #if !defined(WEBRTC_MOZILLA_BUILD) 104 int test_event_base = 0; 105 int test_error_base = 0; 106 int major = 0; 107 int minor = 0; 108 if (XTestQueryExtension(display(), &test_event_base, &test_error_base, &major, 109 &minor)) { 110 XTestGrabControl(display(), true); 111 } 112 #endif 113 } 114 115 } // namespace webrtc