J'écris une application sous Linux en utilisant Xlib pour gérer une fenêtre et cairo pour dessiner un texte en elle. Le contenu du texte de la fenêtre change pendant l'exécution, donc je veux adapter la taille de la fenêtre à celle de l'extension du texte. Si la taille de l'extension de texte ne change pas, la fenêtre est toujours correctement mise à jour avec le nouveau texte.Après XResizeWindow, le nouveau contenu de la fenêtre tirée ne s'affiche
Mais lorsque l'étendue du texte change et que la fenêtre est redimensionnée en conséquence, la fenêtre est effacée mais le nouveau texte n'est jamais affiché. Seulement s'il n'y a aucun appel à XResizeWindow le texte est réellement affiché. Le code que je utilise est
if (/* Text extent is changed */)
{
XResizeWindow (display, window, new_width, new_height);
cairo_xlib_surface_set_size (surface, new_width, new_height);
}
XClearWindow (display, window);
/* ... Cairo code to draw the text ... */
// cairo_surface_flush (surface);
// XFlush (display);
J'ai aussi essayé d'ajouter après le code du Caire qui attire le texte les méthodes cairo_surface_flush et XFlush (commenté dans l'exemple), mais rien ne change.
EDIT: je résolu le problème en utilisant deux fils: le premier fil avec la boucle habituelle pour écouter les événements Expose plus le code pour redessiner le contenu et le second fil qui délivre le redimensionnement de la fenêtre et envoie un événement Expose pour réveiller le premier thread.
Dans cet exemple, la fenêtre est redimensionnée toutes les 500 ms à une largeur et une hauteur aléatoires et un compteur progressif y est affiché à chaque redimensionnement. J'utilise C++ 11, compiler avec:
g++ -std=c++11 -o test test.cpp -lX11 -lcairo -lpthread
Le code est:
#include <random>
#include <chrono>
#include <thread>
#include <string>
#include <X11/Xlib.h>
#include <cairo/cairo-xlib.h>
Display * d;
Window w;
cairo_surface_t * surface;
int width = 300, height = 300;
unsigned char counter = 0;
std::random_device rd;
std::knuth_b gen (rd());
std::uniform_int_distribution < > dist (150, 300);
void logic()
{
XEvent send_event;
send_event.type = Expose;
send_event.xexpose.window = w;
while (true)
{
std::this_thread::sleep_for (std::chrono::milliseconds (500));
++ counter;
width = dist (gen);
height = dist (gen);
cairo_xlib_surface_set_size (surface, width, height);
XResizeWindow (d, w, width, height);
XSendEvent (d, w, False, ExposureMask, & send_event);
XFlush (d);
}
}
int main ()
{
XInitThreads();
d = XOpenDisplay (NULL);
w = XCreateSimpleWindow (d, RootWindow (d, 0), 0, 0, width, height, 0, 0, 0x000000);
XMapWindow (d, w);
XSelectInput (d, w, ExposureMask | KeyPressMask);
surface = cairo_xlib_surface_create (d, w, DefaultVisual (d, 0), width, height);
cairo_t * cairo = cairo_create (surface);
cairo_select_font_face (cairo, "FreeSans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size (cairo, 40);
cairo_set_source_rgb (cairo, 0.8, 0.8, 0.8);
cairo_move_to (cairo, 40.0, 60.0);
cairo_show_text (cairo, std::to_string (counter).c_str());
XFlush (d);
std::thread T (logic);
XEvent event;
while (true)
{
XNextEvent (d, & event);
if (event.type == Expose)
{
XClearWindow (d, w);
cairo_move_to (cairo, 40.0, 60.0);
cairo_show_text (cairo, std::to_string (counter).c_str());
}
else if (event.type == KeyPress)
{
XCloseDisplay (d);
return 0;
}
}
}
Mais une question reste: est-il possible d'obtenir le même résultat en utilisant seulement un fil?
Avez-vous un exemple autonome que l'on pourrait tester? À quoi ressemble votre boucle d'événements, c'est-à-dire que faites-vous sur les événements Expose? –
Ok Je vais fournir un exemple de code autonome compact qui reproduit le comportement. – disquisitiones