序言:
我有一个非常具体的远程 X 客户端,需要固定分辨率。 1280x1024,可以说。我的笔记本电脑的分辨率是 1440x900。还有窗户。因此,我们的想法是缩放客户端的输出以适应 900px 的输出。平移不是一个选项。
第一种方法是 Xserver,在 VirtualBox 下运行。但这并没有像我想要的那样工作,VB窗口的缩放只会截断屏幕,并带有滚动条。
于是,我尝试了Xming。使用此参数创建屏幕:
-screen 0 640x512
就成功启动了。连接我的 X 客户端,好吧,图像被截断了,但这是预料之中的。我运行 xrandr 来创建显示并得到输出:
$ xrandr
xrandr: Failed to get size of gamma for output default
Screen 0: minimum 0 x 0, current 640 x 512, maximum 32768 x 32768
default connected primary 640x512+0+0 0mm x 0 mm
640x512 0.00*
好的,尝试改变比例:
$ xrandr --output default --scale 2x2
xrandr: Failed to get size of gamma for output default
X Error of failed request: BadValue (integer parameter out of range for operation)
Major opcode of failed request: 139 (RANDR)
Minor opcode of failed request: 26 (RRSetCrtcTransform)
Value in failed request: 0x3e
Serial number of failed request: 21
Current serial number in output stream: 22
而且规模没有改变。但屏幕尺寸扩大,显示所有客户端数据入站。如果再次查询配置:
$ xrandr
xrandr: Failed to get size of gamma for output default
Screen 0: minimum 0 x 0, current 1280 x 1024, maximum 32768 x 32768
default connected primary 1280x1024+0+0 0mm x 0 mm
1280x1024 0.00*
我尝试了 Xming 和 Cygwin/X,结果相同。 “请求失败的值”不依赖于请求的比例值,并且始终为 0x3e。
如果请求的比例大于 1,则屏幕的新尺寸始终是请求的比例乘以初始尺寸。否则,不会发生任何变化,但错误消息仍然存在。如果新尺寸大于我的客户尺寸,则所有备用像素均为黑色。
我找到了这里 此类 Xserver 输出是由 xf86-video-vesa 和较旧的 nvidia 驱动程序引起的。但我不知道这是否是我的情况,以及如何更改 Xming 或 Cygwin/X 内部驱动程序的某些内容。无论如何,Windows 主机驱动程序已更新。
我还在 Cygwin 中尝试了 x11vnc,并且在 x11vnc 和 vnc 客户端上都可以进行缩放。但这很慢,而且太棘手。
所以问题是关于 xrandr,为什么它不能按预期工作并在手册页中声明?
更新:
好吧,我更深入地研究了 RANDR 扩展的来源。我发现的唯一在对 RRSetCrtcTransform 请求的回复中产生 BadValue 的情况是布尔变量的 False 值crtc->转换,这意味着驱动程序转换支持的指标:
/*
* Set the pending CRTC transformation
*/
int
RRCrtcTransformSet(RRCrtcPtr crtc,
PictTransformPtr transform,
struct pixman_f_transform *f_transform,
struct pixman_f_transform *f_inverse,
char *filter_name,
int filter_len, xFixed * params, int nparams)
{
PictFilterPtr filter = NULL;
int width = 0, height = 0;
if (!crtc->transforms)
return BadValue;
if (filter_len) {
filter = PictureFindFilter(crtc->pScreen, filter_name, filter_len);
if (!filter)
return BadName;
if (filter->ValidateParams) {
if (!filter->ValidateParams(crtc->pScreen, filter->id,
params, nparams, &width, &height))
return BadMatch;
}
else {
width = filter->width;
height = filter->height;
}
}
else {
if (nparams)
return BadMatch;
}
if (!RRTransformSetFilter(&crtc->client_pending_transform,
filter, params, nparams, width, height))
return BadAlloc;
crtc->client_pending_transform.transform = *transform;
crtc->client_pending_transform.f_transform = *f_transform;
crtc->client_pending_transform.f_inverse = *f_inverse;
return Success;
}
修改该值的唯一行是 setter 函数:
/*
* Set whether transforms are allowed on a CRTC
*/
void
RRCrtcSetTransformSupport(RRCrtcPtr crtc, Bool transforms)
{
crtc->transforms = transforms;
}
但它在标头中声明为导出函数,并且没有人在 RANDR srcs 中调用它。
一些进一步的查找显示,该值是在回复 RRGetCrtcTransform 请求时报告的(行回复->hasTransforms = crtc->transforms;):
int
ProcRRGetCrtcTransform(ClientPtr client)
{
REQUEST(xRRGetCrtcTransformReq);
xRRGetCrtcTransformReply *reply;
RRCrtcPtr crtc;
int nextra;
RRTransformPtr current, pending;
char *extra;
REQUEST_SIZE_MATCH(xRRGetCrtcTransformReq);
VERIFY_RR_CRTC(stuff->crtc, crtc, DixReadAccess);
pending = &crtc->client_pending_transform;
current = &crtc->client_current_transform;
nextra = (transform_filter_length(pending) +
transform_filter_length(current));
reply = calloc(1, sizeof(xRRGetCrtcTransformReply) + nextra);
if (!reply)
return BadAlloc;
extra = (char *) (reply + 1);
reply->type = X_Reply;
reply->sequenceNumber = client->sequence;
reply->length = bytes_to_int32(CrtcTransformExtra + nextra);
reply->hasTransforms = crtc->transforms;
transform_encode(client, &reply->pendingTransform, &pending->transform);
extra += transform_filter_encode(client, extra,
&reply->pendingNbytesFilter,
&reply->pendingNparamsFilter, pending);
transform_encode(client, &reply->currentTransform, ¤t->transform);
extra += transform_filter_encode(client, extra,
&reply->currentNbytesFilter,
&reply->currentNparamsFilter, current);
if (client->swapped) {
swaps(&reply->sequenceNumber);
swapl(&reply->length);
}
WriteToClient(client, sizeof(xRRGetCrtcTransformReply) + nextra, reply);
free(reply);
return Success;
}
但请求本身是由 XRRGetCrtcTransform 客户端函数生成的,无法从其输出中获取有关扩展支持的信息。该函数只是忽略该值(代表.hasTransforms)在回复中:
Status
XRRGetCrtcTransform (Display *dpy,
RRCrtc crtc,
XRRCrtcTransformAttributes **attributes)
{
XExtDisplayInfo *info = XRRFindDisplay(dpy);
xRRGetCrtcTransformReply rep;
xRRGetCrtcTransformReq *req;
int major_version, minor_version;
XRRCrtcTransformAttributes *attr;
char *extra = NULL, *e;
int p;
*attributes = NULL;
RRCheckExtension (dpy, info, False);
if (!XRRQueryVersion (dpy, &major_version, &minor_version) ||
!_XRRHasTransform (major_version, minor_version))
{
/* For pre-1.3 servers, just report identity matrices everywhere */
rep.pendingTransform = identity;
rep.pendingNbytesFilter = 0;
rep.pendingNparamsFilter = 0;
rep.currentTransform = identity;
rep.currentNbytesFilter = 0;
rep.currentNparamsFilter = 0;
}
else
{
LockDisplay (dpy);
GetReq (RRGetCrtcTransform, req);
req->reqType = info->codes->major_opcode;
req->randrReqType = X_RRGetCrtcTransform;
req->crtc = crtc;
if (!_XReply (dpy, (xReply *) &rep, CrtcTransformExtra >> 2, xFalse))
{
rep.pendingTransform = identity;
rep.pendingNbytesFilter = 0;
rep.pendingNparamsFilter = 0;
rep.currentTransform = identity;
rep.currentNbytesFilter = 0;
rep.currentNparamsFilter = 0;
}
else
{
int extraBytes = rep.length * 4 - CrtcTransformExtra;
extra = Xmalloc (extraBytes);
if (!extra) {
_XEatDataWords (dpy, rep.length - (CrtcTransformExtra >> 2));
UnlockDisplay (dpy);
SyncHandle ();
return False;
}
_XRead (dpy, extra, extraBytes);
}
UnlockDisplay (dpy);
SyncHandle ();
}
attr = Xmalloc (sizeof (XRRCrtcTransformAttributes) +
rep.pendingNparamsFilter * sizeof (XFixed) +
rep.currentNparamsFilter * sizeof (XFixed) +
rep.pendingNbytesFilter + 1 +
rep.currentNbytesFilter + 1);
if (!attr) {
XFree (extra);
return False;
}
XTransform_from_xRenderTransform (&attr->pendingTransform, &rep.pendingTransform);
XTransform_from_xRenderTransform (&attr->currentTransform, &rep.currentTransform);
attr->pendingParams = (XFixed *) (attr + 1);
attr->currentParams = attr->pendingParams + rep.pendingNparamsFilter;
attr->pendingFilter = (char *) (attr->currentParams + rep.currentNparamsFilter);
attr->currentFilter = attr->pendingFilter + rep.pendingNbytesFilter + 1;
e = extra;
memcpy (attr->pendingFilter, e, rep.pendingNbytesFilter);
attr->pendingFilter[rep.pendingNbytesFilter] = '\0';
e += (rep.pendingNbytesFilter + 3) & ~3;
for (p = 0; p < rep.pendingNparamsFilter; p++) {
INT32 f;
memcpy (&f, e, 4);
e += 4;
attr->pendingParams[p] = (XFixed) f;
}
attr->pendingNparams = rep.pendingNparamsFilter;
memcpy (attr->currentFilter, e, rep.currentNbytesFilter);
attr->currentFilter[rep.currentNbytesFilter] = '\0';
e += (rep.currentNbytesFilter + 3) & ~3;
for (p = 0; p < rep.currentNparamsFilter; p++) {
INT32 f;
memcpy (&f, e, 4);
e += 4;
attr->currentParams[p] = (XFixed) f;
}
attr->currentNparams = rep.currentNparamsFilter;
if (extra)
XFree (extra);
*attributes = attr;
return True;
}
此时此刻,事实如下:
- Cygwin 或 Xming 内的 X 服务器驱动程序不支持转换;
- 尽管服务器端发送了此类信息,但无法使用 XRandr 客户端 API 获取此信息(是否应将其视为缺陷?)
好了,原因找到了,但是如何让驱动支持转变呢?
答案1
我无法评论,所以我必须给出一个解决方案:
建议的解决方案:我会回到 VirtualBox。我可能也必须这样做。
评论:cygwin 上的 xrandr 有任何解决方案吗?
对于 3000x2000 高 dpi 屏幕,旧的 UNIX 应用程序无法使用。我什至尝试过Windows中的放大镜工具,但它很糟糕。
是否有支持应用程序扩展的 Windows 商业 x 服务器?我还没找到。