2013-06-10 16 views
10

Przesyłam pewien kod z systemu Windows do XLib. W kodzie systemu Windows mogę wymusić przerysowanie, wywołując InvalidateRect, a następnie przetwarzając odpowiednią wiadomość WM_PAINT. Jednak mam problem ze znalezieniem sposobu, aby to zrobić w X11/XLib. Widzę komunikat Expose, ale nie jestem pewien, czy to jest to samo.Równoważnik "Invalidate Rect"/"WM_PAINT" w X11

Jeśli to ma znaczenie, muszę to zrobić, aby wymusić wykonanie okna z określoną liczbą klatek na sekundę dla programu opartego na OpenGL.

+0

Również, jeśli ktokolwiek mógłby zaproponować świetne odniesienie XLib, naprawdę bym to docenił. Podręczniki XLib na X.org nie wydają się być pomocne dla początkujących, przynajmniej nie dla mnie. – pauld

+0

Tak, to jest to samo. Zdecydowanie odradzam używanie surowego Xlib. Użyj nowoczesnego zestawu narzędzi, takiego jak Qt, gtk lub wX. –

+0

Ponadto, chociaż funkcja Expose będzie działać, polecam wywołanie funkcji odrysowywania bezpośrednio. To jest łatwiejsze i prostsze. –

Odpowiedz

4

Musisz obsługiwać zdarzenia ekspozycji. This tutorial wyjaśnia na przykładzie, jak radzić sobie Expose zdarzenia:

#include <stdio.h> 
#include <stdlib.h> 
#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <X11/Xos.h> 
#include <X11/Xatom.h> 
#include <X11/keysym.h> 
/*Linux users will need to add -ldl to the Makefile to compile 
*this example. 
*/ 
Display *dis; 
Window win; 
XEvent report; 
GC green_gc; 
XColor green_col; 
Colormap colormap; 
/* 
Try changing the green[] = below to a different color. 
The color can also be from /usr/X11R6/lib/X11/rgb.txt, such as RoyalBlue4. 
A # (number sign) is only needed when using hexadecimal colors. 
*/ 
char green[] = "#00FF00"; 

int main() { 
    dis = XOpenDisplay(NULL); 
    win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 500, 500, 0, BlackPixel (dis, 0), BlackPixel(dis, 0)); 
    XMapWindow(dis, win); 
    colormap = DefaultColormap(dis, 0); 
    green_gc = XCreateGC(dis, win, 0, 0); 
    XParseColor(dis, colormap, green, &green_col); 
    XAllocColor(dis, colormap, &green_col); 
    XSetForeground(dis, green_gc, green_col.pixel); 

    XSelectInput(dis, win, ExposureMask | KeyPressMask | ButtonPressMask); 

    XDrawRectangle(dis, win, green_gc, 1, 1, 497, 497); 
    XDrawRectangle(dis, win, green_gc, 50, 50, 398, 398); 
    XFlush(dis); 

    while (1) { 
    XNextEvent(dis, &report); 
     switch (report.type) { 
     case Expose: 
      fprintf(stdout, "I have been exposed.\n"); 
       XDrawRectangle(dis, win, green_gc, 1, 1, 497, 497); 
       XDrawRectangle(dis, win, green_gc, 50, 50, 398, 398); 
       XFlush(dis); 
      break; 
      case KeyPress: 
     /*Close the program if q is pressed.*/ 
       if (XLookupKeysym(&report.xkey, 0) == XK_q) { 
       exit(0); 
       } 
      break; 
     } 
    } 

return 0; 
} 

może ja źle na pytanie. Jeśli chcesz utworzyć zdarzenia ekspozycji w swojej aplikacji, możesz utworzyć i ustawić expose event i wysłać je za pomocą XSendEvent.

+0

Ok. Tak więc w oknach nazywam 'InvalidateRect', który później uruchamia okna, aby wysłać komunikat' WM_PAINT', w którym to momencie renderuję moją otwartą scenę. Więc w X11 nazwałbym 'XSendEvent' komunikatem' Expose', a następnie pętlą zdarzeń, która obsługuje komunikat 'Expose' i renderuje scenę open gl? – pauld

+0

@pauld Nie jestem pewien, czy podążam za Tobą. X11 używa systemu zdarzeń do powiadamiania aplikacji o różnych zdarzeniach. Mówisz, które zdarzenia chcesz obsłużyć.Jeśli chcesz wyrenderować swoją scenę po zdemaskowaniu zdarzeń, musisz dodać kod renderujący do tego programu obsługi zdarzeń. Nie rozumiem, dlaczego miałbyś wygenerować wydarzenie ekspozycyjne dla swojej aplikacji. –

+1

Ok Myślę, że rozumiem. W oknach mogę rysować do okna _ponownie_ podczas wiadomości 'WM_PAINT'. W X11 wydaje mi się, że mogę rysować do okna, kiedy tylko chcę, nie tylko w odpowiedzi na zdarzenie "Expose". W takim przypadku nie muszę generować zdarzeń ekspozycji, mogę rysować, kiedy jestem gotowy. – pauld

4

Aby rozwinąć nieco na użytecznych odpowiedzi udzielonych przez BЈовић,

z surowego Xlib można narysować w dowolnym momencie w jednym wątku, ponieważ każda funkcja Xlib określa pełną monitor, okna i kontekst. AFAIK, z wielowątkowością wszystkie zakłady są wyłączone.

Musisz mieć także funkcję obsługi zdarzeń Expose i wybrać dla nich zdarzenia, jeśli jesteś w środowisku graficznym. I nie zaszkodzi mieć, nawet jeśli piszesz program pełnoekranowy.

Większość zestawów narzędzi nie jest tak elastyczna i rysuje tylko w wyznaczonym programie obsługi zdarzeń (ale o wiele przyjemniejszym w użyciu na wiele innych sposobów) i ma odpowiednik Windows InvalidateRect. W surowym Xlib masz ten sam efekt, wysyłając sobie zdarzenie Expose. Nie spowoduje to żadnych rzeczywistych problemów z wydajnością i sprawi, że kod będzie bardziej zrozumiały dla innych programistów i łatwiejszy do przeniesienia, więc równie dobrze możesz.

Dostępne są również funkcje XClearArea i XClearWindow, które będą generować zdarzenia ekspozycji, ale najpierw usuwają część/całość z kolorem tła, co może powodować migotanie.

Z OpenGL robi się to nieco bardziej skomplikowane, ponieważ musisz także pracować z GLX. Mam bardzo prosty program OpenGL/Xlib online pod adresem http://cs.anu.edu.au/~hugh.fisher/3dteach/ , który może być przydatny jako przykład.

+3

Używanie 'XClearArea (disp, win, 0, 0, 1, 1, true)' aby wyczyścić jeden obszar pikseli wystarcza, aby spowodować "Zdarzenie ekspozycyjne" bez dodawania migotania. Możesz natychmiast użyć 'XClearArea()' z 'XFlush()', jeśli nie zobaczysz od razu zdarzeń 'Expose'. – Harvey