| Index: app/x11_util.cc
|
| ===================================================================
|
| --- app/x11_util.cc (revision 71854)
|
| +++ app/x11_util.cc (working copy)
|
| @@ -1,880 +0,0 @@
|
| -// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -// This file defines utility functions for X11 (Linux only). This code has been
|
| -// ported from XCB since we can't use XCB on Ubuntu while its 32-bit support
|
| -// remains woefully incomplete.
|
| -
|
| -#include "app/x11_util.h"
|
| -
|
| -#include <gdk/gdk.h>
|
| -#include <gdk/gdkx.h>
|
| -#include <gtk/gtk.h>
|
| -
|
| -#include <sys/ipc.h>
|
| -#include <sys/shm.h>
|
| -
|
| -#include <list>
|
| -#include <set>
|
| -
|
| -#include "base/command_line.h"
|
| -#include "base/logging.h"
|
| -#include "base/stringprintf.h"
|
| -#include "base/string_number_conversions.h"
|
| -#include "base/threading/thread.h"
|
| -#include "app/x11_util_internal.h"
|
| -#include "gfx/rect.h"
|
| -#include "gfx/size.h"
|
| -
|
| -namespace x11_util {
|
| -
|
| -namespace {
|
| -
|
| -// Used to cache the XRenderPictFormat for a visual/display pair.
|
| -struct CachedPictFormat {
|
| - bool equals(Display* display, Visual* visual) const {
|
| - return display == this->display && visual == this->visual;
|
| - }
|
| -
|
| - Display* display;
|
| - Visual* visual;
|
| - XRenderPictFormat* format;
|
| -};
|
| -
|
| -typedef std::list<CachedPictFormat> CachedPictFormats;
|
| -
|
| -// Returns the cache of pict formats.
|
| -CachedPictFormats* get_cached_pict_formats() {
|
| - static CachedPictFormats* formats = NULL;
|
| - if (!formats)
|
| - formats = new CachedPictFormats();
|
| - return formats;
|
| -}
|
| -
|
| -// Maximum number of CachedPictFormats we keep around.
|
| -const size_t kMaxCacheSize = 5;
|
| -
|
| -int DefaultX11ErrorHandler(Display* d, XErrorEvent* e) {
|
| - LOG(ERROR) << GetErrorEventDescription(d, e);
|
| - return 0;
|
| -}
|
| -
|
| -int DefaultX11IOErrorHandler(Display* d) {
|
| - // If there's an IO error it likely means the X server has gone away
|
| - LOG(ERROR) << "X IO Error detected";
|
| - _exit(1);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -bool XDisplayExists() {
|
| - return (gdk_display_get_default() != NULL);
|
| -}
|
| -
|
| -Display* GetXDisplay() {
|
| - static Display* display = NULL;
|
| -
|
| - if (!display)
|
| - display = gdk_x11_get_default_xdisplay();
|
| -
|
| - return display;
|
| -}
|
| -
|
| -static SharedMemorySupport DoQuerySharedMemorySupport(Display* dpy) {
|
| - // A temporary flag for tracking down shared memory problems.
|
| - // TODO(evanm): remove this.
|
| - if (CommandLine::ForCurrentProcess()->HasSwitch("disable-xshm"))
|
| - return SHARED_MEMORY_NONE;
|
| -
|
| - int dummy;
|
| - Bool pixmaps_supported;
|
| - // Query the server's support for XSHM.
|
| - if (!XShmQueryVersion(dpy, &dummy, &dummy, &pixmaps_supported))
|
| - return SHARED_MEMORY_NONE;
|
| -
|
| - // Next we probe to see if shared memory will really work
|
| - int shmkey = shmget(IPC_PRIVATE, 1, 0666);
|
| - if (shmkey == -1)
|
| - return SHARED_MEMORY_NONE;
|
| - void* address = shmat(shmkey, NULL, 0);
|
| - // Mark the shared memory region for deletion
|
| - shmctl(shmkey, IPC_RMID, NULL);
|
| -
|
| - XShmSegmentInfo shminfo;
|
| - memset(&shminfo, 0, sizeof(shminfo));
|
| - shminfo.shmid = shmkey;
|
| -
|
| - gdk_error_trap_push();
|
| - bool result = XShmAttach(dpy, &shminfo);
|
| - XSync(dpy, False);
|
| - if (gdk_error_trap_pop())
|
| - result = false;
|
| - shmdt(address);
|
| - if (!result)
|
| - return SHARED_MEMORY_NONE;
|
| -
|
| - XShmDetach(dpy, &shminfo);
|
| - return pixmaps_supported ? SHARED_MEMORY_PIXMAP : SHARED_MEMORY_PUTIMAGE;
|
| -}
|
| -
|
| -SharedMemorySupport QuerySharedMemorySupport(Display* dpy) {
|
| - static SharedMemorySupport shared_memory_support = SHARED_MEMORY_NONE;
|
| - static bool shared_memory_support_cached = false;
|
| -
|
| - if (shared_memory_support_cached)
|
| - return shared_memory_support;
|
| -
|
| - shared_memory_support = DoQuerySharedMemorySupport(dpy);
|
| - shared_memory_support_cached = true;
|
| -
|
| - return shared_memory_support;
|
| -}
|
| -
|
| -bool QueryRenderSupport(Display* dpy) {
|
| - static bool render_supported = false;
|
| - static bool render_supported_cached = false;
|
| -
|
| - if (render_supported_cached)
|
| - return render_supported;
|
| -
|
| - // We don't care about the version of Xrender since all the features which
|
| - // we use are included in every version.
|
| - int dummy;
|
| - render_supported = XRenderQueryExtension(dpy, &dummy, &dummy);
|
| - render_supported_cached = true;
|
| -
|
| - return render_supported;
|
| -}
|
| -
|
| -int GetDefaultScreen(Display* display) {
|
| - return XDefaultScreen(display);
|
| -}
|
| -
|
| -XID GetX11RootWindow() {
|
| - return GDK_WINDOW_XID(gdk_get_default_root_window());
|
| -}
|
| -
|
| -bool GetCurrentDesktop(int* desktop) {
|
| - return GetIntProperty(GetX11RootWindow(), "_NET_CURRENT_DESKTOP", desktop);
|
| -}
|
| -
|
| -XID GetX11WindowFromGtkWidget(GtkWidget* widget) {
|
| - return GDK_WINDOW_XID(widget->window);
|
| -}
|
| -
|
| -XID GetX11WindowFromGdkWindow(GdkWindow* window) {
|
| - return GDK_WINDOW_XID(window);
|
| -}
|
| -
|
| -void* GetVisualFromGtkWidget(GtkWidget* widget) {
|
| - return GDK_VISUAL_XVISUAL(gtk_widget_get_visual(widget));
|
| -}
|
| -
|
| -int BitsPerPixelForPixmapDepth(Display* dpy, int depth) {
|
| - int count;
|
| - XPixmapFormatValues* formats = XListPixmapFormats(dpy, &count);
|
| - if (!formats)
|
| - return -1;
|
| -
|
| - int bits_per_pixel = -1;
|
| - for (int i = 0; i < count; ++i) {
|
| - if (formats[i].depth == depth) {
|
| - bits_per_pixel = formats[i].bits_per_pixel;
|
| - break;
|
| - }
|
| - }
|
| -
|
| - XFree(formats);
|
| - return bits_per_pixel;
|
| -}
|
| -
|
| -bool IsWindowVisible(XID window) {
|
| - XWindowAttributes win_attributes;
|
| - XGetWindowAttributes(GetXDisplay(), window, &win_attributes);
|
| - if (win_attributes.map_state != IsViewable)
|
| - return false;
|
| - // Some compositing window managers (notably kwin) do not actually unmap
|
| - // windows on desktop switch, so we also must check the current desktop.
|
| - int window_desktop, current_desktop;
|
| - return (!GetWindowDesktop(window, &window_desktop) ||
|
| - !GetCurrentDesktop(¤t_desktop) ||
|
| - window_desktop == kAllDesktops ||
|
| - window_desktop == current_desktop);
|
| -}
|
| -
|
| -bool GetWindowRect(XID window, gfx::Rect* rect) {
|
| - Window root, child;
|
| - int x, y;
|
| - unsigned int width, height;
|
| - unsigned int border_width, depth;
|
| -
|
| - if (!XGetGeometry(GetXDisplay(), window, &root, &x, &y,
|
| - &width, &height, &border_width, &depth))
|
| - return false;
|
| -
|
| - if (!XTranslateCoordinates(GetSecondaryDisplay(), window, root,
|
| - 0, 0, &x, &y, &child))
|
| - return false;
|
| -
|
| - *rect = gfx::Rect(x, y, width, height);
|
| - return true;
|
| -}
|
| -
|
| -bool GetIntProperty(XID window, const std::string& property_name, int* value) {
|
| - Atom property_atom = gdk_x11_get_xatom_by_name_for_display(
|
| - gdk_display_get_default(), property_name.c_str());
|
| -
|
| - Atom 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;
|
| -
|
| - int result = XGetWindowProperty(GetXDisplay(),
|
| - window,
|
| - property_atom,
|
| - 0, // offset into property data to read
|
| - 1, // max length to get
|
| - False, // deleted
|
| - AnyPropertyType,
|
| - &type,
|
| - &format,
|
| - &num_items,
|
| - &remaining_bytes,
|
| - &property);
|
| - if (result != Success)
|
| - return false;
|
| -
|
| - if (format != 32 || num_items != 1) {
|
| - XFree(property);
|
| - return false;
|
| - }
|
| -
|
| - *value = *(reinterpret_cast<int*>(property));
|
| - XFree(property);
|
| - return true;
|
| -}
|
| -
|
| -bool GetIntArrayProperty(XID window,
|
| - const std::string& property_name,
|
| - std::vector<int>* value) {
|
| - Atom property_atom = gdk_x11_get_xatom_by_name_for_display(
|
| - gdk_display_get_default(), property_name.c_str());
|
| -
|
| - Atom type = None;
|
| - int format = 0; // size in bits of each item in 'property'
|
| - long unsigned int num_items = 0, remaining_bytes = 0;
|
| - unsigned char* properties = NULL;
|
| -
|
| - int result = XGetWindowProperty(GetXDisplay(),
|
| - window,
|
| - property_atom,
|
| - 0, // offset into property data to read
|
| - (~0L), // max length to get (all of them)
|
| - False, // deleted
|
| - AnyPropertyType,
|
| - &type,
|
| - &format,
|
| - &num_items,
|
| - &remaining_bytes,
|
| - &properties);
|
| - if (result != Success)
|
| - return false;
|
| -
|
| - if (format != 32) {
|
| - XFree(properties);
|
| - return false;
|
| - }
|
| -
|
| - int* int_properties = reinterpret_cast<int*>(properties);
|
| - value->clear();
|
| - value->insert(value->begin(), int_properties, int_properties + num_items);
|
| - XFree(properties);
|
| - return true;
|
| -}
|
| -
|
| -bool GetStringProperty(
|
| - XID window, const std::string& property_name, std::string* value) {
|
| - Atom property_atom = gdk_x11_get_xatom_by_name_for_display(
|
| - gdk_display_get_default(), property_name.c_str());
|
| -
|
| - Atom 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;
|
| -
|
| - int result = XGetWindowProperty(GetXDisplay(),
|
| - window,
|
| - property_atom,
|
| - 0, // offset into property data to read
|
| - 1024, // max length to get
|
| - False, // deleted
|
| - AnyPropertyType,
|
| - &type,
|
| - &format,
|
| - &num_items,
|
| - &remaining_bytes,
|
| - &property);
|
| - if (result != Success)
|
| - return false;
|
| -
|
| - if (format != 8) {
|
| - XFree(property);
|
| - return false;
|
| - }
|
| -
|
| - value->assign(reinterpret_cast<char*>(property), num_items);
|
| - XFree(property);
|
| - return true;
|
| -}
|
| -
|
| -XID GetParentWindow(XID window) {
|
| - XID root = None;
|
| - XID parent = None;
|
| - XID* children = NULL;
|
| - unsigned int num_children = 0;
|
| - XQueryTree(GetXDisplay(), window, &root, &parent, &children, &num_children);
|
| - if (children)
|
| - XFree(children);
|
| - return parent;
|
| -}
|
| -
|
| -XID GetHighestAncestorWindow(XID window, XID root) {
|
| - while (true) {
|
| - XID parent = x11_util::GetParentWindow(window);
|
| - if (parent == None)
|
| - return None;
|
| - if (parent == root)
|
| - return window;
|
| - window = parent;
|
| - }
|
| -}
|
| -
|
| -bool GetWindowDesktop(XID window, int* desktop) {
|
| - return GetIntProperty(window, "_NET_WM_DESKTOP", desktop);
|
| -}
|
| -
|
| -// Returns true if |window| is a named window.
|
| -bool IsWindowNamed(XID window) {
|
| - XTextProperty prop;
|
| - if (!XGetWMName(GetXDisplay(), window, &prop) || !prop.value)
|
| - return false;
|
| -
|
| - XFree(prop.value);
|
| - return true;
|
| -}
|
| -
|
| -bool EnumerateChildren(EnumerateWindowsDelegate* delegate, XID window,
|
| - const int max_depth, int depth) {
|
| - if (depth > max_depth)
|
| - return false;
|
| -
|
| - XID root, parent, *children;
|
| - unsigned int num_children;
|
| - int status = XQueryTree(GetXDisplay(), window, &root, &parent, &children,
|
| - &num_children);
|
| - if (status == 0)
|
| - return false;
|
| -
|
| - std::set<XID> windows;
|
| - for (unsigned int i = 0; i < num_children; i++)
|
| - windows.insert(children[i]);
|
| -
|
| - XFree(children);
|
| -
|
| - // XQueryTree returns the children of |window| in bottom-to-top order, so
|
| - // reverse-iterate the list to check the windows from top-to-bottom.
|
| - std::set<XID>::reverse_iterator iter;
|
| - for (iter = windows.rbegin(); iter != windows.rend(); iter++) {
|
| - if (IsWindowNamed(*iter) && delegate->ShouldStopIterating(*iter))
|
| - return true;
|
| - }
|
| -
|
| - // If we're at this point, we didn't find the window we're looking for at the
|
| - // current level, so we need to recurse to the next level. We use a second
|
| - // loop because the recursion and call to XQueryTree are expensive and is only
|
| - // needed for a small number of cases.
|
| - if (++depth <= max_depth) {
|
| - for (iter = windows.rbegin(); iter != windows.rend(); iter++) {
|
| - if (EnumerateChildren(delegate, *iter, max_depth, depth))
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -bool EnumerateAllWindows(EnumerateWindowsDelegate* delegate, int max_depth) {
|
| - XID root = GetX11RootWindow();
|
| - return EnumerateChildren(delegate, root, max_depth, 0);
|
| -}
|
| -
|
| -bool GetXWindowStack(std::vector<XID>* windows) {
|
| - windows->clear();
|
| -
|
| - static Atom atom = XInternAtom(GetXDisplay(),
|
| - "_NET_CLIENT_LIST_STACKING", False);
|
| -
|
| - Atom type;
|
| - int format;
|
| - unsigned long count;
|
| - unsigned long bytes_after;
|
| - unsigned char *data = NULL;
|
| - if (XGetWindowProperty(GetXDisplay(),
|
| - GetX11RootWindow(),
|
| - atom,
|
| - 0, // offset
|
| - ~0L, // length
|
| - False, // delete
|
| - AnyPropertyType, // requested type
|
| - &type,
|
| - &format,
|
| - &count,
|
| - &bytes_after,
|
| - &data) != Success) {
|
| - return false;
|
| - }
|
| -
|
| - bool result = false;
|
| - if (type == XA_WINDOW && format == 32 && data && count > 0) {
|
| - result = true;
|
| - XID* stack = reinterpret_cast<XID*>(data);
|
| - for (unsigned long i = 0; i < count; i++)
|
| - windows->insert(windows->begin(), stack[i]);
|
| - }
|
| -
|
| - if (data)
|
| - XFree(data);
|
| -
|
| - return result;
|
| -}
|
| -
|
| -void RestackWindow(XID window, XID sibling, bool above) {
|
| - XWindowChanges changes;
|
| - changes.sibling = sibling;
|
| - changes.stack_mode = above ? Above : Below;
|
| - XConfigureWindow(GetXDisplay(), window, CWSibling | CWStackMode, &changes);
|
| -}
|
| -
|
| -XSharedMemoryId AttachSharedMemory(Display* display, int shared_memory_key) {
|
| - DCHECK(QuerySharedMemorySupport(display));
|
| -
|
| - XShmSegmentInfo shminfo;
|
| - memset(&shminfo, 0, sizeof(shminfo));
|
| - shminfo.shmid = shared_memory_key;
|
| -
|
| - // This function is only called if QuerySharedMemorySupport returned true. In
|
| - // which case we've already succeeded in having the X server attach to one of
|
| - // our shared memory segments.
|
| - if (!XShmAttach(display, &shminfo))
|
| - NOTREACHED();
|
| -
|
| - return shminfo.shmseg;
|
| -}
|
| -
|
| -void DetachSharedMemory(Display* display, XSharedMemoryId shmseg) {
|
| - DCHECK(QuerySharedMemorySupport(display));
|
| -
|
| - XShmSegmentInfo shminfo;
|
| - memset(&shminfo, 0, sizeof(shminfo));
|
| - shminfo.shmseg = shmseg;
|
| -
|
| - if (!XShmDetach(display, &shminfo))
|
| - NOTREACHED();
|
| -}
|
| -
|
| -XID CreatePictureFromSkiaPixmap(Display* display, XID pixmap) {
|
| - XID picture = XRenderCreatePicture(
|
| - display, pixmap, GetRenderARGB32Format(display), 0, NULL);
|
| -
|
| - return picture;
|
| -}
|
| -
|
| -void PutARGBImage(Display* display, void* visual, int depth, XID pixmap,
|
| - void* pixmap_gc, const uint8* data, int width, int height) {
|
| - // TODO(scherkus): potential performance impact... consider passing in as a
|
| - // parameter.
|
| - int pixmap_bpp = BitsPerPixelForPixmapDepth(display, depth);
|
| -
|
| - XImage image;
|
| - memset(&image, 0, sizeof(image));
|
| -
|
| - image.width = width;
|
| - image.height = height;
|
| - image.format = ZPixmap;
|
| - image.byte_order = LSBFirst;
|
| - image.bitmap_unit = 8;
|
| - image.bitmap_bit_order = LSBFirst;
|
| - image.depth = depth;
|
| - image.bits_per_pixel = pixmap_bpp;
|
| - image.bytes_per_line = width * pixmap_bpp / 8;
|
| -
|
| - if (pixmap_bpp == 32) {
|
| - image.red_mask = 0xff0000;
|
| - image.green_mask = 0xff00;
|
| - image.blue_mask = 0xff;
|
| -
|
| - // If the X server depth is already 32-bits and the color masks match,
|
| - // then our job is easy.
|
| - Visual* vis = static_cast<Visual*>(visual);
|
| - if (image.red_mask == vis->red_mask &&
|
| - image.green_mask == vis->green_mask &&
|
| - image.blue_mask == vis->blue_mask) {
|
| - image.data = const_cast<char*>(reinterpret_cast<const char*>(data));
|
| - XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
|
| - 0, 0 /* source x, y */, 0, 0 /* dest x, y */,
|
| - width, height);
|
| - } else {
|
| - // Otherwise, we need to shuffle the colors around. Assume red and blue
|
| - // need to be swapped.
|
| - //
|
| - // It's possible to use some fancy SSE tricks here, but since this is the
|
| - // slow path anyway, we do it slowly.
|
| -
|
| - uint8_t* bitmap32 = static_cast<uint8_t*>(malloc(4 * width * height));
|
| - if (!bitmap32)
|
| - return;
|
| - uint8_t* const orig_bitmap32 = bitmap32;
|
| - const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data);
|
| - for (int y = 0; y < height; ++y) {
|
| - for (int x = 0; x < width; ++x) {
|
| - const uint32_t pixel = *(bitmap_in++);
|
| - bitmap32[0] = (pixel >> 16) & 0xff; // Red
|
| - bitmap32[1] = (pixel >> 8) & 0xff; // Green
|
| - bitmap32[2] = pixel & 0xff; // Blue
|
| - bitmap32[3] = (pixel >> 24) & 0xff; // Alpha
|
| - bitmap32 += 4;
|
| - }
|
| - }
|
| - image.data = reinterpret_cast<char*>(orig_bitmap32);
|
| - XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
|
| - 0, 0 /* source x, y */, 0, 0 /* dest x, y */,
|
| - width, height);
|
| - free(orig_bitmap32);
|
| - }
|
| - } else if (pixmap_bpp == 16) {
|
| - // Some folks have VNC setups which still use 16-bit visuals and VNC
|
| - // doesn't include Xrender.
|
| -
|
| - uint16_t* bitmap16 = static_cast<uint16_t*>(malloc(2 * width * height));
|
| - if (!bitmap16)
|
| - return;
|
| - uint16_t* const orig_bitmap16 = bitmap16;
|
| - const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data);
|
| - for (int y = 0; y < height; ++y) {
|
| - for (int x = 0; x < width; ++x) {
|
| - const uint32_t pixel = *(bitmap_in++);
|
| - uint16_t out_pixel = ((pixel >> 8) & 0xf800) |
|
| - ((pixel >> 5) & 0x07e0) |
|
| - ((pixel >> 3) & 0x001f);
|
| - *(bitmap16++) = out_pixel;
|
| - }
|
| - }
|
| -
|
| - image.data = reinterpret_cast<char*>(orig_bitmap16);
|
| - image.red_mask = 0xf800;
|
| - image.green_mask = 0x07e0;
|
| - image.blue_mask = 0x001f;
|
| -
|
| - XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image,
|
| - 0, 0 /* source x, y */, 0, 0 /* dest x, y */,
|
| - width, height);
|
| - free(orig_bitmap16);
|
| - } else {
|
| - LOG(FATAL) << "Sorry, we don't support your visual depth without "
|
| - "Xrender support (depth:" << depth
|
| - << " bpp:" << pixmap_bpp << ")";
|
| - }
|
| -}
|
| -
|
| -void FreePicture(Display* display, XID picture) {
|
| - XRenderFreePicture(display, picture);
|
| -}
|
| -
|
| -void FreePixmap(Display* display, XID pixmap) {
|
| - XFreePixmap(display, pixmap);
|
| -}
|
| -
|
| -// Called on BACKGROUND_X11 thread.
|
| -Display* GetSecondaryDisplay() {
|
| - static Display* display = NULL;
|
| - if (!display) {
|
| - display = XOpenDisplay(NULL);
|
| - CHECK(display);
|
| - }
|
| -
|
| - return display;
|
| -}
|
| -
|
| -// Called on BACKGROUND_X11 thread.
|
| -bool GetWindowGeometry(int* x, int* y, unsigned* width, unsigned* height,
|
| - XID window) {
|
| - Window root_window, child_window;
|
| - unsigned border_width, depth;
|
| - int temp;
|
| -
|
| - if (!XGetGeometry(GetSecondaryDisplay(), window, &root_window, &temp, &temp,
|
| - width, height, &border_width, &depth))
|
| - return false;
|
| - if (!XTranslateCoordinates(GetSecondaryDisplay(), window, root_window,
|
| - 0, 0 /* input x, y */, x, y /* output x, y */,
|
| - &child_window))
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -// Called on BACKGROUND_X11 thread.
|
| -bool GetWindowParent(XID* parent_window, bool* parent_is_root, XID window) {
|
| - XID root_window, *children;
|
| - unsigned num_children;
|
| -
|
| - Status s = XQueryTree(GetSecondaryDisplay(), window, &root_window,
|
| - parent_window, &children, &num_children);
|
| - if (!s)
|
| - return false;
|
| -
|
| - if (children)
|
| - XFree(children);
|
| -
|
| - *parent_is_root = root_window == *parent_window;
|
| - return true;
|
| -}
|
| -
|
| -bool GetWindowManagerName(std::string* wm_name) {
|
| - DCHECK(wm_name);
|
| - int wm_window = 0;
|
| - if (!x11_util::GetIntProperty(x11_util::GetX11RootWindow(),
|
| - "_NET_SUPPORTING_WM_CHECK",
|
| - &wm_window)) {
|
| - return false;
|
| - }
|
| -
|
| - // It's possible that a window manager started earlier in this X session left
|
| - // a stale _NET_SUPPORTING_WM_CHECK property when it was replaced by a
|
| - // non-EWMH window manager, so we trap errors in the following requests to
|
| - // avoid crashes (issue 23860).
|
| -
|
| - // EWMH requires the supporting-WM window to also have a
|
| - // _NET_SUPPORTING_WM_CHECK property pointing to itself (to avoid a stale
|
| - // property referencing an ID that's been recycled for another window), so we
|
| - // check that too.
|
| - gdk_error_trap_push();
|
| - int wm_window_property = 0;
|
| - bool result = x11_util::GetIntProperty(
|
| - wm_window, "_NET_SUPPORTING_WM_CHECK", &wm_window_property);
|
| - gdk_flush();
|
| - bool got_error = gdk_error_trap_pop();
|
| - if (got_error || !result || wm_window_property != wm_window)
|
| - return false;
|
| -
|
| - gdk_error_trap_push();
|
| - result = x11_util::GetStringProperty(
|
| - static_cast<XID>(wm_window), "_NET_WM_NAME", wm_name);
|
| - gdk_flush();
|
| - got_error = gdk_error_trap_pop();
|
| - return !got_error && result;
|
| -}
|
| -
|
| -static cairo_status_t SnapshotCallback(
|
| - void *closure, const unsigned char *data, unsigned int length) {
|
| - std::vector<unsigned char>* png_representation =
|
| - static_cast<std::vector<unsigned char>*>(closure);
|
| -
|
| - size_t old_size = png_representation->size();
|
| - png_representation->resize(old_size + length);
|
| - memcpy(&(*png_representation)[old_size], data, length);
|
| - return CAIRO_STATUS_SUCCESS;
|
| -}
|
| -
|
| -void GrabWindowSnapshot(GtkWindow* gtk_window,
|
| - std::vector<unsigned char>* png_representation) {
|
| - GdkWindow* gdk_window = GTK_WIDGET(gtk_window)->window;
|
| - Display* display = GDK_WINDOW_XDISPLAY(gdk_window);
|
| - XID win = GDK_WINDOW_XID(gdk_window);
|
| - XWindowAttributes attr;
|
| - if (XGetWindowAttributes(display, win, &attr) == 0) {
|
| - LOG(ERROR) << "Couldn't get window attributes";
|
| - return;
|
| - }
|
| - XImage* image = XGetImage(
|
| - display, win, 0, 0, attr.width, attr.height, AllPlanes, ZPixmap);
|
| - if (!image) {
|
| - LOG(ERROR) << "Couldn't get image";
|
| - return;
|
| - }
|
| - if (image->depth != 24) {
|
| - LOG(ERROR)<< "Unsupported image depth " << image->depth;
|
| - return;
|
| - }
|
| - cairo_surface_t* surface =
|
| - cairo_image_surface_create_for_data(
|
| - reinterpret_cast<unsigned char*>(image->data),
|
| - CAIRO_FORMAT_RGB24,
|
| - image->width,
|
| - image->height,
|
| - image->bytes_per_line);
|
| -
|
| - if (!surface) {
|
| - LOG(ERROR) << "Unable to create Cairo surface from XImage data";
|
| - return;
|
| - }
|
| - cairo_surface_write_to_png_stream(
|
| - surface, SnapshotCallback, png_representation);
|
| - cairo_surface_destroy(surface);
|
| -}
|
| -
|
| -bool ChangeWindowDesktop(XID window, XID destination) {
|
| - int desktop;
|
| - if (!GetWindowDesktop(destination, &desktop))
|
| - return false;
|
| -
|
| - // If |window| is sticky, use the current desktop.
|
| - if (desktop == kAllDesktops &&
|
| - !GetCurrentDesktop(&desktop))
|
| - return false;
|
| -
|
| - XEvent event;
|
| - event.xclient.type = ClientMessage;
|
| - event.xclient.window = window;
|
| - event.xclient.message_type = gdk_x11_get_xatom_by_name_for_display(
|
| - gdk_display_get_default(), "_NET_WM_DESKTOP");
|
| - event.xclient.format = 32;
|
| - event.xclient.data.l[0] = desktop;
|
| - event.xclient.data.l[1] = 1; // source indication
|
| -
|
| - int result = XSendEvent(GetXDisplay(), GetX11RootWindow(), False,
|
| - SubstructureNotifyMask, &event);
|
| - return result == Success;
|
| -}
|
| -
|
| -void SetDefaultX11ErrorHandlers() {
|
| - SetX11ErrorHandlers(NULL, NULL);
|
| -}
|
| -
|
| -// ----------------------------------------------------------------------------
|
| -// These functions are declared in x11_util_internal.h because they require
|
| -// XLib.h to be included, and it conflicts with many other headers.
|
| -XRenderPictFormat* GetRenderARGB32Format(Display* dpy) {
|
| - static XRenderPictFormat* pictformat = NULL;
|
| - if (pictformat)
|
| - return pictformat;
|
| -
|
| - // First look for a 32-bit format which ignores the alpha value
|
| - XRenderPictFormat templ;
|
| - templ.depth = 32;
|
| - templ.type = PictTypeDirect;
|
| - templ.direct.red = 16;
|
| - templ.direct.green = 8;
|
| - templ.direct.blue = 0;
|
| - templ.direct.redMask = 0xff;
|
| - templ.direct.greenMask = 0xff;
|
| - templ.direct.blueMask = 0xff;
|
| - templ.direct.alphaMask = 0;
|
| -
|
| - static const unsigned long kMask =
|
| - PictFormatType | PictFormatDepth |
|
| - PictFormatRed | PictFormatRedMask |
|
| - PictFormatGreen | PictFormatGreenMask |
|
| - PictFormatBlue | PictFormatBlueMask |
|
| - PictFormatAlphaMask;
|
| -
|
| - pictformat = XRenderFindFormat(dpy, kMask, &templ, 0 /* first result */);
|
| -
|
| - if (!pictformat) {
|
| - // Not all X servers support xRGB32 formats. However, the XRENDER spec says
|
| - // that they must support an ARGB32 format, so we can always return that.
|
| - pictformat = XRenderFindStandardFormat(dpy, PictStandardARGB32);
|
| - CHECK(pictformat) << "XRENDER ARGB32 not supported.";
|
| - }
|
| -
|
| - return pictformat;
|
| -}
|
| -
|
| -XRenderPictFormat* GetRenderVisualFormat(Display* dpy, Visual* visual) {
|
| - DCHECK(QueryRenderSupport(dpy));
|
| -
|
| - CachedPictFormats* formats = get_cached_pict_formats();
|
| -
|
| - for (CachedPictFormats::const_iterator i = formats->begin();
|
| - i != formats->end(); ++i) {
|
| - if (i->equals(dpy, visual))
|
| - return i->format;
|
| - }
|
| -
|
| - // Not cached, look up the value.
|
| - XRenderPictFormat* pictformat = XRenderFindVisualFormat(dpy, visual);
|
| - CHECK(pictformat) << "XRENDER does not support default visual";
|
| -
|
| - // And store it in the cache.
|
| - CachedPictFormat cached_value;
|
| - cached_value.visual = visual;
|
| - cached_value.display = dpy;
|
| - cached_value.format = pictformat;
|
| - formats->push_front(cached_value);
|
| -
|
| - if (formats->size() == kMaxCacheSize) {
|
| - formats->pop_back();
|
| - // We should really only have at most 2 display/visual combinations:
|
| - // one for normal browser windows, and possibly another for an argb window
|
| - // created to display a menu.
|
| - //
|
| - // If we get here it's not fatal, we just need to make sure we aren't
|
| - // always blowing away the cache. If we are, then we should figure out why
|
| - // and make it bigger.
|
| - NOTREACHED();
|
| - }
|
| -
|
| - return pictformat;
|
| -}
|
| -
|
| -void SetX11ErrorHandlers(XErrorHandler error_handler,
|
| - XIOErrorHandler io_error_handler) {
|
| - XSetErrorHandler(error_handler ? error_handler : DefaultX11ErrorHandler);
|
| - XSetIOErrorHandler(
|
| - io_error_handler ? io_error_handler : DefaultX11IOErrorHandler);
|
| -}
|
| -
|
| -std::string GetErrorEventDescription(Display *dpy,
|
| - XErrorEvent *error_event) {
|
| - char error_str[256];
|
| - char request_str[256];
|
| -
|
| - XGetErrorText(dpy, error_event->error_code, error_str, sizeof(error_str));
|
| -
|
| - strncpy(request_str, "Unknown", sizeof(request_str));
|
| - if (error_event->request_code < 128) {
|
| - std::string num = base::UintToString(error_event->request_code);
|
| - XGetErrorDatabaseText(
|
| - dpy, "XRequest", num.c_str(), "Unknown", request_str,
|
| - sizeof(request_str));
|
| - } else {
|
| - int num_ext;
|
| - char **ext_list = XListExtensions(dpy, &num_ext);
|
| -
|
| - for (int i = 0; i < num_ext; i++) {
|
| - int ext_code, first_event, first_error;
|
| - XQueryExtension(dpy, ext_list[i], &ext_code, &first_event, &first_error);
|
| - if (error_event->request_code == ext_code) {
|
| - std::string msg = StringPrintf(
|
| - "%s.%d", ext_list[i], error_event->minor_code);
|
| - XGetErrorDatabaseText(
|
| - dpy, "XRequest", msg.c_str(), "Unknown", request_str,
|
| - sizeof(request_str));
|
| - break;
|
| - }
|
| - }
|
| - XFreeExtensionList(ext_list);
|
| - }
|
| -
|
| - return base::StringPrintf(
|
| - "X Error detected: serial %lu, error_code %u (%s), "
|
| - "request_code %u minor_code %u (%s)",
|
| - error_event->serial, error_event->error_code, error_str,
|
| - error_event->request_code, error_event->minor_code, request_str);
|
| -}
|
| -// ----------------------------------------------------------------------------
|
| -// End of x11_util_internal.h
|
| -
|
| -
|
| -} // namespace x11_util
|
|
|