2016-08-17 1 views
5

X11에서 화면에 직접 모양을 그려야합니다 (작은 화살표). 오버레이로 사용됩니다. 나는 좋은 결과가없는 한 시간 정도를 찾고 있습니다. 누구든지 내가 필요한 것을 얻을 수있는 좋은 진입 점을 제공 할 수 있습니까? 내가 사용할 수있는 기술은 카이로, gtk 또는 XLib입니다.X11 : 오버레이 그리기/오버레이에서 도면 제거

내가 지금까지 찾은 모든 것이 항상 사용할 수있는 것은 아니지만, 내 화살표 (사각형, 창) 뒤에 흰색 모양을 만듭니다.

편집 : 이제 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를 시험해 보았고, 나는 카이로를 overpaint하려고 시도했다. 나는 Cairo Clear operator를 시도했다. 아무것도하지 않았다. 누군가가 올바른 방향으로 나를 가리킬 수 있습니까?

+2

Core X11에서는이 작업을 수행하지 않으므로 일부 확장자가 필요합니다. 복합 또는 모양 확장을 사용할 수 있습니다. 모양은 컴포지트보다 쉽게 ​​사용할 수 있습니다. 사용 가능한 경우 오버레이 비주얼을 사용할 수도 있습니다 (하드웨어에서 OpenGL 및 오버레이 지원 필요). –

+0

기존 창 바로 위에 그릴 수도 있지만 권장하지는 않습니다. 다른 프로그램이 동시에 다시 그리기를 시도하면 결과가 제대로 표시되지 않을 수 있습니다. –

+0

xeyes의 근원을보십시오. 고대지만 작동합니다. –

답변

0

에서 sdbbs로 이동 X11에서 모양 확장 및 스레드에서 별도의 메시지 루프. 그 이상은 아니지만 작동합니다. 내가 코드에 다시 액세스하자마자 병약 한 게시물 코드 (아픈 atm).

0

이 대답은 당신을 도움이 될 것입니다

"How can I draw selection rectangle on screen for my script?"

크레딧은 나 자신이 지금를 사용하여이 문제를 해결 한 askubuntu.com

#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; 
} 
+0

이것은 화면을 사각형과 XOR 처리하여 사각형을 그립니다. 이 방법은 정적 화면에서는 정상적으로 작동하지만 지속적으로 업데이트되는 창에서는 실패합니다. –

+0

미안하지만 이것은 내가 원하는 것이 아닙니다. 이것은 내 커서를 대체합니다. 나는 두 번째 것을 갖고 싶다. – Nidhoegger

+1

@Nidhoegger 커서를 바꿀 필요가 없습니다. 함수를 잡으려고 할 때'cursor'와'cursor2'를'None'으로 변경하십시오. –