Skip to content
This repository has been archived by the owner on Jul 18, 2024. It is now read-only.

Xorg input driver #53

Merged
merged 20 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 26 additions & 20 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
#
# Stage 0: Build xserver-xorg-video-dummy 0.3.8-2 with RandR support.
# Stage 0: Build xorg dependencies.
#
FROM debian:bullseye-slim as xserver-xorg-video-dummy

WORKDIR /usr/local/src
FROM debian:bullseye-slim as xorg-deps

ENV DEBIAN_FRONTEND=noninteractive

RUN set -eux; \
cp /etc/apt/sources.list /etc/apt/sources.list~; \
sed -Ei 's/^deb /deb-src /' /etc/apt/sources.list; \
cat /etc/apt/sources.list~ >> /etc/apt/sources.list; \
apt-get update; \
apt-get install -y dpkg-dev git; \
apt-get build-dep -y xserver-xorg-video-dummy; \
git clone --depth 1 --branch xserver-xorg-video-dummy-1_0.3.8-2 https://salsa.debian.org/xorg-team/driver/xserver-xorg-video-dummy; \
#
# clean up
apt-get clean -y; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
apt-get install -y \
git gcc pkgconf autoconf automake libtool make xorg-dev xutils-dev \
&& rm -rf /var/lib/apt/lists/*;

WORKDIR /xorg

COPY runtime/xdummy-randr.patch /tmp/xdummy-randr.patch
COPY xorg/ /xorg/

# build xserver-xorg-video-dummy 0.3.8-2 with RandR support.
RUN set -eux; \
cd xf86-video-dummy; \
git clone --depth 1 --branch xserver-xorg-video-dummy-1_0.3.8-2 https://salsa.debian.org/xorg-team/driver/xserver-xorg-video-dummy; \
cd xserver-xorg-video-dummy; \
patch -p1 < /tmp/xdummy-randr.patch; \
bash ./autogen.sh; \
make; \
patch -p1 < ../xdummy-randr.patch; \
./autogen.sh; \
make -j$(nproc); \
make install;

# build custom input driver
RUN set -eux; \
cd xf86-input-neko; \
./autogen.sh --prefix=/usr; \
./configure; \
make -j$(nproc); \
make install;

#
Expand Down Expand Up @@ -129,8 +134,9 @@ RUN set -eux; \
apt-get clean -y; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*

# replace version
COPY --from=xserver-xorg-video-dummy /usr/local/lib/xorg/modules/drivers/dummy_drv.so /usr/lib/xorg/modules/drivers/dummy_drv.so
# copy dependencies from previous stage
COPY --from=xorg-deps /usr/local/lib/xorg/modules/drivers/dummy_drv.so /usr/lib/xorg/modules/drivers/dummy_drv.so
COPY --from=xorg-deps /usr/local/lib/xorg/modules/input/neko_drv.so /usr/lib/xorg/modules/input/neko_drv.so

#
# copy runtime configs
Expand Down
46 changes: 26 additions & 20 deletions Dockerfile.nvidia
Original file line number Diff line number Diff line change
Expand Up @@ -52,33 +52,38 @@ RUN set -eux; \
meson install -C build;

#
# Stage 0: Build xserver-xorg-video-dummy 0.3.8-2 with RandR support.
# Stage 0: Build xorg dependencies.
#
FROM debian:bullseye-slim as xserver-xorg-video-dummy

WORKDIR /usr/local/src
FROM debian:bullseye-slim as xorg-deps

ENV DEBIAN_FRONTEND=noninteractive

RUN set -eux; \
cp /etc/apt/sources.list /etc/apt/sources.list~; \
sed -Ei 's/^deb /deb-src /' /etc/apt/sources.list; \
cat /etc/apt/sources.list~ >> /etc/apt/sources.list; \
apt-get update; \
apt-get install -y dpkg-dev git; \
apt-get build-dep -y xserver-xorg-video-dummy; \
git clone --depth 1 --branch xserver-xorg-video-dummy-1_0.3.8-2 https://salsa.debian.org/xorg-team/driver/xserver-xorg-video-dummy; \
#
# clean up
apt-get clean -y; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
apt-get install -y \
git gcc pkgconf autoconf automake libtool make xorg-dev xutils-dev \
&& rm -rf /var/lib/apt/lists/*;

WORKDIR /xorg

COPY runtime/xdummy-randr.patch /tmp/xdummy-randr.patch
COPY xorg/ /xorg/

# build xserver-xorg-video-dummy 0.3.8-2 with RandR support.
RUN set -eux; \
cd xf86-video-dummy; \
git clone --depth 1 --branch xserver-xorg-video-dummy-1_0.3.8-2 https://salsa.debian.org/xorg-team/driver/xserver-xorg-video-dummy; \
cd xserver-xorg-video-dummy; \
patch -p1 < /tmp/xdummy-randr.patch; \
bash ./autogen.sh; \
make; \
patch -p1 < ../xdummy-randr.patch; \
./autogen.sh; \
make -j$(nproc); \
make install;

# build custom input driver
RUN set -eux; \
cd xf86-input-neko; \
./autogen.sh --prefix=/usr; \
./configure; \
make -j$(nproc); \
make install;

#
Expand Down Expand Up @@ -236,8 +241,9 @@ RUN set -eux; \
apt-get clean -y; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*

# replace version
COPY --from=xserver-xorg-video-dummy /usr/local/lib/xorg/modules/drivers/dummy_drv.so /usr/lib/xorg/modules/drivers/dummy_drv.so
# copy dependencies from previous stage
COPY --from=xorg-deps /usr/local/lib/xorg/modules/drivers/dummy_drv.so /usr/lib/xorg/modules/drivers/dummy_drv.so
COPY --from=xorg-deps /usr/local/lib/xorg/modules/input/neko_drv.so /usr/lib/xorg/modules/input/neko_drv.so

#
# configure EGL and Vulkan manually
Expand Down
32 changes: 32 additions & 0 deletions dev/rebuild.input
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/bash
cd "$(dirname "$0")"
cd ../xorg/xf86-input-neko

#
# aborting if any command returns a non-zero value
set -e

#
# check if docker image exists
if [ -z "$(docker images -q xf86-input-neko)" ]; then
echo "Docker image not found, building it"
docker build -t xf86-input-neko .
fi

#
# if there is no ./configure script, run autogen.sh and configure
if [ ! -f ./configure ]; then
docker run -v $PWD/:/app --rm xf86-input-neko bash -c './autogen.sh && ./configure'
fi

#
# make install
docker run -v $PWD/:/app --rm xf86-input-neko bash -c 'make && make install DESTDIR=/app/build'

#
# replace input driver in container
docker cp "${PWD}/build/usr/local/lib/xorg/modules/input/neko_drv.so" neko_server_dev:/usr/lib/xorg/modules/input/neko_drv.so

#
# restart server
docker exec neko_server_dev supervisorctl -c /etc/neko/supervisord.conf restart x-server
41 changes: 29 additions & 12 deletions internal/config/desktop.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@ import (

"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/demodesk/neko/pkg/types"
)

type Desktop struct {
Display string

Unminimize bool
ScreenSize types.ScreenSize

ScreenWidth int
ScreenHeight int
ScreenRate int16
UseInputDriver bool
InputSocket string

Unminimize bool
}

func (Desktop) Init(cmd *cobra.Command) error {
Expand All @@ -25,6 +28,16 @@ func (Desktop) Init(cmd *cobra.Command) error {
return err
}

cmd.PersistentFlags().Bool("desktop.input.enabled", true, "whether custom xf86 input driver should be used to handle touchscreen")
if err := viper.BindPFlag("desktop.input.enabled", cmd.PersistentFlags().Lookup("desktop.input.enabled")); err != nil {
return err
}

cmd.PersistentFlags().String("desktop.input.socket", "/tmp/xf86-input-neko.sock", "socket path for custom xf86 input driver connection")
if err := viper.BindPFlag("desktop.input.socket", cmd.PersistentFlags().Lookup("desktop.input.socket")); err != nil {
return err
}

cmd.PersistentFlags().Bool("desktop.unminimize", true, "automatically unminimize window when it is minimized")
if err := viper.BindPFlag("desktop.unminimize", cmd.PersistentFlags().Lookup("desktop.unminimize")); err != nil {
return err
Expand All @@ -37,11 +50,11 @@ func (s *Desktop) Set() {
// Display is provided by env variable
s.Display = os.Getenv("DISPLAY")

s.Unminimize = viper.GetBool("desktop.unminimize")

s.ScreenWidth = 1280
s.ScreenHeight = 720
s.ScreenRate = 30
s.ScreenSize = types.ScreenSize{
Width: 1280,
Height: 720,
Rate: 30,
}

r := regexp.MustCompile(`([0-9]{1,4})x([0-9]{1,4})@([0-9]{1,3})`)
res := r.FindStringSubmatch(viper.GetString("desktop.screen"))
Expand All @@ -52,9 +65,13 @@ func (s *Desktop) Set() {
rate, err3 := strconv.ParseInt(res[3], 10, 64)

if err1 == nil && err2 == nil && err3 == nil {
s.ScreenWidth = int(width)
s.ScreenHeight = int(height)
s.ScreenRate = int16(rate)
s.ScreenSize.Width = int(width)
s.ScreenSize.Height = int(height)
s.ScreenSize.Rate = int16(rate)
}
}

s.UseInputDriver = viper.GetBool("desktop.input.enabled")
s.InputSocket = viper.GetString("desktop.input.socket")
s.Unminimize = viper.GetBool("desktop.unminimize")
}
59 changes: 44 additions & 15 deletions internal/desktop/manager.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package desktop

import (
"fmt"
"sync"
"time"

Expand All @@ -10,26 +9,39 @@ import (
"github.com/rs/zerolog/log"

"github.com/demodesk/neko/internal/config"
"github.com/demodesk/neko/pkg/types"
"github.com/demodesk/neko/pkg/xevent"
"github.com/demodesk/neko/pkg/xinput"
"github.com/demodesk/neko/pkg/xorg"
)

var mu = sync.Mutex{}

type DesktopManagerCtx struct {
logger zerolog.Logger
wg sync.WaitGroup
shutdown chan struct{}
emmiter events.EventEmmiter
config *config.Desktop
logger zerolog.Logger
wg sync.WaitGroup
shutdown chan struct{}
emmiter events.EventEmmiter
config *config.Desktop
screenSize types.ScreenSize // cached screen size
input xinput.Driver
}

func New(config *config.Desktop) *DesktopManagerCtx {
var input xinput.Driver
if config.UseInputDriver {
input = xinput.NewDriver(config.InputSocket)
} else {
input = xinput.NewDummy()
}

return &DesktopManagerCtx{
logger: log.With().Str("module", "desktop").Logger(),
shutdown: make(chan struct{}),
emmiter: events.New(),
config: config,
logger: log.With().Str("module", "desktop").Logger(),
shutdown: make(chan struct{}),
emmiter: events.New(),
config: config,
screenSize: config.ScreenSize,
input: input,
}
}

Expand All @@ -40,10 +52,24 @@ func (manager *DesktopManagerCtx) Start() {

xorg.GetScreenConfigurations()

width, height, rate, err := xorg.ChangeScreenSize(manager.config.ScreenWidth, manager.config.ScreenHeight, manager.config.ScreenRate)
manager.logger.Err(err).
Str("screen_size", fmt.Sprintf("%dx%d@%d", width, height, rate)).
Msgf("setting initial screen size")
screenSize, err := xorg.ChangeScreenSize(manager.config.ScreenSize)
if err != nil {
manager.logger.Err(err).
Str("screen_size", screenSize.String()).
Msgf("unable to set initial screen size")
} else {
// cache screen size
manager.screenSize = screenSize
manager.logger.Info().
Str("screen_size", screenSize.String()).
Msgf("setting initial screen size")
}

err = manager.input.Connect()
if err != nil {
// TODO: fail silently to dummy driver?
manager.logger.Panic().Err(err).Msg("unable to connect to input driver")
}

xevent.Unminimize = manager.config.Unminimize
go xevent.EventLoop(manager.config.Display)
Expand All @@ -68,12 +94,15 @@ func (manager *DesktopManagerCtx) Start() {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()

const debounceDuration = 10 * time.Second

for {
select {
case <-manager.shutdown:
return
case <-ticker.C:
xorg.CheckKeys(time.Second * 10)
xorg.CheckKeys(debounceDuration)
manager.input.Debounce(debounceDuration)
}
}
}()
Expand Down
36 changes: 36 additions & 0 deletions internal/desktop/xinput.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package desktop

import "github.com/demodesk/neko/pkg/xinput"

func (manager *DesktopManagerCtx) inputRelToAbs(x, y int) (int, int) {
return (x * xinput.AbsX) / manager.screenSize.Width, (y * xinput.AbsY) / manager.screenSize.Height
}

func (manager *DesktopManagerCtx) HasTouchSupport() bool {
// we assume now, that if the input driver is enabled, we have touch support
return manager.config.UseInputDriver
}

func (manager *DesktopManagerCtx) TouchBegin(touchId uint32, x, y int, pressure uint8) error {
mu.Lock()
defer mu.Unlock()

x, y = manager.inputRelToAbs(x, y)
return manager.input.TouchBegin(touchId, x, y, pressure)
}

func (manager *DesktopManagerCtx) TouchUpdate(touchId uint32, x, y int, pressure uint8) error {
mu.Lock()
defer mu.Unlock()

x, y = manager.inputRelToAbs(x, y)
return manager.input.TouchUpdate(touchId, x, y, pressure)
}

func (manager *DesktopManagerCtx) TouchEnd(touchId uint32, x, y int, pressure uint8) error {
mu.Lock()
defer mu.Unlock()

x, y = manager.inputRelToAbs(x, y)
return manager.input.TouchEnd(touchId, x, y, pressure)
}
Loading
Loading