2011-12-21 6 views
22

sotto Windows, il filo GUI di solito chiamare GetMessage di attesa del messaggio, quando un altro uso filo PoseMessage messo un messaggio nella coda, poi il filo GUI tornerà GetMessage (quit blocco) .come uscire il blocco dei XNextEvent di xlib

Qualcuno può dirmi, quando uso XNextEvent in XWindows per attendere l'evento , come posso "attivare" il thread della GUI in un altro thread. Ci sono alcune API come PoseMessage che posso usare?

risposta

35

No. Questo è il motivo per cui la maggior parte dei framework UI (Gtk, KDE, ecc.) Utilizzano loop principali personalizzati per poter ascoltare più sorgenti di eventi.

Internamente, XNextEvent utilizza un socket, quindi chiama select() per sapere quando l'input è disponibile. Così puoi: Chiama ConnectionNumber(display) per ottenere il descrittore di file che devi passare select()

Ciò consente di ascoltare diversi descrittori di file.

codice di esempio da 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

Ciao Aaron questa è una soluzione eccezionale. In questa finestra si verificano solo gli eventi, è possibile ascoltare gli eventi del mouse a livello globale? E possibile bloccare gli eventi del mouse con questo metodo? – Noitidart

+1

@Noitidart: Forse, ma non posso rispondere in un commento. Fai una nuova domanda, per favore e non dimenticare di fornire maggiori dettagli su cosa esattamente devi ottenere. –

+0

Ah grazie mille ho postato domanda qui per favore: http://stackoverflow.com/questions/32262767/mouse-events-callback – Noitidart

9

È possibile uscire dal XNextEvent blocco, con l'invio di voi stessi un evento fittizio.

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); 
    ... 
} 

In un altro thread si può fare questo per terminare il ciclo:

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

Pericolo, Will Robinson! Xlib è * non thread safe *! Il codice sopra sembrerà funzionare, ma si bloccherà in modo casuale e raro in modo molto difficile da eseguire. Non farlo! –

+1

@DavidGiven cosa succede se abbiamo chiamato 'XInitThreads'? – Noitidart

2

si dovrebbe usare: Bool XCheckMaskEvent (Display *, lunga, Xevent)

I XCheckMaskEvent funzione prime ricerche la coda eventi e quindi tutti gli eventi disponibili sulla connessione server per il primo evento che corrisponde alla maschera specificata.

Se trova una corrispondenza, XCheckMaskEvent rimuove quell'evento, lo copia nella struttura specificata XEvent e restituisce True. Gli altri eventi memorizzati nella coda non vengono eliminati.

Se l'evento richiesto non è disponibile, XCheckMaskEvent restituisce False e il buffer di output è stato svuotato.

+0

Non riuscivo a farlo funzionare. Stavo aspettando gli eventi di PointerBarrier e non ero sicuro di quale maschera sarebbe stata appropriata? Cosa funzionava, stava usando if (XPending (_display)> 0); poi XNextEvent; altrimenti continua; – kevinf