added cursor hiding.
This commit is contained in:
parent
c9f0b694de
commit
20c7aca1db
|
@ -49,7 +49,7 @@ void CXWindowsPrimaryScreen::open(CServer* server)
|
||||||
log((CLOG_INFO "primary display size: %dx%d", m_w, m_h));
|
log((CLOG_INFO "primary display size: %dx%d", m_w, m_h));
|
||||||
|
|
||||||
// get the root window
|
// get the root window
|
||||||
Window root = RootWindow(m_display, m_screen);
|
m_root = RootWindow(m_display, m_screen);
|
||||||
|
|
||||||
// create the grab window. this window is used to capture user
|
// create the grab window. this window is used to capture user
|
||||||
// input when the user is focussed on another client. don't let
|
// input when the user is focussed on another client. don't let
|
||||||
|
@ -61,15 +61,15 @@ void CXWindowsPrimaryScreen::open(CServer* server)
|
||||||
KeymapStateMask;
|
KeymapStateMask;
|
||||||
attr.do_not_propagate_mask = 0;
|
attr.do_not_propagate_mask = 0;
|
||||||
attr.override_redirect = True;
|
attr.override_redirect = True;
|
||||||
attr.cursor = None;
|
attr.cursor = createBlankCursor();
|
||||||
m_window = ::XCreateWindow(m_display, root, 0, 0, m_w, m_h, 0, 0,
|
m_window = ::XCreateWindow(m_display, m_root, 0, 0, m_w, m_h, 0, 0,
|
||||||
InputOnly, CopyFromParent,
|
InputOnly, CopyFromParent,
|
||||||
CWDontPropagate | CWEventMask |
|
CWDontPropagate | CWEventMask |
|
||||||
CWOverrideRedirect | CWCursor,
|
CWOverrideRedirect | CWCursor,
|
||||||
&attr);
|
&attr);
|
||||||
|
|
||||||
// start watching for events on other windows
|
// start watching for events on other windows
|
||||||
selectEvents(root);
|
selectEvents(m_root);
|
||||||
|
|
||||||
// start processing events
|
// start processing events
|
||||||
m_eventThread = new CThread(new TMethodJob<CXWindowsPrimaryScreen>(
|
m_eventThread = new CThread(new TMethodJob<CXWindowsPrimaryScreen>(
|
||||||
|
@ -179,8 +179,7 @@ void CXWindowsPrimaryScreen::warpCursor(SInt32 x, SInt32 y)
|
||||||
{
|
{
|
||||||
|
|
||||||
// warp the mouse
|
// warp the mouse
|
||||||
Window root = RootWindow(m_display, m_screen);
|
::XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y);
|
||||||
::XWarpPointer(m_display, None, root, 0, 0, 0, 0, x, y);
|
|
||||||
::XSync(m_display, False);
|
::XSync(m_display, False);
|
||||||
log((CLOG_DEBUG "warped to %d,%d", x, y));
|
log((CLOG_DEBUG "warped to %d,%d", x, y));
|
||||||
|
|
||||||
|
@ -233,6 +232,41 @@ void CXWindowsPrimaryScreen::selectEvents(Window w) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Cursor CXWindowsPrimaryScreen::createBlankCursor()
|
||||||
|
{
|
||||||
|
// this seems just a bit more complicated than really necessary
|
||||||
|
|
||||||
|
// get the closet cursor size to 1x1
|
||||||
|
unsigned int w, h;
|
||||||
|
::XQueryBestCursor(m_display, m_root, 1, 1, &w, &h);
|
||||||
|
|
||||||
|
// make bitmap data for cursor of closet size. since the cursor
|
||||||
|
// is blank we can use the same bitmap for shape and mask: all
|
||||||
|
// zeros.
|
||||||
|
const int size = ((w + 7) >> 3) * h;
|
||||||
|
char* data = new char[size];
|
||||||
|
memset(data, 0, size);
|
||||||
|
|
||||||
|
// make bitmap
|
||||||
|
Pixmap bitmap = ::XCreateBitmapFromData(m_display, m_root, data, w, h);
|
||||||
|
|
||||||
|
// need an arbitrary color for the cursor
|
||||||
|
XColor color;
|
||||||
|
color.pixel = 0;
|
||||||
|
color.red = color.green = color.blue = 0;
|
||||||
|
color.flags = DoRed | DoGreen | DoBlue;
|
||||||
|
|
||||||
|
// make cursor from bitmap
|
||||||
|
Cursor cursor = ::XCreatePixmapCursor(m_display, bitmap, bitmap,
|
||||||
|
&color, &color, 0, 0);
|
||||||
|
|
||||||
|
// don't need bitmap or the data anymore
|
||||||
|
delete[] data;
|
||||||
|
::XFreePixmap(m_display, bitmap);
|
||||||
|
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
void CXWindowsPrimaryScreen::eventThread(void*)
|
void CXWindowsPrimaryScreen::eventThread(void*)
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ class CXWindowsPrimaryScreen : public IPrimaryScreen {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void selectEvents(Window) const;
|
void selectEvents(Window) const;
|
||||||
|
Cursor createBlankCursor();
|
||||||
|
|
||||||
void eventThread(void*);
|
void eventThread(void*);
|
||||||
KeyModifierMask mapModifier(unsigned int state) const;
|
KeyModifierMask mapModifier(unsigned int state) const;
|
||||||
|
@ -35,6 +36,7 @@ class CXWindowsPrimaryScreen : public IPrimaryScreen {
|
||||||
CThread* m_eventThread;
|
CThread* m_eventThread;
|
||||||
Display* m_display;
|
Display* m_display;
|
||||||
int m_screen;
|
int m_screen;
|
||||||
|
Window m_root;
|
||||||
SInt32 m_w, m_h;
|
SInt32 m_w, m_h;
|
||||||
Window m_window;
|
Window m_window;
|
||||||
bool m_active;
|
bool m_active;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "CClient.h"
|
#include "CClient.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "TMethodJob.h"
|
#include "TMethodJob.h"
|
||||||
|
#include "CLog.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <X11/X.h>
|
#include <X11/X.h>
|
||||||
#include <X11/extensions/XTest.h>
|
#include <X11/extensions/XTest.h>
|
||||||
|
@ -33,6 +34,7 @@ void CXWindowsSecondaryScreen::open(CClient* client)
|
||||||
m_client = client;
|
m_client = client;
|
||||||
|
|
||||||
// open the display
|
// open the display
|
||||||
|
log((CLOG_DEBUG "XOpenDisplay(%s)", "NULL"));
|
||||||
m_display = ::XOpenDisplay(NULL); // FIXME -- allow non-default
|
m_display = ::XOpenDisplay(NULL); // FIXME -- allow non-default
|
||||||
if (m_display == NULL)
|
if (m_display == NULL)
|
||||||
throw int(5); // FIXME -- make exception for this
|
throw int(5); // FIXME -- make exception for this
|
||||||
|
@ -44,6 +46,7 @@ void CXWindowsSecondaryScreen::open(CClient* client)
|
||||||
// get screen size
|
// get screen size
|
||||||
m_w = WidthOfScreen(screen);
|
m_w = WidthOfScreen(screen);
|
||||||
m_h = HeightOfScreen(screen);
|
m_h = HeightOfScreen(screen);
|
||||||
|
log((CLOG_INFO "secondary display size: %dx%d", m_w, m_h));
|
||||||
|
|
||||||
// verify the availability of the XTest extension
|
// verify the availability of the XTest extension
|
||||||
int majorOpcode, firstEvent, firstError;
|
int majorOpcode, firstEvent, firstError;
|
||||||
|
@ -51,9 +54,30 @@ void CXWindowsSecondaryScreen::open(CClient* client)
|
||||||
&majorOpcode, &firstEvent, &firstError))
|
&majorOpcode, &firstEvent, &firstError))
|
||||||
throw int(6); // FIXME -- make exception for this
|
throw int(6); // FIXME -- make exception for this
|
||||||
|
|
||||||
|
// get the root window
|
||||||
|
m_root = RootWindow(m_display, m_screen);
|
||||||
|
|
||||||
|
// create the cursor hiding window. this window is used to hide the
|
||||||
|
// cursor when it's not on the screen. the window is hidden as soon
|
||||||
|
// as the cursor enters the screen or the display's real cursor is
|
||||||
|
// moved.
|
||||||
|
XSetWindowAttributes attr;
|
||||||
|
attr.event_mask = LeaveWindowMask;
|
||||||
|
attr.do_not_propagate_mask = 0;
|
||||||
|
attr.override_redirect = True;
|
||||||
|
attr.cursor = createBlankCursor();
|
||||||
|
m_window = ::XCreateWindow(m_display, m_root, 0, 0, 1, 1, 0, 0,
|
||||||
|
InputOnly, CopyFromParent,
|
||||||
|
CWDontPropagate | CWEventMask |
|
||||||
|
CWOverrideRedirect | CWCursor,
|
||||||
|
&attr);
|
||||||
|
|
||||||
// become impervious to server grabs
|
// become impervious to server grabs
|
||||||
::XTestGrabControl(m_display, True);
|
::XTestGrabControl(m_display, True);
|
||||||
|
|
||||||
|
// hide the cursor
|
||||||
|
leave();
|
||||||
|
|
||||||
// start processing events
|
// start processing events
|
||||||
m_eventThread = new CThread(new TMethodJob<CXWindowsSecondaryScreen>(
|
m_eventThread = new CThread(new TMethodJob<CXWindowsSecondaryScreen>(
|
||||||
this, &CXWindowsSecondaryScreen::eventThread));
|
this, &CXWindowsSecondaryScreen::eventThread));
|
||||||
|
@ -73,6 +97,10 @@ void CXWindowsSecondaryScreen::close()
|
||||||
// no longer impervious to server grabs
|
// no longer impervious to server grabs
|
||||||
::XTestGrabControl(m_display, False);
|
::XTestGrabControl(m_display, False);
|
||||||
|
|
||||||
|
// destroy window
|
||||||
|
::XDestroyWindow(m_display, m_window);
|
||||||
|
m_window = None;
|
||||||
|
|
||||||
// close the display
|
// close the display
|
||||||
::XCloseDisplay(m_display);
|
::XCloseDisplay(m_display);
|
||||||
m_display = NULL;
|
m_display = NULL;
|
||||||
|
@ -81,20 +109,25 @@ void CXWindowsSecondaryScreen::close()
|
||||||
void CXWindowsSecondaryScreen::enter(SInt32 x, SInt32 y)
|
void CXWindowsSecondaryScreen::enter(SInt32 x, SInt32 y)
|
||||||
{
|
{
|
||||||
assert(m_display != NULL);
|
assert(m_display != NULL);
|
||||||
|
assert(m_window != None);
|
||||||
|
|
||||||
// warp to requested location
|
// warp to requested location
|
||||||
warpCursor(x, y);
|
warpCursor(x, y);
|
||||||
|
|
||||||
// show cursor
|
// show cursor
|
||||||
// FIXME
|
::XUnmapWindow(m_display, m_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CXWindowsSecondaryScreen::leave()
|
void CXWindowsSecondaryScreen::leave()
|
||||||
{
|
{
|
||||||
assert(m_display != NULL);
|
assert(m_display != NULL);
|
||||||
|
assert(m_window != None);
|
||||||
|
|
||||||
// hide cursor
|
// raise and show the hider window
|
||||||
// FIXME
|
::XMapRaised(m_display, m_window);
|
||||||
|
|
||||||
|
// hide cursor by moving it into the hider window
|
||||||
|
::XWarpPointer(m_display, None, m_window, 0, 0, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CXWindowsSecondaryScreen::warpCursor(SInt32 x, SInt32 y)
|
void CXWindowsSecondaryScreen::warpCursor(SInt32 x, SInt32 y)
|
||||||
|
@ -180,8 +213,46 @@ SInt32 CXWindowsSecondaryScreen::getJumpZoneSize() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Cursor CXWindowsSecondaryScreen::createBlankCursor()
|
||||||
|
{
|
||||||
|
// this seems just a bit more complicated than really necessary
|
||||||
|
|
||||||
|
// get the closet cursor size to 1x1
|
||||||
|
unsigned int w, h;
|
||||||
|
::XQueryBestCursor(m_display, m_root, 1, 1, &w, &h);
|
||||||
|
|
||||||
|
// make bitmap data for cursor of closet size. since the cursor
|
||||||
|
// is blank we can use the same bitmap for shape and mask: all
|
||||||
|
// zeros.
|
||||||
|
const int size = ((w + 7) >> 3) * h;
|
||||||
|
char* data = new char[size];
|
||||||
|
memset(data, 0, size);
|
||||||
|
|
||||||
|
// make bitmap
|
||||||
|
Pixmap bitmap = ::XCreateBitmapFromData(m_display, m_root, data, w, h);
|
||||||
|
|
||||||
|
// need an arbitrary color for the cursor
|
||||||
|
XColor color;
|
||||||
|
color.pixel = 0;
|
||||||
|
color.red = color.green = color.blue = 0;
|
||||||
|
color.flags = DoRed | DoGreen | DoBlue;
|
||||||
|
|
||||||
|
// make cursor from bitmap
|
||||||
|
Cursor cursor = ::XCreatePixmapCursor(m_display, bitmap, bitmap,
|
||||||
|
&color, &color, 0, 0);
|
||||||
|
|
||||||
|
// don't need bitmap or the data anymore
|
||||||
|
delete[] data;
|
||||||
|
::XFreePixmap(m_display, bitmap);
|
||||||
|
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
void CXWindowsSecondaryScreen::eventThread(void*)
|
void CXWindowsSecondaryScreen::eventThread(void*)
|
||||||
{
|
{
|
||||||
|
assert(m_display != NULL);
|
||||||
|
assert(m_window != None);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// wait for and then get the next event
|
// wait for and then get the next event
|
||||||
while (XPending(m_display) == 0) {
|
while (XPending(m_display) == 0) {
|
||||||
|
@ -193,8 +264,8 @@ void CXWindowsSecondaryScreen::eventThread(void*)
|
||||||
// handle event
|
// handle event
|
||||||
switch (xevent.type) {
|
switch (xevent.type) {
|
||||||
case LeaveNotify:
|
case LeaveNotify:
|
||||||
// mouse moved out of window somehow. hide the window.
|
// mouse moved out of hider window somehow. hide the window.
|
||||||
// ::XUnmapWindow(m_display, m_window);
|
::XUnmapWindow(m_display, m_window);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -28,6 +28,7 @@ class CXWindowsSecondaryScreen : public ISecondaryScreen {
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
virtual SInt32 getJumpZoneSize() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Cursor createBlankCursor();
|
||||||
void eventThread(void*);
|
void eventThread(void*);
|
||||||
KeyCode mapKey(KeyID, KeyModifierMask) const;
|
KeyCode mapKey(KeyID, KeyModifierMask) const;
|
||||||
unsigned int mapButton(ButtonID button) const;
|
unsigned int mapButton(ButtonID button) const;
|
||||||
|
@ -37,6 +38,7 @@ class CXWindowsSecondaryScreen : public ISecondaryScreen {
|
||||||
CThread* m_eventThread;
|
CThread* m_eventThread;
|
||||||
Display* m_display;
|
Display* m_display;
|
||||||
int m_screen;
|
int m_screen;
|
||||||
|
Window m_root;
|
||||||
Window m_window;
|
Window m_window;
|
||||||
SInt32 m_w, m_h;
|
SInt32 m_w, m_h;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue