Remove app/xvfb and lib/xev_track

The xvfb support remained unused for years. So let's remove it.
This commit is contained in:
Norman Feske 2017-01-02 18:44:54 +01:00
parent 3268a16d13
commit 7f5e2c2eb2
9 changed files with 0 additions and 1176 deletions

View File

@ -1,5 +0,0 @@
SRC_CC = xev_track.cc
REQUIRES = x11 xdamage
LIBS = lx_hybrid
vpath xev_track.cc $(REP_DIR)/src/lib/xev_track

View File

@ -1,48 +0,0 @@
Xvfb is a virtual X server that uses a plain file as framebuffer instead of a
physical screen. The 'xvfb' glue program makes an Xvfb session available to the
Linux version of Genode such that both native Genode programs and X clients can
run seamlessly integrated in one Nitpicker session. Using the 'xvfb' glue
program contained in this directory. Because Xvfb is executed as Nitpicker
client, it is possible to integrate multiple instances of Xvfb into the same
Nitpicker session.
Preconditions for compiling
---------------------------
The 'xvfb' glue program is a hybrid process using the Genode interfaces and the
Linux interfaces directly. It tracks dirty screen regions using the X damage
extension and injects user-input events into the X server using the X test
extension. So you need the development package of both extensions to compile
it. The Debian package for the X damage extension is called 'libxdamage-dev'.
The X test extension is normally installed by default. Furthermore you need to
enhance your 'SPECS' declaration in your
'<builddir>/etc/specs.conf' file as follows:
! SPECS += x11 xdamage xtest
Usage
-----
First start Xvfb using the following command-line arguments:
! Xvfb :1 -fbdir /tmp -screen 0 1024x768x16
While Xvfb is running, '/tmp/Xvfb_screen0' will contain the content of the X
server's frame buffer. This file must be specified for the 'xvfb' declaration
in the config file. In addition, the display of X server instance must be
declared via the 'display' tag. For example:
! <config>
! <display>:1</display>
! <xvfb>/tmp/Xvfb_screen0</xvfb>
! </config>
Known Limitations
-----------------
* With the current version, some keycodes are not mapped correctly.
* The screen mode of Nitpicker and the Xvfb session must be the same.
Only modes with 16bit color depth are supported.

View File

@ -1,99 +0,0 @@
/*
* \brief Inject input event into an X server
* \author Norman Feske
* \date 2009-11-04
*/
/*
* Copyright (C) 2009-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* local includes */
#include "inject_input.h"
/* Genode includes */
#include <input/keycodes.h>
#include <base/printf.h>
/* X11 includes */
#include <X11/extensions/XTest.h>
static int convert_keycode_to_x11[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 43, 85, 86, 87, 88, 115, 119, 120, 121, 375, 123, 90,
284, 285, 309, 298, 312, 91, 327, 328, 329, 331, 333, 335, 336, 337, 338, 339,
367, 294, 293, 286, 350, 92, 334, 512, 116, 377, 109, 111, 373, 347, 348, 349,
360, 93, 94, 95, 98, 376, 100, 101, 357, 316, 354, 304, 289, 102, 351, 355,
103, 104, 105, 275, 281, 272, 306, 106, 274, 107, 288, 364, 358, 363, 362, 361,
291, 108, 381, 290, 287, 292, 279, 305, 280, 99, 112, 257, 258, 113, 270, 114,
118, 117, 125, 374, 379, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269,
271, 273, 276, 277, 278, 282, 283, 295, 296, 297, 299, 300, 301, 302, 303, 307,
308, 310, 313, 314, 315, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 330,
332, 340, 341, 342, 343, 344, 345, 346, 356, 359, 365, 368, 369, 370, 371, 372
};
static int convert_keycode(int keycode)
{
if (keycode < 0 || keycode >= (int)(sizeof(convert_keycode_to_x11)/sizeof(int)))
return 0;
return convert_keycode_to_x11[keycode] + 8;
}
/**********************
** Public functions **
**********************/
bool inject_input_init(Display *dpy)
{
int dummy;
if (!XTestQueryExtension (dpy, &dummy, &dummy, &dummy, &dummy)) {
Genode::printf ("Error: Could not query Xtest extension\n");
return false;
}
return true;
}
void inject_input_event(Display *dpy, Input::Event &ev)
{
switch (ev.type()) {
case Input::Event::MOTION:
XTestFakeMotionEvent(dpy, -1, ev.ax(), ev.ay(), CurrentTime);
break;
case Input::Event::PRESS:
if (ev.code() == Input::BTN_LEFT)
XTestFakeButtonEvent(dpy, 1, 1, CurrentTime);
if (ev.code() == Input::BTN_RIGHT)
XTestFakeButtonEvent(dpy, 2, 1, CurrentTime);
else
XTestFakeKeyEvent(dpy, convert_keycode(ev.code()), 1, CurrentTime);
break;
case Input::Event::RELEASE:
if (ev.code() == Input::BTN_LEFT)
XTestFakeButtonEvent(dpy, 1, 0, CurrentTime);
if (ev.code() == Input::BTN_RIGHT)
XTestFakeButtonEvent(dpy, 2, 0, CurrentTime);
else
XTestFakeKeyEvent(dpy, convert_keycode(ev.code()), 0, CurrentTime);
break;
default: break;
}
/* flush faked input events */
XFlush(dpy);
}

View File

@ -1,38 +0,0 @@
/*
* \brief Interface for X input injection
* \author Norman Feske
* \date 2009-11-04
*/
/*
* Copyright (C) 2009-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INJECT_INPUT_H_
#define _INJECT_INPUT_H_
/* Genode includes */
#include <input/event.h>
/* X11 includes */
#include <X11/Xlib.h>
/**
* Initialize X input-injection mechanism
*
* \return true on success
*/
bool inject_input_init(Display *dpy);
/**
* Inject input event to the X session
*/
void inject_input_event(Display *dpy, Input::Event &ev);
#endif /* _INJECT_INPUT_H_ */

View File

@ -1,348 +0,0 @@
/*
* \brief Xvfb display application for Nitpicker
* \author Norman Feske
* \date 2009-11-03
*/
/*
* Copyright (C) 2009-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Linux includes */
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
/* X11 includes */
#include <X11/XWDFile.h>
#include <X11/Xlib.h>
/* Genode includes */
#include <base/printf.h>
#include <nitpicker_session/connection.h>
#include <nitpicker_view/client.h>
#include <framebuffer_session/client.h>
#include <input_session/client.h>
#include <input/event.h>
#include <timer_session/connection.h>
#include <blit/blit.h>
#include <xev_track/xev_track.h>
#include <os/config.h>
/* local includes */
#include "inject_input.h"
typedef Genode::uint16_t Pixel;
/**
* Variables defined by the supplied config file
*/
char *config_xvfb_file_name = 0;
char *config_x_display = 0;
int config_force_top = 1;
/**
* Variables derived from the xvfb screen
*/
static int xvfb_width, xvfb_height;
static Pixel *xvfb_addr;
static Framebuffer::Session *fb_session;
static Framebuffer::Mode fb_mode;
static Pixel *fb_addr;
static Nitpicker::Session *nitpicker()
{
struct Connection : Nitpicker::Connection
{
Connection()
{
Nitpicker::Connection::buffer(mode(), false);
}
};
static Connection connection;
return &connection;
}
/**
* Parse configuration
*
* \return true if configuration is complete
*/
static bool read_config()
{
using namespace Genode;
Xml_node config_node = config()->xml_node();
try {
static char buf[256];
config_node.sub_node("xvfb").value(buf, sizeof(buf));
config_xvfb_file_name = buf;
} catch (Xml_node::Nonexistent_sub_node) {
printf("Error: Declaration of xvfb file name is missing\n");
return false;
}
try {
static char buf[256];
config_node.sub_node("display").value(buf, sizeof(buf));
config_x_display = buf;
} catch (Xml_node::Nonexistent_sub_node) {
printf("Error: Display declaration is missing\n");
return false;
}
return true;
}
static inline long convert_from_big_endian(long x)
{
char v[4] = {
(char)((x & 0xff000000) >> 24),
(char)((x & 0x00ff0000) >> 16),
(char)((x & 0x0000ff00) >> 8),
(char)((x & 0x000000ff) >> 0),
};
return *(long *)v;
}
/**
* Map file (read only) to local address space
*/
static void *mmap_file(const char *file_name)
{
int fd = open(file_name, O_RDONLY);
if (fd < 0)
Genode::printf("Error: Could not open file %s\n", file_name);
struct stat stat;
if (fstat(fd, &stat) < 0)
Genode::printf("Error: Could not fstat file %s\n", file_name);
void *addr = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (addr == (void *)-1)
Genode::printf("Error: Could not mmap file\n");
return addr;
}
/**
* Flush part of the Xvfb screen to the Nitpicker session
*/
static void flush(int x, int y, int width, int height, Framebuffer::Mode const &mode)
{
/* clip arguments against framebuffer geometry */
if (x < 0) width += x, x = 0;
if (y < 0) height += y, y = 0;
if (width > mode.width() - x) width = mode.width() - x;
if (height > mode.height() - y) height = mode.height() - y;
if (width <= 0 || height <= 0) return;
/* copy pixels from xvfb to the nitpicker buffer */
blit(xvfb_addr + x + xvfb_width*y, xvfb_width*sizeof(Pixel),
fb_addr + x + mode.width()*y, mode.width()*sizeof(Pixel),
width*sizeof(Pixel), height);
/* refresh nitpicker views */
fb_session->refresh(x, y, width, height);
}
class Bounding_box
{
private:
int _x1, _y1, _x2, _y2;
public:
/**
* Constructor
*/
Bounding_box() { reset(); }
bool valid() { return _x1 <= _x2 && _y1 <= _y2; }
void reset() { _x1 = 0, _y1 = 0, _x2 = -1, _y2 = -1; }
void extend(int x, int y, int w, int h)
{
int nx2 = x + w - 1;
int ny2 = y + h - 1;
if (!valid()) {
_x1 = x, _y1 = y, _x2 = x + w - 1, _y2 = y + h - 1;
} else {
_x1 = Genode::min(_x1, x);
_y1 = Genode::min(_y1, y);
_x2 = Genode::max(_x2, nx2);
_y2 = Genode::max(_y2, ny2);
}
}
int x() { return _x1; }
int y() { return _y1; }
int w() { return _x2 - _x1 + 1; }
int h() { return _y2 - _y1 + 1; }
};
static Bounding_box pending_redraw;
/**************************************************
** Hook functions called by the X event tracker **
**************************************************/
struct View
{
Nitpicker::View_capability cap;
};
static View views[MAX_VIEWS];
void create_view(int view_id)
{
views[view_id].cap = nitpicker()->create_view();
}
void destroy_view(int view_id)
{
nitpicker()->destroy_view(views[view_id].cap);
/* invalidate capability */
views[view_id].cap = Nitpicker::View_capability();
}
void set_background_view(int view_id)
{
nitpicker()->background(views[view_id].cap);
}
void place_view(int view_id, int x, int y, int w, int h)
{
Nitpicker::View_client view(views[view_id].cap);
view.viewport(x, y, w, h, -x, -y, false);
}
void stack_view(int view_id, int neighbor_id, bool behind)
{
Nitpicker::View_client view(views[view_id].cap);
/* translate invalid neighbor ID to invalid capability */
Nitpicker::View_capability neighbor_cap;
if (neighbor_id >= 0)
neighbor_cap = views[neighbor_id].cap;
view.stack(neighbor_cap, behind, true);
}
void refresh(int x, int y, int w, int h)
{
pending_redraw.extend(x, y, w, h);
}
int main(int, char **)
{
if (!read_config()) return -1;
static Timer::Connection timer;
static Framebuffer::Session_client fb(nitpicker()->framebuffer_session());
static Input::Session_client input(nitpicker()->input_session());
fb_session = &fb;
fb_addr = Genode::env()->rm_session()->attach(fb.dataspace());
fb_mode = fb.mode();
XWDFileHeader *xwd = (XWDFileHeader *)mmap_file(config_xvfb_file_name);
if (!xwd) return -1;
xvfb_width = convert_from_big_endian(xwd->pixmap_width);
xvfb_height = convert_from_big_endian(xwd->pixmap_height);
enum { SUPPORTED_BPP = 16 };
if (convert_from_big_endian(xwd->bits_per_pixel) != SUPPORTED_BPP) {
Genode::printf("Error: Color depth %d is not supported (use %d bpp)\n",
(int)convert_from_big_endian(xwd->pixmap_depth), SUPPORTED_BPP);
return -2;
}
xvfb_addr = (Pixel *)((long)xwd + convert_from_big_endian(xwd->header_size)
+ convert_from_big_endian(xwd->ncolors)*sizeof(XWDColor));
if (xvfb_width != fb_mode.width() || xvfb_height != fb_mode.height()) {
Genode::printf("Error: Xvfb mode must equal the Nitpicker screen mode of %dx%d\n",
fb_mode.width(), fb_mode.height());
return -3;
}
Input::Event *ev_buf = Genode::env()->rm_session()->attach(input.dataspace());
Display *dpy = XOpenDisplay(config_x_display);
if (!dpy) {
Genode::printf("Error: Cannot open display\n");
return -4;
}
if (!inject_input_init(dpy))
return -5;
if (!xev_track_init(dpy))
return -6;
for (;;) {
pending_redraw.reset();
/*
* Process due X events and update 'pending_redraw' as side effect
*/
XEvent ev;
while (XPending(dpy)) {
XNextEvent(dpy, &ev);
xev_track_handle_event(dpy, ev);
}
/*
* Forward input events to the X session
*/
while (input.pending()) {
int num_ev = input.flush();
for (int i = 0; i < num_ev; i++)
inject_input_event(dpy, ev_buf[i]);
}
/*
* Track mouse cursor and update 'pending_redraw' as side effect
*/
xev_track_handle_cursor(dpy);
if (pending_redraw.valid())
flush(pending_redraw.x(), pending_redraw.y(),
pending_redraw.w(), pending_redraw.h(), fb_mode);
timer.msleep(5);
}
return 0;
}

View File

@ -1,6 +0,0 @@
TARGET = xvfb
REQUIRES = linux x11 xtest xdamage
SRC_CC = main.cc inject_input.cc
LIBS = lx_hybrid syscall-linux blit xev_track config
EXT_OBJECTS += -lX11 -lXdamage /usr/lib/libXtst.so.6

View File

@ -1,529 +0,0 @@
/*
* \brief Window-event tracker for the X Window System
* \author Norman Feske
* \date 2009-11-04
*/
/*
* Copyright (C) 2009-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Linux includes */
#include <signal.h>
#include <stdio.h>
/* X11 includes */
#include <X11/Xlib.h>
#include <X11/extensions/Xdamage.h>
/* xev includes */
#include <xev_track/xev_track.h>
struct View
{
bool tracked; /* flag indicating that the view is in use */
Window xwin;
Window above;
int x, y, w, h, border;
/**
* Default constructor
*
* Make sure that the window is initially marked as free
*/
View() : tracked(false) { }
};
static View views[MAX_VIEWS];
static Window root;
static int xdamage_ev;
static Damage damage;
/***************
** Utilities **
***************/
/**
* Allocate view ID
*
* \return allocated view ID, or
* -1 if allocation failed
*/
static int alloc_view_id()
{
int i;
for (i = 0; i < MAX_VIEWS; i++)
if (!views[i].tracked) break;
if (i == MAX_VIEWS)
return -1;
views[i].tracked = true;
return i;
}
/**
* Mark view ID as free
*/
static void release_view_id(int view_id)
{
views[view_id].tracked = false;
}
/**
* Find view ID for a given X window ID
*/
static int find_view_id(Window xwin)
{
/* search for window with matchin xwin id */
for (int i = 0; i < MAX_VIEWS; i++)
if (views[i].xwin == xwin && views[i].tracked)
return i;
return -1;
}
/**
* Create new window
*
* \param position -1 .. at top,
* -2 .. background,
* otherwise window id of the neighbor behind the new
* window
*/
static void assign_window(int view_id, Window xwin, Display *dpy, int position)
{
/* sanity check */
if (view_id < 0) return;
View *view = &views[view_id];
view->xwin = xwin;
/* request position and size of new window */
XWindowAttributes attr;
XGetWindowAttributes(dpy, xwin, &attr);
view->x = attr.x;
view->y = attr.y;
view->w = attr.width;
view->h = attr.height;
view->border = attr.border_width;
create_view(view_id);
if (position == -2) {
stack_view(view_id, -1, false);
set_background_view(view_id);
}
if (position == -1)
stack_view(view_id, -1, true);
if (position >= 0)
stack_view(view_id, position, true);
place_view(view_id, view->x, view->y, view->w + view->border*2,
view->h + view->border*2);
}
/**
* Scan all currently present windows
*/
static void scan_windows(Display *dpy, Window root)
{
Window dummy_w1, dummy_w2, *win_list;
unsigned int num_wins;
XQueryTree(dpy, root, &dummy_w1, &dummy_w2, &win_list, &num_wins);
for (unsigned i = 0; i < num_wins; i++) {
XWindowAttributes attr;
XGetWindowAttributes(dpy, win_list[i], &attr);
if (attr.map_state != IsViewable)
continue;
int view_id = alloc_view_id();
if (view_id >= 0)
assign_window(view_id, win_list[i], dpy, -1);
}
XFree(win_list);
/* listen at the root window */
XSelectInput(dpy, root, SubstructureNotifyMask | PointerMotionMask);
}
/**
* Find view belonging to the window in front of the specified X window
*
* \return view ID, or
* -1 if no matching view exists
*/
static int find_view_in_front(Display *dpy, Window root, Window win)
{
Window dummy_w1, dummy_w2, *win_list;
unsigned int num_wins, i;
XQueryTree(dpy, root, &dummy_w1, &dummy_w2, &win_list, &num_wins);
/* find window in X window stack */
for (i = 0; i < num_wins; i++)
if (win_list[i] == win)
break;
/* skip current window */
i++;
/* find and return view belonging to the X window */
int curr;
for (; i < num_wins; i++)
if ((curr = find_view_id(win_list[i])))
return curr;
return -1;
}
static void get_pointer_pos(Display *dpy, int *mx, int *my)
{
Window dummy_win;
int dummy_int;
unsigned dummy_uint;
XQueryPointer(dpy, root, &dummy_win, &dummy_win,
mx, my, &dummy_int, &dummy_int, &dummy_uint);
}
struct Mouse_cursor_tracker
{
private:
enum { CURSOR_WIDTH = 20, CURSOR_HEIGHT = 20 };
int _x1, _y1, _x2, _y2;
bool _valid;
public:
Mouse_cursor_tracker() : _valid(false) { }
void reset(int x, int y)
{
_x1 = x - CURSOR_WIDTH;
_y1 = y - CURSOR_HEIGHT;
_x2 = x + CURSOR_WIDTH;
_y2 = y + CURSOR_HEIGHT;
_valid = false;
}
void track(int x, int y)
{
if (_x1 > x - CURSOR_WIDTH) _x1 = x - CURSOR_WIDTH;
if (_y1 > y - CURSOR_HEIGHT) _y1 = y - CURSOR_HEIGHT;
if (_x2 < x + CURSOR_WIDTH) _x2 = x + CURSOR_WIDTH;
if (_y2 < y + CURSOR_HEIGHT) _y2 = y + CURSOR_HEIGHT;
_valid = true;
}
bool bounding_box(int *x, int *y, int *w, int *h)
{
*x = _x1;
*y = _y1;
*w = _x2 - _x1 + 1;
*h = _y2 - _y1 + 1;
return _valid;
}
};
struct Mouse_cursor_tracker mouse_cursor_tracker;
/****************************
** Top-window enforcement **
****************************/
/*
* Some window managers do not raise a window that is already on top. This is
* bad because there may be overlay windows that are not known to the X window
* system but that cover the topmost X window. Thus, we want always to receive
* a top event. For this, we create a dedicated invisible window that stays
* always on top of all others. The topmost real X window is always the second.
* Therefore, the window manager thinks that this window can be topped and
* generates the desired event.
*/
static Window topwin;
static bool window_left_of_screen(Display *dpy, Window xwin)
{
XWindowAttributes attr;
XGetWindowAttributes(dpy, xwin, &attr);
return (attr.x + attr.width <= 0);
}
enum {
MAGIC_WIN_X = 2000, MAGIC_WIN_Y = 2000,
MAGIC_WIN_W = 1, MAGIC_WIN_H = 1
};
/**
* Create magic window that stays always on top
*/
static void create_magic_topwin(Display *dpy, Window root)
{
XWindowChanges wincfg;
/* create magic window that stays always on top */
topwin = XCreateWindow(dpy, root,
MAGIC_WIN_X, MAGIC_WIN_Y, /* position */
MAGIC_WIN_W, MAGIC_WIN_H, /* size */
0, /* border */
CopyFromParent, /* depth */
InputOutput, /* class */
CopyFromParent, /* visual */
0, 0);
wincfg.x = MAGIC_WIN_X;
wincfg.y = MAGIC_WIN_Y;
XConfigureWindow(dpy, topwin, CWX | CWY , &wincfg);
XMapWindow(dpy, topwin);
wincfg.x = MAGIC_WIN_X;
wincfg.y = MAGIC_WIN_Y;
XConfigureWindow(dpy, topwin, CWX | CWY , &wincfg);
int view_id = alloc_view_id();
if (view_id >= 0)
assign_window(view_id, topwin, dpy, root);
}
/**
* Bring magic window in front of all others
*/
static void raise_magic_window(Display *dpy)
{
XRaiseWindow(dpy, topwin);
/*
* Some window managers tend to relocate existing windows on startup. So
* let's re-position the window to make sure that it remains invisible in
* such cases.
*/
XMoveWindow(dpy, topwin, -200, -200);
}
/**********************
** X event handling **
**********************/
static void handle_xwindow_event(Display *dpy, Window root, XEvent &ev)
{
int view_id, behind_id;
int x, y, w, h;
View *view;
switch (ev.type) {
case MotionNotify:
x = ev.xmotion.x_root;
y = ev.xmotion.y_root;
mouse_cursor_tracker.track(x, y);
break;
case ConfigureNotify:
if ((view_id = find_view_id(ev.xconfigure.window)) < 0)
break;
x = ev.xconfigure.x;
y = ev.xconfigure.y;
w = ev.xconfigure.width;
h = ev.xconfigure.height;
view = &views[view_id];
/*
* If window position and size keeps the same,
* we assume, the window has been topped.
*/
if (x == view->x && y == view->y && w == view->w && h == view->h) {
int behind_id = find_view_in_front(dpy, root, ev.xconfigure.window);
stack_view(view_id, behind_id, true);
if (!window_left_of_screen(dpy, ev.xconfigure.window) && config_force_top)
raise_magic_window(dpy);
} else {
/* keep track new window position */
view->x = x; view->y = y; view->w = w; view->h = h;
place_view(view_id, x, y, w + view->border*2, h + view->border*2);
}
break;
case Expose:
if ((view_id = find_view_id(ev.xconfigure.window)) < 0)
break;
stack_view(view_id, -1, true);
break;
case UnmapNotify:
if ((view_id = find_view_id(ev.xconfigure.window)) < 0)
break;
/* avoid destroying a view twice */
if (!views[view_id].tracked)
break;
destroy_view(view_id);
release_view_id(view_id);
break;
case MapNotify:
if ((view_id = find_view_id(ev.xconfigure.window)) >= 0) {
printf("MapRequest: window already present - view ID %d\n", view_id);
break;
}
behind_id = find_view_in_front(dpy, root, ev.xconfigure.window);
/*
* Idea: Call XQueryTree to obtain the position where the new
* window is located in the window stack.
*
*/
view_id = alloc_view_id();
if (view_id >= 0)
assign_window(view_id, ev.xconfigure.window, dpy, behind_id);
if (!window_left_of_screen(dpy, ev.xconfigure.window) && config_force_top)
raise_magic_window(dpy);
break;
}
}
static void handle_xdamage_event(Display *dpy, XEvent &ev)
{
if (ev.type != XDamageNotify + xdamage_ev)
return;
static XserverRegion region = XFixesCreateRegion (dpy, 0, 0);
static XserverRegion part = XFixesCreateRegion (dpy, 0, 0);
XDamageNotifyEvent *dev = (XDamageNotifyEvent *)&ev;
XFixesSetRegion(dpy, part, &dev->area, 1);
XFixesUnionRegion(dpy, region, region, part);
XFlush(dpy);
XRectangle *rects;
int nrects;
nrects = 0;
rects = XFixesFetchRegion (dpy, region, &nrects);
for (int i = 0; i < nrects; i++)
refresh(rects[i].x, rects[i].y, rects[i].width, rects[i].height);
/* clear collected damage region from damage */
XDamageSubtract (dpy, damage, region, None);
/* empty collected region */
XFixesSetRegion (dpy, region, 0, 0);
}
/**
* Error handler that is called on xlib errors
*/
static int x_error_handler(Display *dpy, XErrorEvent *r)
{
printf("Error: x_error_handler called\n");
return 0;
}
/**********************
** Public interface **
**********************/
void xev_track_handle_event(Display *dpy, XEvent &ev)
{
handle_xwindow_event(dpy, root, ev);
handle_xdamage_event(dpy, ev);
}
void xev_track_handle_cursor(Display *dpy)
{
int x = 0, y = 0, w = 0, h = 0;
static int old_mx, old_my;
int new_mx, new_my;
get_pointer_pos(dpy, &new_mx, &new_my);
if (new_mx != old_mx || new_my != old_my)
mouse_cursor_tracker.track(new_mx, new_my);
if (mouse_cursor_tracker.bounding_box(&x, &y, &w, &h))
refresh(x, y, w, h);
mouse_cursor_tracker.reset(old_mx, old_my);
mouse_cursor_tracker.track(new_mx, new_my);
old_mx = new_mx, old_my = new_my;
}
bool xev_track_init(Display *dpy)
{
XSetErrorHandler(x_error_handler);
int screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
int error;
if (!XDamageQueryExtension (dpy, &xdamage_ev, &error)) {
printf("Error: Could not query Xdamage extension\n");
return false;
}
damage = XDamageCreate(dpy, root, XDamageReportBoundingBox);
if (config_force_top)
create_magic_topwin(dpy, root);
/* create background view */
int bg_view_id = alloc_view_id();
if (bg_view_id >= 0)
assign_window(bg_view_id, root, dpy, -2);
/* retrieve information about currently present windows */
scan_windows(dpy, root);
return true;
}

View File

@ -1,97 +0,0 @@
/*
* \brief Test for X event tracker, dumping X11 events
* \author Norman Feske
* \date 2010-02-11
*/
/*
* Copyright (C) 2010-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* X11 includes */
#include <X11/XWDFile.h>
#include <X11/Xlib.h>
/* X event-tracker includes */
#include <xev_track/xev_track.h>
/* standard includes */
#include <stdio.h>
/*****************************
** configuration variables **
*****************************/
int config_force_top = 1; /* evaluated by the X event-tracker library */
static int config_dump_refresh = false;
/*******************************
** X event-tracker callbacks **
*******************************/
void create_view(int view_id) {
printf("create_view(view_id=%d)\n", view_id); }
void destroy_view(int view_id) {
printf("destroy_view(view_id=%d)\n", view_id); }
void set_background_view(int view_id) {
printf("set_background_view(view_id=%d)\n", view_id); }
void place_view(int view_id, int x, int y, int w, int h) {
printf("place_view(view_id=%d, x=%d, y=%d, w=%d, h=%d)\n",
view_id, x, y, w, h); }
void stack_view(int view_id, int neighbor_id, bool behind) {
printf("stack_view(view_id=%d, neighbor_id=%d, behind=%d)\n",
view_id, neighbor_id, behind); }
void refresh(int x, int y, int w, int h) {
if (config_dump_refresh)
printf("refresh(x=%d, y=%d, w=%d, h=%d)\n", x, y, w, h); }
/**
* Main program
*/
int main()
{
/* create connection to the X server */
Display *dpy = XOpenDisplay(":0");
if (!dpy) {
printf("Error: Cannot open display\n");
return -4;
}
/* init event tracker library */
if (!xev_track_init(dpy))
return -6;
/* busy loop polls X events */
for (;;) {
XEvent ev;
XNextEvent(dpy, &ev);
/*
* By calling this function, the callbacks defined above are
* triggered.
*/
xev_track_handle_event(dpy, ev);
xev_track_handle_cursor(dpy);
}
return 0;
}

View File

@ -1,6 +0,0 @@
TARGET = test-xev_track
REQUIRES = host x11 xtest xdamage
SRC_CC = main.cc
LIBS = xev_track
EXT_OBJECTS += -lX11 -lXdamage /usr/lib/libXtst.so.6