mirror of
https://github.com/m1k1o/neko.git
synced 2024-07-24 14:40:50 +12:00
Custom sizes with XRandR (#25)
* xserver dummy with RandR. * update. * remove screen configurations from xorg. * screen size cannot be nil anymore. * use predefined screen configurations. * use screen configurations. * fix error. * remove comment.
This commit is contained in:
parent
bfabee12e2
commit
f8b128e1e9
41
Dockerfile
41
Dockerfile
@ -1,3 +1,33 @@
|
|||||||
|
#
|
||||||
|
# Stage 0: Build xserver-xorg-video-dummy 0.3.8-2 with RandR support.
|
||||||
|
#
|
||||||
|
FROM debian:bullseye-slim as xserver-xorg-video-dummy
|
||||||
|
|
||||||
|
WORKDIR /usr/local/src
|
||||||
|
|
||||||
|
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/*
|
||||||
|
|
||||||
|
COPY runtime/xdummy-randr.patch /tmp/xdummy-randr.patch
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
cd xserver-xorg-video-dummy; \
|
||||||
|
patch -p1 < /tmp/xdummy-randr.patch; \
|
||||||
|
bash ./autogen.sh; \
|
||||||
|
make; \
|
||||||
|
make install;
|
||||||
|
|
||||||
#
|
#
|
||||||
# Stage 1: Build.
|
# Stage 1: Build.
|
||||||
#
|
#
|
||||||
@ -12,6 +42,10 @@ RUN set -eux; \
|
|||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
libx11-dev libxrandr-dev libxtst-dev libgtk-3-dev \
|
libx11-dev libxrandr-dev libxtst-dev libgtk-3-dev \
|
||||||
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev; \
|
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev; \
|
||||||
|
# install libxcvt-dev (not available in debian:bullseye)
|
||||||
|
wget http://ftp.de.debian.org/debian/pool/main/libx/libxcvt/libxcvt-dev_0.1.2-1_amd64.deb; \
|
||||||
|
wget http://ftp.de.debian.org/debian/pool/main/libx/libxcvt/libxcvt0_0.1.2-1_amd64.deb; \
|
||||||
|
apt-get install --no-install-recommends ./libxcvt0_0.1.2-1_amd64.deb ./libxcvt-dev_0.1.2-1_amd64.deb; \
|
||||||
#
|
#
|
||||||
# clean up
|
# clean up
|
||||||
apt-get clean -y; \
|
apt-get clean -y; \
|
||||||
@ -57,6 +91,10 @@ RUN set -eux; \
|
|||||||
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
|
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
|
||||||
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
|
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
|
||||||
gstreamer1.0-pulseaudio; \
|
gstreamer1.0-pulseaudio; \
|
||||||
|
# install libxcvt0 (not available in debian:bullseye)
|
||||||
|
wget http://ftp.de.debian.org/debian/pool/main/libx/libxcvt/libxcvt0_0.1.2-1_amd64.deb; \
|
||||||
|
apt-get install --no-install-recommends ./libxcvt0_0.1.2-1_amd64.deb; \
|
||||||
|
rm ./libxcvt0_0.1.2-1_amd64.deb; \
|
||||||
#
|
#
|
||||||
# create a non-root user
|
# create a non-root user
|
||||||
groupadd --gid $USER_GID $USERNAME; \
|
groupadd --gid $USER_GID $USERNAME; \
|
||||||
@ -95,6 +133,9 @@ RUN set -eux; \
|
|||||||
apt-get clean -y; \
|
apt-get clean -y; \
|
||||||
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
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 runtime configs
|
# copy runtime configs
|
||||||
COPY --chown=neko:neko runtime/.Xresources /home/$USERNAME/.Xresources
|
COPY --chown=neko:neko runtime/.Xresources /home/$USERNAME/.Xresources
|
||||||
|
@ -1,6 +1,36 @@
|
|||||||
ARG UBUNTU_RELEASE=20.04
|
ARG UBUNTU_RELEASE=20.04
|
||||||
ARG CUDA_VERSION=11.2.2
|
ARG CUDA_VERSION=11.2.2
|
||||||
|
|
||||||
|
#
|
||||||
|
# Stage 0: Build xserver-xorg-video-dummy 0.3.8-2 with RandR support.
|
||||||
|
#
|
||||||
|
FROM debian:bullseye-slim as xserver-xorg-video-dummy
|
||||||
|
|
||||||
|
WORKDIR /usr/local/src
|
||||||
|
|
||||||
|
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/*
|
||||||
|
|
||||||
|
COPY runtime/xdummy-randr.patch /tmp/xdummy-randr.patch
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
cd xserver-xorg-video-dummy; \
|
||||||
|
patch -p1 < /tmp/xdummy-randr.patch; \
|
||||||
|
bash ./autogen.sh; \
|
||||||
|
make; \
|
||||||
|
make install;
|
||||||
|
|
||||||
#
|
#
|
||||||
# Stage 1: Build.
|
# Stage 1: Build.
|
||||||
#
|
#
|
||||||
@ -15,6 +45,10 @@ RUN set -eux; \
|
|||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
libx11-dev libxrandr-dev libxtst-dev libgtk-3-dev \
|
libx11-dev libxrandr-dev libxtst-dev libgtk-3-dev \
|
||||||
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev; \
|
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev; \
|
||||||
|
# install libxcvt-dev (not available in debian:bullseye)
|
||||||
|
wget http://ftp.de.debian.org/debian/pool/main/libx/libxcvt/libxcvt-dev_0.1.2-1_amd64.deb; \
|
||||||
|
wget http://ftp.de.debian.org/debian/pool/main/libx/libxcvt/libxcvt0_0.1.2-1_amd64.deb; \
|
||||||
|
apt-get install --no-install-recommends ./libxcvt0_0.1.2-1_amd64.deb ./libxcvt-dev_0.1.2-1_amd64.deb; \
|
||||||
#
|
#
|
||||||
# clean up
|
# clean up
|
||||||
apt-get clean -y; \
|
apt-get clean -y; \
|
||||||
@ -73,6 +107,10 @@ RUN set -eux; \
|
|||||||
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
|
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
|
||||||
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
|
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
|
||||||
gstreamer1.0-pulseaudio; \
|
gstreamer1.0-pulseaudio; \
|
||||||
|
# install libxcvt0 (not available in debian:bullseye)
|
||||||
|
wget http://ftp.de.debian.org/debian/pool/main/libx/libxcvt/libxcvt0_0.1.2-1_amd64.deb; \
|
||||||
|
apt-get install --no-install-recommends ./libxcvt0_0.1.2-1_amd64.deb; \
|
||||||
|
rm ./libxcvt0_0.1.2-1_amd64.deb; \
|
||||||
#
|
#
|
||||||
# create a non-root user
|
# create a non-root user
|
||||||
groupadd --gid $USER_GID $USERNAME; \
|
groupadd --gid $USER_GID $USERNAME; \
|
||||||
@ -111,6 +149,9 @@ RUN set -eux; \
|
|||||||
apt-get clean -y; \
|
apt-get clean -y; \
|
||||||
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
|
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
|
||||||
|
|
||||||
#
|
#
|
||||||
# Install and configure Vulkan manually
|
# Install and configure Vulkan manually
|
||||||
RUN if [ "${UBUNTU_RELEASE}" = "18.04" ]; then apt-get update && apt-get install --no-install-recommends -y vulkan-utils; else apt-get update && apt-get install --no-install-recommends -y vulkan-tools; fi && \
|
RUN if [ "${UBUNTU_RELEASE}" = "18.04" ]; then apt-get update && apt-get install --no-install-recommends -y vulkan-utils; else apt-get update && apt-get install --no-install-recommends -y vulkan-tools; fi && \
|
||||||
|
@ -20,12 +20,11 @@ type ScreenConfigurationPayload struct {
|
|||||||
func (h *RoomHandler) screenConfiguration(w http.ResponseWriter, r *http.Request) error {
|
func (h *RoomHandler) screenConfiguration(w http.ResponseWriter, r *http.Request) error {
|
||||||
size := h.desktop.GetScreenSize()
|
size := h.desktop.GetScreenSize()
|
||||||
|
|
||||||
if size == nil {
|
return utils.HttpSuccess(w, ScreenConfigurationPayload{
|
||||||
return utils.HttpInternalServerError().WithInternalMsg("unable to get screen configuration")
|
Width: size.Width,
|
||||||
}
|
Height: size.Height,
|
||||||
|
Rate: size.Rate,
|
||||||
payload := ScreenConfigurationPayload(*size)
|
})
|
||||||
return utils.HttpSuccess(w, payload)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *RoomHandler) screenConfigurationChange(w http.ResponseWriter, r *http.Request) error {
|
func (h *RoomHandler) screenConfigurationChange(w http.ResponseWriter, r *http.Request) error {
|
||||||
@ -34,30 +33,37 @@ func (h *RoomHandler) screenConfigurationChange(w http.ResponseWriter, r *http.R
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
size := types.ScreenSize(*data)
|
size, err := h.desktop.SetScreenSize(types.ScreenSize{
|
||||||
if err := h.desktop.SetScreenSize(size); err != nil {
|
Width: data.Width,
|
||||||
|
Height: data.Height,
|
||||||
|
Rate: data.Rate,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
return utils.HttpUnprocessableEntity("cannot set screen size").WithInternalErr(err)
|
return utils.HttpUnprocessableEntity("cannot set screen size").WithInternalErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
payload := message.ScreenSize(*data)
|
h.sessions.Broadcast(event.SCREEN_UPDATED, message.ScreenSize{
|
||||||
h.sessions.Broadcast(event.SCREEN_UPDATED, payload)
|
Width: size.Width,
|
||||||
|
Height: size.Height,
|
||||||
|
Rate: size.Rate,
|
||||||
|
})
|
||||||
|
|
||||||
return utils.HttpSuccess(w, data)
|
return utils.HttpSuccess(w, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove.
|
||||||
func (h *RoomHandler) screenConfigurationsList(w http.ResponseWriter, r *http.Request) error {
|
func (h *RoomHandler) screenConfigurationsList(w http.ResponseWriter, r *http.Request) error {
|
||||||
list := []ScreenConfigurationPayload{}
|
configurations := h.desktop.ScreenConfigurations()
|
||||||
|
|
||||||
ScreenConfigurations := h.desktop.ScreenConfigurations()
|
list := make([]ScreenConfigurationPayload, 0, len(configurations))
|
||||||
for _, size := range ScreenConfigurations {
|
for _, conf := range configurations {
|
||||||
for _, fps := range size.Rates {
|
|
||||||
list = append(list, ScreenConfigurationPayload{
|
list = append(list, ScreenConfigurationPayload{
|
||||||
Width: size.Width,
|
Width: conf.Width,
|
||||||
Height: size.Height,
|
Height: conf.Height,
|
||||||
Rate: fps,
|
Rate: conf.Rate,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return utils.HttpSuccess(w, list)
|
return utils.HttpSuccess(w, list)
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ func New(desktop types.DesktopManager, config *config.Capture) *CaptureManagerCt
|
|||||||
}
|
}
|
||||||
|
|
||||||
screen := desktop.GetScreenSize()
|
screen := desktop.GetScreenSize()
|
||||||
pipeline, err := pipelineConf.GetPipeline(*screen)
|
pipeline, err := pipelineConf.GetPipeline(screen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -40,9 +40,9 @@ func (manager *DesktopManagerCtx) Start() {
|
|||||||
|
|
||||||
xorg.GetScreenConfigurations()
|
xorg.GetScreenConfigurations()
|
||||||
|
|
||||||
err := xorg.ChangeScreenSize(manager.config.ScreenWidth, manager.config.ScreenHeight, manager.config.ScreenRate)
|
width, height, rate, err := xorg.ChangeScreenSize(manager.config.ScreenWidth, manager.config.ScreenHeight, manager.config.ScreenRate)
|
||||||
manager.logger.Err(err).
|
manager.logger.Err(err).
|
||||||
Str("screen_size", fmt.Sprintf("%dx%d@%d", manager.config.ScreenWidth, manager.config.ScreenHeight, manager.config.ScreenRate)).
|
Str("screen_size", fmt.Sprintf("%dx%d@%d", width, height, rate)).
|
||||||
Msgf("setting initial screen size")
|
Msgf("setting initial screen size")
|
||||||
|
|
||||||
go xevent.EventLoop(manager.config.Display)
|
go xevent.EventLoop(manager.config.Display)
|
||||||
|
@ -66,11 +66,26 @@ func (manager *DesktopManagerCtx) ResetKeys() {
|
|||||||
xorg.ResetKeys()
|
xorg.ResetKeys()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (manager *DesktopManagerCtx) ScreenConfigurations() map[int]types.ScreenConfiguration {
|
func (manager *DesktopManagerCtx) ScreenConfigurations() []types.ScreenSize {
|
||||||
return xorg.ScreenConfigurations
|
var configs []types.ScreenSize
|
||||||
|
for _, size := range xorg.ScreenConfigurations {
|
||||||
|
for _, fps := range size.Rates {
|
||||||
|
// filter out all irrelevant rates
|
||||||
|
if fps > 60 || (fps > 30 && fps%10 != 0) {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (manager *DesktopManagerCtx) SetScreenSize(size types.ScreenSize) error {
|
configs = append(configs, types.ScreenSize{
|
||||||
|
Width: size.Width,
|
||||||
|
Height: size.Height,
|
||||||
|
Rate: fps,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return configs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (manager *DesktopManagerCtx) SetScreenSize(size types.ScreenSize) (types.ScreenSize, error) {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
manager.emmiter.Emit("before_screen_size_change")
|
manager.emmiter.Emit("before_screen_size_change")
|
||||||
|
|
||||||
@ -79,10 +94,15 @@ func (manager *DesktopManagerCtx) SetScreenSize(size types.ScreenSize) error {
|
|||||||
mu.Unlock()
|
mu.Unlock()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return xorg.ChangeScreenSize(size.Width, size.Height, size.Rate)
|
w, h, r, err := xorg.ChangeScreenSize(size.Width, size.Height, size.Rate)
|
||||||
|
return types.ScreenSize{
|
||||||
|
Width: w,
|
||||||
|
Height: h,
|
||||||
|
Rate: r,
|
||||||
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (manager *DesktopManagerCtx) GetScreenSize() *types.ScreenSize {
|
func (manager *DesktopManagerCtx) GetScreenSize() types.ScreenSize {
|
||||||
return xorg.GetScreenSize()
|
return xorg.GetScreenSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,11 +13,20 @@ func (h *MessageHandlerCtx) screenSet(session types.Session, payload *message.Sc
|
|||||||
return errors.New("is not the admin")
|
return errors.New("is not the admin")
|
||||||
}
|
}
|
||||||
|
|
||||||
data := types.ScreenSize(*payload)
|
size, err := h.desktop.SetScreenSize(types.ScreenSize{
|
||||||
if err := h.desktop.SetScreenSize(data); err != nil {
|
Width: payload.Width,
|
||||||
|
Height: payload.Height,
|
||||||
|
Rate: payload.Rate,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
h.sessions.Broadcast(event.SCREEN_UPDATED, payload)
|
h.sessions.Broadcast(event.SCREEN_UPDATED, message.ScreenSize{
|
||||||
|
Width: size.Width,
|
||||||
|
Height: size.Height,
|
||||||
|
Rate: size.Rate,
|
||||||
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
@ -25,8 +23,10 @@ func (h *MessageHandlerCtx) systemInit(session types.Session) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size := h.desktop.GetScreenSize()
|
size := h.desktop.GetScreenSize()
|
||||||
if size == nil {
|
screenSize := message.ScreenSize{
|
||||||
return errors.New("could not get screen size")
|
Width: size.Width,
|
||||||
|
Height: size.Height,
|
||||||
|
Rate: size.Rate,
|
||||||
}
|
}
|
||||||
|
|
||||||
sessions := map[string]message.SessionData{}
|
sessions := map[string]message.SessionData{}
|
||||||
@ -44,7 +44,7 @@ func (h *MessageHandlerCtx) systemInit(session types.Session) error {
|
|||||||
message.SystemInit{
|
message.SystemInit{
|
||||||
SessionId: session.ID(),
|
SessionId: session.ID(),
|
||||||
ControlHost: controlHost,
|
ControlHost: controlHost,
|
||||||
ScreenSize: message.ScreenSize(*size),
|
ScreenSize: screenSize,
|
||||||
Sessions: sessions,
|
Sessions: sessions,
|
||||||
Settings: h.sessions.Settings(),
|
Settings: h.sessions.Settings(),
|
||||||
ScreencastEnabled: h.capture.Screencast().Enabled(),
|
ScreencastEnabled: h.capture.Screencast().Enabled(),
|
||||||
@ -57,22 +57,22 @@ func (h *MessageHandlerCtx) systemInit(session types.Session) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *MessageHandlerCtx) systemAdmin(session types.Session) error {
|
func (h *MessageHandlerCtx) systemAdmin(session types.Session) error {
|
||||||
screenSizesList := []message.ScreenSize{}
|
configurations := h.desktop.ScreenConfigurations()
|
||||||
for _, size := range h.desktop.ScreenConfigurations() {
|
|
||||||
for _, rate := range size.Rates {
|
list := make([]message.ScreenSize, 0, len(configurations))
|
||||||
screenSizesList = append(screenSizesList, message.ScreenSize{
|
for _, conf := range configurations {
|
||||||
Width: size.Width,
|
list = append(list, message.ScreenSize{
|
||||||
Height: size.Height,
|
Width: conf.Width,
|
||||||
Rate: rate,
|
Height: conf.Height,
|
||||||
|
Rate: conf.Rate,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
broadcast := h.capture.Broadcast()
|
broadcast := h.capture.Broadcast()
|
||||||
session.Send(
|
session.Send(
|
||||||
event.SYSTEM_ADMIN,
|
event.SYSTEM_ADMIN,
|
||||||
message.SystemAdmin{
|
message.SystemAdmin{
|
||||||
ScreenSizesList: screenSizesList,
|
ScreenSizesList: list, // TODO: remove
|
||||||
BroadcastStatus: message.BroadcastStatus{
|
BroadcastStatus: message.BroadcastStatus{
|
||||||
IsActive: broadcast.Started(),
|
IsActive: broadcast.Started(),
|
||||||
URL: broadcast.Url(),
|
URL: broadcast.Url(),
|
||||||
|
@ -188,16 +188,13 @@ func (config *VideoConfig) GetPipeline(screen ScreenSize) (string, error) {
|
|||||||
}[:], " "), nil
|
}[:], " "), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *VideoConfig) GetBitrateFn(getScreen func() *ScreenSize) func() (int, error) {
|
func (config *VideoConfig) GetBitrateFn(getScreen func() ScreenSize) func() (int, error) {
|
||||||
return func() (int, error) {
|
return func() (int, error) {
|
||||||
if config.Bitrate > 0 {
|
if config.Bitrate > 0 {
|
||||||
return config.Bitrate, nil
|
return config.Bitrate, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
screen := getScreen()
|
screen := getScreen()
|
||||||
if screen == nil {
|
|
||||||
return 0, fmt.Errorf("screen is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
values := map[string]any{
|
values := map[string]any{
|
||||||
"width": screen.Width,
|
"width": screen.Width,
|
||||||
|
@ -19,12 +19,6 @@ type ScreenSize struct {
|
|||||||
Rate int16
|
Rate int16
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScreenConfiguration struct {
|
|
||||||
Width int
|
|
||||||
Height int
|
|
||||||
Rates map[int]int16
|
|
||||||
}
|
|
||||||
|
|
||||||
type KeyboardModifiers struct {
|
type KeyboardModifiers struct {
|
||||||
NumLock *bool
|
NumLock *bool
|
||||||
CapsLock *bool
|
CapsLock *bool
|
||||||
@ -57,9 +51,9 @@ type DesktopManager interface {
|
|||||||
ButtonPress(code uint32) error
|
ButtonPress(code uint32) error
|
||||||
KeyPress(codes ...uint32) error
|
KeyPress(codes ...uint32) error
|
||||||
ResetKeys()
|
ResetKeys()
|
||||||
ScreenConfigurations() map[int]ScreenConfiguration
|
ScreenConfigurations() []ScreenSize
|
||||||
SetScreenSize(ScreenSize) error
|
SetScreenSize(ScreenSize) (ScreenSize, error)
|
||||||
GetScreenSize() *ScreenSize
|
GetScreenSize() ScreenSize
|
||||||
SetKeyboardMap(KeyboardMap) error
|
SetKeyboardMap(KeyboardMap) error
|
||||||
GetKeyboardMap() (*KeyboardMap, error)
|
GetKeyboardMap() (*KeyboardMap, error)
|
||||||
SetKeyboardModifiers(mod KeyboardModifiers)
|
SetKeyboardModifiers(mod KeyboardModifiers)
|
||||||
|
146
pkg/xorg/xorg.c
146
pkg/xorg/xorg.c
@ -229,6 +229,82 @@ void XKey(KeySym keysym, int down) {
|
|||||||
XSync(display, 0);
|
XSync(display, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Status XSetScreenConfiguration(int width, int height, short *rate) {
|
||||||
|
Display *display = getXDisplay();
|
||||||
|
Window root = RootWindow(display, 0);
|
||||||
|
XRRScreenConfiguration *conf = XRRGetScreenInfo(display, root);
|
||||||
|
|
||||||
|
XRRScreenSize *xrrs;
|
||||||
|
int num_sizes;
|
||||||
|
xrrs = XRRConfigSizes(conf, &num_sizes);
|
||||||
|
|
||||||
|
int size_index = -1;
|
||||||
|
for (int i = 0; i < num_sizes; i++) {
|
||||||
|
if (xrrs[i].width == width && xrrs[i].height == height) {
|
||||||
|
size_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we cannot find the size
|
||||||
|
if (size_index == -1) {
|
||||||
|
return RRSetConfigFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
short current_rate = 0;
|
||||||
|
if (rate != NULL) {
|
||||||
|
short *rates;
|
||||||
|
int num_rates;
|
||||||
|
rates = XRRConfigRates(conf, size_index, &num_rates);
|
||||||
|
|
||||||
|
// try to find the nearest rate
|
||||||
|
short nearest_rate = 0;
|
||||||
|
float diff = 0;
|
||||||
|
for (int i = 0; i < num_rates; i++) {
|
||||||
|
if (nearest_rate == 0 || abs(rates[i] - *rate) < diff) {
|
||||||
|
nearest_rate = rates[i];
|
||||||
|
diff = abs(rates[i] - *rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nearest_rate != 0 && diff < 10) {
|
||||||
|
current_rate = nearest_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
*rate = current_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status status;
|
||||||
|
status = XRRSetScreenConfigAndRate(display, conf, root, size_index, RR_Rotate_0, current_rate, CurrentTime);
|
||||||
|
|
||||||
|
XRRFreeScreenConfigInfo(conf);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XGetScreenConfiguration(int *width, int *height, short *rate) {
|
||||||
|
Display *display = getXDisplay();
|
||||||
|
Window root = RootWindow(display, 0);
|
||||||
|
XRRScreenConfiguration *conf = XRRGetScreenInfo(display, root);
|
||||||
|
|
||||||
|
Rotation current_rotation;
|
||||||
|
SizeID current_size_id = XRRConfigCurrentConfiguration(conf, ¤t_rotation);
|
||||||
|
|
||||||
|
XRRScreenSize *xrrs;
|
||||||
|
int num_sizes;
|
||||||
|
xrrs = XRRConfigSizes(conf, &num_sizes);
|
||||||
|
|
||||||
|
// if we cannot find the size
|
||||||
|
if (current_size_id >= num_sizes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*width = xrrs[current_size_id].width;
|
||||||
|
*height = xrrs[current_size_id].height;
|
||||||
|
*rate = XRRConfigCurrentRate(conf);
|
||||||
|
|
||||||
|
XRRFreeScreenConfigInfo(conf);
|
||||||
|
}
|
||||||
|
|
||||||
void XGetScreenConfigurations() {
|
void XGetScreenConfigurations() {
|
||||||
Display *display = getXDisplay();
|
Display *display = getXDisplay();
|
||||||
Window root = RootWindow(display, 0);
|
Window root = RootWindow(display, 0);
|
||||||
@ -248,23 +324,71 @@ void XGetScreenConfigurations() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XSetScreenConfiguration(int index, short rate) {
|
// Inspired by https://github.com/raboof/xrandr/blob/master/xrandr.c
|
||||||
|
void XCreateScreenMode(int width, int height, short rate) {
|
||||||
Display *display = getXDisplay();
|
Display *display = getXDisplay();
|
||||||
Window root = RootWindow(display, 0);
|
Window root = RootWindow(display, 0);
|
||||||
XRRSetScreenConfigAndRate(display, XRRGetScreenInfo(display, root), root, index, RR_Rotate_0, rate, CurrentTime);
|
|
||||||
|
char name[128];
|
||||||
|
XRRModeInfo mode;
|
||||||
|
mode = XCreateScreenModeInfo(width, height, rate);
|
||||||
|
|
||||||
|
snprintf(name, sizeof name, "%dx%d_%d", width, height, rate);
|
||||||
|
mode.nameLength = strlen(name);
|
||||||
|
mode.name = name;
|
||||||
|
|
||||||
|
// create new mode
|
||||||
|
XRRCreateMode(display, root, &mode);
|
||||||
|
XSync(display, 0);
|
||||||
|
|
||||||
|
// find newly created mode in resources
|
||||||
|
RRMode mode_id;
|
||||||
|
XRRScreenResources *resources = XRRGetScreenResources(display, root);
|
||||||
|
for (int i = 0; i < resources->nmode; ++i) {
|
||||||
|
if (strcmp(resources->modes[i].name, mode.name) == 0) {
|
||||||
|
mode_id = resources->modes[i].id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int XGetScreenSize() {
|
// add new mode to all outputs
|
||||||
Display *display = getXDisplay();
|
for (int i = 0; i < resources->noutput; ++i) {
|
||||||
XRRScreenConfiguration *conf = XRRGetScreenInfo(display, RootWindow(display, 0));
|
XRRAddOutputMode(display, resources->outputs[i], mode_id);
|
||||||
Rotation original_rotation;
|
|
||||||
return XRRConfigCurrentConfiguration(conf, &original_rotation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
short XGetScreenRate() {
|
XRRFreeScreenResources(resources);
|
||||||
Display *display = getXDisplay();
|
}
|
||||||
XRRScreenConfiguration *conf = XRRGetScreenInfo(display, RootWindow(display, 0));
|
|
||||||
return XRRConfigCurrentRate(conf);
|
// Inspired by https://fossies.org/linux/xwayland/hw/xwayland/xwayland-cvt.c
|
||||||
|
XRRModeInfo XCreateScreenModeInfo(int hdisplay, int vdisplay, short vrefresh) {
|
||||||
|
XRRModeInfo modeinfo;
|
||||||
|
memset(&modeinfo, 0, sizeof modeinfo);
|
||||||
|
|
||||||
|
#ifdef _LIBCVT_H_
|
||||||
|
struct libxcvt_mode_info *mode_info;
|
||||||
|
|
||||||
|
// get screen mode from libxcvt, if available
|
||||||
|
mode_info = libxcvt_gen_mode_info(hdisplay, vdisplay, vrefresh, false, false);
|
||||||
|
|
||||||
|
modeinfo.width = mode_info->hdisplay;
|
||||||
|
modeinfo.height = mode_info->vdisplay;
|
||||||
|
modeinfo.dotClock = mode_info->dot_clock * 1000;
|
||||||
|
modeinfo.hSyncStart = mode_info->hsync_start;
|
||||||
|
modeinfo.hSyncEnd = mode_info->hsync_end;
|
||||||
|
modeinfo.hTotal = mode_info->htotal;
|
||||||
|
modeinfo.vSyncStart = mode_info->vsync_start;
|
||||||
|
modeinfo.vSyncEnd = mode_info->vsync_end;
|
||||||
|
modeinfo.vTotal = mode_info->vtotal;
|
||||||
|
modeinfo.modeFlags = mode_info->mode_flags;
|
||||||
|
|
||||||
|
free(mode_info);
|
||||||
|
#else
|
||||||
|
// fallback to a simple mode without refresh rate
|
||||||
|
modeinfo.width = hdisplay;
|
||||||
|
modeinfo.height = vdisplay;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return modeinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XSetKeyboardModifier(int mod, int on) {
|
void XSetKeyboardModifier(int mod, int on) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package xorg
|
package xorg
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo LDFLAGS: -lX11 -lXrandr -lXtst -lXfixes
|
#cgo LDFLAGS: -lX11 -lXrandr -lXtst -lXfixes -lxcvt
|
||||||
|
|
||||||
#include "xorg.h"
|
#include "xorg.h"
|
||||||
*/
|
*/
|
||||||
@ -27,7 +27,13 @@ const (
|
|||||||
KbdModNumLock KbdMod = 16
|
KbdModNumLock KbdMod = 16
|
||||||
)
|
)
|
||||||
|
|
||||||
var ScreenConfigurations = make(map[int]types.ScreenConfiguration)
|
type ScreenConfiguration struct {
|
||||||
|
Width int
|
||||||
|
Height int
|
||||||
|
Rates map[int]int16
|
||||||
|
}
|
||||||
|
|
||||||
|
var ScreenConfigurations = make(map[int]ScreenConfiguration)
|
||||||
|
|
||||||
var debounce_button = make(map[uint32]time.Time)
|
var debounce_button = make(map[uint32]time.Time)
|
||||||
var debounce_key = make(map[uint32]time.Time)
|
var debounce_key = make(map[uint32]time.Time)
|
||||||
@ -178,42 +184,48 @@ func CheckKeys(duration time.Duration) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChangeScreenSize(width int, height int, rate int16) error {
|
// set screen configuration, create new one if not exists
|
||||||
|
func ChangeScreenSize(width int, height int, rate int16) (int, int, int16, error) {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
|
|
||||||
for index, size := range ScreenConfigurations {
|
// round width and height to 8
|
||||||
if size.Width == width && size.Height == height {
|
width = width - (width % 8)
|
||||||
for _, fps := range size.Rates {
|
height = height - (height % 8)
|
||||||
if rate == fps {
|
|
||||||
C.XSetScreenConfiguration(C.int(index), C.short(fps))
|
// convert variables to C types
|
||||||
return nil
|
c_width, c_height, c_rate := C.int(width), C.int(height), C.short(rate)
|
||||||
}
|
|
||||||
}
|
// if screen configuration already exists, just set it
|
||||||
}
|
if status := C.XSetScreenConfiguration(c_width, c_height, &c_rate); status == C.RRSetConfigSuccess {
|
||||||
|
return width, height, int16(c_rate), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("unknown screen configuration %dx%d@%d", width, height, rate)
|
// create new screen configuration
|
||||||
|
C.XCreateScreenMode(c_width, c_height, c_rate)
|
||||||
|
|
||||||
|
// screen configuration should exist now, set it
|
||||||
|
if status := C.XSetScreenConfiguration(c_width, c_height, &c_rate); status == C.RRSetConfigSuccess {
|
||||||
|
return width, height, int16(c_rate), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetScreenSize() *types.ScreenSize {
|
return 0, 0, 0, fmt.Errorf("unknown screen configuration %dx%d@%d", width, height, rate)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetScreenSize() types.ScreenSize {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
|
|
||||||
index := int(C.XGetScreenSize())
|
c_width, c_height, c_rate := C.int(0), C.int(0), C.short(0)
|
||||||
rate := int16(C.XGetScreenRate())
|
C.XGetScreenConfiguration(&c_width, &c_height, &c_rate)
|
||||||
|
|
||||||
if conf, ok := ScreenConfigurations[index]; ok {
|
return types.ScreenSize{
|
||||||
return &types.ScreenSize{
|
Width: int(c_width),
|
||||||
Width: conf.Width,
|
Height: int(c_height),
|
||||||
Height: conf.Height,
|
Rate: int16(c_rate),
|
||||||
Rate: rate,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetKeyboardModifier(mod KbdMod, active bool) {
|
func SetKeyboardModifier(mod KbdMod, active bool) {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
@ -300,7 +312,7 @@ func GetScreenshotImage() *image.RGBA {
|
|||||||
|
|
||||||
//export goCreateScreenSize
|
//export goCreateScreenSize
|
||||||
func goCreateScreenSize(index C.int, width C.int, height C.int, mwidth C.int, mheight C.int) {
|
func goCreateScreenSize(index C.int, width C.int, height C.int, mwidth C.int, mheight C.int) {
|
||||||
ScreenConfigurations[int(index)] = types.ScreenConfiguration{
|
ScreenConfigurations[int(index)] = ScreenConfiguration{
|
||||||
Width: int(width),
|
Width: int(width),
|
||||||
Height: int(height),
|
Height: int(height),
|
||||||
Rates: make(map[int]int16),
|
Rates: make(map[int]int16),
|
||||||
@ -309,12 +321,5 @@ func goCreateScreenSize(index C.int, width C.int, height C.int, mwidth C.int, mh
|
|||||||
|
|
||||||
//export goSetScreenRates
|
//export goSetScreenRates
|
||||||
func goSetScreenRates(index C.int, rate_index C.int, rateC C.short) {
|
func goSetScreenRates(index C.int, rate_index C.int, rateC C.short) {
|
||||||
rate := int16(rateC)
|
ScreenConfigurations[int(index)].Rates[int(rate_index)] = int16(rateC)
|
||||||
|
|
||||||
// filter out all irrelevant rates
|
|
||||||
if rate > 60 || (rate > 30 && rate%10 != 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ScreenConfigurations[int(index)].Rates[int(rate_index)] = rate
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,11 @@
|
|||||||
#include <X11/extensions/XTest.h>
|
#include <X11/extensions/XTest.h>
|
||||||
#include <X11/extensions/Xfixes.h>
|
#include <X11/extensions/Xfixes.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// for computing xrandr modelines at runtime
|
||||||
|
#include <libxcvt/libxcvt.h>
|
||||||
|
|
||||||
extern void goCreateScreenSize(int index, int width, int height, int mwidth, int mheight);
|
extern void goCreateScreenSize(int index, int width, int height, int mwidth, int mheight);
|
||||||
extern void goSetScreenRates(int index, int rate_index, short rate);
|
extern void goSetScreenRates(int index, int rate_index, short rate);
|
||||||
@ -31,10 +36,11 @@ static KeyCode XKeyEntryGet(KeySym keysym);
|
|||||||
static KeyCode XkbKeysymToKeycode(Display *dpy, KeySym keysym);
|
static KeyCode XkbKeysymToKeycode(Display *dpy, KeySym keysym);
|
||||||
void XKey(KeySym keysym, int down);
|
void XKey(KeySym keysym, int down);
|
||||||
|
|
||||||
|
Status XSetScreenConfiguration(int width, int height, short *rate);
|
||||||
|
void XGetScreenConfiguration(int *width, int *height, short *rate);
|
||||||
void XGetScreenConfigurations();
|
void XGetScreenConfigurations();
|
||||||
void XSetScreenConfiguration(int index, short rate);
|
void XCreateScreenMode(int width, int height, short rate);
|
||||||
int XGetScreenSize();
|
XRRModeInfo XCreateScreenModeInfo(int hdisplay, int vdisplay, short vrefresh);
|
||||||
short XGetScreenRate();
|
|
||||||
|
|
||||||
void XSetKeyboardModifier(int mod, int on);
|
void XSetKeyboardModifier(int mod, int on);
|
||||||
char XGetKeyboardModifiers();
|
char XGetKeyboardModifiers();
|
||||||
|
316
runtime/xdummy-randr.patch
Normal file
316
runtime/xdummy-randr.patch
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
diff --git a/src/dummy.h b/src/dummy.h
|
||||||
|
index c3fdd6e..9c74f56 100644
|
||||||
|
--- a/src/dummy.h
|
||||||
|
+++ b/src/dummy.h
|
||||||
|
@@ -13,6 +13,8 @@
|
||||||
|
|
||||||
|
#include "compat-api.h"
|
||||||
|
|
||||||
|
+#define DUMMY_MAX_SCREENS 4
|
||||||
|
+
|
||||||
|
/* Supported chipsets */
|
||||||
|
typedef enum {
|
||||||
|
DUMMY_CHIP
|
||||||
|
@@ -72,6 +74,12 @@ typedef struct dummyRec
|
||||||
|
pointer* FBBase;
|
||||||
|
Bool (*CreateWindow)() ; /* wrapped CreateWindow */
|
||||||
|
Bool prop;
|
||||||
|
+ /* XRANDR support begin */
|
||||||
|
+ int num_screens;
|
||||||
|
+ struct _xf86Crtc *paCrtcs[DUMMY_MAX_SCREENS];
|
||||||
|
+ struct _xf86Output *paOutputs[DUMMY_MAX_SCREENS];
|
||||||
|
+ int connected_outputs;
|
||||||
|
+ /* XRANDR support end */
|
||||||
|
} DUMMYRec, *DUMMYPtr;
|
||||||
|
|
||||||
|
/* The privates of the DUMMY driver */
|
||||||
|
diff --git a/src/dummy_driver.c b/src/dummy_driver.c
|
||||||
|
index 2656602..069e330 100644
|
||||||
|
--- a/src/dummy_driver.c
|
||||||
|
+++ b/src/dummy_driver.c
|
||||||
|
@@ -34,6 +34,8 @@
|
||||||
|
#include <X11/extensions/Xv.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#include "xf86Crtc.h"
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Driver data structures.
|
||||||
|
*/
|
||||||
|
@@ -141,6 +143,219 @@ static XF86ModuleVersionInfo dummyVersRec =
|
||||||
|
{0,0,0,0}
|
||||||
|
};
|
||||||
|
|
||||||
|
+
|
||||||
|
+/************************
|
||||||
|
+ * XRANDR support begin *
|
||||||
|
+ ************************/
|
||||||
|
+
|
||||||
|
+static Bool dummy_config_resize(ScrnInfoPtr pScrn, int cw, int ch);
|
||||||
|
+static Bool DUMMYAdjustScreenPixmap(ScrnInfoPtr pScrn, int width, int height);
|
||||||
|
+
|
||||||
|
+static const xf86CrtcConfigFuncsRec DUMMYCrtcConfigFuncs = {
|
||||||
|
+ .resize = dummy_config_resize
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+dummy_crtc_dpms(xf86CrtcPtr crtc, int mode)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static Bool
|
||||||
|
+dummy_crtc_lock (xf86CrtcPtr crtc)
|
||||||
|
+{
|
||||||
|
+ return FALSE;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static Bool
|
||||||
|
+dummy_crtc_mode_fixup (xf86CrtcPtr crtc, DisplayModePtr mode,
|
||||||
|
+ DisplayModePtr adjusted_mode)
|
||||||
|
+{
|
||||||
|
+ return TRUE;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+dummy_crtc_stub (xf86CrtcPtr crtc)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+dummy_crtc_gamma_set (xf86CrtcPtr crtc, CARD16 *red,
|
||||||
|
+ CARD16 *green, CARD16 *blue, int size)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void *
|
||||||
|
+dummy_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height)
|
||||||
|
+{
|
||||||
|
+ return NULL;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+dummy_crtc_mode_set (xf86CrtcPtr crtc, DisplayModePtr mode,
|
||||||
|
+ DisplayModePtr adjusted_mode, int x, int y)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static const xf86CrtcFuncsRec DUMMYCrtcFuncs = {
|
||||||
|
+ .dpms = dummy_crtc_dpms,
|
||||||
|
+ .save = NULL, /* These two are never called by the server. */
|
||||||
|
+ .restore = NULL,
|
||||||
|
+ .lock = dummy_crtc_lock,
|
||||||
|
+ .unlock = NULL, /* This will not be invoked if lock returns FALSE. */
|
||||||
|
+ .mode_fixup = dummy_crtc_mode_fixup,
|
||||||
|
+ .prepare = dummy_crtc_stub,
|
||||||
|
+ .mode_set = dummy_crtc_mode_set,
|
||||||
|
+ .commit = dummy_crtc_stub,
|
||||||
|
+ .gamma_set = dummy_crtc_gamma_set,
|
||||||
|
+ .shadow_allocate = dummy_crtc_shadow_allocate,
|
||||||
|
+ .shadow_create = NULL, /* These two should not be invoked if allocate
|
||||||
|
+ returns NULL. */
|
||||||
|
+ .shadow_destroy = NULL,
|
||||||
|
+ .set_cursor_colors = NULL,
|
||||||
|
+ .set_cursor_position = NULL,
|
||||||
|
+ .show_cursor = NULL,
|
||||||
|
+ .hide_cursor = NULL,
|
||||||
|
+ .load_cursor_argb = NULL,
|
||||||
|
+ .destroy = dummy_crtc_stub
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+dummy_output_stub (xf86OutputPtr output)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+dummy_output_dpms (xf86OutputPtr output, int mode)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+dummy_output_mode_valid (xf86OutputPtr output, DisplayModePtr mode)
|
||||||
|
+{
|
||||||
|
+ return MODE_OK;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static Bool
|
||||||
|
+dummy_output_mode_fixup (xf86OutputPtr output, DisplayModePtr mode,
|
||||||
|
+ DisplayModePtr adjusted_mode)
|
||||||
|
+{
|
||||||
|
+ return TRUE;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+dummy_output_mode_set (xf86OutputPtr output, DisplayModePtr mode,
|
||||||
|
+ DisplayModePtr adjusted_mode)
|
||||||
|
+{
|
||||||
|
+ DUMMYPtr dPtr = DUMMYPTR(output->scrn);
|
||||||
|
+ int index = (int64_t)output->driver_private;
|
||||||
|
+
|
||||||
|
+ /* set to connected at first mode set */
|
||||||
|
+ dPtr->connected_outputs |= 1 << index;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* The first virtual monitor is always connected. Others only after setting its
|
||||||
|
+ * mode */
|
||||||
|
+static xf86OutputStatus
|
||||||
|
+dummy_output_detect (xf86OutputPtr output)
|
||||||
|
+{
|
||||||
|
+ DUMMYPtr dPtr = DUMMYPTR(output->scrn);
|
||||||
|
+ int index = (int64_t)output->driver_private;
|
||||||
|
+
|
||||||
|
+ if (dPtr->connected_outputs & (1 << index))
|
||||||
|
+ return XF86OutputStatusConnected;
|
||||||
|
+ else
|
||||||
|
+ return XF86OutputStatusDisconnected;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static DisplayModePtr
|
||||||
|
+dummy_output_get_modes (xf86OutputPtr output)
|
||||||
|
+{
|
||||||
|
+ DisplayModePtr pModes = NULL, pMode, pModeSrc;
|
||||||
|
+
|
||||||
|
+ /* copy modes from config */
|
||||||
|
+ for (pModeSrc = output->scrn->modes; pModeSrc; pModeSrc = pModeSrc->next)
|
||||||
|
+ {
|
||||||
|
+ pMode = xnfcalloc(1, sizeof(DisplayModeRec));
|
||||||
|
+ memcpy(pMode, pModeSrc, sizeof(DisplayModeRec));
|
||||||
|
+ pMode->next = NULL;
|
||||||
|
+ pMode->prev = NULL;
|
||||||
|
+ pMode->name = strdup(pModeSrc->name);
|
||||||
|
+ pModes = xf86ModesAdd(pModes, pMode);
|
||||||
|
+ if (pModeSrc->next == output->scrn->modes)
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ return pModes;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+static const xf86OutputFuncsRec DUMMYOutputFuncs = {
|
||||||
|
+ .create_resources = dummy_output_stub,
|
||||||
|
+ .dpms = dummy_output_dpms,
|
||||||
|
+ .save = NULL, /* These two are never called by the server. */
|
||||||
|
+ .restore = NULL,
|
||||||
|
+ .mode_valid = dummy_output_mode_valid,
|
||||||
|
+ .mode_fixup = dummy_output_mode_fixup,
|
||||||
|
+ .prepare = dummy_output_stub,
|
||||||
|
+ .commit = dummy_output_stub,
|
||||||
|
+ .mode_set = dummy_output_mode_set,
|
||||||
|
+ .detect = dummy_output_detect,
|
||||||
|
+ .get_modes = dummy_output_get_modes,
|
||||||
|
+#ifdef RANDR_12_INTERFACE
|
||||||
|
+ .set_property = NULL,
|
||||||
|
+#endif
|
||||||
|
+ .destroy = dummy_output_stub
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static Bool
|
||||||
|
+dummy_config_resize(ScrnInfoPtr pScrn, int cw, int ch)
|
||||||
|
+{
|
||||||
|
+ if (!pScrn->vtSema) {
|
||||||
|
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||||||
|
+ "We do not own the active VT, exiting.\n");
|
||||||
|
+ return TRUE;
|
||||||
|
+ }
|
||||||
|
+ return DUMMYAdjustScreenPixmap(pScrn, cw, ch);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+Bool DUMMYAdjustScreenPixmap(ScrnInfoPtr pScrn, int width, int height)
|
||||||
|
+{
|
||||||
|
+ ScreenPtr pScreen = pScrn->pScreen;
|
||||||
|
+ PixmapPtr pPixmap = pScreen->GetScreenPixmap(pScreen);
|
||||||
|
+ DUMMYPtr dPtr = DUMMYPTR(pScrn);
|
||||||
|
+ uint64_t cbLine = (width * xf86GetBppFromDepth(pScrn, pScrn->depth) / 8 + 3) & ~3;
|
||||||
|
+ int displayWidth = cbLine * 8 / xf86GetBppFromDepth(pScrn, pScrn->depth);
|
||||||
|
+
|
||||||
|
+ if ( width == pScrn->virtualX
|
||||||
|
+ && height == pScrn->virtualY
|
||||||
|
+ && displayWidth == pScrn->displayWidth)
|
||||||
|
+ return TRUE;
|
||||||
|
+ if (!pPixmap) {
|
||||||
|
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||||||
|
+ "Failed to get the screen pixmap.\n");
|
||||||
|
+ return FALSE;
|
||||||
|
+ }
|
||||||
|
+ if (cbLine > UINT32_MAX || cbLine * height >= pScrn->videoRam * 1024)
|
||||||
|
+ {
|
||||||
|
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||||||
|
+ "Unable to set up a virtual screen size of %dx%d with %d Kb of video memory available. Please increase the video memory size.\n",
|
||||||
|
+ width, height, pScrn->videoRam);
|
||||||
|
+ return FALSE;
|
||||||
|
+ }
|
||||||
|
+ pScreen->ModifyPixmapHeader(pPixmap, width, height,
|
||||||
|
+ pScrn->depth, xf86GetBppFromDepth(pScrn, pScrn->depth), cbLine,
|
||||||
|
+ pPixmap->devPrivate.ptr);
|
||||||
|
+ pScrn->virtualX = width;
|
||||||
|
+ pScrn->virtualY = height;
|
||||||
|
+ pScrn->displayWidth = displayWidth;
|
||||||
|
+
|
||||||
|
+ return TRUE;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**********************
|
||||||
|
+ * XRANDR support end *
|
||||||
|
+ **********************/
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* This is the module init data.
|
||||||
|
* Its name has to be the driver name followed by ModuleData
|
||||||
|
@@ -568,6 +783,56 @@ DUMMYScreenInit(SCREEN_INIT_ARGS_DECL)
|
||||||
|
|
||||||
|
xf86SetBlackWhitePixels(pScreen);
|
||||||
|
|
||||||
|
+ /* initialize XRANDR */
|
||||||
|
+ xf86CrtcConfigInit(pScrn, &DUMMYCrtcConfigFuncs);
|
||||||
|
+ /* FIXME */
|
||||||
|
+ dPtr->num_screens = DUMMY_MAX_SCREENS;
|
||||||
|
+
|
||||||
|
+ for (int i=0; i < dPtr->num_screens; i++) {
|
||||||
|
+ char szOutput[256];
|
||||||
|
+
|
||||||
|
+ dPtr->paCrtcs[i] = xf86CrtcCreate(pScrn, &DUMMYCrtcFuncs);
|
||||||
|
+ dPtr->paCrtcs[i]->driver_private = (void *)(uintptr_t)i;
|
||||||
|
+
|
||||||
|
+ /* Set up our virtual outputs. */
|
||||||
|
+ snprintf(szOutput, sizeof(szOutput), "DUMMY%u", i);
|
||||||
|
+ dPtr->paOutputs[i] = xf86OutputCreate(pScrn, &DUMMYOutputFuncs,
|
||||||
|
+ szOutput);
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ xf86OutputUseScreenMonitor(dPtr->paOutputs[i], FALSE);
|
||||||
|
+ dPtr->paOutputs[i]->possible_crtcs = 1 << i;
|
||||||
|
+ dPtr->paOutputs[i]->possible_clones = 0;
|
||||||
|
+ dPtr->paOutputs[i]->driver_private = (void *)(uintptr_t)i;
|
||||||
|
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Created crtc (%p) and output %s (%p)\n",
|
||||||
|
+ (void *)dPtr->paCrtcs[i], szOutput,
|
||||||
|
+ (void *)dPtr->paOutputs[i]);
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* bitmask */
|
||||||
|
+ dPtr->connected_outputs = 1;
|
||||||
|
+
|
||||||
|
+ xf86CrtcSetSizeRange(pScrn, 64, 64, DUMMY_MAX_WIDTH, DUMMY_MAX_HEIGHT);
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ /* Now create our initial CRTC/output configuration. */
|
||||||
|
+ if (!xf86InitialConfiguration(pScrn, TRUE)) {
|
||||||
|
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Initial CRTC configuration failed!\n");
|
||||||
|
+ return (FALSE);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Initialise randr 1.2 mode-setting functions and set first mode.
|
||||||
|
+ * Note that the mode won't be usable until the server has resized the
|
||||||
|
+ * framebuffer to something reasonable. */
|
||||||
|
+ if (!xf86CrtcScreenInit(pScreen)) {
|
||||||
|
+ return FALSE;
|
||||||
|
+ }
|
||||||
|
+ if (!xf86SetDesiredModes(pScrn)) {
|
||||||
|
+ return FALSE;
|
||||||
|
+ }
|
||||||
|
+ /* XRANDR initialization end */
|
||||||
|
+
|
||||||
|
#ifdef USE_DGA
|
||||||
|
DUMMYDGAInit(pScreen);
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user