我需要在X11中直接在屏幕上绘制一个形状(一个小箭头),它用作叠加层。我正在寻找大约一个小时没有没有好结果。任何人都可以为我提供一个很好的切入点吗?我可以使用的技术是cairo,gtk或XLib。
到目前为止我发现的所有东西都取决于构图,它并不总是可用,或者会在我的箭头后面创建一个白色的形状(矩形,一个窗口)。
编辑:我现在能够使用Composite和Cairo绘制X11叠加层。我是这样做的(注意:这是一个最小的例子。几乎没有错误检查!!!)。从终端开始可以退出它!
// COMPILE WITH: g++ -o overlay overlay.cc -lXfixes -lXcomposite -lX11 `pkg-config --cflags --libs cairo`
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/shape.h>
#include <cairo/cairo.h>
#include <cairo/cairo-xlib.h>
#include <stdio.h>
#include <unistd.h>
Display *display_;
int old_x_, old_y_;
cairo_surface_t *surf_;
Window overlay_;
int screen_;
int height_;
int width_;
cairo_t *cr_;
void paint_cursor(int new_x, int new_y, bool first = false)
{
if (!first)
{
cairo_set_operator(cr_, CAIRO_OPERATOR_CLEAR);
cairo_rectangle(cr_, old_x_, old_y_, 20, 20);
cairo_fill(cr_);
}
old_x_ = new_x;
old_y_ = new_y;
cairo_set_operator(cr_, CAIRO_OPERATOR_SOURCE);
cairo_move_to(cr_, new_x, new_y);
cairo_line_to(cr_, new_x + 0, new_y + 16);
cairo_line_to(cr_, new_x + 4, new_y + 13);
cairo_line_to(cr_, new_x + 7, new_y + 18);
cairo_line_to(cr_, new_x + 9, new_y + 17);
cairo_line_to(cr_, new_x + 6, new_y + 12);
cairo_line_to(cr_, new_x + 11, new_y + 12);
cairo_line_to(cr_, new_x + 0, new_y + 0);
cairo_set_source_rgba(cr_, 0.0, 0.0, 0.0, 0.5);
cairo_stroke_preserve(cr_);
cairo_set_source_rgba(cr_, 0.0, 1.0, 0.0, 0.5);
cairo_fill(cr_);
}
int main()
{
display_ = ::XOpenDisplay(0);
if (!display_)
{
return -1;
}
screen_ = ::XDefaultScreen(display_);
Window root = RootWindow(display_, screen_);
::XCompositeRedirectSubwindows(display_, root, CompositeRedirectAutomatic);
::XSelectInput(display_, root, SubstructureNotifyMask);
overlay_ = ::XCompositeGetOverlayWindow(display_, root);
XserverRegion region = ::XFixesCreateRegion(display_, 0, 0);
::XFixesSetWindowShapeRegion(display_, overlay_, ShapeBounding, 0, 0, 0);
::XFixesSetWindowShapeRegion(display_, overlay_, ShapeInput, 0, 0, region);
::XFixesDestroyRegion(display_, region);
width_ = DisplayWidth(display_, screen_);
height_ = DisplayHeight(display_, screen_);
surf_ = ::cairo_xlib_surface_create(display_, overlay_, DefaultVisual(display_, screen_), width_, height_);
cr_ = ::cairo_create(surf_);
::XSelectInput(display_, overlay_, ExposureMask);
old_x_ = 0;
old_y_ = 0;
paint_cursor(0, 0, true);
XEvent ev;
Window root_return, child_return;
int root_x_return, root_y_return;
int win_x_return, win_y_return;
unsigned int mask;
for (;;)
{
XQueryPointer(display_, root, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask);
paint_cursor(root_x_return, root_y_return);
printf("Paint\n");
}
return 0;
}
剩下的问题:如何删除绘制的旧光标?我尝试了XClearArea,我试图用开罗重复绘图,我尝试了Cairo Clear操作符等。没有任何效果。有人能指出我在正确的方向吗?
答案 0 :(得分:0)
这个答案可以帮助你:
"How can I draw selection rectangle on screen for my script?"
积分转到askubuntu.com上的sdbbs
#include<stdio.h>
#include<stdlib.h>
#include<X11/Xlib.h>
#include<X11/cursorfont.h>
#include<unistd.h> // added for sleep/usleep
// original from [https://bbs.archlinux.org/viewtopic.php?id=85378 Select a screen area with mouse and return the geometry of this area? / Programming & Scripting / Arch Linux Forums]
// build with (Ubuntu 14.04):
// gcc -Wall xrectsel.c -o xrectsel -lX11
int main(void)
{
int rx = 0, ry = 0, rw = 0, rh = 0;
int rect_x = 0, rect_y = 0, rect_w = 0, rect_h = 0;
int btn_pressed = 0, done = 0;
XEvent ev;
Display *disp = XOpenDisplay(NULL);
if(!disp)
return EXIT_FAILURE;
Screen *scr = NULL;
scr = ScreenOfDisplay(disp, DefaultScreen(disp));
Window root = 0;
root = RootWindow(disp, XScreenNumberOfScreen(scr));
Cursor cursor, cursor2;
cursor = XCreateFontCursor(disp, XC_left_ptr);
cursor2 = XCreateFontCursor(disp, XC_lr_angle);
XGCValues gcval;
gcval.foreground = XWhitePixel(disp, 0);
gcval.function = GXxor;
gcval.background = XBlackPixel(disp, 0);
gcval.plane_mask = gcval.background ^ gcval.foreground;
gcval.subwindow_mode = IncludeInferiors;
GC gc;
gc = XCreateGC(disp, root,
GCFunction | GCForeground | GCBackground | GCSubwindowMode,
&gcval);
/* this XGrab* stuff makes XPending true ? */
if ((XGrabPointer
(disp, root, False,
ButtonMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync,
GrabModeAsync, root, cursor, CurrentTime) != GrabSuccess))
printf("couldn't grab pointer:");
if ((XGrabKeyboard
(disp, root, False, GrabModeAsync, GrabModeAsync,
CurrentTime) != GrabSuccess))
printf("couldn't grab keyboard:");
// see also: http://stackoverflow.com/questions/19659486/xpending-cycle-is-making-cpu-100
while (!done) {
//~ while (!done && XPending(disp)) {
//~ XNextEvent(disp, &ev);
if (!XPending(disp)) { usleep(1000); continue; } // fixes the 100% CPU hog issue in original code
if ( (XNextEvent(disp, &ev) >= 0) ) {
switch (ev.type) {
case MotionNotify:
/* this case is purely for drawing rect on screen */
if (btn_pressed) {
if (rect_w) {
/* re-draw the last rect to clear it */
XDrawRectangle(disp, root, gc, rect_x, rect_y, rect_w, rect_h);
} else {
/* Change the cursor to show we're selecting a region */
XChangeActivePointerGrab(disp,
ButtonMotionMask | ButtonReleaseMask,
cursor2, CurrentTime);
}
rect_x = rx;
rect_y = ry;
rect_w = ev.xmotion.x - rect_x;
rect_h = ev.xmotion.y - rect_y;
if (rect_w < 0) {
rect_x += rect_w;
rect_w = 0 - rect_w;
}
if (rect_h < 0) {
rect_y += rect_h;
rect_h = 0 - rect_h;
}
/* draw rectangle */
XDrawRectangle(disp, root, gc, rect_x, rect_y, rect_w, rect_h);
XFlush(disp);
}
break;
case ButtonPress:
btn_pressed = 1;
rx = ev.xbutton.x;
ry = ev.xbutton.y;
break;
case ButtonRelease:
done = 1;
break;
}
}
}
/* clear the drawn rectangle */
if (rect_w) {
XDrawRectangle(disp, root, gc, rect_x, rect_y, rect_w, rect_h);
XFlush(disp);
}
rw = ev.xbutton.x - rx;
rh = ev.xbutton.y - ry;
/* cursor moves backwards */
if (rw < 0) {
rx += rw;
rw = 0 - rw;
}
if (rh < 0) {
ry += rh;
rh = 0 - rh;
}
XCloseDisplay(disp);
printf("%dx%d+%d+%d\n",rw,rh,rx,ry);
return EXIT_SUCCESS;
}
答案 1 :(得分:0)
我现在使用X11中的Shape扩展和线程中的单独消息循环自己解决了这个问题。它不理想,但它的工作原理。一旦我再次访问代码(生病的atm),就会发布错误的邮政编码。