I'm trying to make an application with a borderless window in SDL2.
I've implemented moving and resizing via drag. Moving works perfectly fine. Resizing by dragging the bottom and right borders also works fine.
Resizing by dragging the top and left borders functions fine, but it has a cosmetic bug.
Basically if I drag from the left border, the right side of the window makes little jumps (maybe 1-2 pixels) as I move it. Dragging from the top border causes the bottom to make little jumps. When I stop dragging the window is always in the right position, but this bug makes it seem very inelegant.
The bug exists on Linux (multiple WMs/DEs) and Windows. I haven't tested on OS X.
I'm using SDL_SetWindowPosition
and SDL_SetWindowSize
. I've tried bypassing SDL and using XMoveResizeWindow
but it causes the same bug.
While I'd strongly prefer not to bypass SDL, I'd be willing to use Xlib and/or WinAPI if I need to.
Here's a snippet of my code:
// mousePos is initialized to current mouse pos
// newWindowSize initilized to current window size
// newWindowPos initialized to current window position
// mWindowResizeOffset variable is where the mouse grabbed the window
// omitted code for right and bottom borders because the bug doesn't exist there
// Logic for the top border is the same
if (mLeftBorderGrabbed)
{
newWindowPos.x = mousePos.x - mWindowResizeOffset.x;
newWindowSize.x += windowPos.x - newWindowPos.x;
}
SDL_SetWindowPosition(mInternalWindow, newWindowPos.x, newWindowPos.y);
SDL_SetWindowSize(mInternalWindow, newWindowSize.x, newWindowSize.y);
I picked up SDL2 and spent the last few hours experimenting with different window moving/sizing/redrawing APIs:
SDL_SetWindowPosition(window, newWindowPos.x, newWindowPos.y);
SDL_SetWindowSize(window, newWindowSize.x, newWindowSize.y);
SetWindowPos(windowHandle, nullptr, newWindowPos.x, newWindowPos.y, newWindowSize.x, newWindowSize.y, SWP_SHOWWINDOW);
MoveWindow(windowHandle, newWindowPos.x, newWindowPos.y, newWindowSize.x, newWindowSize.y, TRUE);
and
MoveWindow(windowHandle, newWindowPos.x, newWindowPos.y, newWindowSize.x, newWindowSize.y, TRUE);
InvalidateRect(windowHandle, &windowRect, TRUE);
I've learned that the SDL APIs do okay with slow, small drags, but larger, faster drags trigger the visual glitch you describe.
SetWindowPos
and MoveWindow
seem almost identical - both work correctly on my system. There is some glitching on the left edge of the window during dragging, but this is consistent with the behavior of other windows on my system. The right edge stays visually fixed in place without glitching. I would probably pick the MoveWindow
call for a permanent solution, although that's mostly gut feeling based on how the different API setups ran. YMMV.
InvalidateRect
doesn't seem to make any difference in how things are drawn. It does not exacerbate the left-border glitch I mentioned, nor does it alleviate it. I would guess this is because I specified a redrawing flag for the MoveWindow
call.
For reference, here's the code I used for testing. I just commented/uncommented the relevant APIs and rebuilt the project as needed. Sorry about the messiness - I was more interested in getting something up and running than making the code look perfect. Let me know if you'd like me to clean it up a bit.
//Using SDL and standard IO
#include <windows.h>
#include <SDL.h>
#include <SDL_syswm.h>
#include <stdio.h>
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
struct Point
{
int x;
int y;
};
int main(int argc, char* args[])
{
bool quit = false, dragging = false;
//The window we'll be rendering to
SDL_Window* window = NULL;
//The surface contained by the window
SDL_Surface* screenSurface = NULL;
SDL_Event e;
SDL_SysWMinfo windowInfo;
HWND windowHandle;
Point mousePos, windowPos, newWindowPos, newWindowSize, mWindowResizeOffset;
//Initialize SDL
if(SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
}
else
{
//Create window
window = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS); // | SDL_WINDOW_RESIZABLE
if(window == NULL)
{
printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
}
else
{
//Get window surface
screenSurface = SDL_GetWindowSurface(window);
SDL_VERSION(&windowInfo.version);
SDL_GetWindowWMInfo(window, &windowInfo);
windowHandle = windowInfo.info.win.window;
//While application is running
while(!quit)
{
//Handle events on queue
while(SDL_PollEvent(&e) != 0)
{
//process events
switch(e.type)
{
case SDL_QUIT:
quit = true;
break;
case SDL_WINDOWEVENT:
if(e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
screenSurface = SDL_GetWindowSurface(window);
}
//Fill the surface blue
SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0x00, 0xA2, 0xE8));
//Update the surface
SDL_UpdateWindowSurface(window);
break;
case SDL_MOUSEBUTTONDOWN:
SDL_GetMouseState(&mWindowResizeOffset.x, &mWindowResizeOffset.y);
SDL_GetWindowPosition(window, &windowPos.x, &windowPos.y);
dragging = true;
break;
case SDL_MOUSEBUTTONUP:
dragging = false;
break;
case SDL_MOUSEMOTION:
if(dragging)
{
SDL_GetMouseState(&mousePos.x, &mousePos.y);
SDL_GetWindowPosition(window, &newWindowPos.x, &newWindowPos.y);
SDL_GetWindowSize(window, &newWindowSize.x, &newWindowSize.y);
newWindowPos.x = newWindowPos.x + mousePos.x - mWindowResizeOffset.x;
newWindowSize.x += windowPos.x - newWindowPos.x;
//SDL_SetWindowPosition(window, newWindowPos.x, newWindowPos.y);
//SDL_SetWindowSize(window, newWindowSize.x, newWindowSize.y);
//SetWindowPos(windowHandle, nullptr, newWindowPos.x, newWindowPos.y, newWindowSize.x, newWindowSize.y, SWP_SHOWWINDOW);
MoveWindow(windowHandle, newWindowPos.x, newWindowPos.y, newWindowSize.x, newWindowSize.y, TRUE);
/*RECT drawRect;
drawRect.left = windowPos.x;
drawRect.top = windowPos.y;
drawRect.right = windowPos.x + newWindowSize.x;
drawRect.bottom = windowPos.y + newWindowSize.y;
InvalidateRect(windowHandle, &drawRect, TRUE);*/
windowPos = newWindowPos;
}
break;
}
}
SDL_Delay(1);
}
}
}
//Destroy window
SDL_DestroyWindow(window);
//Quit SDL subsystems
SDL_Quit();
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With