2
* Copyright (c) 2003 Billy Biggs <vektor@dumbterm.net> and
3
* Per von Zweigbergk <pvz@e.kth.se>
5
* Permission is hereby granted, free of charge, to any person obtaining
6
* a copy of this software and associated documentation files (the
7
* "Software"), to deal in the Software without restriction, including
8
* without limitation the rights to use, copy, modify, merge, publish,
9
* distribute, sublicense, and/or sell copies of the Software, and to
10
* permit persons to whom the Software is furnished to do so, subject to
11
* the following conditions:
13
* The above copyright notice and this permission notice shall be
14
* included in all copies or substantial portions of the Software.
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33
#ifdef HAVE_XF86VIDMODE
34
#include <X11/extensions/xf86vmode.h>
37
#include <X11/extensions/Xinerama.h>
39
#include "xfullscreen.h"
42
#define SIGN(x) ( (x) == 0 ? 0 : (x) > 0 ? 1 : -1 )
44
typedef struct head_s {
68
head_t heads[ MAX_HEADS ];
71
#ifdef HAVE_XF86VIDMODE
72
static int get_largest_vidmode_resolution( Display *display, int screen,
73
int *max_h, int *max_v )
75
XF86VidModeModeInfo **modelist;
80
if( !XF86VidModeGetAllModeLines( display, screen, &nummodes, &modelist ) ) {
84
for( i = 0; i < nummodes; i++ ) {
85
if( modelist[ i ]->hdisplay > *max_h ) *max_h = modelist[ i ]->hdisplay;
86
if( modelist[ i ]->vdisplay > *max_v ) *max_v = modelist[ i ]->vdisplay;
92
int get_current_modeline_parameters( Display *display, int screen, int *panx,
93
int *pany, int *hdisp, int *vdisp,
96
XF86VidModeModeLine mode_line;
99
if( !XF86VidModeGetModeLine( display, screen, &dot_clock, &mode_line ) ||
100
!XF86VidModeGetViewPort( display, screen, panx, pany ) ) {
103
*hdisp = mode_line.hdisplay;
104
*vdisp = mode_line.vdisplay;
105
*refresh = ( (double) ( (double) dot_clock * 1000.0 ) /
106
(double) ( mode_line.htotal * mode_line.vtotal ) );
113
xfullscreen_t *xfullscreen_new( Display *display, int screen, int verbose )
115
xfullscreen_t *xf = malloc( sizeof( xfullscreen_t ) );
116
int event_base, error_base;
123
xf->display = display;
126
/* Default settings. */
130
xf->heads[ 0 ].x = 0;
131
xf->heads[ 0 ].y = 0;
132
xf->heads[ 0 ].w = DisplayWidth( xf->display, xf->screen );
133
xf->heads[ 0 ].h = DisplayHeight( xf->display, xf->screen );
136
if( XineramaQueryExtension( xf->display, &event_base, &error_base ) &&
137
XineramaIsActive( xf->display ) ) {
138
XineramaScreenInfo *screens;
141
screens = XineramaQueryScreens( xf->display, &xf->nheads );
142
if( xf->nheads > MAX_HEADS ) xf->nheads = MAX_HEADS;
143
for( i = 0; i < xf->nheads; i++ ) {
144
xf->heads[ i ].x = screens[ i ].x_org;
145
xf->heads[ i ].y = screens[ i ].y_org;
146
xf->heads[ i ].w = screens[ i ].width;
147
xf->heads[ i ].h = screens[ i ].height;
151
fprintf( stderr, "xfullscreen: Using XINERAMA for "
152
"dual-head information.\n" );
159
#ifdef HAVE_XF86VIDMODE
160
if( XF86VidModeQueryExtension( xf->display, &event_base, &error_base ) &&
161
get_current_modeline_parameters( xf->display, xf->screen, &xf->panx,
162
&xf->pany, &xf->hdisplay,
163
&xf->vdisplay, &xf->refresh ) &&
164
get_largest_vidmode_resolution( xf->display, xf->screen,
169
if( max_h < DisplayWidth( xf->display, xf->screen ) ||
170
max_v < DisplayHeight( xf->display, xf->screen ) ) {
173
fprintf( stderr, "xfullscreen: Desktop larger than "
174
"primary display, assuming square pixels.\n" );
179
fprintf( stderr, "xfullscreen: Single-head detected, "
180
"pixel aspect will be calculated.\n" );
184
xf->widthmm = DisplayWidthMM( xf->display, xf->screen );
185
xf->heightmm = DisplayHeightMM( xf->display, xf->screen );
192
/* There is no support for XINERAMA or VidMode. */
194
fprintf( stderr, "xfullscreen: No support for the vidmode "
195
"extension, assuming square pixels.\n" );
201
void xfullscreen_delete( xfullscreen_t *xf )
206
void xfullscreen_print_summary( xfullscreen_t *xf )
210
if( xf->squarepixel ) {
211
fprintf( stderr, "xfullscreen: Pixels are square.\n" );
213
xfullscreen_get_pixel_aspect( xf, &n, &d );
214
fprintf( stderr, "xfullscreen: Pixel aspect ratio on the primary "
215
"head is: %d/%d == %.2f.\n", n, d, ( (double) n / d ) );
218
if( xf->usevidmode ) {
219
fprintf( stderr, "xfullscreen: Using the XFree86-VidModeExtension "
220
"to calculate fullscreen size.\n" );
221
fprintf( stderr, "xfullscreen: Fullscreen to %d,%d with size %dx%d.\n",
222
xf->panx, xf->pany, xf->hdisplay, xf->vdisplay );
226
fprintf( stderr, "xfullscreen: Number of displays is %d.\n",
229
for( i = 0; i < xf->nheads; i++ ) {
230
fprintf( stderr, "xfullscreen: Head %d at %d,%d with size %dx%d.\n",
231
i, xf->heads[ i ].x, xf->heads[ i ].y,
232
xf->heads[ i ].w, xf->heads[ i ].h );
237
void xfullscreen_update( xfullscreen_t *xf )
239
#ifdef HAVE_XF86VIDMODE
240
if( xf->usevidmode ) {
241
get_current_modeline_parameters( xf->display, xf->screen, &xf->panx,
242
&xf->pany, &xf->hdisplay,
243
&xf->vdisplay, &xf->refresh );
248
void xfullscreen_get_position( xfullscreen_t *xf, int window_x, int window_y,
249
int *x, int *y, int *w, int *h )
251
if( xf->usevidmode ) {
259
for( i = 0; i < xf->nheads; i++ ) {
260
if( (xf->heads[ i ].x <= window_x) &&
261
(window_x < (xf->heads[ i ].x + xf->heads[ i ].w)) &&
262
(xf->heads[ i ].y <= window_y) &&
263
(window_y < (xf->heads[ i ].y + xf->heads[ i ].h)) ) {
264
*x = xf->heads[ i ].x;
265
*y = xf->heads[ i ].y;
266
*w = xf->heads[ i ].w;
267
*h = xf->heads[ i ].h;
274
static int calculate_gcd( int x, int y )
276
if( y > x ) return calculate_gcd( y, x );
277
if( y < 0 ) return calculate_gcd( -y, 0 );
288
static void simplify_fraction( int *n, int *d )
290
int gcd = calculate_gcd( *n, *d );
295
void xfullscreen_get_pixel_aspect( xfullscreen_t *xf, int *aspect_w,
298
if( xf->squarepixel ) {
299
*aspect_h = *aspect_w = 1;
305
* To simplify the code, we enter all snapratios as ratios with a
306
* common denominator.
308
* In this code, we're only using two cases. A ratio of 1:1, the
309
* common square pixel case, and 16:15, the short pixel case that
310
* arises when 1280x1024 is displayed on a 4:3 monitor.
312
* Putting these on a common denominator gets us 15:15 and 16:15.
314
int snapratio_w[] = { 15, 16 };
315
int snapratio_cd = 15;
316
int snapratio_count = sizeof( snapratio_w ) / sizeof ( *snapratio_w );
317
int *snapratio_w_end = snapratio_w + snapratio_count;
320
/* Calculate the aspect ratio from the X11 metrics. */
321
*aspect_w = xf->widthmm * xf->vdisplay;
322
*aspect_h = xf->heightmm * xf->hdisplay;
323
simplify_fraction( aspect_h, aspect_w );
326
* Calculate the maximum error, assuming that the
327
* maximum error in the sources is half a millimeter.
329
error_w = 1 * xf->hdisplay;
330
error_h = 2 * (xf->heightmm - 1) * xf->vdisplay;
331
simplify_fraction( &error_h, &error_w );
333
/* Put ERROR, ASPECT and SNAPRATIOs on a common denominator. */
334
cd = *aspect_h * error_h * snapratio_cd;
335
*aspect_w *= error_h * snapratio_cd;
336
error_w *= *aspect_h * snapratio_cd;
337
for( ratio_w = snapratio_w; ratio_w < snapratio_w_end; ratio_w++ )
338
*ratio_w *= *aspect_h * error_h;
342
* We want to see if the error means that we could end up either
343
* above or below a set aspect ratio. (Capital letters represent
346
* <==> This equivalent to saying:
348
* (ASPECT + ERROR > RATIO && ASPECT - ERROR < RATIO) ||
349
* (ASPECT + ERROR < RATIO && ASPECT - ERROR > RATIO)
351
* <==> Changing to compare all to zero.
353
* (ASPECT + ERROR - RATIO > 0 && ASPECT - ERROR - RATIO < 0) ||
354
* (ASPECT + ERROR - RATIO < 0 && ASPECT - ERROR - RATIO > 0)
356
* <==> By inspection we can see that this is equivalent to:
358
* SIGN(ASPECT + ERROR - RATIO) != SIGN(ASPECT - ERROR - RATIO)
360
* <==> Now, we multiply the test by the common denominator.
361
* (if this has any effect on the signedness, it'll be mirrored),
362
* and we get the final test:
364
for( ratio_w = snapratio_w; ratio_w < snapratio_w_end; ratio_w++ ) {
365
if( SIGN(*aspect_w + error_w - *ratio_w) !=
366
SIGN(*aspect_w - error_w - *ratio_w) ) {
367
*aspect_w = *ratio_w;
371
simplify_fraction( aspect_w, aspect_h );
375
int xfullscreen_get_refresh( xfullscreen_t *xf, double *refresh )
377
if( xf->usevidmode ) {
378
*refresh = xf->refresh;