Impossible de se débarrasser de la gigue en faisant glisser le bord gauche d’une fenêtre

À partir du 26 mars 2015, le problème était résolu, voir au bas de cette page, un tour très sale.

Au 18 août 2014, en partie résolu: DWM est le coupable (voir le dernier commentaire).

J’ai construit mon propre style de fenêtre à l’aide de l’API Win32. Tout se passa bien sous Windows XP et Windows 7. Cependant, sous Windows 8, il se passait des choses étranges: faire glisser le bord gauche de la fenêtre provoquait une instabilité extrême du côté droit, alors qu’elle ne devait absolument pas bouger. Regardez cela et vous comprendrez ce que je veux dire.

Lorsque je déplace le bord droit, le côté gauche ne bouge pas comme il se doit. Certes, il y a du scintillement, mais c’est acceptable. Voir ce

J’ai essayé SetWindowPos() et (begin/End)DeferWindowPos avec plusieurs drapeaux, mais en vain. Même avec SWP_NOREDRAW et le blocage de toutes les autres peintures n’aide pas. Ni avec ni sans CS_HREDRAW et CS_VREDRAW .

Bien sûr, j’utilise un double tampon. Pourtant, il semble impossible de se débarrasser de cette agitation embêtante. J’ai également essayé un autre pilote pour le moteur graphique Intel HD 4000, encore une fois en vain. Est-ce que je néglige quelque chose? Est-ce un bug de Windows 8?

En passant, lorsque j’active l’option “Afficher le contenu de la fenêtre lors du déplacement” (dans le menu Paramètres système avancés), toutes les autres applications affichent le même comportement.

Toute aide est la bienvenue.

Cordialement, Edmond.

PS: Désactiver “Afficher le contenu de la fenêtre en faisant glisser” n’est pas une option, car c’est une fonctionnalité intégrée de mon application.

Edit1: Il semble que d7samurai se débat avec le même problème.

Suivi: J’ai essayé beaucoup de choses pour éliminer la gigue, mais rien n’y fait. Le problème est que W8 ne fait tout simplement pas ce qu’il devrait faire. Prenons l’exemple de l’indicateur SWP_NOREDRAW . Comme prévu, la peinture du côté de la fenêtre qui a été déplacée est supprimée. Jusqu’ici tout va bien. MAIS …. de l’autre côté (de la fenêtre), qui est toujours valable, celui-ci est repeint! Ce n’est pas seulement totalement inutile et inutile, mais il est repeint avec jitter! De plus, la peinture est deux fois plus lente que W7 et XP. Après avoir passé une semaine entière sur ce problème, je suis complètement passé avec W8! C’est vraiment un POC et les gars qui sont responsables de ce boulot sont mentalement dérangés. J’espère vraiment que W9 fera un meilleur travail. Amen.

THAL SHIT JITTER:

Il est apparu que les anomalies décrites ci-dessus ne se limitaient pas à W8. W7 a également présenté le même comportement lorsqu’il est défini sur “Meilleure apparence” ou au moins sur “Activer la composition du bureau” avec “Utiliser les styles visuels sur les fenêtres et les boutons”. J’ai alors pensé qu’il serait possible de tromper les fenêtres en n’utilisant pas du tout la fonction SetWindowPos, mais en envoyant une commande ShowWindow( hWnd, SW_MAXIMIZE ) et en interceptant le msg WM_GETMINMAXINFO lequel je spécifie la taille et la position souhaitées. Devine quoi? J’ai encore de la gigue. Arghhh !!!

Que faire ensuite? Y a-t-il une possibilité d’intercepter la peinture à un niveau plus bas / plus profond (crochets?) Afin de redessiner une fenêtre de manière décente?

Mise à jour du 26/03/2015, un truc très sale:

Eureka! J’ai finalement trouvé la solution au problème. Mais tout d’abord, laissez-moi vous expliquer ce qui se passe et pourquoi le fait de glisser est accompagné de gigue. Supposons que vous souhaitiez agrandir le côté gauche d’une fenêtre. Contrairement à l’expansion du côté droit, cela se fait en deux étapes. Tout d’abord, le contenu de la fenêtre avec sa taille d’origine est déplacé vers la gauche. Une fois cette opération effectuée, le contenu est étendu de telle sorte que le nouveau côté droit coïncide avec le côté précédent. En bref, c’est la combinaison d’un “mouvement” suivi d’un “redimensionnement” et c’est ce qui cause la mauvaise gigue. Des choses similaires se produisent lorsque vous faites glisser le haut d’une fenêtre. Sous Windows 8.1 ou 10, vous ne pouvez rien y faire. J’ai également essayé les nouvelles fonctions DWM ( BufferedPaintInit , BeginBufferedPaint , EndBufferedPaint , BufferedPaintUnInit ), malheureusement, en vain. De plus, SetWindowPlacement() produit une gigue. Apparemment, toutes ces fonctions mènent au même coupable qui gâche un redimensionnement. Je me suis alors dit que lorsque vous créez une nouvelle fenêtre et que vous l’affichez avec une nouvelle taille, elle ne gigue pas du tout. Plutôt évident, je dirais. Ainsi, la création répétée d’une nouvelle fenêtre et la destruction ultérieure de la précédente pourraient constituer une solution, mais ce n’est pas très efficace, bien sûr. En jouant avec cette idée, j’ai découvert par hasard que rendre une fenêtre cachée visible avec une nouvelle / une autre taille, suivie du masquage de la fenêtre précédente, ne montre pas non plus le jitter. Cette procédure est beaucoup plus efficace qu’une séquence de création / destruction. Donc, au début de mon programme, je viens de créer deux fenêtres, la première cachée et la seconde visible. L’extrait de code ci-dessous devrait expliquer la procédure de redimensionnement sans gigue de manière plus détaillée:

 ........ i = prm->hpi; // get current index h1 = prm->parent[i]; // get current handle flags = SWP_NOCOPYBITS; flags |= SWP_NOSENDCHANGING; // if DWM sortinges to make a mess of it: // DWM enabled top border right border if( prm->parent[1] && ( rgn == TBE || rgn == LBE ) ) { i = i + 1 & 1; // get new index prm->hpi = i; // save new index h2 = prm->parent[i]; // get new handle prm->hParent = h2; // set as current one flags |= SWP_NOREDRAW; // bypass message pump flags |= SWP_SHOWWINDOW; // make h2 visible SetWindowPos( h2, HWND_TOP, px, py, cx, cy, flags ); PaintParent( h2 ); // paint it now DwmFlush(); // wait till finished ShowWindow( h1, SW_HIDE ); // make h1 invisible } // DWM disabled or dragging the right or bottom border: else SetWindowPos( h1, HWND_TOP, px, py, cx, cy, flags ); 

Une dernière chose: utilisez DwmFlush() pour vous assurer que toute la peinture de la nouvelle fenêtre est terminée, puis masquez l’autre fenêtre, sinon des scintillements seront visibles. Bien sûr, la procédure ci-dessus est un peu plus lente que celle habituelle. Sur mon système (avec un processeur i5-3570K) 3..26ms, en fonction de la taille de la fenêtre et de son contenu. Mais au moins cette horrible gigue a disparu.

Je me rends compte que c’est un truc assez sale, alors si quelqu’un connaît une solution plus ordonnée, faites-le nous savoir.

Cela ressemble à Windows 8.1 et supérieur, vous devez coopérer avec DWM plutôt que de le contourner.

Cela signifie que vous devez connaître le calendrier de la composition via DwmGetCompositionTimingInfo et vous assurer que vous DwmGetCompositionTimingInfo vos événements de rendu dans la queue aux moments appropriés. Vous pouvez également constater que vous devez ré-invalider et repeindre la fenêtre juste après l’événement WM_SIZING, ou même utiliser votre propre temporisateur pour peindre plus souvent que les événements WM_SIZING sont envoyés. Par exemple, si DWM compose à 50 images par seconde, mais que vous obtenez uniquement des événements WM_Sizing par seconde, si vous utilisez votre propre timer avec GetWindowPos vous pourrez peut-être peindre plus souvent que si vous utilisez WM_SIZING.

Vous constaterez peut-être qu’une utilisation judicieuse de DwmFlush juste après la peinture peut également aider à réduire cette gigue.

J’ai trouvé une solution au problème. Veuillez consulter la dernière mise à jour du message d’origine.

Cette solution à deux fenêtres est très créative! Je ne pense pas pouvoir appliquer cette solution car ma fenêtre est une fenêtre OpenGL avec un état lourd qui devrait être maintenue / répliquée sur plusieurs instances de la fenêtre.

Je pense que je peux expliquer un peu plus pourquoi vous avez continué à voir cette instabilité malgré le fait de jouer avec tous les suspects habituels comme SWP_NOREDRAW et SWP_NOCOPYBITS .

J’ai rencontré le même problème de gigue et découvert que, dans la mesure où les applications sous Windows 8/10 Aero ne dessinaient pas directement à l’écran, mais utilisaient plutôt des tampons hors écran composés ensuite par le gestionnaire de fenêtres DWM.exe, il est avéré que DWM ajoute en fait une autre couche de comportement de type BitBlt au-dessus du comportement hérité existant XP / Vista / 7 BitBlt .

Et le comportement de blit DWM est encore plus fou car ils ne copient pas simplement la zone client, mais ils répliquent en fait les pixels sur les bords de votre ancienne zone client pour en créer une nouvelle. Malheureusement, faire en sorte que DWM ne fasse pas son travail est beaucoup plus difficile que de simplement passer des drapeaux supplémentaires.

Il semble que votre astuce à deux fenêtres empêche DWM de ne pas faire plus, mais je cherche un moyen de le faire avec une seule fenêtre.

Je n’ai pas de solution à 100%, mais j’espère que les informations ci-dessus vous aideront, et j’ai du code pour une implémentation de la super idée de Ben afin de minimiser les chances de DWM:

Comment lisser la gigue / scintillement / saut moche lors du redimensionnement des fenêtres, en particulier en faisant glisser la bordure gauche / supérieure (Win 7-10; bg, bitblt et DWM)?

Prendre plaisir!