Hi, > > > I have some EDA tools running on a Linux machine and display on my Windows > > > PC using xorg-server-21.1.3 XWin multiwindow mode > > > Sometimes the application window flickers forever for an unknown reason. > > > The problem became more severe after my PC upgrade to Windows10. > > > > > > Knowing the root cause, I am now able to demonstrate the issue with a > > > small > > > test case as well as a patch that works for me. Both are attached below. > > > > Thanks very much for taking the time to look into this, and writing a patch. > > But I'd like to add a bit more commentary, which perhaps you can supply, > > about the analysis you did to determine: > > > > 1. how the code is misbehaving > > 2. how this change remedies that > > 3. how this change doesn't effect anything else > > > > What your fix does is examine the queue of pending WM messages to > > determine if there are any more pending for the window receiving a > > WM_WM_CHANGE_STATE message, and if there are, ignore it. > > > > It seems to me that is error prone, in a couple of ways: > > > > 1. it should check the message type as well, as e.g. a pending message > > of a different type could cause a WM_WM_CHANGE_STATE message to be ignored. > > > > 2. even then, assuming that successive WM_WM_CHANGE_STATE messages > > cancel out each other isn't always true e.g. consider a sequence of > > _NET_WM_STATE_ADD _NET_WM_STATE_MAXIMIZED_VERT followed by > > _NET_WM_STATE_ADD _NET_WM_STATE_MAXIMIZED_HORZ. > >
> Here I have some details on the problem: > In following, WWCS means WM_WM_CHANGE_STATE > There exists a message self-generating loop > I.e., a WWCS message may generate another WWCS. > > winSendMessageToWM(WWCS) --> MultiWindowWMProc(WWCS) > --> UpdateState() --> ShowWindow() --> MultiWindowProc(WM_SIZE) > --> winAdjustXWindowState() --> winSendMessageToWM(WWCS) > > In normal case, there is a conditional code inside UpdateState() that > could break the loop. > > if (current_state == state) > return; > > Normally after maximizing the window, the WWCS just > to be self-generated once. On processing the 2nd WWCS, > the current window state matches WWCS target state > and ShowWindow() won't be called and the loop could end. > > Initial > Window state normal > queue : | WWCS(max1) | > --> process WWCS(max1) : > Winow state (norm) != target state (max2) > Set Window state to max and generate WWCS(max2) > queue : | WWCS(max2) | > --> Process WWCS(max2) : > Winow state (max) == target state (max) > break > > where WWCS(max1) means WWCS msg with target state max > and 1 means first generated/inserted WWCS in queue. > > However, there is case triggering this loop running forever. > Assuming intitially there are two WWCS message exists > where one is to maximize window and one is to normal window > The condition of state compare in UpdateState() would never match. > And WWCS(max) and WWCS(norm) is going to self-generate in turn. > > Initial > Window state normal > queue : | WWCS(max1) | WWCS(norm1) | > --> process WWCS(max1) > Winow state (norm) != target state (max) > Set window state to max and generate WWCS(max2) > queue : | WWCS(norm1) | WWCS(max2) | > --> Process WWCS(norm1) > Winow state (max) != target state (norm) > Set window state to norm and generate WWCS(norm2) > queue : | WWCS(max2) | WWCS(norm2) | > --> Process WWCS(max2) > Winow state (norm) != target state (max) > Set window state to max and generate WWCS(max3) > queue : | WWCS(norm2) | WWCS(max3) | > --> Process WWCS(norm2) > Winow state (max) != target state (norm) > Set window state to norm and generate WWCS(norm3) > queue : | WWCS(max3) | WWCS(norm3) | > : > (loop forever) > I just did some more study on the code of multiwindow window manager and X11 Window Properties as well as the questions you brought up. The first question : > it should check the message type as well, as e.g. > a different type mesage could cause WM_WM_CHANGE_STYLE to be ignored. Not sure what the "type" of a message means. Do you mean window manager message WM_xxxxx that is processed by winMultiWindowWMProc() where it is alreadychecked in HaveMessage(), or do you mean X message XCB_xxxxxx that is processed by winMultiWindowXMsgProc()? Maybe you can provide an example of another message type? The second question: > Successive WM_WM_CHANGE_STATE messages cancel out each other > isn't always true ex. _NET_WM_STATE_ADD _NET_WM_STATE_MAXIMIZED_VERT > followed by _NET_WM_STATE_ADD _NET_WM_STATE_MAXIMIZED_HORZ. Inspecting the code that deal with XCB_CLIENT_MESSAGE, it seems already true before the patch: The window goes maximized only if X client do one _WM_STATE_ADD action with _NET_WM_STATE_MAXIMIZED_VERT and _NET_WM_STATE_MAXIMIZED_HORZ simultaneously specified. Otherwise, the WM_WM_CHANGE would not be sent to the queue. Further, in UpdateWindowState(), the state and related X properties are either all-overwritten or all-skipped. There seems to be no state property half-update case if we skip UpdateWindowState(). In anyway, I just came out somewhat different patch attached. Where it just skips the Win32 ShowWindow() call instead of skipping processing WM_WM_CHANGE_STATE. It might be better because the X properties are still always updated in each in WM_WM_CHANGE_STATE. Maybe you could provide further comment. SL
diff --git a/hw/xwin/winmultiwindowwm.c b/hw/xwin/winmultiwindowwm.c index 7eee2fb..b2e5dc9 100644 --- a/hw/xwin/winmultiwindowwm.c +++ b/hw/xwin/winmultiwindowwm.c @@ -153,6 +153,9 @@ static void static WMMsgNodePtr PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo); +static Bool + HaveMessage(WMMsgQueuePtr pQueue, UINT msg, xcb_window_t iWindow); + static Bool InitQueue(WMMsgQueuePtr pQueue); @@ -319,7 +322,6 @@ PopMessage(WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo) return pNode; } -#if 0 /* * HaveMessage - */ @@ -331,12 +333,11 @@ HaveMessage(WMMsgQueuePtr pQueue, UINT msg, xcb_window_t iWindow) for (pNode = pQueue->pHead; pNode != NULL; pNode = pNode->pNext) { if (pNode->msg.msg == msg && pNode->msg.iWindow == iWindow) - return True; + return TRUE; } - return False; + return FALSE; } -#endif /* * InitQueue - Initialize the Window Manager message queue @@ -748,12 +749,12 @@ UpdateStyle(WMInfoPtr pWMInfo, xcb_window_t iWindow, unsigned long *maxmin) */ static void -UpdateState(WMInfoPtr pWMInfo, xcb_window_t iWindow, int state) +UpdateState(WMInfoPtr pWMInfo, xcb_window_t iWindow, int state, BOOL bShow) { HWND hWnd; int current_state = -1; - winDebug("UpdateState: iWindow 0x%08x %d\n", (int)iWindow, state); + winDebug("UpdateState: iWindow 0x%08x %d %d\n", (int)iWindow, state, (int) bShow); hWnd = getHwnd(pWMInfo, iWindow); if (hWnd) @@ -764,29 +765,36 @@ UpdateState(WMInfoPtr pWMInfo, xcb_window_t iWindow, int state) if (current_state == state) return; + // There would be small interval that variable 'state' does not + // match to Windows window state if bShow==0 + // But meanwhile there should be a another WM_WM_CHANGE pending + // and soon the Windows state will be updated SetProp(hWnd, WIN_STATE_PROP, (HANDLE)(intptr_t)state); - switch (state) - { - case XCB_ICCCM_WM_STATE_ICONIC: - ShowWindow(hWnd, SW_SHOWMINNOACTIVE); - break; - -#define XCB_ICCCM_WM_STATE_ZOOM 2 - case XCB_ICCCM_WM_STATE_ZOOM: - // There doesn't seem to be a SW_SHOWMAXNOACTIVE. Hopefully - // always activating a maximized window isn't so bad... - ShowWindow(hWnd, SW_SHOWMAXIMIZED); - break; - - case XCB_ICCCM_WM_STATE_NORMAL: - ShowWindow(hWnd, SW_SHOWNOACTIVATE); - break; - - case XCB_ICCCM_WM_STATE_WITHDRAWN: - ShowWindow(hWnd, SW_HIDE); - break; - } + if(bShow) { + + switch (state) + { + case XCB_ICCCM_WM_STATE_ICONIC: + ShowWindow(hWnd, SW_SHOWMINNOACTIVE); + break; + + #define XCB_ICCCM_WM_STATE_ZOOM 2 + case XCB_ICCCM_WM_STATE_ZOOM: + // There doesn't seem to be a SW_SHOWMAXNOACTIVE. Hopefully + // always activating a maximized window isn't so bad... + ShowWindow(hWnd, SW_SHOWMAXIMIZED); + break; + + case XCB_ICCCM_WM_STATE_NORMAL: + ShowWindow(hWnd, SW_SHOWNOACTIVATE); + break; + + case XCB_ICCCM_WM_STATE_WITHDRAWN: + ShowWindow(hWnd, SW_HIDE); + break; + } + } } // Update WM_STATE property @@ -1012,7 +1020,7 @@ winMultiWindowWMProc(void *pArg) UpdateWindow(pNode->msg.hwndWindow); /* Establish initial state */ - UpdateState(pWMInfo, pNode->msg.iWindow, XCB_ICCCM_WM_STATE_NORMAL); + UpdateState(pWMInfo, pNode->msg.iWindow, XCB_ICCCM_WM_STATE_NORMAL, TRUE); /* It only makes sense to apply minimize/maximize override as the @@ -1173,7 +1181,11 @@ winMultiWindowWMProc(void *pArg) break; case WM_WM_CHANGE_STATE: - UpdateState(pWMInfo, pNode->msg.iWindow, pNode->msg.dwID); + if(HaveMessage(&pWMInfo->wmMsgQueue, pNode->msg.msg, pNode->msg.iWindow)) + UpdateState(pWMInfo, pNode->msg.iWindow, pNode->msg.dwID, FALSE); + else + UpdateState(pWMInfo, pNode->msg.iWindow, pNode->msg.dwID, TRUE); + break; default:
-- Problem reports: https://cygwin.com/problems.html FAQ: https://cygwin.com/faq/ Documentation: https://cygwin.com/docs.html Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple