2

I am working on a window manager. Here is some code to stack windows diagonally:

void stack_windows_diagonal(HWND* windows, int width, int height){
    if(windows == NULL) return;

    int size = 0;
    for(;windows[size]; size++);

    RECT scr_dim;
    scr_dim.left   = GetSystemMetrics(SM_XVIRTUALSCREEN);
    scr_dim.top    = GetSystemMetrics(SM_YVIRTUALSCREEN);
    scr_dim.right  = GetSystemMetrics(SM_CXVIRTUALSCREEN);
    scr_dim.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN);

    int xoffset = 40;
    int yoffset = 40;

    int startx = (scr_dim.right - width) / 2 - (((size - 1) * xoffset) / 2);
    int starty = (scr_dim.bottom - height) / 2 - (((size - 1) * yoffset) / 2);

    for(int i = size - 1; i >= 0; i--){
        bool success = SetWindowPos(windows[i], i == size - 1? HWND_TOP : windows[i - 1], startx + xoffset * i, starty + yoffset * i, width, height, 0);
        if(!success) {
            DWORD error = GetLastError();
            fprintf(stderr, "Failed to reposition window. Error code: %lu\n", error);
            continue;
        }

        if(i < size - 1)
            continue;

        success = SetForegroundWindow(windows[i]);
        if(!success){
            DWORD error = GetLastError();
            if(GetLastError())
                fprintf(stderr, "Failed to bring window to top. Error code: %lu\n", error);
        }

    }

    free(windows);

}

windows is terminated by NULL. Currently, this is only used for managing file explorer windows. The appear at the right x y coordinates, but the Z order is often very wrong. I get the same result setting all windows to HWND_TOP. The order they appear in is sometimes correct, but it seems very random. Why is this?

EDIT: Image showing the issue:

They are overlapping eachother in the wrong order

Andreas Sandberg
  • 241
  • 1
  • 3
  • 10
  • Hmm. What will `windows[i - 1]` refer to when the loop runs with `i == 0`? Maybe not the cause of your problem, though, if you've also tried with `HWND_TOP` for all windows. – Adrian Mole Aug 08 '23 at 14:56
  • Also, you may find [this answer](https://stackoverflow.com/a/3283922/10871073) useful. – Adrian Mole Aug 08 '23 at 14:58
  • Another thought: Should your `windows[i - 1]` actually be `windows[i + 1]` ?? – Adrian Mole Aug 08 '23 at 15:01
  • 2
    I currently don't have the resources to run a test but, thinking a bit more about this, I'm fairly sure that changing `windows[i - 1]` to `windows[i + 1]` will be the fix. As it stands, you have undefined behaviour on the last run of the `for` loop (trying to access `windows[-1]`) and, for other non-initial runs of the loop, the window you are referring to as the "insert after" will have an (as yet) unspecified z-order. – Adrian Mole Aug 08 '23 at 15:11
  • @AdrianMole You are right, this is a typo! However, the z order still is wrong after fixing it. Sometimes, not all windows are brought to the top, and sometimes they are, but even then they might be in the wrong order. – Andreas Sandberg Aug 08 '23 at 16:45
  • Window positioning is asynchronous, so I suspect the issue is simply that things are happening out of order at times. You could try putting a Sleep() in after the call to SetWindowPos to see. – Jonathan Potter Aug 08 '23 at 22:34
  • @AndreasSandberg Have you tried using `HWND_TOPMOST`? – Torrecto - MSFT Aug 09 '23 at 03:06
  • @Torrecto-MSFT Yes, but the problem is that it stays focused even if you click another window then. I want to bring them all to the top in order, but not have them force the system to make them stay on top. – Andreas Sandberg Aug 09 '23 at 15:52
  • @JonathanPotter This fixed it! Thanks – Andreas Sandberg Aug 09 '23 at 17:53

1 Answers1

1

As Jonathan Potter said, window positioning is asynchronous.

Putting a Sleep() in after the call to SetWindowPos() works.