我在Ubuntu 14.04平台上,我正在尝试为我的截屏项目制作橡皮带。我找到了使用xlib的橡皮带示例,但是在拖动鼠标的同时我得到了闪烁和部分缺失的矩形。我想知道它是否特定于我的系统或xlib库已被弃用? 有解决方法吗?
我还注意到imagemagic的屏幕位置抓取命令import window.miff
以同样的方式闪烁。
以下是我尝试的代码
答案 0 :(得分:3)
看起来背景中的终端正在重绘自己。你可能总是自私,做一个XGrabServer()
,在移动/调整窗口大小时使用矩形的WM会这样做。屏幕上没有任何其他内容(时钟,负载监视器)将更新,直到您释放抓取。
应避免服务器抓取。您可能希望添加--grab/--nograb
选项,让用户决定是否更喜欢避免使用可视化工件,还是让其他应用程序(电影播放器,负载监视器,时钟......)在橡皮带过程中更新屏幕。
另一个选择是使用半透明窗口而不是轮廓矩形,类似于现代窗口管理器倾向于使用真实窗口而不是橡皮带来移动/调整窗口大小(即使这可能意味着重新涂抹窗口很多次之前操作完成后,对于远程X移动/调整大小的橡皮带绝对是更好的表现。)
XGrabServer()
令人讨厌的例子:
XGrabServer()
冻结在其他窗口上播放的视频,并对流媒体网络连接造成严重破坏。XGrabServer()
,用户在启动应用程序时抱怨大约25秒长冻结。答案 1 :(得分:1)
如果在GC中使用xor,则可以通过再次绘制完全相同的图形来有选择地擦除线条。您不需要重新绘制整个窗口。
XSetFunction(dpy,gc,GXxor); // sets xor mode
只需设置一些缓冲区并保留绘制内容的副本,以便您可以再次进行绘制(包括颜色)。
我去年写过这篇文章:https://www.raspberrypi.org/forums/viewtopic.php?p=1317849我将最后50行存储在循环缓冲区中,然后重画以擦除它们。我可以运行数小时,而不会出现不完整的擦除工件。而且CPU使用率非常低。这几乎是xscreensaver的质量。
答案 2 :(得分:0)
定义:Rubberbanding 是在屏幕上拖动鼠标时在屏幕上绘制的屏幕选择矩形。当鼠标按钮释放时,它会打印屏幕的几何图形。 X Window 系统在桌面上缺乏透明度,因此它通过合并图层来使用伪透明。包含桌面壁纸的屏幕称为“根窗口”。在根窗口上绘制是一个问题,因为其他窗口,例如时钟,需要重新绘制自身,在这种情况下,您的橡皮筋矩形闪烁。为避免此问题,您需要使用覆盖整个屏幕的半透明或透明窗口。
解决方案:正如@ninjalj 在他的回答中所述,您需要使用覆盖整个屏幕的透明/半透明窗口。
源代码:
// gcc xrubberband.c -o xrubberband -lX11
// use case ; maim -w root -g $(./xrubberband) `date +%H-%M-%S`.png
#include <stdio.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/extensions/XTest.h>
#include <X11/extensions/XInput.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdlib.h>
#include <stdarg.h>
#include <X11/Xatom.h>
#define MAKE_RECT(etype) \
x = event.etype.x_root; \
y = event.etype.y_root; \
rw = x - rootx; \
if (rw < 0) rw = -rw; \
rh = y - rooty; \
if (rh < 0) rh = -rh; \
rx = x < rootx ? x : rootx; \
ry = y < rooty ? y : rooty
/* MAKE_CURSOR assigns a correct cursor */
#define MAKE_CURSOR(etype) \
pointer = (event.etype.x_root > rootx ? \
(event.etype.y_root > rooty ? pointer2 : pointer4) : \
(event.etype.y_root > rooty ? pointer3 : pointer1));
XRectangle Select_Rect(Display *dpy, int screen_num, Window root, Window parent, unsigned int display_width, unsigned int display_height)
{
int status;
XRectangle xrect;
XEvent event;
unsigned int x = 0, y = 0, rootx = 0, rooty = 0;
Cursor pointer1, pointer2, pointer3, pointer4, pointer;
int boxDrawn = False, selectionDone = False;
int rx = 0, ry = 0, rw = 0, rh = 0;
GC gc;
/* get some cursors for rectangle formation */
pointer1 = XCreateFontCursor(dpy, XC_ul_angle);
pointer2 = XCreateFontCursor(dpy, XC_lr_angle);
pointer3 = XCreateFontCursor(dpy, XC_ll_angle);
pointer4 = XCreateFontCursor(dpy, XC_ur_angle);
/* grab the pointer */
status = XGrabPointer(dpy, root, False, ButtonPressMask,
GrabModeAsync, GrabModeAsync, root,
pointer1, CurrentTime);
// if (status != GrabSuccess) Fatal_Error("Can't grab the mouse.");
//if (status != GrabSuccess) fprintf( stderr, "Can't grab the mouse.\n");
/* create a graphics context to draw with */
gc = XCreateGC(dpy, parent, 0, NULL);
// if (!gc) Fatal_Error("Could not get drawing resources.");
if (!gc) fprintf( stderr, "Could not get drawing resources.\n");
XSetSubwindowMode(dpy, gc, IncludeInferiors);
XSetForeground(dpy, gc, 255);
XSetFunction(dpy, gc, GXinvert);
/* get a button-press and pull out the root location */
XMaskEvent(dpy, ButtonPressMask, &event);
rootx = rx = event.xbutton.x_root;
rooty = ry = event.xbutton.y_root;
/* get pointer motion events */
XChangeActivePointerGrab(dpy, ButtonMotionMask | ButtonReleaseMask, pointer2, CurrentTime);
/* loop to let the user drag a rectangle */
while (!selectionDone) {
XNextEvent(dpy, &event);
switch(event.type) {
case ButtonRelease:
if (boxDrawn) {
XDrawRectangle(dpy, parent, gc, rx, ry, rw, rh);
boxDrawn = False;
}
XFlush(dpy);
/* record the final location */
MAKE_RECT(xbutton);
selectionDone = True;
break;
case MotionNotify:
if (boxDrawn) {
XDrawRectangle(dpy, parent, gc, rx, ry, rw, rh);
boxDrawn = False;
}
// while (XCheckTypedEvent(dpy, MotionNotify, &event)) { }
MAKE_RECT(xmotion);
XDrawRectangle(dpy, parent, gc, rx, ry, rw, rh);
boxDrawn = True;
MAKE_CURSOR(xmotion);
XChangeActivePointerGrab(dpy,
ButtonMotionMask | ButtonReleaseMask,
pointer, CurrentTime);
break;
}
}
xrect.x = rx;
xrect.y = ry;
xrect.width = rw;
xrect.height = rh;
/* release resources */
XFreeGC(dpy, gc);
XFreeCursor(dpy, pointer1);
XFreeCursor(dpy, pointer2);
XFreeCursor(dpy, pointer3);
XFreeCursor(dpy, pointer4);
XUngrabPointer(dpy, CurrentTime);
int x1 = rx + rw, y1 = ry + rh;
if ( display_width < x1 ) x1 = rx - rw;
if ( display_height < y1 ) y1 = ry - rh;
printf("\n%dx%d+%d+%d", rw, rh, rx, ry);
return xrect;
}
int main(int argc, char* argv[])
{
Display* dpy; /* pointer to X Display structure. */
int screen_num; /* number of screen to place the window on. */
Window win; /* pointer to the newly created window. */
unsigned int display_width,
display_height; /* height and width of the X display. */
unsigned int width, height; /* height and width for the new window. */
unsigned int win_x, win_y; /* location of the window's top-left corner. */
unsigned int win_border_width; /* width of window's border. */
char *display_name = getenv("DISPLAY"); /* address of the X display. */
Atom skip, state;
dpy = XOpenDisplay(display_name);
if (dpy == NULL) {
fprintf(stderr, "%s: cannot connect to X server '%s'\n",
argv[0], display_name);
exit(1);
}
/* get the geometry of the default screen for our display. */
screen_num = DefaultScreen(dpy);
display_width = DisplayWidth(dpy, screen_num);
display_height = DisplayHeight(dpy, screen_num);
// display_width =1280;
// display_height =800;
char *window_name = (char*)"Drawing window";
int whiteColor = WhitePixel(dpy, screen_num);
Window root = RootWindow(dpy,screen_num);
XVisualInfo vinfo;
XMatchVisualInfo(dpy, DefaultScreen(dpy), 32, TrueColor, &vinfo);
XSetWindowAttributes attr;
attr.colormap = XCreateColormap(dpy, root, vinfo.visual, AllocNone);
attr.border_pixel = 0;
attr.background_pixel = 0;
attr.override_redirect = 1;
attr.border_pixel = 0;
Window parent = XCreateWindow(dpy, root, 0, 0, display_width, display_height, 0, vinfo.depth, InputOutput, vinfo.visual, CWColormap | CWBorderPixel | CWBackPixel, &attr);
state = XInternAtom(dpy, "_NET_WM_STATE", True);
skip = XInternAtom(dpy, "_NET_WM_STATE_SKIP_TASKBAR", True);
Atom wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", 0);
XSetWMProtocols(dpy, parent, &wm_delete_window, 1);
XChangeProperty(dpy, parent, state, XA_ATOM, 32,
PropModeReplace, (unsigned char*)&skip, 1);
XStoreName(dpy, parent, window_name);
XMapWindow(dpy, parent);
XSelectInput(dpy, parent, StructureNotifyMask| ButtonPressMask| PointerMotionMask| LeaveWindowMask| EnterWindowMask| ButtonReleaseMask );
Drawable d = parent;
XGCValues values;
values.line_width = 4;
values.line_style = LineSolid;
GC gc = XCreateGC(dpy, d, GCLineWidth, &values);
Select_Rect(dpy, screen_num, root, parent, display_width, display_height);
return 0;
}
我使用了 http://web.mit.edu/graphics/src/xgrabsc/xgrabsc.c 中的 #define MAKE_RECT(etype)