c linux x11 xlib

¿Cómo salgo con gracia de un ciclo de eventos X11?



linux xlib (2)

Casi todos los tutoriales que encuentro me dicen que haga esto para mi ciclo de eventos:

XEvent event; while (true) { XNextEvent(display, &event); switch (event.type) { case Expose: printf("Expose/n"); break; default: break; } }

Sin embargo, al hacer clic en la X para cerrar el programa, aparece este mensaje.

XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0" after 10 requests (10 known processed) with 0 events remaining.

De hecho, es extraño para mí que los ejemplos sugieran el uso de un ciclo infinito. Eso no suena natural, y mis otros programas X11 no hacen eso. Entonces busqué alrededor. Descubrí cómo capturar el evento close de la ventana.

Atom wmDeleteMessage = XInternAtom(mDisplay, "WM_DELETE_WINDOW", False); XSetWMProtocols(display, window, &wmDeleteMessage, 1); XEvent event; bool running = true; while (running) { XNextEvent(display, &event); switch (event.type) { case Expose: printf("Expose/n"); break; case ClientMessage: if (event.xclient.data.l[0] == wmDeleteMessage) running = false; break; default: break; } }

Eso funciona. Sale sin errores. ... Pero me niego a creer que esta es la forma normal de hacer las cosas. Quiero decir, ¿es esta la única forma de salir correctamente de una aplicación X11? Parece mucho trabajo solo capturar el evento cercano. ¿Cómo puedo hacer un ciclo de evento ''apropiado''? ¿Por qué el evento cercano está tan profundamente enterrado? ¿Qué me estoy perdiendo?


El problema radica en la comunicación entre X Server y Window Manager.

Cuando llamas a XCreateWindow o XCreateSimpleWindow , el servidor X crea tu ventana (no la muestra hasta que explícitamente la XMapWindow a la pantalla llamando a XMapWindow ), y luego Window Manager es responsable de adjuntar todas las decoraciones y botones y el menú del sistema alrededor de tu ventana .

Puede llamar a XDestroyWindow por su cuenta para eliminar la ventana, y esto generalmente significa que simplemente desaparece de la pantalla, pero su programa aún se está ejecutando y la conexión con el servidor X aún está abierta, por lo que puede enviarle más solicitudes.

El problema comienza cuando el usuario hace clic en el pequeño botón X adjunto a su ventana por el Administrador de ventanas, porque no es creado por el Servidor X y no le corresponde a él decidir qué hacer entonces. Ahora todo está en manos de Window Manager.

Si el Administrador de ventanas simplemente llamara a XDestroyWindow en su ventana, causaría un problema si su aplicación quisiera capturar el evento de cierre para hacer algo antes de que se destruya la ventana. Entonces, la convención se estableció entre el Servidor X y los Administradores de Ventanas para manejar este proceso.

El comportamiento predeterminado de la mayoría de los administradores de ventanas es destruir la ventana y cerrar la conexión con el servidor X , porque esto es lo que la mayoría de los usuarios de los administradores de ventanas esperarían: cuando cierren la ventana, el programa terminará (y la conexión al X Server se cerrará con la ventana cerrada). Y luego, cuando intente llamar a XCloseDisplay(display) , causará el error de IO que ha mencionado, porque la conexión al servidor ya está cerrada y la estructura de display no es válida.

Aquí hay un extracto de la documentación de Xlib que explica esto:

Los clientes que elijan no incluir WM_DELETE_WINDOW en la propiedad WM_PROTOCOLS pueden desconectarse del servidor si el usuario solicita que se elimine una de las ventanas de nivel superior del cliente.

Sí, sería genial si no lo ocultaran tan profundamente en sus documentos, sin embargo :-P Pero cuando ya lo encuentras, afortunadamente también sugiere la solución.

Si desea un comportamiento diferente (es decir, para capturar el evento de cierre desde el Administrador de ventanas), debe usar el protocolo WM_DESTROY_WINDOW .

Otro extracto de los documentos:

Los clientes, generalmente aquellos con múltiples ventanas de nivel superior, cuya conexión de servidor debe sobrevivir a la eliminación de algunas de sus ventanas de nivel superior, deben incluir el átomo WM_DELETE_WINDOW en la propiedad WM_PROTOCOLS en cada una de esas ventanas. Recibirán un evento de ClientMessage como se describe arriba, cuyo campo de data[0] es WM_DELETE_WINDOW .

Tuve el mismo error y quería saber exactamente qué lo causa y por qué. Me llevó algo de tiempo descubrirlo y encontrar la explicación adecuada en el documento, así que puse mi explicación aquí para ahorrarle tiempo a otros desinformados.


No hay elementos como "botón de salida" o "aplicación" o "evento cercano" en X11. Esto es por diseño.

Decoraciones de ventanas, botones de salida y muchas otras cosas de las que dependemos no están integradas en X11. Se implementan en la parte superior del núcleo X11 en su lugar. El nombre del conjunto particular de convenciones responsable de wmDeleteMessage es ICCCM, wmDeleteMessage .

Xlib solo trata con el protocolo core X11. No hay evento cerrado incorporado allí.

Hay juegos de herramientas que facilitan el trato con ICCCM y todas las demás cosas que no están integradas en X11 (GTK, wxWindows, Qt, ...). Probablemente desee utilizar uno de esos.