@@ -107,6 +107,7 @@ GHOST_SystemX11::GHOST_SystemX11()
|
||||
: GHOST_System(),
|
||||
m_xkb_descr(nullptr),
|
||||
m_start_time(0),
|
||||
m_start_time_monotonic(0),
|
||||
m_keyboard_vector{0},
|
||||
m_keycode_last_repeat_key(uint(-1))
|
||||
{
|
||||
@@ -172,14 +173,23 @@ GHOST_SystemX11::GHOST_SystemX11()
|
||||
m_last_release_keycode = 0;
|
||||
m_last_release_time = 0;
|
||||
|
||||
/* compute the initial time */
|
||||
timeval tv;
|
||||
if (gettimeofday(&tv, nullptr) == -1) {
|
||||
GHOST_ASSERT(false, "Could not instantiate timer!");
|
||||
/* Compute the initial time. */
|
||||
{
|
||||
timeval tv;
|
||||
if (gettimeofday(&tv, nullptr) == -1) {
|
||||
GHOST_ASSERT(false, "Could not instantiate timer!");
|
||||
}
|
||||
/* Taking care not to overflow the `tv.tv_sec * 1000`. */
|
||||
m_start_time = uint64_t(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
|
||||
}
|
||||
|
||||
/* Taking care not to overflow the `tv.tv_sec * 1000`. */
|
||||
m_start_time = uint64_t(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
|
||||
{
|
||||
struct timespec ts = {0, 0};
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
|
||||
GHOST_ASSERT(false, "Could not instantiate monotonic timer!");
|
||||
}
|
||||
m_start_time_monotonic = ((uint64_t(ts.tv_sec) * 1000) + (ts.tv_nsec / 1000000));
|
||||
}
|
||||
|
||||
/* Use detectable auto-repeat, mac and windows also do this. */
|
||||
int use_xkb;
|
||||
@@ -279,6 +289,16 @@ uint64_t GHOST_SystemX11::getMilliSeconds() const
|
||||
return uint64_t(tv.tv_sec) * 1000 + tv.tv_usec / 1000 - m_start_time;
|
||||
}
|
||||
|
||||
uint64_t GHOST_SystemX11::ms_from_input_time(const Time timestamp) const
|
||||
{
|
||||
GHOST_ASSERT(timestamp >= m_start_time_monotonic, "Invalid time-stemp");
|
||||
/* NOTE(@ideasman42): Return a time compatible with `getMilliSeconds()`,
|
||||
* this is needed as X11 time-stamps use monotonic time.
|
||||
* The X11 implementation *could* use any basis, in practice though we are supporting
|
||||
* XORG/LIBINPUT which uses time-stamps based on the monotonic time. */
|
||||
return uint64_t(timestamp) - m_start_time_monotonic;
|
||||
}
|
||||
|
||||
uint8_t GHOST_SystemX11::getNumDisplays() const
|
||||
{
|
||||
return uint8_t(1);
|
||||
@@ -637,6 +657,7 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
|
||||
XPeekEvent(m_display, &xev_next);
|
||||
|
||||
if (ELEM(xev_next.type, KeyPress, KeyRelease)) {
|
||||
const uint64_t event_ms = ms_from_input_time(xev_next.xkey.time);
|
||||
/* XK_Hyper_L/R currently unused. */
|
||||
const static KeySym modifiers[] = {
|
||||
XK_Shift_L,
|
||||
@@ -652,7 +673,7 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
|
||||
for (int i = 0; i < int(ARRAY_SIZE(modifiers)); i++) {
|
||||
KeyCode kc = XKeysymToKeycode(m_display, modifiers[i]);
|
||||
if (kc != 0 && ((xevent.xkeymap.key_vector[kc >> 3] >> (kc & 7)) & 1) != 0) {
|
||||
pushEvent(new GHOST_EventKey(getMilliSeconds(),
|
||||
pushEvent(new GHOST_EventKey(event_ms,
|
||||
GHOST_kEventKeyDown,
|
||||
window,
|
||||
ghost_key_from_keysym(modifiers[i]),
|
||||
@@ -850,16 +871,19 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
const XExposeEvent &xee = xe->xexpose;
|
||||
|
||||
if (xee.count == 0) {
|
||||
/* Only generate a single expose event
|
||||
* per read of the event queue. */
|
||||
/* Only generate a single expose event per read of the event queue. */
|
||||
|
||||
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window);
|
||||
/* Event has no timestamp. */
|
||||
const uint64_t event_ms = getMilliSeconds();
|
||||
|
||||
g_event = new GHOST_Event(event_ms, GHOST_kEventWindowUpdate, window);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MotionNotify: {
|
||||
const XMotionEvent &xme = xe->xmotion;
|
||||
const uint64_t event_ms = ms_from_input_time(xme.time);
|
||||
|
||||
bool is_tablet = window->GetTabletData().Active != GHOST_kTabletModeNone;
|
||||
|
||||
@@ -932,7 +956,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
setCursorPosition(x_new, y_new); /* wrap */
|
||||
}
|
||||
else {
|
||||
g_event = new GHOST_EventCursor(getMilliSeconds(),
|
||||
g_event = new GHOST_EventCursor(event_ms,
|
||||
GHOST_kEventCursorMove,
|
||||
window,
|
||||
xme.x_root + x_accum,
|
||||
@@ -941,7 +965,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
}
|
||||
}
|
||||
else {
|
||||
g_event = new GHOST_EventCursor(getMilliSeconds(),
|
||||
g_event = new GHOST_EventCursor(event_ms,
|
||||
GHOST_kEventCursorMove,
|
||||
window,
|
||||
xme.x_root,
|
||||
@@ -954,6 +978,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
case KeyPress:
|
||||
case KeyRelease: {
|
||||
XKeyEvent *xke = &(xe->xkey);
|
||||
const uint64_t event_ms = ms_from_input_time(xke->time);
|
||||
KeySym key_sym;
|
||||
char *utf8_buf = nullptr;
|
||||
char ascii;
|
||||
@@ -1146,7 +1171,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
}
|
||||
}
|
||||
|
||||
g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, is_repeat, utf8_buf);
|
||||
g_event = new GHOST_EventKey(event_ms, type, window, gkey, is_repeat, utf8_buf);
|
||||
|
||||
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
|
||||
/* when using IM for some languages such as Japanese,
|
||||
@@ -1171,8 +1196,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
/* Enqueue previous character. */
|
||||
pushEvent(g_event);
|
||||
|
||||
g_event = new GHOST_EventKey(
|
||||
getMilliSeconds(), type, window, gkey, is_repeat, &utf8_buf[i]);
|
||||
g_event = new GHOST_EventKey(event_ms, type, window, gkey, is_repeat, &utf8_buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1187,6 +1211,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
case ButtonPress:
|
||||
case ButtonRelease: {
|
||||
const XButtonEvent &xbe = xe->xbutton;
|
||||
const uint64_t event_ms = ms_from_input_time(xbe.time);
|
||||
GHOST_TButton gbmask = GHOST_kButtonMaskLeft;
|
||||
GHOST_TEventType type = (xbe.type == ButtonPress) ? GHOST_kEventButtonDown :
|
||||
GHOST_kEventButtonUp;
|
||||
@@ -1194,13 +1219,13 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
/* process wheel mouse events and break, only pass on press events */
|
||||
if (xbe.button == Button4) {
|
||||
if (xbe.type == ButtonPress) {
|
||||
g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1);
|
||||
g_event = new GHOST_EventWheel(event_ms, window, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (xbe.button == Button5) {
|
||||
if (xbe.type == ButtonPress) {
|
||||
g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
|
||||
g_event = new GHOST_EventWheel(event_ms, window, -1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1234,15 +1259,17 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
break;
|
||||
}
|
||||
|
||||
g_event = new GHOST_EventButton(
|
||||
getMilliSeconds(), type, window, gbmask, window->GetTabletData());
|
||||
g_event = new GHOST_EventButton(event_ms, type, window, gbmask, window->GetTabletData());
|
||||
break;
|
||||
}
|
||||
|
||||
/* change of size, border, layer etc. */
|
||||
case ConfigureNotify: {
|
||||
// const XConfigureEvent & xce = xe->xconfigure;
|
||||
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window);
|
||||
/* Event has no timestamp. */
|
||||
const uint64_t event_ms = getMilliSeconds();
|
||||
|
||||
g_event = new GHOST_Event(event_ms, GHOST_kEventWindowSize, window);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1338,8 +1365,9 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
* also send grab/un-grab crossings for mouse-wheel events.
|
||||
*/
|
||||
const XCrossingEvent &xce = xe->xcrossing;
|
||||
const uint64_t event_ms = ms_from_input_time(xce.time);
|
||||
if (xce.mode == NotifyNormal) {
|
||||
g_event = new GHOST_EventCursor(getMilliSeconds(),
|
||||
g_event = new GHOST_EventCursor(event_ms,
|
||||
GHOST_kEventCursorMove,
|
||||
window,
|
||||
xce.x_root,
|
||||
@@ -2538,8 +2566,12 @@ GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
|
||||
void *data)
|
||||
{
|
||||
GHOST_SystemX11 *system = ((GHOST_SystemX11 *)getSystem());
|
||||
|
||||
/* Caller has no timestamp. */
|
||||
const uint64_t event_ms = system->getMilliSeconds();
|
||||
|
||||
return system->pushEvent(new GHOST_EventDragnDrop(
|
||||
system->getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, data));
|
||||
event_ms, eventType, draggedObjectType, window, mouseX, mouseY, data));
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
|
||||
@@ -200,6 +200,13 @@ class GHOST_SystemX11 : public GHOST_System {
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Use this function instead of #GHOST_System::getMilliSeconds,
|
||||
* passing in the time-stamp from X to input to get the event
|
||||
* time-stamp with an offset applied to make it compatible with `getMilliSeconds`.
|
||||
*/
|
||||
uint64_t ms_from_input_time(const Time timestamp_as_uint) const;
|
||||
|
||||
/** Helped function for get data from the clipboard. */
|
||||
void getClipboard_xcout(const XEvent *evt,
|
||||
Atom sel,
|
||||
@@ -343,6 +350,8 @@ class GHOST_SystemX11 : public GHOST_System {
|
||||
|
||||
/** Start time at initialization. */
|
||||
uint64_t m_start_time;
|
||||
/** Start time at initialization (using `CLOCK_MONOTONIC`). */
|
||||
uint64_t m_start_time_monotonic;
|
||||
|
||||
/** A vector of keyboard key masks. */
|
||||
char m_keyboard_vector[32];
|
||||
|
||||
Reference in New Issue
Block a user