2011-12-21 8 views
22

Debajo de Windows, el hilo de la GUI generalmente llama a GetMessage al mensaje en espera, cuando otro hilo usa PoseMessage pone un mensaje en la cola, entonces el hilo de la GUI devolverá GetMessage (dejar de bloquear) .cómo cerrar el bloqueo de xLib XNextEvent

¿Alguien puede decirme que cuando uso XNextEvent en XWindows para esperar el evento , cómo puedo "activar" el hilo de la GUI en otro hilo. ¿Hay alguna API de como PoseMessage que pueda usar?

Respuesta

35

No. Esta es la razón por la que la mayoría de los marcos de IU (Gtk, KDE, etc.) utilizan bucles principales personalizados para poder escuchar más fuentes de eventos.

Internamente, XNextEvent usa un socket, por lo que llama a select() para saber cuándo hay entradas disponibles. Entonces puede: Llamar al ConnectionNumber(display) para obtener el descriptor de archivo que necesita pasar select()

que le permite escuchar varios descriptores de archivos.

código de ejemplo de 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

Hola Aaron esta es una solución increíble. Esto solo captura eventos en esa ventana, ¿es posible escuchar eventos de mouse globalmente? ¿Y es posible bloquear los eventos del mouse con este método? – Noitidart

+1

@Noitidart: Tal vez, pero no puedo responder eso en un comentario. Haga una nueva pregunta, por favor y no se olvide de dar más detalles de lo que necesita lograr exactamente. –

+0

Ah, muchas gracias, he publicado una pregunta aquí, por favor: http://stackoverflow.com/questions/32262767/mouse-events-callback – Noitidart

9

Puede salir de la XNextEvent bloqueo, mediante el envío de un evento simulado mismo.

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

En otro hilo se puede hacer esto para terminar el bucle:

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

¡Peligro, Will Robinson! Xlib * no es seguro para subprocesos *! El código anterior parecerá que funciona, pero de hecho fallará aleatoriamente y con poca frecuencia de una manera muy difícil de depurar. No lo hagas! –

+1

@DavidGiven ¿y si llamamos a 'XInitThreads'? – Noitidart

2

que puedes usar: Bool XCheckMaskEvent (Pantalla *, largo, XEvent)

Los XCheckMaskEvent función primeras búsquedas la cola de eventos, y luego cualquier evento disponible en la conexión del servidor para el primer evento que coincida con la máscara especificada.

Si se encuentra una coincidencia, XCheckMaskEvent elimina ese evento, lo copia en el XEvent estructura especificada y devuelve True. Los otros eventos almacenados en la cola no se descartan.

Si el evento solicitado no está disponible, XCheckMaskEvent devuelve False, y el búfer de salida se habrá enjuagado.

+0

No pude hacer que eso funcione. Estaba esperando los eventos de PointerBarrier y no estaba seguro de qué máscara sería apropiada. Lo que funcionó, fue usar if (XPending (_display)> 0); luego XNextEvent; else continuar; – kevinf

Cuestiones relacionadas