O preâmbulo:
Eu tenho um cliente X remoto muito específico, que precisa de resolução fixa. 1280x1024, para dizer. E meu notebook tem 1440x900. E o Windows a bordo. Então, a ideia é dimensionar a saída do cliente para caber na saída de 900px. Panning não é uma opção.
A primeira abordagem foi o Xserver, rodando no VirtualBox. Mas isso não funcionou como eu queria, o dimensionamento da janela do VB apenas truncou a tela, com barras de rolagem.
Então, eu tentei Xming. Criado a tela usando este args:
-screen 0 640x512
Começou com sucesso. Conectei meu cliente X, bem, a imagem estava truncada, mas isso era esperado. Do que eu corri xrandr para exibição criada e tenho a saída:
$ 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*
Ok, tente mudar a escala:
$ 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
E a escala não mudou. Mas o tamanho da tela estendido, mostrando todos os dados do cliente de entrada. Se consultar a configuração novamente:
$ 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*
Eu tentei o Xming e o Cygwin / X, o mesmo resultado.
"Valor em falha solicitada" não depende do valor de escala solicitado e é sempre 0x3e.
Novas dimensões da tela são sempre uma escala solicitada multiplicada pelas dimensões iniciais se a escala solicitada for maior que 1. Caso contrário, nada muda, enquanto a mensagem de erro ainda está lá.
Se novas dimensões forem maiores do que minhas dimensões de cliente, todos os pixels de reposição serão pretos.
Encontrei aqui
que tal saída do Xserver é causada pelo xf86-video-vesa e por drivers nvidia mais antigos. Mas eu não sei se esse é o meu caso, e como mudar algo sobre o driver dentro do Xming ou Cygwin / X. Os drivers de host do Windows foram atualizados, de qualquer maneira.
Eu também tentei x11vnc dentro do Cygwin, e o escalonamento funcionou, tanto do lado do cliente x11vnc quanto do vnc. Mas isso foi lento e é muito complicado.
Então a questão é sobre xrandr, por que isso não funciona como esperado e declarado em man pages?
Atualização:
Bem, eu fui mais fundo e olhei através de fontes de extensão RANDR. E o único caso que eu encontrei, que produz BadValue na resposta à requisição RRSetCrtcTransform, é o valor False da variável booleana crtc- > transforms , que serve como um indicador do suporte à transformação do driver:
/*
* 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;
}
A única linha que modifica esse valor é uma função setter:
/*
* Set whether transforms are allowed on a CRTC
*/
void
RRCrtcSetTransformSupport(RRCrtcPtr crtc, Bool transforms)
{
crtc->transforms = transforms;
}
Mas é declarado como função de exportação no cabeçalho, e ninguém o chama dentro de srcs RANDR.
Algumas pesquisas adicionais mostram que esse valor é relatado em resposta à solicitação RRGetCrtcTransform (linha resposta- > hasTransforms = crtc- > transforma; ):
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;
}
Mas a solicitação em si é produzida pela função cliente XRRGetCrtcTransform e não é possível obter de sua saída as informações sobre suporte a dimensionamento. A função simplesmente ignora esse valor ( rep.hasTransforms ) na resposta:
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] = '-screen 0 640x512
';
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] = '$ 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*
';
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;
}
Neste momento, aqui estão os fatos:
- O driver do servidor X dentro do Cygwin ou Xming não suporta transformações;
- Não há como obter essas informações usando a API do lado do cliente XRandr, embora o servidor envie essas informações (deve ser considerado como um defeito?)
Ok, o motivo foi encontrado, mas como fazer com que o suporte a drivers seja transformado?