Browse Source

Implemented cursor visibility setting in X11.

David Piuva 2 years ago
parent
commit
6c1ce41995

+ 10 - 0
Source/DFPSR/api/guiAPI.cpp

@@ -158,6 +158,16 @@ void dsr::window_setPixelScale(const Window& window, int scale) {
 	window->setPixelScale(scale);
 	window->setPixelScale(scale);
 }
 }
 
 
+bool dsr::window_setCursorVisibility(const Window& window, bool visible) {
+	MUST_EXIST(window, window_setCursorVisibility);
+	return window->backend->setCursorVisibility(visible);
+}
+
+bool dsr::window_getCursorVisibility(const Window& window) {
+	MUST_EXIST(window, window_getCursorVisibility);
+	return window->backend->visibleCursor;
+}
+
 void dsr::window_setFullScreen(const Window& window, bool enabled) {
 void dsr::window_setFullScreen(const Window& window, bool enabled) {
 	MUST_EXIST(window, window_setFullScreen);
 	MUST_EXIST(window, window_setFullScreen);
 	window->setFullScreen(enabled);
 	window->setFullScreen(enabled);

+ 5 - 0
Source/DFPSR/api/guiAPI.h

@@ -126,6 +126,11 @@ namespace dsr {
 	//   Just like when handling a window resize, this will replace the canvas and depth buffer.
 	//   Just like when handling a window resize, this will replace the canvas and depth buffer.
 	//     Any old handles to canvas and depth buffer will become useless, so fetch new image handles from the window to avoid black flickering.
 	//     Any old handles to canvas and depth buffer will become useless, so fetch new image handles from the window to avoid black flickering.
 	void window_setPixelScale(const Window& window, int scale);
 	void window_setPixelScale(const Window& window, int scale);
+	// Sets the cursor visibility for window, hiding if visible is false and showing if visible is true.
+	// Returns true on success and false on failure.
+	bool window_setCursorVisibility(const Window& window, bool visible);
+	// Returns true iff the cursor is allowed to be displayed over window.
+	bool window_getCursorVisibility(const Window& window);
 
 
 // Full screen
 // Full screen
 	void window_setFullScreen(const Window& window, bool enabled);
 	void window_setFullScreen(const Window& window, bool enabled);

+ 5 - 0
Source/DFPSR/gui/BackendWindow.h

@@ -80,6 +80,11 @@ public:
 	virtual void resizeCanvas(int width, int height) = 0;
 	virtual void resizeCanvas(int width, int height) = 0;
 	virtual String getTitle() { return this->title; }
 	virtual String getTitle() { return this->title; }
 	virtual void setTitle(const String &newTitle) = 0;
 	virtual void setTitle(const String &newTitle) = 0;
+public:
+	// Cursor interface
+	bool visibleCursor = true; // Written to by setCursorVisibility on success.
+	virtual bool setCursorVisibility(bool visible) { return false; } // Returns true on success.
+public:
 	// Each callback declaration has a public variable and a public getter and setter
 	// Each callback declaration has a public variable and a public getter and setter
 	DECLARE_CALLBACK(closeEvent, emptyCallback);
 	DECLARE_CALLBACK(closeEvent, emptyCallback);
 	DECLARE_CALLBACK(resizeEvent, sizeCallback);
 	DECLARE_CALLBACK(resizeEvent, sizeCallback);

+ 3 - 2
Source/DFPSR/gui/DsrWindow.h

@@ -40,9 +40,10 @@ namespace dsr {
 void gui_initialize();
 void gui_initialize();
 
 
 class DsrWindow {
 class DsrWindow {
-private:
-	// Window backend
+public:
+	// Window backend, which the API is allowed to call directly to bypass DsrWindow for trivial operations.
 	std::shared_ptr<BackendWindow> backend;
 	std::shared_ptr<BackendWindow> backend;
+private:
 	// The root component
 	// The root component
 	std::shared_ptr<VisualComponent> mainPanel;
 	std::shared_ptr<VisualComponent> mainPanel;
 	AlignedImageF32 depthBuffer;
 	AlignedImageF32 depthBuffer;

+ 37 - 6
Source/windowManagers/X11Window.cpp

@@ -31,6 +31,8 @@ private:
 	Window window;
 	Window window;
 	// Holds settings for drawing to the window
 	// Holds settings for drawing to the window
 	GC graphicsContext;
 	GC graphicsContext;
+	// Invisible cursor for hiding it over the window
+	Cursor noCursor;
 
 
 	// Double buffering to allow drawing to a canvas while displaying the previous one
 	// Double buffering to allow drawing to a canvas while displaying the previous one
 	// The image which can be drawn to, sharing memory with the X11 image
 	// The image which can be drawn to, sharing memory with the X11 image
@@ -54,6 +56,9 @@ private:
 	//   Closing the window, moving the mouse, pressing a key, et cetera
 	//   Closing the window, moving the mouse, pressing a key, et cetera
 	void prefetchEvents() override;
 	void prefetchEvents() override;
 
 
+	// Called to change the cursor visibility and returning true on success
+	bool setCursorVisibility(bool visible) override;
+
 	// Color format
 	// Color format
 	dsr::PackOrderIndex packOrderIndex = dsr::PackOrderIndex::RGBA;
 	dsr::PackOrderIndex packOrderIndex = dsr::PackOrderIndex::RGBA;
 	dsr::PackOrderIndex getColorFormat_locked();
 	dsr::PackOrderIndex getColorFormat_locked();
@@ -89,6 +94,22 @@ public:
 	void showCanvas() override;
 	void showCanvas() override;
 };
 };
 
 
+bool X11Window::setCursorVisibility(bool visible) {
+	windowLock.lock();
+		if (visible) {
+			// Reset to parent cursor
+			XUndefineCursor(this->display, this->window);
+		} else {
+			// Let the window display an empty cursor
+			XDefineCursor(this->display, this->window, this->noCursor);
+		}
+	windowLock.unlock();
+	// Remember the cursor's visibility for anyone asking
+	this->visibleCursor = visible;
+	// Indicate success
+	return true;
+}
+
 void X11Window::updateTitle_locked() {
 void X11Window::updateTitle_locked() {
 	windowLock.lock();
 	windowLock.lock();
 		XSetStandardProperties(this->display, this->window, this->title.toStdString().c_str(), "Icon", None, NULL, 0, NULL);
 		XSetStandardProperties(this->display, this->window, this->title.toStdString().c_str(), "Icon", None, NULL, 0, NULL);
@@ -193,12 +214,9 @@ void X11Window::createGCWindow_locked(const dsr::String& title, int width, int h
 		this->windowWidth = width;
 		this->windowWidth = width;
 		this->windowHeight = height;
 		this->windowHeight = height;
 		this->receivedWindowResize(width, height);
 		this->receivedWindowResize(width, height);
-
-		// Screen handle
-		int defaultScreenIndex = DefaultScreen(this->display);
-		unsigned long black = BlackPixel(this->display, defaultScreenIndex);
-		unsigned long white = WhitePixel(this->display, defaultScreenIndex);
-
+		int screenIndex = DefaultScreen(this->display);
+		unsigned long black = BlackPixel(this->display, screenIndex);
+		unsigned long white = WhitePixel(this->display, screenIndex);
 		// Create a new window
 		// Create a new window
 		this->window = XCreateSimpleWindow(this->display, DefaultRootWindow(this->display), 0, 0, width, height, 0, white, black);
 		this->window = XCreateSimpleWindow(this->display, DefaultRootWindow(this->display), 0, 0, width, height, 0, white, black);
 	windowLock.unlock();
 	windowLock.unlock();
@@ -299,6 +317,18 @@ X11Window::X11Window(const dsr::String& title, int width, int height) {
 	} else {
 	} else {
 		this->createWindowed_locked(title, width, height);
 		this->createWindowed_locked(title, width, height);
 	}
 	}
+
+	// Create a hidden cursor stored as noCursor
+	// Create a black color using zero bits, which will not be visible anyway
+	XColor black; memset(&black, 0, sizeof(XColor));
+	// Store all 8x8 pixels in a 64-bit unsigned integer
+	uint64_t zeroBits = 0u;
+	// Create a temporary image for both 1-bit color selection and a visibility mask
+	Pixmap zeroBitmap = XCreateBitmapFromData(this->display, this->window, (char*)&zeroBits, 8, 8);
+	// Create the cursor
+	this->noCursor = XCreatePixmapCursor(this->display, zeroBitmap, zeroBitmap, &black, &black, 0, 0);
+	// Free the temporary bitmap used to create the cursor
+	XFreePixmap(this->display, zeroBitmap);
 }
 }
 
 
 // Convert keycodes from XLib to DSR
 // Convert keycodes from XLib to DSR
@@ -603,6 +633,7 @@ X11Window::~X11Window() {
 	#endif
 	#endif
 	windowLock.lock();
 	windowLock.lock();
 		if (this->display) {
 		if (this->display) {
+			XFreeCursor(this->display, this->noCursor);
 			XFreeGC(this->display, this->graphicsContext);
 			XFreeGC(this->display, this->graphicsContext);
 			XDestroyWindow(this->display, this->window);
 			XDestroyWindow(this->display, this->window);
 			XCloseDisplay(this->display);
 			XCloseDisplay(this->display);