~ubuntu-branches/ubuntu/maverick/tvtime/maverick

« back to all changes in this revision

Viewing changes to src/xfullscreen.c

  • Committer: Bazaar Package Importer
  • Author(s): Simon Law
  • Date: 2004-01-13 18:00:36 UTC
  • Revision ID: james.westby@ubuntu.com-20040113180036-h996q67t476jymsu
Tags: upstream-0.9.12
ImportĀ upstreamĀ versionĀ 0.9.12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Copyright (c) 2003 Billy Biggs <vektor@dumbterm.net> and
 
3
 *                    Per von Zweigbergk <pvz@e.kth.se>
 
4
 *
 
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:
 
12
 *
 
13
 * The above copyright notice and this permission notice shall be
 
14
 * included in all copies or substantial portions of the Software.
 
15
 *
 
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
 
23
 * SOFTWARE.
 
24
 */
 
25
 
 
26
#include <stdio.h>
 
27
#include <unistd.h>
 
28
#include <stdlib.h>
 
29
#ifdef HAVE_CONFIG_H
 
30
# include "config.h"
 
31
#endif
 
32
#include <X11/Xlib.h>
 
33
#ifdef HAVE_XF86VIDMODE
 
34
#include <X11/extensions/xf86vmode.h>
 
35
#endif
 
36
#ifdef HAVE_XINERAMA
 
37
#include <X11/extensions/Xinerama.h>
 
38
#endif
 
39
#include "xfullscreen.h"
 
40
 
 
41
#define MAX_HEADS 64
 
42
#define SIGN(x) ( (x) == 0 ? 0 : (x) > 0 ? 1 : -1 )
 
43
 
 
44
typedef struct head_s {
 
45
    int x;
 
46
    int y;
 
47
    int w;
 
48
    int h;
 
49
} head_t;
 
50
 
 
51
struct xfullscreen_s
 
52
{
 
53
    Display *display;
 
54
    int screen;
 
55
 
 
56
    int hdisplay;
 
57
    int vdisplay;
 
58
    int panx;
 
59
    int pany;
 
60
    double refresh;
 
61
 
 
62
    int usevidmode;
 
63
    int squarepixel;
 
64
    int widthmm;
 
65
    int heightmm;
 
66
 
 
67
    int nheads;
 
68
    head_t heads[ MAX_HEADS ];
 
69
};
 
70
 
 
71
#ifdef HAVE_XF86VIDMODE
 
72
static int get_largest_vidmode_resolution( Display *display, int screen,
 
73
                                           int *max_h, int *max_v )
 
74
{
 
75
    XF86VidModeModeInfo **modelist;
 
76
    int nummodes, i;
 
77
 
 
78
    *max_h = *max_v = 0;
 
79
 
 
80
    if( !XF86VidModeGetAllModeLines( display, screen, &nummodes, &modelist ) ) {
 
81
        return 0;
 
82
    }
 
83
 
 
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;
 
87
    }
 
88
 
 
89
    return 1;
 
90
}
 
91
 
 
92
int get_current_modeline_parameters( Display *display, int screen, int *panx,
 
93
                                     int *pany, int *hdisp, int *vdisp,
 
94
                                     double *refresh )
 
95
{
 
96
    XF86VidModeModeLine mode_line;
 
97
    int dot_clock;
 
98
 
 
99
    if( !XF86VidModeGetModeLine( display, screen, &dot_clock, &mode_line ) ||
 
100
        !XF86VidModeGetViewPort( display, screen, panx, pany ) ) {
 
101
        return 0;
 
102
    } else {
 
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 ) );
 
107
    }
 
108
 
 
109
    return 1;
 
110
}
 
111
#endif
 
112
 
 
113
xfullscreen_t *xfullscreen_new( Display *display, int screen, int verbose )
 
114
{
 
115
    xfullscreen_t *xf = malloc( sizeof( xfullscreen_t ) );
 
116
    int event_base, error_base;
 
117
    int max_h, max_v;
 
118
 
 
119
    if( !xf ) {
 
120
        return 0;
 
121
    }
 
122
 
 
123
    xf->display = display;
 
124
    xf->screen = screen;
 
125
 
 
126
    /* Default settings. */
 
127
    xf->usevidmode = 0;
 
128
    xf->squarepixel = 1;
 
129
    xf->nheads = 1;
 
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 );
 
134
 
 
135
#ifdef HAVE_XINERAMA
 
136
    if( XineramaQueryExtension( xf->display, &event_base, &error_base ) &&
 
137
        XineramaIsActive( xf->display ) ) {
 
138
        XineramaScreenInfo *screens;
 
139
        int i;
 
140
 
 
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;
 
148
        }
 
149
 
 
150
        if( verbose ) {
 
151
            fprintf( stderr, "xfullscreen: Using XINERAMA for "
 
152
                             "dual-head information.\n" );
 
153
        }
 
154
        return xf;
 
155
    }
 
156
#endif
 
157
 
 
158
 
 
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,
 
165
                                        &max_h, &max_v ) ) {
 
166
 
 
167
        xf->usevidmode = 1;
 
168
 
 
169
        if( max_h < DisplayWidth( xf->display, xf->screen ) ||
 
170
            max_v < DisplayHeight( xf->display, xf->screen ) ) {
 
171
 
 
172
            if( verbose ) {
 
173
                fprintf( stderr, "xfullscreen: Desktop larger than "
 
174
                                 "primary display, assuming square pixels.\n" );
 
175
            }
 
176
 
 
177
        } else {
 
178
            if( verbose ) {
 
179
                fprintf( stderr, "xfullscreen: Single-head detected, "
 
180
                                 "pixel aspect will be calculated.\n" );
 
181
            }
 
182
 
 
183
            xf->squarepixel = 0;
 
184
            xf->widthmm = DisplayWidthMM( xf->display, xf->screen );
 
185
            xf->heightmm = DisplayHeightMM( xf->display, xf->screen );
 
186
        }
 
187
 
 
188
        return xf;
 
189
    }
 
190
#endif
 
191
 
 
192
    /* There is no support for XINERAMA or VidMode. */
 
193
    if( verbose ) {
 
194
        fprintf( stderr, "xfullscreen: No support for the vidmode "
 
195
                         "extension, assuming square pixels.\n" );
 
196
    }
 
197
 
 
198
    return xf;
 
199
}
 
200
 
 
201
void xfullscreen_delete( xfullscreen_t *xf )
 
202
{
 
203
    free( xf );
 
204
}
 
205
 
 
206
void xfullscreen_print_summary( xfullscreen_t *xf )
 
207
{
 
208
    int n;
 
209
    int d;
 
210
    if( xf->squarepixel ) {
 
211
        fprintf( stderr, "xfullscreen: Pixels are square.\n" );
 
212
    } else {
 
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 ) );
 
216
    }
 
217
 
 
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 );
 
223
    } else {
 
224
        int i;
 
225
 
 
226
        fprintf( stderr, "xfullscreen: Number of displays is %d.\n",
 
227
                 xf->nheads );
 
228
 
 
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 );
 
233
        }
 
234
    }
 
235
}
 
236
 
 
237
void xfullscreen_update( xfullscreen_t *xf )
 
238
{
 
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 );
 
244
    }
 
245
#endif
 
246
}
 
247
 
 
248
void xfullscreen_get_position( xfullscreen_t *xf, int window_x, int window_y,
 
249
                               int *x, int *y, int *w, int *h )
 
250
{
 
251
    if( xf->usevidmode ) {
 
252
        *x = xf->panx;
 
253
        *y = xf->pany;
 
254
        *w = xf->hdisplay;
 
255
        *h = xf->vdisplay;
 
256
    } else {
 
257
        int i;
 
258
 
 
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;
 
268
                return;
 
269
            }
 
270
        }
 
271
    }
 
272
}
 
273
 
 
274
static int calculate_gcd( int x, int y )
 
275
{
 
276
    if( y > x ) return calculate_gcd( y, x );
 
277
    if( y < 0 ) return calculate_gcd( -y, 0 );
 
278
 
 
279
    while( y ) {
 
280
        int tmp = y;
 
281
        y = x % y;
 
282
        x = tmp;
 
283
    }
 
284
 
 
285
    return x;
 
286
}
 
287
 
 
288
static void simplify_fraction( int *n, int *d )
 
289
{
 
290
    int gcd = calculate_gcd( *n, *d );
 
291
    *n /= gcd;
 
292
    *d /= gcd;
 
293
}
 
294
 
 
295
void xfullscreen_get_pixel_aspect( xfullscreen_t *xf, int *aspect_w,
 
296
                                   int *aspect_h )
 
297
{
 
298
    if( xf->squarepixel ) {
 
299
        *aspect_h = *aspect_w = 1;
 
300
    } else {
 
301
        int cd;
 
302
        int error_h;
 
303
        int error_w;
 
304
        /*
 
305
         * To simplify the code, we enter all snapratios as ratios with a
 
306
         * common denominator.
 
307
         *
 
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.
 
311
         *
 
312
         * Putting these on a common denominator gets us 15:15 and 16:15.
 
313
         */
 
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;
 
318
        int *ratio_w;
 
319
 
 
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 );
 
324
 
 
325
        /**
 
326
         * Calculate the maximum error, assuming that the
 
327
         * maximum error in the sources is half a millimeter.
 
328
         */
 
329
        error_w = 1 * xf->hdisplay;
 
330
        error_h = 2 * (xf->heightmm - 1) * xf->vdisplay;
 
331
        simplify_fraction( &error_h, &error_w );
 
332
 
 
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;
 
339
        *aspect_h = cd;
 
340
 
 
341
        /**
 
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
 
344
         * pseudo-variables.)
 
345
         *
 
346
         * <==> This equivalent to saying:
 
347
         * 
 
348
         * (ASPECT + ERROR > RATIO && ASPECT - ERROR < RATIO) ||
 
349
         * (ASPECT + ERROR < RATIO && ASPECT - ERROR > RATIO)
 
350
         *
 
351
         * <==> Changing to compare all to zero.
 
352
         *
 
353
         * (ASPECT + ERROR - RATIO > 0 && ASPECT - ERROR - RATIO < 0) ||
 
354
         * (ASPECT + ERROR - RATIO < 0 && ASPECT - ERROR - RATIO > 0)
 
355
         *
 
356
         * <==> By inspection we can see that this is equivalent to:
 
357
         *
 
358
         * SIGN(ASPECT + ERROR - RATIO) != SIGN(ASPECT - ERROR - RATIO)
 
359
         *
 
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:
 
363
         */ 
 
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;
 
368
                break;
 
369
            }
 
370
        }
 
371
        simplify_fraction( aspect_w, aspect_h );
 
372
    }
 
373
}
 
374
 
 
375
int xfullscreen_get_refresh( xfullscreen_t *xf, double *refresh )
 
376
{
 
377
    if( xf->usevidmode ) {
 
378
        *refresh = xf->refresh;
 
379
        return 1;
 
380
    }
 
381
 
 
382
    return 0;
 
383
}
 
384