11

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);
DormoTheNord
  • 999
  • 1
  • 9
  • 20
  • Why don't you paste your resizing handling code? Perhaps the order you call `SDL_SetWindowPosition` and `SDL_SetWindowSize` causes these jumps. – ysalmi Mar 29 '14 at 17:18
  • @sashoalm Sorry, I meant I haven't tested on OS X. – DormoTheNord Mar 29 '14 at 20:44
  • @ysalmi I tried changing the order, but the bug persisted. Using XMoveResizeWindow (where you enter both the new position and the new size) didn't help, either. I'll put in some code now. – DormoTheNord Mar 29 '14 at 20:47
  • This is how windows are resized in X11, even with the window manager. I have not noticed this effect on Windows. Please try [this example code](http://pastebin.com/nvCrsJw3) at http://pastebin.com/nvCrsJw3 and tell me whether you are seeing this artifact. I see the same effect whether I resize with WM handles or by clicking and dragging in the window. – n. m. could be an AI Apr 03 '14 at 12:23
  • @n.m. I do not see the artifact with that sample code. – DormoTheNord Apr 03 '14 at 12:44
  • @n.m. One thing about your sample code is that you're using events. On Linux I'm opening/closing a connection with X server to get the mouse position each time. On Windows I'm calling `GetCursorPos` On To check if the mouse button is press I'm calling `SDL_GetMouseState` (not sure how that is implemented). Could that be my problem? – DormoTheNord Apr 03 '14 at 12:52
  • Try computing dx, dy and posx += dx, sizex -= dx etc. I'm not sure your signs are correct. – n. m. could be an AI Apr 03 '14 at 15:56
  • @n.m. Alright, I'll try it when I get home tonight. – DormoTheNord Apr 03 '14 at 16:25
  • @n.m. I took your logic and adapted it to SDL (using `setPosition` and `setSize` instead of `XMoveResizeWindow`) and I'm getting the exact same effect that I was before. – DormoTheNord Apr 04 '14 at 13:08
  • Your Window might be using `CS_HREDRAW | CS_VREDRAW` on Windows.. You can try setting it to `CS_PARENTDC` as specified here: http://msdn.microsoft.com/en-us/library/windows/desktop/ff729176(v=vs.85).aspx MAYBE it'll improve performance and fix it? I'm not sure if it'll help (hopefully it does). It's just a guess but OpenGL and Direct-X windows usually use `CS_OWNDC` or `CS_PARENTDC` on Windows OS. – Brandon Apr 07 '14 at 16:31
  • It's bound to happen this way. You first set position, then window is redrawn as 1 px too big or too small, then you set size, then the window is redrawn in correct dimensions. This is why Win32 `SetWindowPos` sets all this parameters in ONE call. You need to either find SDL function that does it all, or somehow block window redraw until you're finished manipulating the window. – Agent_L Apr 08 '14 at 08:20
  • @Agent_L I'll try `SetWindowPos` in a few hours, but when I used `XMoveResizeWindow` in on Linux, which also takes both the size and position, I had the same bug. – DormoTheNord Apr 08 '14 at 16:47
  • @CantChooseUsernames I'm skeptical of this, because the bug isn't only on Windows. – DormoTheNord Apr 08 '14 at 16:49
  • @Agent_L With `SetWindowPos`, it gets rid of the jumping when I resize the window to be smaller, but it's still there when i make it larger. – DormoTheNord Apr 10 '14 at 02:43

1 Answers1

5

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;
}
cf-
  • 8,598
  • 9
  • 36
  • 58