2011-12-21 7 views
22

Pod oknami, wątek GUI zwykle nazywamy GetMessage do oczekiwania na wiadomość, gdy inny stosowanie nici PoseMessage umieścić komunikat w kolejce, a następnie nić GUI powróci GetMessage (zamknij blokowania) .jak rzucić blokowanie xlib za XNextEvent

Czy ktoś może mi powiedzieć, kiedy używam XNextEvent w XWindows do oczekiwania na zdarzenie , jak mogę "obudzić" wątek GUI w innym wątku. Czy istnieje jakiś interfejs API , taki jak PoseMessage, z którego mogę korzystać?.

Odpowiedz

35

Nie. Dlatego większość frameworków UI (Gtk, KDE itp.) Używa niestandardowych pętli głównych, aby móc słuchać więcej źródeł zdarzeń.

Wewnętrznie, XNextEvent używa gniazda, więc dzwoni select(), aby wiedzieć, kiedy wejście jest dostępne. Możesz więc: zadzwonić pod numer ConnectionNumber(display), aby otrzymać deskryptor pliku, który musisz przekazać select()

Pozwala to na odsłuchiwanie kilku deskryptorów plików.

Przykładowy kod z http://www.linuxquestions.org/questions/showthread.php?p=2431345#post2431345

#include <stdio.h> 
#include <stdlib.h> 
#include <X11/Xlib.h> 
#include <X11/Xutil.h> 

Display *dis; 
Window win; 
int x11_fd; 
fd_set in_fds; 

struct timeval tv; 
XEvent ev; 

int main() { 
    dis = XOpenDisplay(NULL); 
    win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 256, 256, \ 
     0, BlackPixel (dis, 0), BlackPixel(dis, 0)); 

    // You don't need all of these. Make the mask as you normally would. 
    XSelectInput(dis, win, 
     ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | 
     ButtonPressMask | ButtonReleaseMask | StructureNotifyMask 
     ); 

    XMapWindow(dis, win); 
    XFlush(dis); 

    // This returns the FD of the X11 display (or something like that) 
    x11_fd = ConnectionNumber(dis); 

    // Main loop 
    while(1) { 
     // Create a File Description Set containing x11_fd 
     FD_ZERO(&in_fds); 
     FD_SET(x11_fd, &in_fds); 

     // Set our timer. One second sounds good. 
     tv.tv_usec = 0; 
     tv.tv_sec = 1; 

     // Wait for X Event or a Timer 
     int num_ready_fds = select(x11_fd + 1, &in_fds, NULL, NULL, &tv); 
     if (num_ready_fds > 0) 
      printf("Event Received!\n"); 
     else if (num_ready_fds == 0) 
      // Handle timer here 
      printf("Timer Fired!\n"); 
     else 
      printf("An error occured!\n"); 

     // Handle XEvents and flush the input 
     while(XPending(dis)) 
      XNextEvent(dis, &ev); 
    } 
    return(0); 
} 
+0

Cześć Aaron, to niesamowite rozwiązanie. To jest tylko przechwytywanie zdarzeń w tym oknie, czy możliwe jest globalne odsłuchiwanie zdarzeń myszy? I można zablokować zdarzenia myszy za pomocą tej metody? – Noitidart

+1

@Noitidart: Może, ale nie mogę odpowiedzieć na to w komentarzu. Zadaj nowe pytanie, proszę i nie zapomnij podać więcej szczegółów, co dokładnie musisz osiągnąć. –

+0

Ach, dziękuję bardzo, wysłałem pytanie tutaj: http://stackoverflow.com/questions/32262767/mouse-events-callback – Noitidart

9

Można zamknąć blokowanie XNextEvent, wysyłając sobie atrapę wydarzenie.

Window interClientCommunicationWindow; 
Bool x11EventLoopActive = True; 

// create a dummy window, that we can use to end the blocking XNextEvent call 
interClientCommunicationWindow = XCreateSimpleWindow(dpy, root, 10, 10, 10, 10, 0, 0, 0); 
XSelectInput(dpy, interClientCommunicationWindow, StructureNotifyMask); 

XEvent event; 
while(x11EventLoopActive) { 
    XNextEvent(dpy, &event); 
    ... 
} 

W innym wątku można to zrobić, aby zakończyć pętlę:

x11EventLoopActive = False; 
// push a dummy event into the queue so that the event loop has a chance to stop 
XClientMessageEvent dummyEvent; 
memset(&dummyEvent, 0, sizeof(XClientMessageEvent)); 
dummyEvent.type = ClientMessage; 
dummyEvent.window = interClientCommunicationWindow; 
dummyEvent.format = 32; 
XSendEvent(dpy, interClientCommunicationWindow, 0, 0, (XEvent*)&dummyEvent); 
XFlush(dpy); 
+8

Niebezpieczeństwo, Will Robinson! Xlib * nie jest bezpieczny dla wątków *! Powyższy kod będzie wyglądać tak, jakby działał, ale w rzeczywistości spowoduje awarię losową i nieczęsto w bardzo trudny do debugowania sposób. Nie rób tego! –

+1

@DavidDowiedz się, co jeśli nazwiemy 'XInitThreads'? – Noitidart

2

należy użyć: Bool XCheckMaskEvent (Display *, długie, XEvent)

W XCheckMaskEvent Funkcja najpierw wyszukiwania kolejka zdarzeń, a następnie wszelkie zdarzenia dostępne w połączeniu z serwerem dla pierwszego zdarzenia pasującego do określonej maski.

Jeśli znajdzie dopasowanie, XCheckMaskEvent usuwa to zdarzenie, kopiuje je do określonej struktury XEvent i zwraca True. Pozostałe zdarzenia przechowywane w kolejce nie są odrzucane.

Jeśli żądane zdarzenie nie jest dostępne, XCheckMaskEvent zwraca False, a bufor wyjściowy zostanie przepłukany.

+0

Nie mogłem tego zmusić do działania. Czekałem na zdarzenia PointerBarrier i nie wiem, jaka maska ​​byłaby odpowiednia? Co działało, było używane, jeśli (XPending (_display)> 0); następnie XNextEvent; w przeciwnym razie kontynuuj; – kevinf