2016-08-17 15 views
5

Potrzebuję narysować kształt bezpośrednio na ekranie (mała strzałka) w X11, służy on jako nakładka. Szukam około godziny nie bez dobrych wyników. Czy ktokolwiek mógłby mi zapewnić dobry punkt wyjścia do tego, czego potrzebuję? Technologie, z których mogę korzystać to cairo, gtk lub XLib.X11: Rysuj nakładkę/Usuń rysunki z nakładki

Wszystko, co znalazłem do tej pory, zależy od kompozycji, która nie zawsze jest dostępna, lub tworzy biały kształt za moją strzałką (prostokąt, okno).

EDYCJA: Teraz jestem w stanie narysować nakładkę X11 za pomocą kompozytów i Kairu. Robię to w ten sposób (uwaga: jest to minimalny przykład, ma niewiele do sprawdzenia błędów !!!). Zacznij od Terminalu, aby go zamknąć!

// 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; 
} 

Pozostało pytanie: Jak usunąć stary kursor, który został narysowany? Spróbowałem XClearArea, próbowałem przemalować Kair, spróbowałem operatora Clear Cairo, itp. Nic nie działało. Czy ktoś może skierować mnie tutaj w dobrym kierunku?

+2

Core X11 tego nie robi, będziesz potrzebować jakiegoś rozszerzenia. Możesz użyć rozszerzenia złożonego lub kształtu. Kształt jest łatwiej dostępny niż kompozyt. Możesz także użyć nakładki wizualnej, jeśli jest dostępna (wymaga obsługi OpenGL i nakładki w sprzęcie). –

+0

Można również rysować bezpośrednio nad istniejącymi oknami, ale nie jest to zalecane. Jeśli inny program próbuje odświeżyć w tym samym czasie, wynik może nie wyglądać prawidłowo. –

+0

Spójrz na źródło xeyes. Starożytne, ale działa. –

Odpowiedz

0

Mam rozwiązać ten problem sam się używając Rozszerzenie kształtu z X11 i oddzielna pętla wiadomości w wątku. Nie jest idealny, ale działa. Zły kod pocztowy, gdy tylko będę miał dostęp do kodu ponownie (chory bankomat).

0

Ta odpowiedź powinna pomóc:

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

kuponów iść do sdbbs na 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

Powoduje rysowanie prostokąta poprzez XORing ekranu z prostokąta. Chociaż ta metoda działa poprawnie na statycznym ekranie, nie działa z ciągle aktualizowanymi oknami. –

+0

Przykro mi, ale nie tego chcę. To zastępuje mój kursor. Chcę mieć drugi. – Nidhoegger

+1

@Nidhoegger Nie musisz wymieniać kursora. Zmień 'kursor' i' kursor2' na 'Brak' w wywołaniach, aby chwycić funkcje. –