refactor: add cursor class
Puts all cursor relevant code into a single class. Preparation for getting cursor movement directly through libinput.
This commit is contained in:
parent
920fe8bd8f
commit
f7d815a203
2 changed files with 310 additions and 219 deletions
|
@ -153,18 +153,6 @@ float overscanScaleRatio = 1.0;
|
||||||
float zoomScaleRatio = 1.0;
|
float zoomScaleRatio = 1.0;
|
||||||
float globalScaleRatio = 1.0f;
|
float globalScaleRatio = 1.0f;
|
||||||
|
|
||||||
PointerBarrier scaledFocusBarriers[4];
|
|
||||||
int cursorX, cursorY;
|
|
||||||
Bool cursorImageDirty = True;
|
|
||||||
int cursorHotX, cursorHotY;
|
|
||||||
int cursorWidth, cursorHeight;
|
|
||||||
VulkanTexture_t cursorTexture;
|
|
||||||
|
|
||||||
Bool hideCursorForMovement;
|
|
||||||
unsigned int lastCursorMovedTime;
|
|
||||||
static bool cursorImageEmpty;
|
|
||||||
|
|
||||||
|
|
||||||
Bool focusDirty = False;
|
Bool focusDirty = False;
|
||||||
bool hasRepaint = false;
|
bool hasRepaint = false;
|
||||||
|
|
||||||
|
@ -565,23 +553,144 @@ get_window_last_done_commit( win *w, commit_t &commit )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/**
|
||||||
handle_mouse_movement(Display *dpy, int posX, int posY)
|
* Constructor for a cursor. It is hidden in the beginning (normally until moved by user).
|
||||||
|
*/
|
||||||
|
MouseCursor::MouseCursor(_XDisplay *display)
|
||||||
|
: m_texture(0)
|
||||||
|
, m_dirty(true)
|
||||||
|
, m_imageEmpty(false)
|
||||||
|
, m_hideForMovement(true)
|
||||||
|
, m_hasPlane(false)
|
||||||
|
, m_display(display)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseCursor::queryPositions(int &rootX, int &rootY, int &winX, int &winY)
|
||||||
|
{
|
||||||
|
Window window, child;
|
||||||
|
unsigned int mask;
|
||||||
|
|
||||||
|
XQueryPointer(m_display, DefaultRootWindow(m_display), &window, &child,
|
||||||
|
&rootX, &rootY, &winX, &winY, &mask);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseCursor::queryGlobalPosition(int &x, int &y)
|
||||||
|
{
|
||||||
|
int winX, winY;
|
||||||
|
queryPositions(x, y, winX, winY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseCursor::queryButtonMask(unsigned int &mask)
|
||||||
|
{
|
||||||
|
Window window, child;
|
||||||
|
int rootX, rootY, winX, winY;
|
||||||
|
|
||||||
|
XQueryPointer(m_display, DefaultRootWindow(m_display), &window, &child,
|
||||||
|
&rootX, &rootY, &winX, &winY, &mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseCursor::checkSuspension()
|
||||||
|
{
|
||||||
|
unsigned int buttonMask;
|
||||||
|
queryButtonMask(buttonMask);
|
||||||
|
|
||||||
|
if (buttonMask & ( Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask )) {
|
||||||
|
m_hideForMovement = false;
|
||||||
|
m_lastMovedTime = get_time_in_milliseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool suspended = get_time_in_milliseconds() - m_lastMovedTime > CURSOR_HIDE_TIME;
|
||||||
|
if (!m_hideForMovement && suspended) {
|
||||||
|
m_hideForMovement = true;
|
||||||
|
|
||||||
|
win *window = find_win(m_display, currentFocusWindow);
|
||||||
|
|
||||||
|
// Rearm warp count
|
||||||
|
if (window) {
|
||||||
|
window->mouseMoved = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're hiding the cursor, force redraw if we were showing it
|
||||||
|
if (window && gameFocused && !m_imageEmpty ) {
|
||||||
|
hasRepaint = true;
|
||||||
|
XSendEvent(m_display, ourWindow, true, SubstructureRedirectMask, &nudgeEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseCursor::warp(int x, int y)
|
||||||
|
{
|
||||||
|
XWarpPointer(m_display, None, currentFocusWindow, 0, 0, 0, 0, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseCursor::resetPosition()
|
||||||
|
{
|
||||||
|
warp(m_x, m_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseCursor::setDirty()
|
||||||
|
{
|
||||||
|
// We can't prove it's empty until checking again
|
||||||
|
m_imageEmpty = false;
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseCursor::constrainPosition()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
win *window = find_win(m_display, currentFocusWindow);
|
||||||
|
|
||||||
|
// If we had barriers before, get rid of them.
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
if (m_scaledFocusBarriers[i] != None) {
|
||||||
|
XFixesDestroyPointerBarrier(m_display, m_scaledFocusBarriers[i]);
|
||||||
|
m_scaledFocusBarriers[i] = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gameFocused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto barricade = [this](int x1, int y1, int x2, int y2) {
|
||||||
|
return XFixesCreatePointerBarrier(m_display, DefaultRootWindow(m_display),
|
||||||
|
x1, y1, x2, y2, 0, 0, NULL);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constrain it to the window; careful, the corners will leak due to a known X server bug.
|
||||||
|
m_scaledFocusBarriers[0] = barricade(0, window->a.y, root_width, window->a.y);
|
||||||
|
|
||||||
|
m_scaledFocusBarriers[1] = barricade(window->a.x + window->a.width, 0,
|
||||||
|
window->a.x + window->a.width, root_height);
|
||||||
|
m_scaledFocusBarriers[2] = barricade(root_width, window->a.y + window->a.height,
|
||||||
|
0, window->a.y + window->a.height);
|
||||||
|
m_scaledFocusBarriers[3] = barricade(window->a.x, root_height, window->a.x, 0);
|
||||||
|
|
||||||
|
// Make sure the cursor is somewhere in our jail
|
||||||
|
int rootX, rootY;
|
||||||
|
queryGlobalPosition(rootX, rootY);
|
||||||
|
|
||||||
|
if (rootX >= window->a.width || rootY >= window->a.height) {
|
||||||
|
warp(window->a.width / 2, window->a.height / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseCursor::move(int x, int y)
|
||||||
{
|
{
|
||||||
// Some stuff likes to warp in-place
|
// Some stuff likes to warp in-place
|
||||||
if (cursorX == posX && cursorY == posY)
|
if (m_x == x && m_y == y) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
m_x = x;
|
||||||
|
m_y = y;
|
||||||
|
|
||||||
cursorX = posX;
|
win *window = find_win(m_display, currentFocusWindow);
|
||||||
cursorY = posY;
|
|
||||||
|
|
||||||
win *w = find_win(dpy, currentFocusWindow);
|
if (window && gameFocused) {
|
||||||
|
|
||||||
if (w && gameFocused)
|
|
||||||
{
|
|
||||||
// If mouse moved and we're on the hook for showing the cursor, repaint
|
// If mouse moved and we're on the hook for showing the cursor, repaint
|
||||||
if ( !hideCursorForMovement && !cursorImageEmpty )
|
if (!m_hideForMovement && !m_imageEmpty) {
|
||||||
{
|
|
||||||
hasRepaint = true;
|
hasRepaint = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,112 +704,127 @@ handle_mouse_movement(Display *dpy, int posX, int posY)
|
||||||
// Ignore the first events as it's likely to be non-user-initiated warps
|
// Ignore the first events as it's likely to be non-user-initiated warps
|
||||||
// Account for one warp from us, one warp from the app and one warp from
|
// Account for one warp from us, one warp from the app and one warp from
|
||||||
// the toolkit.
|
// the toolkit.
|
||||||
if ( !w || ( w->mouseMoved++ < 3 ) )
|
if (!window || window->mouseMoved++ < 3 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lastCursorMovedTime = get_time_in_milliseconds();
|
m_lastMovedTime = get_time_in_milliseconds();
|
||||||
|
m_hideForMovement = false;
|
||||||
hideCursorForMovement = False;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void MouseCursor::updatePosition()
|
||||||
paint_cursor ( Display *dpy, win *w, struct Composite_t *pComposite, struct VulkanPipeline_t *pPipeline )
|
|
||||||
{
|
{
|
||||||
float scaledCursorX, scaledCursorY;
|
int x,y;
|
||||||
|
queryGlobalPosition(x, y);
|
||||||
|
move(x, y);
|
||||||
|
checkSuspension();
|
||||||
|
}
|
||||||
|
|
||||||
Window window_returned, child;
|
int MouseCursor::x() const
|
||||||
int root_x, root_y;
|
{
|
||||||
int win_x, win_y;
|
return m_x;
|
||||||
unsigned int mask_return;
|
}
|
||||||
|
|
||||||
XQueryPointer(dpy, DefaultRootWindow(dpy), &window_returned,
|
int MouseCursor::y() const
|
||||||
&child, &root_x, &root_y, &win_x, &win_y,
|
{
|
||||||
&mask_return);
|
return m_y;
|
||||||
|
}
|
||||||
|
|
||||||
handle_mouse_movement( dpy, root_x, root_y );
|
bool MouseCursor::getTexture()
|
||||||
|
{
|
||||||
// Also need new texture
|
if (!m_dirty) {
|
||||||
if (cursorImageDirty)
|
return !m_imageEmpty;
|
||||||
{
|
|
||||||
XFixesCursorImage* im = XFixesGetCursorImage(dpy);
|
|
||||||
|
|
||||||
if (!im)
|
|
||||||
return;
|
|
||||||
|
|
||||||
cursorHotX = im->xhot;
|
|
||||||
cursorHotY = im->yhot;
|
|
||||||
|
|
||||||
cursorWidth = im->width;
|
|
||||||
cursorHeight = im->height;
|
|
||||||
|
|
||||||
if ( cursorTexture != 0 )
|
|
||||||
{
|
|
||||||
vulkan_free_texture( cursorTexture );
|
|
||||||
cursorTexture = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assume the cursor is fully translucent unless proven otherwise
|
|
||||||
bool bNoCursor = true;
|
|
||||||
|
|
||||||
unsigned int cursorDataBuffer[cursorWidth * cursorHeight];
|
|
||||||
for (int i = 0; i < cursorWidth * cursorHeight; i++)
|
|
||||||
{
|
|
||||||
cursorDataBuffer[i] = im->pixels[i];
|
|
||||||
|
|
||||||
if ( cursorDataBuffer[i] & 0x000000ff )
|
|
||||||
{
|
|
||||||
bNoCursor = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( bNoCursor != cursorImageEmpty )
|
|
||||||
{
|
|
||||||
cursorImageEmpty = bNoCursor;
|
|
||||||
|
|
||||||
if ( cursorImageEmpty == true )
|
|
||||||
{
|
|
||||||
// fprintf( stderr, "grab?\n" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( cursorImageEmpty == True )
|
|
||||||
return;
|
|
||||||
|
|
||||||
cursorTexture = vulkan_create_texture_from_bits( cursorWidth, cursorHeight, VK_FORMAT_R8G8B8A8_UNORM, cursorDataBuffer );
|
|
||||||
|
|
||||||
assert( cursorTexture != 0 );
|
|
||||||
|
|
||||||
XFree(im);
|
|
||||||
|
|
||||||
cursorImageDirty = False;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( cursorImageEmpty == True )
|
auto *image = XFixesGetCursorImage(m_display);
|
||||||
return;
|
|
||||||
|
|
||||||
|
if (!image) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_hotspotX = image->xhot;
|
||||||
|
m_hotspotY = image->yhot;
|
||||||
|
|
||||||
|
m_width = image->width;
|
||||||
|
m_height = image->height;
|
||||||
|
|
||||||
|
if (m_texture) {
|
||||||
|
vulkan_free_texture(m_texture);
|
||||||
|
m_texture = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume the cursor is fully translucent unless proven otherwise.
|
||||||
|
bool bNoCursor = true;
|
||||||
|
|
||||||
|
unsigned int cursorDataBuffer[m_width * m_height];
|
||||||
|
for (int i = 0; i < m_width * m_height; i++) {
|
||||||
|
cursorDataBuffer[i] = image->pixels[i];
|
||||||
|
|
||||||
|
if ( cursorDataBuffer[i] & 0x000000ff ) {
|
||||||
|
bNoCursor = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bNoCursor != m_imageEmpty) {
|
||||||
|
m_imageEmpty = bNoCursor;
|
||||||
|
|
||||||
|
if (m_imageEmpty) {
|
||||||
|
// fprintf( stderr, "grab?\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_imageEmpty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_texture = vulkan_create_texture_from_bits(m_width, m_height, VK_FORMAT_R8G8B8A8_UNORM,
|
||||||
|
cursorDataBuffer);
|
||||||
|
assert(m_texture);
|
||||||
|
XFree(image);
|
||||||
|
m_dirty = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseCursor::paint(win *window, struct Composite_t *pComposite,
|
||||||
|
struct VulkanPipeline_t *pPipeline)
|
||||||
|
{
|
||||||
|
if (m_hideForMovement || m_imageEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rootX, rootY, winX, winY;
|
||||||
|
queryPositions(rootX, rootY, winX, winY);
|
||||||
|
move(rootX, rootY);
|
||||||
|
|
||||||
|
// Also need new texture
|
||||||
|
if (!getTexture()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scaledX, scaledY;
|
||||||
float currentScaleRatio = 1.0;
|
float currentScaleRatio = 1.0;
|
||||||
float XRatio = (float)currentOutputWidth / w->a.width;
|
float XRatio = (float)currentOutputWidth / window->a.width;
|
||||||
float YRatio = (float)currentOutputHeight / w->a.height;
|
float YRatio = (float)currentOutputHeight / window->a.height;
|
||||||
int cursorOffsetX, cursorOffsetY;
|
int cursorOffsetX, cursorOffsetY;
|
||||||
|
|
||||||
currentScaleRatio = (XRatio < YRatio) ? XRatio : YRatio;
|
currentScaleRatio = (XRatio < YRatio) ? XRatio : YRatio;
|
||||||
|
|
||||||
cursorOffsetX = (currentOutputWidth - w->a.width * currentScaleRatio * globalScaleRatio) / 2.0f;
|
cursorOffsetX = (currentOutputWidth - window->a.width * currentScaleRatio * globalScaleRatio) / 2.0f;
|
||||||
cursorOffsetY = (currentOutputHeight - w->a.height * currentScaleRatio * globalScaleRatio) / 2.0f;
|
cursorOffsetY = (currentOutputHeight - window->a.height * currentScaleRatio * globalScaleRatio) / 2.0f;
|
||||||
|
|
||||||
// Actual point on scaled screen where the cursor hotspot should be
|
// Actual point on scaled screen where the cursor hotspot should be
|
||||||
scaledCursorX = (win_x - w->a.x) * currentScaleRatio * globalScaleRatio + cursorOffsetX;
|
scaledX = (winX - window->a.x) * currentScaleRatio * globalScaleRatio + cursorOffsetX;
|
||||||
scaledCursorY = (win_y - w->a.y) * currentScaleRatio * globalScaleRatio + cursorOffsetY;
|
scaledY = (winY - window->a.y) * currentScaleRatio * globalScaleRatio + cursorOffsetY;
|
||||||
|
|
||||||
if ( zoomScaleRatio != 1.0 )
|
if ( zoomScaleRatio != 1.0 )
|
||||||
{
|
{
|
||||||
scaledCursorX += ((w->a.width / 2) - win_x) * currentScaleRatio * globalScaleRatio;
|
scaledX += ((window->a.width / 2) - winX) * currentScaleRatio * globalScaleRatio;
|
||||||
scaledCursorY += ((w->a.height / 2) - win_y) * currentScaleRatio * globalScaleRatio;
|
scaledY += ((window->a.height / 2) - winY) * currentScaleRatio * globalScaleRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the cursor offset inside the texture using the display scale
|
// Apply the cursor offset inside the texture using the display scale
|
||||||
scaledCursorX = scaledCursorX - cursorHotX;
|
scaledX = scaledX - m_hotspotX;
|
||||||
scaledCursorY = scaledCursorY - cursorHotY;
|
scaledY = scaledY - m_hotspotY;
|
||||||
|
|
||||||
int curLayer = pComposite->nLayerCount;
|
int curLayer = pComposite->nLayerCount;
|
||||||
|
|
||||||
|
@ -709,16 +833,17 @@ paint_cursor ( Display *dpy, win *w, struct Composite_t *pComposite, struct Vulk
|
||||||
pComposite->layers[ curLayer ].flScaleX = 1.0;
|
pComposite->layers[ curLayer ].flScaleX = 1.0;
|
||||||
pComposite->layers[ curLayer ].flScaleY = 1.0;
|
pComposite->layers[ curLayer ].flScaleY = 1.0;
|
||||||
|
|
||||||
pComposite->layers[ curLayer ].flOffsetX = -scaledCursorX;
|
pComposite->layers[ curLayer ].flOffsetX = -scaledX;
|
||||||
pComposite->layers[ curLayer ].flOffsetY = -scaledCursorY;
|
pComposite->layers[ curLayer ].flOffsetY = -scaledY;
|
||||||
|
|
||||||
pPipeline->layerBindings[ curLayer ].surfaceWidth = cursorWidth;
|
pPipeline->layerBindings[ curLayer ].surfaceWidth = m_width;
|
||||||
pPipeline->layerBindings[ curLayer ].surfaceHeight = cursorHeight;
|
pPipeline->layerBindings[ curLayer ].surfaceHeight = m_height;
|
||||||
|
|
||||||
pPipeline->layerBindings[ curLayer ].zpos = 2; // cursor, on top of both bottom layers
|
pPipeline->layerBindings[ curLayer ].zpos = 2; // cursor, on top of both bottom layers
|
||||||
|
|
||||||
pPipeline->layerBindings[ curLayer ].tex = cursorTexture;
|
pPipeline->layerBindings[ curLayer ].tex = m_texture;
|
||||||
pPipeline->layerBindings[ curLayer ].fbid = BIsNested() ? 0 : vulkan_texture_get_fbid( cursorTexture );
|
pPipeline->layerBindings[ curLayer ].fbid = BIsNested() ? 0 :
|
||||||
|
vulkan_texture_get_fbid(m_texture);
|
||||||
|
|
||||||
pPipeline->layerBindings[ curLayer ].bFilter = false;
|
pPipeline->layerBindings[ curLayer ].bFilter = false;
|
||||||
pPipeline->layerBindings[ curLayer ].bBlackBorder = false;
|
pPipeline->layerBindings[ curLayer ].bBlackBorder = false;
|
||||||
|
@ -727,7 +852,8 @@ paint_cursor ( Display *dpy, win *w, struct Composite_t *pComposite, struct Vulk
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
paint_window (Display *dpy, win *w, struct Composite_t *pComposite, struct VulkanPipeline_t *pPipeline, Bool notificationMode)
|
paint_window (Display *dpy, win *w, struct Composite_t *pComposite,
|
||||||
|
struct VulkanPipeline_t *pPipeline, Bool notificationMode, MouseCursor *cursor)
|
||||||
{
|
{
|
||||||
uint32_t sourceWidth, sourceHeight;
|
uint32_t sourceWidth, sourceHeight;
|
||||||
int drawXOffset = 0, drawYOffset = 0;
|
int drawXOffset = 0, drawYOffset = 0;
|
||||||
|
@ -774,8 +900,8 @@ paint_window (Display *dpy, win *w, struct Composite_t *pComposite, struct Vulka
|
||||||
|
|
||||||
if ( zoomScaleRatio != 1.0 )
|
if ( zoomScaleRatio != 1.0 )
|
||||||
{
|
{
|
||||||
drawXOffset += ((sourceWidth / 2) - cursorX) * currentScaleRatio;
|
drawXOffset += ((sourceWidth / 2) - cursor->x()) * currentScaleRatio;
|
||||||
drawYOffset += ((sourceHeight / 2) - cursorY) * currentScaleRatio;
|
drawYOffset += ((sourceHeight / 2) - cursor->y()) * currentScaleRatio;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -877,7 +1003,7 @@ paint_debug_info (Display *dpy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
paint_all (Display *dpy)
|
paint_all(Display *dpy, MouseCursor *cursor)
|
||||||
{
|
{
|
||||||
static long long int paintID = 0;
|
static long long int paintID = 0;
|
||||||
|
|
||||||
|
@ -933,20 +1059,20 @@ paint_all (Display *dpy)
|
||||||
|
|
||||||
// Draw it in the background
|
// Draw it in the background
|
||||||
fadeOutWindow.opacity = (1.0d - newOpacity) * OPAQUE;
|
fadeOutWindow.opacity = (1.0d - newOpacity) * OPAQUE;
|
||||||
paint_window(dpy, &fadeOutWindow, &composite, &pipeline, False);
|
paint_window(dpy, &fadeOutWindow, &composite, &pipeline, False, cursor);
|
||||||
|
|
||||||
w = find_win(dpy, currentFocusWindow);
|
w = find_win(dpy, currentFocusWindow);
|
||||||
|
|
||||||
// Blend new window on top with linear crossfade
|
// Blend new window on top with linear crossfade
|
||||||
w->opacity = newOpacity * OPAQUE;
|
w->opacity = newOpacity * OPAQUE;
|
||||||
|
|
||||||
paint_window(dpy, w, &composite, &pipeline, False);
|
paint_window(dpy, w, &composite, &pipeline, False, cursor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
w = find_win(dpy, currentFocusWindow);
|
w = find_win(dpy, currentFocusWindow);
|
||||||
// Just draw focused window as normal, be it Steam or the game
|
// Just draw focused window as normal, be it Steam or the game
|
||||||
paint_window(dpy, w, &composite, &pipeline, False);
|
paint_window(dpy, w, &composite, &pipeline, False, cursor);
|
||||||
|
|
||||||
if (fadeOutWindow.id) {
|
if (fadeOutWindow.id) {
|
||||||
|
|
||||||
|
@ -966,7 +1092,7 @@ paint_all (Display *dpy)
|
||||||
{
|
{
|
||||||
if (overlay->opacity)
|
if (overlay->opacity)
|
||||||
{
|
{
|
||||||
paint_window(dpy, overlay, &composite, &pipeline, False);
|
paint_window(dpy, overlay, &composite, &pipeline, False, cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -974,17 +1100,13 @@ paint_all (Display *dpy)
|
||||||
{
|
{
|
||||||
if (notification->opacity)
|
if (notification->opacity)
|
||||||
{
|
{
|
||||||
paint_window(dpy, notification, &composite, &pipeline, True);
|
paint_window(dpy, notification, &composite, &pipeline, True, cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw cursor if we need to
|
// Draw cursor if we need to
|
||||||
if (w && gameFocused)
|
if (w && gameFocused) {
|
||||||
{
|
cursor->paint(w, &composite, &pipeline );
|
||||||
if ( !hideCursorForMovement && !cursorImageEmpty )
|
|
||||||
{
|
|
||||||
paint_cursor( dpy, w, &composite, &pipeline );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drawDebugInfo)
|
if (drawDebugInfo)
|
||||||
|
@ -1049,50 +1171,7 @@ paint_all (Display *dpy)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
setup_pointer_barriers (Display *dpy)
|
determine_and_apply_focus (Display *dpy, MouseCursor *cursor)
|
||||||
{
|
|
||||||
int i;
|
|
||||||
win *w = find_win (dpy, currentFocusWindow);
|
|
||||||
|
|
||||||
// If we had barriers before, get rid of them.
|
|
||||||
for (i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
if (scaledFocusBarriers[i] != None)
|
|
||||||
{
|
|
||||||
XFixesDestroyPointerBarrier(dpy, scaledFocusBarriers[i]);
|
|
||||||
scaledFocusBarriers[i] = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gameFocused)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constrain it to the window; careful, the corners will leak due to a known X server bug
|
|
||||||
scaledFocusBarriers[0] = XFixesCreatePointerBarrier(dpy, DefaultRootWindow(dpy), 0, w->a.y, root_width, w->a.y, 0, 0, NULL);
|
|
||||||
scaledFocusBarriers[1] = XFixesCreatePointerBarrier(dpy, DefaultRootWindow(dpy), w->a.x + w->a.width, 0, w->a.x + w->a.width, root_height, 0, 0, NULL);
|
|
||||||
scaledFocusBarriers[2] = XFixesCreatePointerBarrier(dpy, DefaultRootWindow(dpy), root_width, w->a.y + w->a.height, 0, w->a.y + w->a.height, 0, 0, NULL);
|
|
||||||
scaledFocusBarriers[3] = XFixesCreatePointerBarrier(dpy, DefaultRootWindow(dpy), w->a.x, root_height, w->a.x, 0, 0, 0, NULL);
|
|
||||||
|
|
||||||
// Make sure the cursor is somewhere in our jail
|
|
||||||
Window window_returned, child;
|
|
||||||
int root_x, root_y;
|
|
||||||
int win_x, win_y;
|
|
||||||
unsigned int mask_return;
|
|
||||||
|
|
||||||
XQueryPointer(dpy, DefaultRootWindow(dpy), &window_returned,
|
|
||||||
&child, &root_x, &root_y, &win_x, &win_y,
|
|
||||||
&mask_return);
|
|
||||||
|
|
||||||
if (root_x >= w->a.width || root_y >= w->a.height)
|
|
||||||
{
|
|
||||||
XWarpPointer(dpy, None, currentFocusWindow, 0, 0, 0, 0, w->a.width / 2, w->a.height / 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
determine_and_apply_focus (Display *dpy)
|
|
||||||
{
|
{
|
||||||
win *w, *focus = NULL;
|
win *w, *focus = NULL;
|
||||||
win *steam = nullptr;
|
win *steam = nullptr;
|
||||||
|
@ -1203,7 +1282,7 @@ determine_and_apply_focus (Display *dpy)
|
||||||
|
|
||||||
set_win_hidden(dpy, w, False);
|
set_win_hidden(dpy, w, False);
|
||||||
|
|
||||||
setup_pointer_barriers(dpy);
|
cursor->constrainPosition();
|
||||||
|
|
||||||
if (gameFocused || (!gamesRunningCount && list[0].id != focus->id))
|
if (gameFocused || (!gamesRunningCount && list[0].id != focus->id))
|
||||||
{
|
{
|
||||||
|
@ -2086,8 +2165,7 @@ steamcompmgr_main (int argc, char **argv)
|
||||||
|
|
||||||
XF86VidModeLockModeSwitch(dpy, scr, True);
|
XF86VidModeLockModeSwitch(dpy, scr, True);
|
||||||
|
|
||||||
// Start it with the cursor hidden until moved by user
|
std::unique_ptr<MouseCursor> cursor(new MouseCursor(dpy));
|
||||||
hideCursorForMovement = True;
|
|
||||||
|
|
||||||
gamesRunningCount = get_prop(dpy, root, gamesRunningAtom, 0);
|
gamesRunningCount = get_prop(dpy, root, gamesRunningAtom, 0);
|
||||||
overscanScaleRatio = get_prop(dpy, root, screenScaleAtom, 0xFFFFFFFF) / (double)0xFFFFFFFF;
|
overscanScaleRatio = get_prop(dpy, root, screenScaleAtom, 0xFFFFFFFF) / (double)0xFFFFFFFF;
|
||||||
|
@ -2095,7 +2173,7 @@ steamcompmgr_main (int argc, char **argv)
|
||||||
|
|
||||||
globalScaleRatio = overscanScaleRatio * zoomScaleRatio;
|
globalScaleRatio = overscanScaleRatio * zoomScaleRatio;
|
||||||
|
|
||||||
determine_and_apply_focus(dpy);
|
determine_and_apply_focus(dpy, cursor.get());
|
||||||
|
|
||||||
if ( readyPipeFD != -1 )
|
if ( readyPipeFD != -1 )
|
||||||
{
|
{
|
||||||
|
@ -2378,8 +2456,7 @@ steamcompmgr_main (int argc, char **argv)
|
||||||
// This shouldn't happen due to our pointer barriers,
|
// This shouldn't happen due to our pointer barriers,
|
||||||
// but there is a known X server bug; warp to last good
|
// but there is a known X server bug; warp to last good
|
||||||
// position.
|
// position.
|
||||||
XWarpPointer(dpy, None, currentFocusWindow, 0, 0, 0, 0,
|
cursor->resetPosition();
|
||||||
cursorX, cursorY);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MotionNotify:
|
case MotionNotify:
|
||||||
|
@ -2387,7 +2464,7 @@ steamcompmgr_main (int argc, char **argv)
|
||||||
win * w = find_win(dpy, ev.xmotion.window);
|
win * w = find_win(dpy, ev.xmotion.window);
|
||||||
if (w && w->id == currentFocusWindow)
|
if (w && w->id == currentFocusWindow)
|
||||||
{
|
{
|
||||||
handle_mouse_movement( dpy, ev.xmotion.x, ev.xmotion.y );
|
cursor->move(ev.xmotion.x, ev.xmotion.y);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2398,16 +2475,14 @@ steamcompmgr_main (int argc, char **argv)
|
||||||
}
|
}
|
||||||
else if (ev.type == xfixes_event + XFixesCursorNotify)
|
else if (ev.type == xfixes_event + XFixesCursorNotify)
|
||||||
{
|
{
|
||||||
cursorImageDirty = True;
|
cursor->setDirty();
|
||||||
// We can't prove it's empty until checking again
|
|
||||||
cursorImageEmpty = false;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (QLength (dpy));
|
} while (QLength (dpy));
|
||||||
|
|
||||||
if (focusDirty == True)
|
if (focusDirty == True)
|
||||||
determine_and_apply_focus(dpy);
|
determine_and_apply_focus(dpy, cursor.get());
|
||||||
|
|
||||||
if (doRender)
|
if (doRender)
|
||||||
{
|
{
|
||||||
|
@ -2454,7 +2529,7 @@ steamcompmgr_main (int argc, char **argv)
|
||||||
|
|
||||||
if ( hasRepaint == true && vblank == true )
|
if ( hasRepaint == true && vblank == true )
|
||||||
{
|
{
|
||||||
paint_all(dpy);
|
paint_all(dpy, cursor.get());
|
||||||
|
|
||||||
// Consumed the need to repaint here
|
// Consumed the need to repaint here
|
||||||
hasRepaint = false;
|
hasRepaint = false;
|
||||||
|
@ -2468,43 +2543,7 @@ steamcompmgr_main (int argc, char **argv)
|
||||||
if (fadeOutWindow.id)
|
if (fadeOutWindow.id)
|
||||||
XSendEvent(dpy, ourWindow, True, SubstructureRedirectMask, &nudgeEvent);
|
XSendEvent(dpy, ourWindow, True, SubstructureRedirectMask, &nudgeEvent);
|
||||||
|
|
||||||
Window window_returned, child;
|
cursor->updatePosition();
|
||||||
int root_x, root_y;
|
|
||||||
int win_x, win_y;
|
|
||||||
unsigned int mask_return;
|
|
||||||
|
|
||||||
XQueryPointer(dpy, DefaultRootWindow(dpy), &window_returned,
|
|
||||||
&child, &root_x, &root_y, &win_x, &win_y,
|
|
||||||
&mask_return);
|
|
||||||
|
|
||||||
handle_mouse_movement( dpy, root_x, root_y );
|
|
||||||
|
|
||||||
if ( mask_return & ( Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) )
|
|
||||||
{
|
|
||||||
hideCursorForMovement = False;
|
|
||||||
lastCursorMovedTime = get_time_in_milliseconds();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hideCursorForMovement &&
|
|
||||||
(get_time_in_milliseconds() - lastCursorMovedTime) > CURSOR_HIDE_TIME)
|
|
||||||
{
|
|
||||||
hideCursorForMovement = True;
|
|
||||||
|
|
||||||
win *w = find_win(dpy, currentFocusWindow);
|
|
||||||
|
|
||||||
// Rearm warp count
|
|
||||||
if (w)
|
|
||||||
{
|
|
||||||
w->mouseMoved = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're hiding the cursor, force redraw if we were showing it
|
|
||||||
if ( w && gameFocused && !cursorImageEmpty )
|
|
||||||
{
|
|
||||||
hasRepaint = true;
|
|
||||||
XSendEvent(dpy, ourWindow, True, SubstructureRedirectMask, &nudgeEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ask for a new surface every vblank
|
// Ask for a new surface every vblank
|
||||||
if ( vblank == true )
|
if ( vblank == true )
|
||||||
|
|
|
@ -14,16 +14,68 @@ int steamcompmgr_main(int argc, char **argv);
|
||||||
#ifndef C_SIDE
|
#ifndef C_SIDE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "rendervulkan.hpp"
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <wlr/render/dmabuf.h>
|
#include <wlr/render/dmabuf.h>
|
||||||
|
|
||||||
|
#include <X11/extensions/Xfixes.h>
|
||||||
|
|
||||||
struct ResListEntry_t {
|
struct ResListEntry_t {
|
||||||
struct wlr_surface *surf;
|
struct wlr_surface *surf;
|
||||||
struct wlr_dmabuf_attributes attribs;
|
struct wlr_dmabuf_attributes attribs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _XDisplay;
|
||||||
|
struct _win;
|
||||||
|
|
||||||
|
class MouseCursor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit MouseCursor(_XDisplay *display);
|
||||||
|
|
||||||
|
int x() const;
|
||||||
|
int y() const;
|
||||||
|
|
||||||
|
void move(int x, int y);
|
||||||
|
void updatePosition();
|
||||||
|
void constrainPosition();
|
||||||
|
void resetPosition();
|
||||||
|
|
||||||
|
void paint(struct _win *window, struct Composite_t *pComposite,
|
||||||
|
struct VulkanPipeline_t *pPipeline);
|
||||||
|
void setDirty();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void warp(int x, int y);
|
||||||
|
void checkSuspension();
|
||||||
|
|
||||||
|
void queryGlobalPosition(int &x, int &y);
|
||||||
|
void queryPositions(int &rootX, int &rootY, int &winX, int &winY);
|
||||||
|
void queryButtonMask(unsigned int &mask);
|
||||||
|
|
||||||
|
bool getTexture();
|
||||||
|
|
||||||
|
int m_x, m_y;
|
||||||
|
int m_hotspotX, m_hotspotY;
|
||||||
|
int m_width, m_height;
|
||||||
|
|
||||||
|
VulkanTexture_t m_texture;
|
||||||
|
bool m_dirty;
|
||||||
|
bool m_imageEmpty;
|
||||||
|
|
||||||
|
unsigned int m_lastMovedTime;
|
||||||
|
bool m_hideForMovement;
|
||||||
|
|
||||||
|
PointerBarrier m_scaledFocusBarriers[4];
|
||||||
|
|
||||||
|
bool m_hasPlane;
|
||||||
|
|
||||||
|
_XDisplay *m_display;
|
||||||
|
};
|
||||||
|
|
||||||
extern std::mutex wayland_commit_lock;
|
extern std::mutex wayland_commit_lock;
|
||||||
extern std::vector<ResListEntry_t> wayland_commit_queue;
|
extern std::vector<ResListEntry_t> wayland_commit_queue;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue