pixel icon indicating copy to clipboard operation
pixel copied to clipboard

Undecorated window click to drag?

Open coreyog opened this issue 6 years ago • 5 comments

I'm trying to write up a pixel window that can be dragged by clicking anywhere in the window as if it were dragged by the title bar. This will be useful for an undecorated window. Here's the relevant code of what I have:

func run() {
	cfg := pixelgl.WindowConfig{
		Bounds:      pixel.R(0, 0, 1000, 400),
		VSync:       true,
		Undecorated: true,
	}
	win, err := pixelgl.NewWindow(cfg)
	if err != nil {
		panic(err)
	}

	var prevMousePos pixel.Vec
	mouseDown := false

	for !win.Closed() {
		if mouseDown {
			diff := win.MousePosition().Sub(mousePos)
			if diff.X != 0 && diff.Y != 0 {
				fmt.Printf("%.2f, %.2f\n", diff.X, diff.Y)
				winPos := win.GetPos()
				winPos.X += diff.X
				winPos.Y -= diff.Y
				win.SetPos(winPos)
			}
		}

		if win.JustReleased(pixelgl.MouseButton1) {
			mouseDown = false
		}

		if win.JustPressed(pixelgl.MouseButton1) {
			mousePos = win.MousePosition()
			mouseDown = true
		}
	}
}

The basic logic is to store where the mouse is relative to the window on mouse down. While the mouse is down, I check where the mouse is and if it moved from the original position say 2 pixels over and 1 pixel up, I get the window position and move it 2 pixels over and 1 pixel up. This should put the original mouse down position directly under the mouse again.

The window follows the mouse pretty well but occasionally when I still have my mouse clicked and I bring the mouse to a stop, the window will keep moving. diff continues to be non-zero. It seems that this approach doesn't guarantee that the mouse position will be accurate after moving the window. Since there's no other way to get if the mouse is moving I don't know of a way to stop it.

I'm worried there may be a slight disconnect between the position I give to win.SetPos(...) and where the window actually moves to.

I've tried resetting mousePos right after win.SetPos() but then the window lags behind the mouse.

Is there any insight into why I might be experiencing this?

coreyog avatar Jun 26 '18 17:06 coreyog

I've tried reproducing the problem and am having no luck. It's working perfectly for me no matter how erratically I drag the window.

This is the full code I used

package main

import (
	"fmt"

	"github.com/faiface/pixel"
	"github.com/faiface/pixel/pixelgl"
)

func run(win *pixelgl.Window) {
	mouseDown := false
	mousePos := pixel.ZV
	for !win.Closed() {
		if mouseDown {
			diff := win.MousePosition().Sub(mousePos)
			if diff.X != 0 && diff.Y != 0 {
				fmt.Printf("%.2f, %.2f\n", diff.X, diff.Y)
				winPos := win.GetPos()
				winPos.X += diff.X
				winPos.Y -= diff.Y
				win.SetPos(winPos)
			}
		}

		if win.JustReleased(pixelgl.MouseButton1) {
			mouseDown = false
		}

		if win.JustPressed(pixelgl.MouseButton1) {
			mousePos = win.MousePosition()
			mouseDown = true
		}

		win.Update()
	}
}

func initialize() {
	cfg := pixelgl.WindowConfig{
		Bounds:      pixel.R(0, 0, 600, 400),
		VSync:       true,
		Undecorated: true,
	}
	win, err := pixelgl.NewWindow(cfg)
	if err != nil {
		panic(err)
	}
	run(win)
}

func main() {
	pixelgl.Run(initialize)
}

Maybe OS specific? I'm testing on Windows 10

thegtproject avatar Jun 27 '18 13:06 thegtproject

I'm running Linux Mint 18.3 x64 with Go 1.10.3

With your code I recorded this:

drag

The output is constantly printing 5.00, 4.00 when it continues to move after I move the mouse. Note that it only continues to move while I'm holding the mouse down. As soon as I release the mouse button the window stops moving.

EDIT: Here's a slightly modified version so you can see the window much better. It's gray but turns white when mouseDown is true. drag

coreyog avatar Jun 27 '18 19:06 coreyog

I got around to trying this out on my dedicated linux box (arch) and a vm (ubuntu), both work flawlessly for me. Might be a local issue?

thegtproject avatar Jun 27 '18 23:06 thegtproject

I tried this on my Arch Linux / Gnome 3 / Nvidia system and had the same jittering effect. I have a feeling this is some kind of event flood. You can reduce the effect by putting a time.Sleep(25 * time.Millisecond) before win.Update(). This however not a good solution and the movement is still not totally smooth.

@coreyog What might fix it is putting all mouse events in some kind of queue with a timestamp and only process some of them depending on the framerate or smoothen the movement somehow.

dbriemann avatar Jul 01 '18 11:07 dbriemann

There is something else going on here. You can try this run function:

func run(win *pixelgl.Window) {
	winCenter := win.Bounds().Center()

	for !win.Closed() {
		m := win.MousePosition()
		if win.Pressed(pixelgl.MouseButton1) {
			if m != winCenter {
				delta := m.Sub(winCenter)
				delta.X = math.Round(delta.X)
				delta.Y = math.Round(delta.Y) * -1
				win.SetPos(win.GetPos().Add(delta))

				fmt.Println(m, delta, winCenter)
			}
		}

		time.Sleep(25 * time.Millisecond) // ~50fps
		win.Update()
	}
}

It seems like the mouse position is not updated if you have not moved the mouse. The problem is that if the window is moved the mouse position has changed relative to that. This could be a problem with some OS window management.

dbriemann avatar Jul 01 '18 11:07 dbriemann