blob: c5fac03cfc4e001f7d9a4c838eb5fc376796e21e [file] [log] [blame]
// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "window_manager/real_x_connection.h"
extern "C" {
#include <X11/extensions/randr.h>
#include <X11/extensions/shape.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrandr.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/XKBlib.h>
}
#include "chromeos/obsolete_logging.h"
#include "window_manager/util.h"
namespace chromeos {
using std::string;
using std::vector;
using std::hex;
// Maximum number of integer values to allow in a property.
static const size_t kMaxIntPropertySize = 1024;
static int (*old_error_handler)(Display*, XErrorEvent*) = NULL;
static int last_trapped_error_code = 0;
static int last_trapped_request_code = 0;
static int last_trapped_minor_code = 0;
static int HandleXError(Display* display, XErrorEvent* event) {
last_trapped_error_code = event->error_code;
last_trapped_request_code = event->request_code;
last_trapped_minor_code = event->minor_code;
LOG(WARNING) << "Handled X error on display " << display << ":"
<< " error=" << last_trapped_error_code
<< " request=" << last_trapped_request_code
<< " minor=" << last_trapped_minor_code;
return 0;
}
RealXConnection::RealXConnection(Display* display)
: display_(display) {
CHECK(display_);
// TODO: Maybe handle multiple screens later, but we just use the default
// one for now.
root_ = DefaultRootWindow(display_);
CHECK(GetAtom("UTF8_STRING", &utf8_string_atom_));
int error_base = 0; // unused; the Shape extension doesn't define any errors
CHECK(XShapeQueryExtension(display_, &shape_event_base_, &error_base) == True)
<< "Shape extension unsupported by X server";
CHECK(XRRQueryExtension(display_, &xrandr_event_base_, &error_base) == True)
<< "XRandR extension unsupported by X server";
}
bool RealXConnection::GetWindowGeometry(
XWindow xid, int* x, int* y, int* width, int* height) {
TrapErrors();
XWindow root_ret;
int x_ret, y_ret;
unsigned int width_ret, height_ret, border_ret, depth_ret;
XGetGeometry(display_, xid, &root_ret, &x_ret, &y_ret, &width_ret,
&height_ret, &border_ret, &depth_ret);
if (x) *x = x_ret;
if (y) *y = y_ret;
if (width) *width = width_ret;
if (height) *height = height_ret;
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while getting geometry for window "
<< XidStr(xid) << ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::MapWindow(XWindow xid) {
TrapErrors();
XMapWindow(display_, xid);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while mapping window " << XidStr(xid) << ": "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::UnmapWindow(XWindow xid) {
TrapErrors();
XUnmapWindow(display_, xid);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while unmapping window " << XidStr(xid) << ": "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::MoveWindow(XWindow xid, int x, int y) {
TrapErrors();
XMoveWindow(display_, xid, x, y);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while moving window " << XidStr(xid) << ": "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::ResizeWindow(XWindow xid, int width, int height) {
TrapErrors();
XResizeWindow(display_, xid, width, height);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while resizing window " << XidStr(xid) << ": "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::ConfigureWindow(
XWindow xid, int x, int y, int width, int height) {
TrapErrors();
XWindowChanges changes;
changes.x = x;
changes.y = y;
changes.width = width;
changes.height = height;
XConfigureWindow(display_, xid, CWX | CWY | CWWidth | CWHeight, &changes);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while configuring window " << XidStr(xid)
<< ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::RaiseWindow(XWindow xid) {
TrapErrors();
XRaiseWindow(display_, xid);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while raising window " << XidStr(xid) << ": "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::FocusWindow(XWindow xid, Time event_time) {
VLOG(1) << "Focusing window " << XidStr(xid);
TrapErrors();
XSetInputFocus(display_, xid, RevertToParent, event_time);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while focusing window " << XidStr(xid) << ": "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::StackWindow(XWindow xid, XWindow other, bool above) {
TrapErrors();
XWindowChanges changes;
changes.sibling = other;
changes.stack_mode = above ? Above : Below;
XConfigureWindow(display_, xid, CWSibling | CWStackMode, &changes);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while stacking window " << XidStr(xid) << ": "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::ReparentWindow(
XWindow xid, XWindow parent, int x, int y) {
TrapErrors();
XReparentWindow(display_, xid, parent, x, y);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while reparenting window " << XidStr(xid)
<< ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::SetWindowBorderWidth(XWindow xid, int width) {
DCHECK_GE(width, 0);
TrapErrors();
XWindowChanges changes;
changes.border_width = width;
XConfigureWindow(display_, xid, CWBorderWidth, &changes);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while setting " << XidStr(xid)
<< "'s border width to " << width << ": "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::SelectInputOnWindow(
XWindow xid, int event_mask, bool preserve_existing) {
TrapErrors();
if (preserve_existing) {
XWindowAttributes attr;
XGetWindowAttributes(display_, xid, &attr);
event_mask |= attr.your_event_mask;
}
if (!GetLastErrorCode()) {
// Only select the new mask if we were successful in fetching the
// previous one to avoid blowing away the previous mask on failure.
XSelectInput(display_, xid, event_mask);
}
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while selecting input on window "
<< XidStr(xid) << ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::DeselectInputOnWindow(XWindow xid, int event_mask) {
TrapErrors();
XWindowAttributes attr;
XGetWindowAttributes(display_, xid, &attr);
attr.your_event_mask &= ~event_mask;
if (!GetLastErrorCode()) {
// Only select the new mask if we were successful in fetching the
// previous one to avoid blowing away the previous mask on failure.
XSelectInput(display_, xid, attr.your_event_mask);
}
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while deselecting input on window "
<< XidStr(xid) << ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::AddPassiveButtonGrabOnWindow(
XWindow xid, int button, int event_mask) {
TrapErrors();
XGrabButton(display_,
button,
0, // modifiers
xid,
False, // owner_events
event_mask,
GrabModeSync, // pointer_mode
GrabModeAsync, // keyboard_mode
None, // confine_to
None); // cursor
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while installing passive grab for button "
<< button << " on window " << XidStr(xid) << ": "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::RemovePassiveButtonGrabOnWindow(XWindow xid, int button) {
TrapErrors();
XUngrabButton(display_, button, None, xid);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while uninstalling passive grab for button "
<< button << " on window " << XidStr(xid) << ": "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::AddActivePointerGrabForWindow(XWindow xid,
int event_mask,
Time timestamp) {
TrapErrors();
int result = XGrabPointer(display_,
xid,
False, // owner_events
event_mask,
GrabModeAsync, // pointer_mode
GrabModeAsync, // keyboard_mode
None, // confine_to
None, // cursor
timestamp);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while actively grabbing pointer for window "
<< XidStr(xid) << ": " << GetErrorText(error);
return false;
} else if (result != GrabSuccess) {
LOG(WARNING) << "Active pointer grab for window " << XidStr(xid)
<< " failed with " << result;
return false;
}
return true;
}
bool RealXConnection::RemoveActivePointerGrab(bool replay_events) {
TrapErrors();
if (replay_events) {
XAllowEvents(display_, ReplayPointer, CurrentTime);
} else {
XUngrabPointer(display_, CurrentTime);
}
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while repeating grabbed button events: "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::RemoveInputRegionFromWindow(XWindow xid) {
TrapErrors();
XShapeCombineRectangles(display_,
xid,
ShapeInput,
0, // x_off
0, // y_off
NULL, // rectangles
0, // n_rects
ShapeSet,
Unsorted);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while removing input region from "
<< XidStr(xid) << ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::GetSizeHintsForWindow(
XWindow xid, XSizeHints* hints, long* supplied_hints) {
TrapErrors();
int result = XGetWMNormalHints(display_, xid, hints, supplied_hints);
int error = UntrapErrors();
if (!result || error) {
if (error) {
LOG(WARNING) << "Got X error while getting hints for " << XidStr(xid)
<< ": " << GetErrorText(error);
}
return false;
}
return true;
}
bool RealXConnection::GetTransientHintForWindow(
XWindow xid, XWindow* owner_out) {
CHECK(owner_out);
*owner_out = None;
TrapErrors();
XGetTransientForHint(display_, xid, owner_out);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while getting WM_TRANSIENT_FOR for "
<< "window " << XidStr(xid) << ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::GetWindowAttributes(
XWindow xid, XWindowAttributes* attr_out) {
TrapErrors();
int result = XGetWindowAttributes(display_, xid, attr_out);
int error = UntrapErrors();
if (!result || error) {
if (error) {
LOG(WARNING) << "Got X error while getting attributes for window "
<< XidStr(xid) << ": " << GetErrorText(error);
}
return false;
}
return true;
}
bool RealXConnection::RedirectWindowForCompositing(XWindow xid) {
TrapErrors();
// TODO: Manual or Automatic here?
XCompositeRedirectWindow(display_, xid, CompositeRedirectManual);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while redirecting window " << XidStr(xid)
<< ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::UnredirectWindowForCompositing(XWindow xid) {
TrapErrors();
// TODO: Manual or Automatic here? What does the 'update' parameter even
// mean when we're *un*-redirecting a window?
XCompositeUnredirectWindow(display_, xid, CompositeRedirectManual);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while unredirecting window " << XidStr(xid)
<< ": " << GetErrorText(error);
return false;
}
return true;
}
XWindow RealXConnection::GetCompositingOverlayWindow(XWindow root) {
TrapErrors();
XWindow xid = XCompositeGetOverlayWindow(display_, root);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while getting overlay window: "
<< GetErrorText(error);
return None;
}
return xid;
}
XWindow RealXConnection::CreateWindow(
XWindow parent,
int x, int y,
int width, int height,
bool override_redirect,
bool input_only,
int event_mask) {
CHECK_GT(width, 0);
CHECK_GT(height, 0);
CHECK_NE(parent, None);
TrapErrors();
XSetWindowAttributes attr;
attr.override_redirect = override_redirect ? True : False;
attr.event_mask = event_mask;
XWindow xid = XCreateWindow(display_,
parent,
x, y,
width, height,
0, // border width
CopyFromParent, // depth
input_only ? InputOnly : CopyFromParent, // class
CopyFromParent, // visual
CWOverrideRedirect | CWEventMask,
&attr);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while creating window: "
<< GetErrorText(error);
return None;
}
return xid;
}
bool RealXConnection::DestroyWindow(XWindow xid) {
TrapErrors();
XDestroyWindow(display_, xid);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while destroying window " << XidStr(xid)
<< ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::IsWindowShaped(XWindow xid) {
TrapErrors();
Bool bounding_shaped = False, clip_shaped = False;
int x_bounding = 0, y_bounding = 0;
uint w_bounding = 0, h_bounding = 0;
int x_clip = 0, y_clip = 0;
uint w_clip = 0, h_clip = 0;
XShapeQueryExtents(
display_, xid,
&bounding_shaped, &x_bounding, &y_bounding, &w_bounding, &h_bounding,
&clip_shaped, &x_clip, &y_clip, &w_clip, &h_clip);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while checking if window " << XidStr(xid)
<< " is shaped: " << GetErrorText(error);
return false;
}
return (bounding_shaped == True);
}
bool RealXConnection::SelectShapeEventsOnWindow(XWindow xid) {
TrapErrors();
XShapeSelectInput(display_, xid, ShapeNotifyMask);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while selecting ShapeNotify events on "
<< XidStr(xid) << ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::GetWindowBoundingRegion(XWindow xid, ByteMap* bytemap) {
TrapErrors();
int count = 0, ordering = 0;
XRectangle* rects =
XShapeGetRectangles(display_, xid, ShapeBounding, &count, &ordering);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while getting bounding rectangles for "
<< XidStr(xid) << ": " << GetErrorText(error);
return false;
}
bytemap->Clear(0x0);
for (int i = 0; i < count; ++i) {
const XRectangle& rect = rects[i];
bytemap->SetRectangle(rect.x, rect.y, rect.width, rect.height, 0xff);
}
XFree(rects);
return true;
}
bool RealXConnection::SelectXRandREventsOnWindow(XWindow xid) {
TrapErrors();
XRRSelectInput(display_, xid, RRScreenChangeNotifyMask);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while selecting RRScreenChangeNotify events "
<< "on " << XidStr(xid) << ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::GetAtom(const string& name, XAtom* atom_out) {
CHECK(atom_out);
TrapErrors();
*atom_out = XInternAtom(display_, const_cast<char*>(name.c_str()), false);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while getting atom \"" << name << "\": "
<< GetErrorText(error);
return false;
}
if (*atom_out == None) {
LOG(WARNING) << "Unable to get atom \"" << name << "\"";
return false;
}
return true;
}
bool RealXConnection::GetAtoms(
const vector<string>& names, vector<XAtom>* atoms_out) {
CHECK(atoms_out);
atoms_out->clear();
char** names_array = new char*[names.size()];
XAtom* atoms_array = new XAtom[names.size()];
for (size_t i = 0; i < names.size(); ++i) {
// Need to const_cast because XInternAtoms() wants a char**.
names_array[i] = const_cast<char*>(names.at(i).c_str());
}
TrapErrors();
int result = XInternAtoms(display_,
names_array,
names.size(),
False, // only_if_exists
atoms_array);
int error = UntrapErrors();
if (!result || error) {
if (error) {
LOG(WARNING) << "Got X error while getting atoms: "
<< GetErrorText(error);
}
delete[] names_array;
delete[] atoms_array;
return false;
}
for (size_t i = 0; i < names.size(); ++i) {
atoms_out->push_back(atoms_array[i]);
}
delete[] names_array;
delete[] atoms_array;
return true;
}
bool RealXConnection::GetAtomName(XAtom atom, string* name) {
CHECK(name);
TrapErrors();
char* name_ptr = XGetAtomName(display_, atom);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while looking up atom " << XidStr(atom) << ": "
<< GetErrorText(error);
if (name_ptr) {
XFree(name_ptr);
}
return false;
}
if (!name_ptr) {
LOG(WARNING) << "Got NULL string while looking up atom " << XidStr(atom);
return false;
}
name->assign(name_ptr);
XFree(name_ptr);
return true;
}
bool RealXConnection::GetIntArrayProperty(
XWindow xid, XAtom xatom, vector<int>* values) {
CHECK(values);
values->clear();
XAtom type = None;
int format = 0; // size in bits of each item in 'property'
long unsigned int num_items = 0, remaining_bytes = 0;
unsigned char* property = NULL;
TrapErrors();
XGetWindowProperty(display_,
xid,
xatom,
0, // offset into property data to read
kMaxIntPropertySize, // length to get in 32-bit quantities
False, // deleted
AnyPropertyType,
&type,
&format,
&num_items,
&remaining_bytes,
&property);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while getting int property " << XidStr(xatom)
<< " for window " << XidStr(xid) << ": "
<< GetErrorText(error);
return false;
}
if (format == 0) {
// Okay, the property just wasn't set.
return false;
}
// Only read data containing a single 32-bit item.
if (format != kLongFormat) {
LOG(WARNING) << "Not reading property " << XidStr(xatom) << " for window "
<< XidStr(xid) << "; it's supposed to have a 32-bit format "
<< "but is actually " << format << "-bit";
XFree(property);
return false;
}
if (num_items < 1 || remaining_bytes != 0) {
LOG(WARNING) << "Not reading property " << XidStr(xatom) << " for window "
<< XidStr(xid) << "; we got " << num_items << " ints and have "
<< remaining_bytes << " byte(s) remaining (we expected at "
<< "least one int)";
XFree(property);
return false;
}
for (size_t i = 0; i < num_items; ++i) {
values->push_back(reinterpret_cast<int*>(property)[i]);
}
XFree(property);
return true;
}
bool RealXConnection::SetIntArrayProperty(
XWindow xid, XAtom xatom, XAtom type, const vector<int>& values) {
if (values.size() > kMaxIntPropertySize) {
LOG(WARNING) << "Setting int property " << XidStr(xatom) << " for window "
<< XidStr(xid) << " with " << values.size()
<< " values (max is " << kMaxIntPropertySize << ")";
}
CHECK(!values.empty());
int* buf = new int[values.size()];
for (size_t i = 0; i < values.size(); ++i) {
buf[i] = values[i];
}
TrapErrors();
XChangeProperty(display_,
xid,
xatom,
type,
kLongFormat, // size in bits of items in 'value'
PropModeReplace,
reinterpret_cast<const unsigned char*>(buf),
values.size()); // num items
delete[] buf;
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while setting int property " << xatom
<< " for window " << xid << ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::GetStringProperty(XWindow xid, XAtom xatom, string* out) {
CHECK(out);
out->clear();
XAtom type = None;
int format = 0; // size in bits of each item in 'property'
long unsigned int num_items = 0, remaining_bytes = 0;
unsigned char* property = NULL;
TrapErrors();
int result = XGetWindowProperty(display_,
xid,
xatom,
0, // offset
1024, // max size
false, // deleted
AnyPropertyType,
&type,
&format,
&num_items,
&remaining_bytes,
&property);
int error = UntrapErrors();
if (result != Success) {
LOG(WARNING) << "Unable to get property " << XidStr(xatom)
<< " for window " << XidStr(xid);
return false;
}
if (error) {
LOG(WARNING) << "Got X error while getting property " << XidStr(xatom)
<< " for window " << XidStr(xid) << ": "
<< GetErrorText(error);
return false;
}
// Only read data containing 8-bit items.
if (format == kByteFormat) {
if (type != XA_STRING && type != utf8_string_atom_) {
LOG(WARNING) << "Getting property " << XidStr(xatom)
<< " with unsupported type " << type
<< " as string for window " << XidStr(xid);
}
out->assign(reinterpret_cast<char*>(property), num_items);
}
XFree(property);
return true;
}
bool RealXConnection::SetStringProperty(
XWindow xid, XAtom xatom, const string& value) {
TrapErrors();
XChangeProperty(display_,
xid,
xatom,
utf8_string_atom_,
kByteFormat, // size in bits of items in 'value'
PropModeReplace,
reinterpret_cast<const unsigned char*>(value.c_str()),
value.size());
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while setting string property "
<< XidStr(xatom) << " to \"" << value << "\" for window "
<< XidStr(xid) << ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::DeletePropertyIfExists(XWindow xid, XAtom xatom) {
TrapErrors();
XDeleteProperty(display_, xid, xatom);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while deleting property " << XidStr(xatom)
<< " for window " << XidStr(xid) << ": "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::SendEvent(XWindow xid, XEvent* event, int event_mask) {
CHECK(event);
TrapErrors();
XSendEvent(display_,
xid,
False, // propagate
event_mask,
event);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while sending message to window "
<< XidStr(xid) << ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::WaitForEvent(
XWindow xid, int event_mask, XEvent* event_out) {
CHECK(event_out);
TrapErrors();
XWindowEvent(display_, xid, event_mask, event_out);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while waiting for event on window "
<< XidStr(xid) << ": " << GetErrorText(error);
return false;
}
return true;
}
XWindow RealXConnection::GetSelectionOwner(XAtom atom) {
TrapErrors();
XWindow xid = XGetSelectionOwner(display_, atom);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while getting selection owner for "
<< XidStr(atom) << ": " << GetErrorText(error);
return None;
}
return xid;
}
bool RealXConnection::SetSelectionOwner(
XAtom atom, XWindow xid, Time timestamp) {
TrapErrors();
XSetSelectionOwner(display_, atom, xid, timestamp);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while setting selection owner for "
<< XidStr(atom) << ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::SetWindowCursor(XWindow xid, uint32 shape) {
TrapErrors();
XSetWindowAttributes attr;
attr.cursor = XCreateFontCursor(display_, shape);
XChangeWindowAttributes(display_, xid, CWCursor, &attr);
// TODO(derat): Do we need to free the result of XCreateFontCursor above?
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while changing cursor for " << XidStr(xid)
<< ": " << GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::GetChildWindows(XWindow xid,
vector<XWindow>* children_out) {
CHECK(children_out);
children_out->clear();
XWindow root_return, parent_return;
XWindow* children = NULL;
unsigned int num_children = 0;
TrapErrors();
int result = XQueryTree(display_, xid, &root_return, &parent_return,
&children, &num_children);
int error = UntrapErrors();
if (!result || error) {
if (error) {
LOG(WARNING) << "Got X error while querying windows under " << XidStr(xid)
<< ": " << GetErrorText(error);
}
return false;
}
if (!children) {
return true;
}
for (unsigned int i = 0; i < num_children; ++i) {
children_out->push_back(children[i]);
}
XFree(children);
return true;
}
bool RealXConnection::GetParentWindow(XWindow xid, XWindow* parent) {
CHECK(parent);
XWindow root_return, parent_return;
XWindow* children = NULL;
unsigned int num_children = 0;
TrapErrors();
int result = XQueryTree(display_, xid, &root_return, &parent_return,
&children, &num_children);
*parent = parent_return;
if (children)
XFree(children);
int error = UntrapErrors();
if (!result || error) {
if (error) {
LOG(WARNING) << "Got X error while querying parent window for "
<< XidStr(xid) << ": " << GetErrorText(error);
}
return false;
}
return true;
}
KeySym RealXConnection::GetKeySymFromKeyCode(uint32 keycode) {
return XKeycodeToKeysym(display_, keycode, 0);
}
uint32 RealXConnection::GetKeyCodeFromKeySym(KeySym keysym) {
return XKeysymToKeycode(display_, keysym);
}
string RealXConnection::GetStringFromKeySym(KeySym keysym) {
char* ptr = XKeysymToString(keysym);
if (!ptr) {
return "";
}
return string(ptr);
}
bool RealXConnection::GrabKey(KeyCode keycode, uint32 modifiers) {
TrapErrors();
XGrabKey(display_,
keycode,
modifiers,
root_,
False, // owner_events
GrabModeAsync, // pointer_mode
GrabModeAsync); // keyboard_mode
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while grabbing key " << keycode
<< " with modifiers 0x" << hex << modifiers << ": "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::UngrabKey(KeyCode keycode, uint32 modifiers) {
TrapErrors();
XUngrabKey(display_, keycode, modifiers, root_);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while ungrabbing key " << keycode
<< " with modifiers 0x" << hex << modifiers << ": "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::SetDetectableKeyboardAutoRepeat(bool detectable) {
Bool supported = False;
XkbSetDetectableAutoRepeat(
display_, detectable ? True : False, &supported);
return (supported == True ? true : false);
}
bool RealXConnection::GrabServerImpl() {
TrapErrors();
XGrabServer(display_);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while grabbing server: "
<< GetErrorText(error);
return false;
}
return true;
}
bool RealXConnection::UngrabServerImpl() {
TrapErrors();
XUngrabServer(display_);
if (int error = UntrapErrors()) {
LOG(WARNING) << "Got X error while ungrabbing server: "
<< GetErrorText(error);
return false;
}
return true;
}
void RealXConnection::TrapErrors() {
CHECK(!old_error_handler) << "X errors are already being trapped";
old_error_handler = XSetErrorHandler(&HandleXError);
last_trapped_error_code = 0;
last_trapped_request_code = 0;
last_trapped_minor_code = 0;
}
int RealXConnection::UntrapErrors() {
CHECK(old_error_handler) << "X errors aren't being trapped";
// Sync in case we sent a request that didn't require a reply.
// TODO: It seems kinda wasteful to always do this.
XSync(display_, False);
XSetErrorHandler(old_error_handler);
old_error_handler = NULL;
return last_trapped_error_code;
}
int RealXConnection::GetLastErrorCode() {
return last_trapped_error_code;
}
string RealXConnection::GetErrorText(int error_code) {
char str[1024];
XGetErrorText(display_, error_code, str, sizeof(str));
return string(str);
}
} // namespace chromeos