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:
@ -188,16 +188,13 @@ func (config *VideoConfig) GetPipeline(screen ScreenSize) (string, error) {
|
||||
}[:], " "), 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) {
|
||||
if config.Bitrate > 0 {
|
||||
return config.Bitrate, nil
|
||||
}
|
||||
|
||||
screen := getScreen()
|
||||
if screen == nil {
|
||||
return 0, fmt.Errorf("screen is nil")
|
||||
}
|
||||
|
||||
values := map[string]any{
|
||||
"width": screen.Width,
|
||||
|
@ -19,12 +19,6 @@ type ScreenSize struct {
|
||||
Rate int16
|
||||
}
|
||||
|
||||
type ScreenConfiguration struct {
|
||||
Width int
|
||||
Height int
|
||||
Rates map[int]int16
|
||||
}
|
||||
|
||||
type KeyboardModifiers struct {
|
||||
NumLock *bool
|
||||
CapsLock *bool
|
||||
@ -57,9 +51,9 @@ type DesktopManager interface {
|
||||
ButtonPress(code uint32) error
|
||||
KeyPress(codes ...uint32) error
|
||||
ResetKeys()
|
||||
ScreenConfigurations() map[int]ScreenConfiguration
|
||||
SetScreenSize(ScreenSize) error
|
||||
GetScreenSize() *ScreenSize
|
||||
ScreenConfigurations() []ScreenSize
|
||||
SetScreenSize(ScreenSize) (ScreenSize, error)
|
||||
GetScreenSize() ScreenSize
|
||||
SetKeyboardMap(KeyboardMap) error
|
||||
GetKeyboardMap() (*KeyboardMap, error)
|
||||
SetKeyboardModifiers(mod KeyboardModifiers)
|
||||
|
148
pkg/xorg/xorg.c
148
pkg/xorg/xorg.c
@ -229,6 +229,82 @@ void XKey(KeySym keysym, int down) {
|
||||
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() {
|
||||
Display *display = getXDisplay();
|
||||
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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// add new mode to all outputs
|
||||
for (int i = 0; i < resources->noutput; ++i) {
|
||||
XRRAddOutputMode(display, resources->outputs[i], mode_id);
|
||||
}
|
||||
|
||||
XRRFreeScreenResources(resources);
|
||||
}
|
||||
|
||||
int XGetScreenSize() {
|
||||
Display *display = getXDisplay();
|
||||
XRRScreenConfiguration *conf = XRRGetScreenInfo(display, RootWindow(display, 0));
|
||||
Rotation original_rotation;
|
||||
return XRRConfigCurrentConfiguration(conf, &original_rotation);
|
||||
}
|
||||
// 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);
|
||||
|
||||
short XGetScreenRate() {
|
||||
Display *display = getXDisplay();
|
||||
XRRScreenConfiguration *conf = XRRGetScreenInfo(display, RootWindow(display, 0));
|
||||
return XRRConfigCurrentRate(conf);
|
||||
#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) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package xorg
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -lX11 -lXrandr -lXtst -lXfixes
|
||||
#cgo LDFLAGS: -lX11 -lXrandr -lXtst -lXfixes -lxcvt
|
||||
|
||||
#include "xorg.h"
|
||||
*/
|
||||
@ -27,7 +27,13 @@ const (
|
||||
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_key = make(map[uint32]time.Time)
|
||||
@ -178,40 +184,46 @@ 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()
|
||||
defer mu.Unlock()
|
||||
|
||||
for index, size := range ScreenConfigurations {
|
||||
if size.Width == width && size.Height == height {
|
||||
for _, fps := range size.Rates {
|
||||
if rate == fps {
|
||||
C.XSetScreenConfiguration(C.int(index), C.short(fps))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
// round width and height to 8
|
||||
width = width - (width % 8)
|
||||
height = height - (height % 8)
|
||||
|
||||
// convert variables to C types
|
||||
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
|
||||
}
|
||||
|
||||
return 0, 0, 0, fmt.Errorf("unknown screen configuration %dx%d@%d", width, height, rate)
|
||||
}
|
||||
|
||||
func GetScreenSize() *types.ScreenSize {
|
||||
func GetScreenSize() types.ScreenSize {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
index := int(C.XGetScreenSize())
|
||||
rate := int16(C.XGetScreenRate())
|
||||
c_width, c_height, c_rate := C.int(0), C.int(0), C.short(0)
|
||||
C.XGetScreenConfiguration(&c_width, &c_height, &c_rate)
|
||||
|
||||
if conf, ok := ScreenConfigurations[index]; ok {
|
||||
return &types.ScreenSize{
|
||||
Width: conf.Width,
|
||||
Height: conf.Height,
|
||||
Rate: rate,
|
||||
}
|
||||
return types.ScreenSize{
|
||||
Width: int(c_width),
|
||||
Height: int(c_height),
|
||||
Rate: int16(c_rate),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetKeyboardModifier(mod KbdMod, active bool) {
|
||||
@ -300,7 +312,7 @@ func GetScreenshotImage() *image.RGBA {
|
||||
|
||||
//export goCreateScreenSize
|
||||
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),
|
||||
Height: int(height),
|
||||
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
|
||||
func goSetScreenRates(index C.int, rate_index C.int, rateC C.short) {
|
||||
rate := int16(rateC)
|
||||
|
||||
// filter out all irrelevant rates
|
||||
if rate > 60 || (rate > 30 && rate%10 != 0) {
|
||||
return
|
||||
}
|
||||
|
||||
ScreenConfigurations[int(index)].Rates[int(rate_index)] = rate
|
||||
ScreenConfigurations[int(index)].Rates[int(rate_index)] = int16(rateC)
|
||||
}
|
||||
|
@ -7,6 +7,11 @@
|
||||
#include <X11/extensions/XTest.h>
|
||||
#include <X11/extensions/Xfixes.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 goSetScreenRates(int index, int rate_index, short rate);
|
||||
@ -31,10 +36,11 @@ static KeyCode XKeyEntryGet(KeySym keysym);
|
||||
static KeyCode XkbKeysymToKeycode(Display *dpy, KeySym keysym);
|
||||
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 XSetScreenConfiguration(int index, short rate);
|
||||
int XGetScreenSize();
|
||||
short XGetScreenRate();
|
||||
void XCreateScreenMode(int width, int height, short rate);
|
||||
XRRModeInfo XCreateScreenModeInfo(int hdisplay, int vdisplay, short vrefresh);
|
||||
|
||||
void XSetKeyboardModifier(int mod, int on);
|
||||
char XGetKeyboardModifiers();
|
||||
|
Reference in New Issue
Block a user