Skip to content

Commit

Permalink
scroll on linux (closes HumbleUI#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex2772 committed Jul 29, 2021
1 parent ce05cea commit 2f970a9
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
with:
fetch-depth: 0
- uses: seanmiddleditch/gha-setup-ninja@master
- run: sudo apt-get install libxcomposite-dev libxrandr-dev libgl1-mesa-dev
- run: sudo apt-get install libxcomposite-dev libxrandr-dev libgl1-mesa-dev libxi-dev
- run: python3 script/deploy_native.py --arch=x64
env:
SPACE_TOKEN: ${{ secrets.SPACE_TOKEN }}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ x64 Native Tools Command Prompt for VS
libxcomposite-dev
libxrandr-dev
libgl1-mesa-dev
libxi-dev

Build:

Expand Down
2 changes: 1 addition & 1 deletion linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ target_include_directories(jwm PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../shared/cc ${
set_target_properties(jwm PROPERTIES OUTPUT_NAME "jwm_${JWM_ARCH}")


target_link_libraries(jwm PRIVATE X11::X11 X11::Xrandr)
target_link_libraries(jwm PRIVATE X11::X11 X11::Xrandr X11::Xi)
target_link_libraries(jwm PRIVATE OpenGL::GL)
133 changes: 133 additions & 0 deletions linux/cc/WindowManagerX11.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <impl/JNILocal.hh>
#include "AppX11.hh"
#include <X11/extensions/sync.h>
#include <X11/extensions/XInput2.h>
#include "KeyX11.hh"
#include "MouseButtonX11.hh"

Expand Down Expand Up @@ -119,6 +120,46 @@ WindowManagerX11::WindowManagerX11():
x11SWA.override_redirect = true;
}

// XInput2
{
int opcode, firstevent, firsterror;
if (XQueryExtension(display, "XInputExtension", &opcode, &firstevent, &firsterror)) {
int major = 2, minor = 3;
if (XIQueryVersion(display, &major, &minor) != BadRequest) {
_xi2 = std::make_unique<XInput2>(XInput2{ opcode });
_xi2IterateDevices();
}
}
}
}

void WindowManagerX11::_xi2IterateDevices() {
int deviceCount;
XIDeviceInfo* devices = XIQueryDevice(display, XIAllDevices, &deviceCount);
for (int deviceId = 0; deviceId < deviceCount; ++deviceId) {
XIDeviceInfo& device = devices[deviceId];
if (device.use != XIMasterPointer) {
continue;
}
XInput2::Device& myDevice = _xi2->deviceById[device.deviceid];
for (int classId = 0; classId < device.num_classes; ++classId) {
XIAnyClassInfo* classInfo = device.classes[classId];

switch (classInfo->type)
{
case XIScrollClass: {
XIScrollClassInfo* scroll = reinterpret_cast<XIScrollClassInfo*>(classInfo);
myDevice.scroll.push_back(XInput2::Device::ScrollValuator{
scroll->scroll_type == XIScrollTypeHorizontal,
scroll->number,
scroll->increment
});
break;
}
}
}
}
XIFreeDeviceInfo(devices);
}

::Window WindowManagerX11::getRootWindow() const {
Expand All @@ -138,11 +179,90 @@ void WindowManagerX11::runLoop() {
myWindow = it->second;
}
if (myWindow == nullptr) {
// probably an XI2 event
if (ev.type == GenericEvent && _xi2 && _xi2->opcode == ev.xcookie.extension) {
if (XGetEventData(display, &ev.xcookie)) {
XIEvent* xiEvent = reinterpret_cast<XIEvent*>(ev.xcookie.data);
switch (xiEvent->evtype) {
case XI_DeviceChanged:
_xi2->deviceById.clear();
_xi2IterateDevices();
break;

case XI_Motion: {
XIDeviceEvent* deviceEvent = reinterpret_cast<XIDeviceEvent*>(xiEvent);

it = _nativeWindowToMy.find(deviceEvent->event);

if (it != _nativeWindowToMy.end()) {
myWindow = it->second;
} else {
break;
}

if (myWindow->_layer) {
myWindow->_layer->makeCurrent();
}

auto itMyDevice = _xi2->deviceById.find(deviceEvent->deviceid);
if (itMyDevice == _xi2->deviceById.end()) {
break;
}

XInput2::Device& myDevice = itMyDevice->second;
double dX = 0, dY = 0;
for (int i = 0, valuatorIndex = 0; i < deviceEvent->valuators.mask_len * 8; ++i) {
if (!XIMaskIsSet(deviceEvent->valuators.mask, i)) {
continue;
}

for (auto& valuator : myDevice.scroll) {
if (valuator.number == i) {
double value = reinterpret_cast<double*>(deviceEvent->valuators.values)[valuatorIndex];
if (valuator.previousValue == 0) {
valuator.previousValue = value;
value = 0;
} else {
double delta = value - valuator.previousValue;
valuator.previousValue = value;
value = delta;
}
if (valuator.isHorizontal) {
dX = value;
} else {
dY = value;
}
break;
}
}
++valuatorIndex;
}

if (dX != 0 || dY != 0) {
jwm::JNILocal<jobject> eventScroll(
app.getJniEnv(),
EventScroll::make(
app.getJniEnv(),
-dX,
-dY,
jwm::KeyX11::getModifiers()
)
);
myWindow->dispatch(eventScroll.get());
}

break;
}
}
XFreeEventData(display, &ev.xcookie);
}
}
continue;
}
if (myWindow->_layer) {
myWindow->_layer->makeCurrent();
}

switch (ev.type) {
case ClientMessage: {
if (ev.xclient.message_type == _atoms.WM_PROTOCOLS) {
Expand Down Expand Up @@ -322,6 +442,19 @@ void WindowManagerX11::runLoop() {

void WindowManagerX11::registerWindow(WindowX11* window) {
_nativeWindowToMy[window->_x11Window] = window;

// XInput
if (_xi2) {
XIEventMask eventMask;
unsigned char mask[2] = { 0 };
XISetMask(mask, XI_DeviceChanged);
XISetMask(mask, XI_Motion);
eventMask.deviceid = XIAllDevices;
eventMask.mask_len = sizeof(mask);
eventMask.mask = mask;

XISelectEvents(display, window->_x11Window, &eventMask, 1);
}
}

void WindowManagerX11::unregisterWindow(WindowX11* window) {
Expand Down
20 changes: 20 additions & 0 deletions linux/cc/WindowManagerX11.hh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <X11/Xlib.h>
#include <GL/glx.h>
#include <map>
#include <memory>
#include <vector>

namespace jwm {
class WindowX11;
Expand All @@ -19,6 +21,7 @@ namespace jwm {

XVisualInfo* pickVisual();
static int _xerrorhandler(Display* dsp, XErrorEvent* error);
void _xi2IterateDevices();

Display* getDisplay() const { return display; }
::Window getRootWindow() const;
Expand All @@ -40,6 +43,23 @@ namespace jwm {
*/
XIM _im;

struct XInput2 {
int opcode;

struct Device {
struct ScrollValuator {
bool isHorizontal;
int number;
double increment;
double previousValue = 0;
};
std::vector<ScrollValuator> scroll;
};
std::map<int, Device> deviceById;
};

std::unique_ptr<XInput2> _xi2;

struct Atoms {
Atoms(Display* display): _display(display) {}

Expand Down
2 changes: 1 addition & 1 deletion linux/cc/WindowX11.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ bool WindowX11::init()
CWColormap | CWEventMask | CWCursor,
&_windowManager.getSWA()
);
_windowManager.registerWindow(this);
XSetWMProtocols(_windowManager.getDisplay(),
_x11Window,
&_windowManager.getAtoms().WM_DELETE_WINDOW,
Expand Down Expand Up @@ -115,6 +114,7 @@ bool WindowX11::init()
(const unsigned char*)&_xsyncRequestCounter.counter, 1);

}
_windowManager.registerWindow(this);
return true;
}

Expand Down

0 comments on commit 2f970a9

Please sign in to comment.