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:
Roman Gilg 2020-02-24 22:19:39 +01:00
parent 920fe8bd8f
commit f7d815a203
2 changed files with 310 additions and 219 deletions

View file

@ -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);
Window window_returned, child; move(x, y);
int root_x, root_y; checkSuspension();
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 );
// Also need new texture
if (cursorImageDirty)
{
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 int MouseCursor::x() const
{
return m_x;
}
int MouseCursor::y() const
{
return m_y;
}
bool MouseCursor::getTexture()
{
if (!m_dirty) {
return !m_imageEmpty;
}
auto *image = XFixesGetCursorImage(m_display);
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; bool bNoCursor = true;
unsigned int cursorDataBuffer[cursorWidth * cursorHeight]; unsigned int cursorDataBuffer[m_width * m_height];
for (int i = 0; i < cursorWidth * cursorHeight; i++) for (int i = 0; i < m_width * m_height; i++) {
{ cursorDataBuffer[i] = image->pixels[i];
cursorDataBuffer[i] = im->pixels[i];
if ( cursorDataBuffer[i] & 0x000000ff ) if ( cursorDataBuffer[i] & 0x000000ff ) {
{
bNoCursor = false; bNoCursor = false;
} }
} }
if ( bNoCursor != cursorImageEmpty ) if (bNoCursor != m_imageEmpty) {
{ m_imageEmpty = bNoCursor;
cursorImageEmpty = bNoCursor;
if ( cursorImageEmpty == true ) if (m_imageEmpty) {
{
// fprintf( stderr, "grab?\n" ); // fprintf( stderr, "grab?\n" );
} }
} }
if ( cursorImageEmpty == True ) if (m_imageEmpty) {
return; return false;
cursorTexture = vulkan_create_texture_from_bits( cursorWidth, cursorHeight, VK_FORMAT_R8G8B8A8_UNORM, cursorDataBuffer );
assert( cursorTexture != 0 );
XFree(im);
cursorImageDirty = False;
} }
if ( cursorImageEmpty == True ) m_texture = vulkan_create_texture_from_bits(m_width, m_height, VK_FORMAT_R8G8B8A8_UNORM,
return; 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 )

View file

@ -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;