1
votes

I want to create a borderless, fullscreen OpenGL window with the Windows API. This is seen in many games so that you can quickly tab between your game and another application.

My problem is that when I create my window (which works) and I tab out, it does tab out, because I see my cursor change to the text cursor for my text editor, but the screen is still completely red from my OpenGL application, thus I cannot see anything.

The issue however is resolved when I set a breakpoint (Visual Studio) in the main loop (or before the main loop but after window creation), before I swap the buffers, and let it resume after that. Below is my mainloop. I am using my own window class.

while(window.Running())
{
    window.PollEvents();

    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);

    glClear(GL_COLOR_BUFFER_BIT);

    window.SwapBuffers();
    Sleep(10);
}

My question is: What happens when I pause my application before the swapping of buffers that makes the window behave differently (for me correctly)?

The inside of window.SwapBuffers() is the following:

void GLWindowImpWin32::swapBuffers()
{
    SwapBuffers(handleDeviceContext);
}

Where handleDeviceContext is my HDC.

Also pressing the Windows button does not visually bring up the taskbar in front of the application.

Here's my minimized source code which behaves the same as my original code, it also works if you put a breakpoint before swapping the buffers. If you are compiling, don't forget to link to opengl32.lib:

#include <Windows.h>
#include <gl/GL.h>

WNDCLASSEX windowClass;
HWND handleWindow;
HDC handleDeviceContext;
HGLRC handleGLRenderingContext;
bool running = false;

// set this to your screen size
const int windowWidth = 1680;
const int windowHeight = 1050;

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_CREATE:
        {
            handleDeviceContext = GetDC(hWnd);

            PIXELFORMATDESCRIPTOR pfd =
            {
                sizeof(PIXELFORMATDESCRIPTOR),
                1,                              
                PFD_SUPPORT_OPENGL |            
                PFD_DRAW_TO_WINDOW |            
                PFD_DOUBLEBUFFER,       
                PFD_TYPE_RGBA,                  
                32,                             
                0, 0, 0, 0, 0, 0,               
                0,
                0,
                0,
                0, 0, 0, 0,
                16,                             
                8,                              
                0,
                PFD_MAIN_PLANE,
                0,
                0, 0, 0
            };

            int pixelFormat = ChoosePixelFormat(handleDeviceContext, &pfd);
            SetPixelFormat(handleDeviceContext, pixelFormat, &pfd);

            handleGLRenderingContext = wglCreateContext(handleDeviceContext);

            wglMakeCurrent(handleDeviceContext, handleGLRenderingContext);

            running = true;

            break;
        }
    case WM_DESTROY:
    case WM_CLOSE:
        {
            wglMakeCurrent(handleDeviceContext, NULL);
            wglDeleteContext(handleGLRenderingContext);

            running = false;

            break;
        }
    default:
        break;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR cmdLine, int cmdShow)
{
    memset(&windowClass, 0, sizeof(WNDCLASSEX));
    windowClass.cbSize          = sizeof(WNDCLASSEX);
    windowClass.style           = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
    windowClass.cbClsExtra      = 0;
    windowClass.cbWndExtra      = 0;
    windowClass.hInstance       = hInstance;
    windowClass.hIcon           = LoadIcon(NULL, IDI_APPLICATION);
    windowClass.hIconSm         = LoadIcon(NULL, IDI_WINLOGO);
    windowClass.hCursor         = LoadCursor(NULL, IDC_ARROW);
    windowClass.hbrBackground   = NULL;
    windowClass.lpszMenuName    = NULL;
    windowClass.lpszClassName   = "GLWindowClass";
    windowClass.lpfnWndProc     = WndProc;

    if(!RegisterClassEx(&windowClass))
    {
        return false;
    }

    DWORD windowStyleEx = WS_EX_APPWINDOW;
    DWORD windowStyle = WS_POPUP;

    handleWindow = CreateWindow(
        "GLWindowClass",
        "title",
        windowStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,    
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        windowWidth,
        windowHeight,
        NULL,
        NULL,
        hInstance,
        NULL);

    if(!handleWindow)
    {
        return false;
    }

    handleDeviceContext = GetDC(handleWindow);

    ShowWindow(handleWindow, SW_SHOW);

    while(running)
    {
        MSG msg;

        while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        glClearColor(1.0f, 0.0f, 0.0f, 1.0f);

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        SwapBuffers(handleDeviceContext);
        Sleep(10);
    }

    PostQuitMessage(0);

    return 0;
}
2
I believe your issue your issue is related to the handling of fullscreen GL windows by Windows ; related to a similar issue I still have, see stackoverflow.com/questions/2378918/…rotoglup
Yes, my problem seems to be very similar if not the same. Although I still find it strange that I don't experience any problem if I put a breakpoint after window creation, so there has to be a way for it to work :/toteload

2 Answers

0
votes

Buffer swapping is not enough. You need to tell Windows that you have switched windows. In order to get the 'other application' to show its screen, Windows needs to know that your application is no longer on top and the other application should be brought to the front, and allowed to repaint.

EDIT/REWRITE: Now that you have provided the source code for a sample, and I have compiled and tested the code, I make the following observations.

  1. I cannot reproduce the problem. On Windows 8 dual monitor, the main monitor is completely replaced by a red panel, but Alt+Tab and the Windows key behave normally. The second monitor is unaffected. I have no idea whether it's the Windows 8, the dual monitor or something else that makes the difference.

  2. The code as provided assumes a 1680x1050 monitor. Mine is 1920x1080. The screen height and width must exactly match for the program to work as intended. I edited the code to match.

  3. The DC being used is from a window handle. This means that all OpenGL drawing will be inside the window. However, it will not respect the NC boundaries -- it will overwrite the entire window.

  4. There is no WM_PAINT handler, so Windows may assume that the window has never been painted and the entire client area is invalid. The DefWindowProc willpaint and validate the NC area (if any).

Apart from my belief that this is where the problem is, I don't think I can help further. You might want to try on a different version of Windows, or a dual monitor system. You might want to try adding a paint handler (it just needs to call BeingPaint/EndPaint).

0
votes

I am not sure if this helps, but try to change glClear(GL_COLOR_BUFFER_BIT); to glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

I think this might be interesting. Though I don't know a lot about your case:

Depth Buffer

The depth buffer stores a depth value for each pixel. As described in "A Hidden-Surface Removal Survival Kit" in Chapter 5, depth is usually measured in terms of distance to the eye, so pixels with larger depth-buffer values are overwritten by pixels with smaller values. This is just a useful convention, however, and the depth buffer's behavior can be modified as described in "Depth Test." The depth buffer is sometimes called the z buffer (the z comes from the fact that x and y values measure horizontal and vertical displacement on the screen, and the z value measures distance perpendicular to the screen).

Source:

http://www.glprogramming.com/red/chapter10.html

Also, I think you should show what happens in window.SwapBuffers();

Sorry if this doesn't work, but you should try it at least.

EDIT:

I really think the problem is with the Sleep() function. I tried it and it stopped drawing(though still working).