PageRenderTime 49ms CodeModel.GetById 15ms app.highlight 31ms RepoModel.GetById 1ms app.codeStats 0ms

/packages/ptc/src/x11/x11modesi.inc

https://github.com/slibre/freepascal
Pascal | 461 lines | 340 code | 68 blank | 53 comment | 42 complexity | c19e0bc2a331d9b7fa61494fe934e993 MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, LGPL-3.0
  1{
  2    This file is part of the PTCPas framebuffer library
  3    Copyright (C) 2001-2012 Nikolay Nikolov (nickysn@users.sourceforge.net)
  4    Original C++ version by Christian Nentwich (c.nentwich@cs.ucl.ac.uk)
  5
  6    This library is free software; you can redistribute it and/or
  7    modify it under the terms of the GNU Lesser General Public
  8    License as published by the Free Software Foundation; either
  9    version 2.1 of the License, or (at your option) any later version
 10    with the following modification:
 11
 12    As a special exception, the copyright holders of this library give you
 13    permission to link this library with independent modules to produce an
 14    executable, regardless of the license terms of these independent modules,and
 15    to copy and distribute the resulting executable under terms of your choice,
 16    provided that you also meet, for each linked independent module, the terms
 17    and conditions of the license of that module. An independent module is a
 18    module which is not derived from or based on this library. If you modify
 19    this library, you may extend this exception to your version of the library,
 20    but you are not obligated to do so. If you do not wish to do so, delete this
 21    exception statement from your version.
 22
 23    This library is distributed in the hope that it will be useful,
 24    but WITHOUT ANY WARRANTY; without even the implied warranty of
 25    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 26    Lesser General Public License for more details.
 27
 28    You should have received a copy of the GNU Lesser General Public
 29    License along with this library; if not, write to the Free Software
 30    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 31}
 32
 33constructor TX11Modes.Create(ADisplay: PDisplay; AScreen: cint);
 34begin
 35  FDisplay := ADisplay;
 36  FScreen := AScreen;
 37end;
 38
 39constructor TX11ModesNoModeSwitching.Create(ADisplay: PDisplay; AScreen: cint);
 40begin
 41  inherited;
 42
 43  FWidth := DisplayWidth(FDisplay, FScreen);
 44  FHeight := DisplayHeight(FDisplay, FScreen);
 45end;
 46
 47procedure TX11ModesNoModeSwitching.GetModes(var AModes: TPTCModeList; ACurrentDesktopFormat: IPTCFormat);
 48begin
 49  SetLength(AModes, 1);
 50  AModes[0] := TPTCMode.Create(FWidth,
 51                               FHeight,
 52                               ACurrentDesktopFormat);
 53end;
 54
 55procedure TX11ModesNoModeSwitching.SetBestMode(AWidth, AHeight: Integer);
 56begin
 57  FWidth := DisplayWidth(FDisplay, FScreen);
 58  FHeight := DisplayHeight(FDisplay, FScreen);
 59end;
 60
 61procedure TX11ModesNoModeSwitching.RestorePreviousMode;
 62begin
 63  { do nothing }
 64end;
 65
 66function TX11ModesNoModeSwitching.GetWidth: Integer;
 67begin
 68  Result := FWidth;
 69end;
 70
 71function TX11ModesNoModeSwitching.GetHeight: Integer;
 72begin
 73  Result := FHeight;
 74end;
 75
 76{$IFDEF ENABLE_X11_EXTENSION_XRANDR}
 77constructor TX11ModesXrandr.Create(ADisplay: PDisplay; AScreen: cint);
 78var
 79  dummy1, dummy2: cint;
 80  Major, Minor: cint;
 81begin
 82  inherited;
 83
 84  FInMode := False;
 85
 86  if not XRRQueryExtension(FDisplay, @dummy1, @dummy2) then
 87    raise TPTCError.Create('Xrandr extension not available');
 88
 89  XRRQueryVersion(FDisplay, @Major, @Minor); // todo: check
 90  LOG('Xrandr version: ' + IntToStr(Major) + '.' + IntToStr(Minor));
 91
 92  FRoot := RootWindow(FDisplay, FScreen);
 93
 94  { is this necessary? }
 95  CreateScreenConfig;
 96  DestroyScreenConfig;
 97end;
 98
 99destructor TX11ModesXrandr.Destroy;
100begin
101  RestorePreviousMode;
102
103  inherited;
104end;
105
106procedure TX11ModesXrandr.CreateScreenConfig;
107begin
108  DestroyScreenConfig;
109
110  FXRRConfig := XRRGetScreenInfo(FDisplay, FRoot);
111  if FXRRConfig = nil then
112    raise TPTCError.Create('XRRGetScreenInfo failed');
113end;
114
115procedure TX11ModesXrandr.DestroyScreenConfig;
116var
117  tmp: PXRRScreenConfiguration;
118begin
119  if FXRRConfig <> nil then
120  begin
121    tmp := FXRRConfig;
122    FXRRConfig := nil;
123    XRRFreeScreenConfigInfo(tmp);
124  end;
125end;
126
127procedure TX11ModesXrandr.GetModes(var AModes: TPTCModeList; ACurrentDesktopFormat: IPTCFormat);
128var
129  ScreenSizes: PXRRScreenSize;
130  ScreenSizesNum: cint;
131  I: Integer;
132begin
133  ScreenSizes := XRRConfigSizes(FXRRConfig, @ScreenSizesNum);
134
135  SetLength(AModes, ScreenSizesNum);
136  for I := 0 to ScreenSizesNum - 1 do
137    AModes[I] := TPTCMode.Create(ScreenSizes[I].width,
138                                 ScreenSizes[I].height,
139                                 ACurrentDesktopFormat);
140end;
141
142class function TX11ModesXrandr.FindBestMode(AScreenSizes: PXRRScreenSize;
143                                            AScreenSizesNum: Integer;
144                                            ARequestedWidth,
145                                            ARequestedHeight: Integer): Integer;
146var
147  I: Integer;
148  min_diff: Integer;
149  d_x, d_y: Integer;
150  found_mode: Integer;
151begin
152  { Find exact match }
153  for I := 0 to AScreenSizesNum - 1 do
154    if (AScreenSizes[I].width = ARequestedWidth) and
155       (AScreenSizes[I].height = ARequestedHeight) then
156      exit(I);
157
158  { try to find a mode that matches the width first }
159  for I := 0 to AScreenSizesNum - 1 do
160    if (AScreenSizes[I].width = ARequestedWidth) and
161       (AScreenSizes[I].height >= ARequestedHeight) then
162      exit(I);
163
164  { Next try to match the height }
165  for I := 0 to AScreenSizesNum - 1 do
166    if (AScreenSizes[I].width >= ARequestedWidth) and
167       (AScreenSizes[I].height = ARequestedHeight) then
168      exit(I);
169
170  { Finally, find the mode that is bigger than the requested one and makes }
171  { the least difference }
172  found_mode := -1;
173  min_diff := High(Integer);
174  for I := 0 to AScreenSizesNum - 1 do
175    if (AScreenSizes[I].width >= ARequestedWidth) and
176       (AScreenSizes[I].height >= ARequestedHeight) then
177    begin
178      d_x := Sqr(AScreenSizes[I].width - ARequestedWidth);
179      d_y := Sqr(AScreenSizes[I].height - ARequestedHeight);
180      if (d_x + d_y) < min_diff then
181      begin
182        min_diff := d_x + d_y;
183        found_mode := I;
184      end;
185    end;
186
187  if found_mode <> -1 then
188    exit(found_mode);
189
190  raise TPTCError.Create('Cannot find matching video mode');
191end;
192
193procedure TX11ModesXrandr.SetBestMode(AWidth, AHeight: Integer);
194var
195  ScreenSizes: PXRRScreenSize;
196  ScreenSizesNum: cint;
197  BestMode: Integer;
198  CurrentRotation: TRotation;
199begin
200  CreateScreenConfig;
201  try
202    if not FInMode then
203      SaveCurrentMode;
204
205    ScreenSizes := XRRConfigSizes(FXRRConfig, @ScreenSizesNum);
206
207    BestMode := FindBestMode(ScreenSizes, ScreenSizesNum, AWidth, AHeight);
208    FWidth := ScreenSizes[BestMode].width;
209    FHeight := ScreenSizes[BestMode].height;
210
211    XRRConfigCurrentConfiguration(FXRRConfig, @CurrentRotation);
212
213    X11CheckSuccess(XRRSetScreenConfig(FDisplay, FXRRConfig, FRoot, BestMode,
214                                       CurrentRotation, CurrentTime),
215                    'XRRSetScreenConfig failed');
216
217    FInMode := True;
218  finally
219    DestroyScreenConfig;
220  end;
221end;
222
223procedure TX11ModesXrandr.SaveCurrentMode;
224var
225  SizeIndex: TSizeID;
226  ScreenSizes: PXRRScreenSize;
227  ScreenSizesNum: cint;
228begin
229  LOG('xrandr: saving previous mode');
230
231  SizeIndex := XRRConfigCurrentConfiguration(FXRRConfig, @FSavedMode.Rotation);
232  FSavedMode.Rate := XRRConfigCurrentRate(FXRRConfig);
233
234  ScreenSizes := XRRConfigSizes(FXRRConfig, @ScreenSizesNum);
235  if (SizeIndex < 0) or (SizeIndex >= ScreenSizesNum) then
236    raise TPTCError.Create('XRRConfigCurrentConfiguration returned a size index outside the range of screen sizes');
237  FSavedMode.ScreenSize := ScreenSizes[SizeIndex];
238end;
239
240procedure TX11ModesXrandr.RestorePreviousMode;
241var
242  I: Integer;
243  SizeIndex: cint;
244  ScreenSizes: PXRRScreenSize;
245  ScreenSizesNum: cint;
246begin
247  if not FInMode then
248    exit;
249
250  LOG('xrandr: restoring previous mode');
251
252  CreateScreenConfig;
253  try
254    SizeIndex := -1;
255    ScreenSizes := XRRConfigSizes(FXRRConfig, @ScreenSizesNum);
256    for I := 0 to ScreenSizesNum - 1 do
257      if (ScreenSizes[I].width   = FSavedMode.ScreenSize.width  ) and
258         (ScreenSizes[I].height  = FSavedMode.ScreenSize.height ) and
259         (ScreenSizes[I].mwidth  = FSavedMode.ScreenSize.mwidth ) and
260         (ScreenSizes[I].mheight = FSavedMode.ScreenSize.mheight) then
261      begin
262        SizeIndex := I;
263        Break;
264      end;
265    if SizeIndex = -1 then
266      for I := 0 to ScreenSizesNum - 1 do
267        if (ScreenSizes[I].width  = FSavedMode.ScreenSize.width ) and
268           (ScreenSizes[I].height = FSavedMode.ScreenSize.height) then
269        begin
270          SizeIndex := I;
271          Break;
272        end;
273    if SizeIndex = -1 then
274      raise TPTCError.Create('xrandr: saved mode size not found in size list');
275
276    X11CheckSuccess(XRRSetScreenConfigAndRate(FDisplay,
277                                              FXRRConfig,
278                                              FRoot,
279                                              SizeIndex,
280                                              FSavedMode.Rotation,
281                                              FSavedMode.Rate,
282                                              CurrentTime),
283                    'XRRSetScreenConfigAndRate failed');
284
285    FInMode := False;
286  finally
287    DestroyScreenConfig;
288  end;
289end;
290
291function TX11ModesXrandr.GetWidth: Integer;
292begin
293  Result := FWidth;
294end;
295
296function TX11ModesXrandr.GetHeight: Integer;
297begin
298  Result := FHeight;
299end;
300{$ENDIF ENABLE_X11_EXTENSION_XRANDR}
301
302{$IFDEF ENABLE_X11_EXTENSION_XF86VIDMODE}
303constructor TX11ModesXF86VidMode.Create(ADisplay: PDisplay; AScreen: Integer);
304var
305  dummy1, dummy2: cint;
306begin
307  inherited;
308
309  FSavedMode := nil;
310  FSavedDotClock := 0;
311  FModeList := nil;
312  FModeListCount := 0;
313
314  if not XF86VidModeQueryExtension(FDisplay, @dummy1, @dummy2) then
315    raise TPTCError.Create('VidMode extension not available');
316end;
317
318destructor TX11ModesXF86VidMode.Destroy;
319begin
320  if FSavedMode <> nil then
321  begin
322    RestorePreviousMode;
323    if FSavedMode^.privsize <> 0 then
324      XFree(FSavedMode^.c_private);
325    Dispose(FSavedMode);
326  end;
327
328  if FModeList <> nil then
329    XFree(FModeList);
330
331  inherited Destroy;
332end;
333
334{todo: move the saving of the previous mode to a separate function...}
335procedure TX11ModesXF86VidMode.RetrieveModeList;
336begin
337  { if we have been called before, do nothing }
338  if FModeList <> nil then
339    exit;
340
341  { Save previous mode }
342  New(FSavedMode);
343  FillChar(FSavedMode^, SizeOf(FSavedMode^), 0);
344  XF86VidModeGetModeLine(FDisplay, FScreen, @FSavedDotClock, FSavedMode);
345
346  { Get all available video modes }
347  XF86VidModeGetAllModeLines(FDisplay, FScreen, @FModeListCount, @FModeList);
348end;
349
350procedure TX11ModesXF86VidMode.GetModes(var AModes: TPTCModeList; ACurrentDesktopFormat: IPTCFormat);
351var
352  I: Integer;
353begin
354  RetrieveModeList;
355
356  SetLength(AModes, FModeListCount);
357  for I := 0 to FModeListCount - 1 do
358    AModes[I] := TPTCMode.Create(FModeList[I]^.hdisplay, FModeList[I]^.vdisplay, ACurrentDesktopFormat);
359end;
360
361function TX11ModesXF86VidMode.FindNumberOfBestMode(AWidth, AHeight: Integer): Integer;
362var
363  min_diff: Integer;
364  d_x, d_y: Integer;
365  found_mode: Integer;
366  I: Integer;
367begin
368  { try an exact match }
369  for I := 0 to FModeListCount - 1 do
370    if (FModeList[I]^.hdisplay = AWidth) and (FModeList[I]^.vdisplay = AHeight) then
371      exit(I);
372
373  { try to find a mode that matches the width first }
374  for I := 0 to FModeListCount - 1 do
375    if (FModeList[I]^.hdisplay = AWidth) and (FModeList[I]^.vdisplay >= AHeight) then
376      exit(I);
377
378  { Next try to match the height }
379  for I := 0 to FModeListCount - 1 do
380    if (FModeList[I]^.hdisplay >= AWidth) and (FModeList[I]^.vdisplay = AHeight) then
381      exit(I);
382
383  { Finally, find the mode that is bigger than the requested one and makes }
384  { the least difference }
385  found_mode := -1;
386  min_diff := High(Integer);
387  for I := 0 to FModeListCount - 1 do
388    if (FModeList[I]^.hdisplay >= AWidth) and (FModeList[I]^.vdisplay >= AHeight) then
389    begin
390      d_x := Sqr(FModeList[I]^.hdisplay - AWidth);
391      d_y := Sqr(FModeList[I]^.vdisplay - AHeight);
392      if (d_x + d_y) < min_diff then
393      begin
394        min_diff := d_x + d_y;
395        found_mode := I;
396      end;
397    end;
398
399  if found_mode <> -1 then
400    Result := found_mode
401  else
402    raise TPTCError.Create('Cannot find matching video mode');
403end;
404
405procedure TX11ModesXF86VidMode.SetBestMode(AWidth, AHeight: Integer);
406var
407  BestMode: Integer;
408begin
409  RetrieveModeList;
410
411  BestMode := FindNumberOfBestMode(AWidth, AHeight);
412  if not XF86VidModeSwitchToMode(FDisplay, FScreen, FModeList[BestMode]) then
413    raise TPTCError.Create('Error switching to the requested video mode');
414
415  FWidth := FModeList[BestMode]^.hdisplay;
416  FHeight := FModeList[BestMode]^.vdisplay;
417
418  XWarpPointer(FDisplay, None, RootWindow(FDisplay, FScreen), 0, 0, 0, 0,
419               FWidth div 2,
420               FHeight div 2);
421
422  if not XF86VidModeSetViewPort(FDisplay, FScreen, 0, 0) then
423    raise TPTCError.Create('Error moving the viewport to the upper-left corner');
424end;
425
426procedure TX11ModesXF86VidMode.RestorePreviousMode;
427var
428  ModeInfo: TXF86VidModeModeInfo;
429begin
430  if FSavedMode <> nil then
431  begin
432    {FSavedMode is a TXF86VidModeModeLine, but XF86VidModeSwitchToMode wants a
433                     TXF86VidModeModeInfo :}
434    FillChar(ModeInfo, SizeOf(ModeInfo), 0);
435    ModeInfo.dotclock := FSavedDotClock;
436    ModeInfo.hdisplay := FSavedMode^.hdisplay;
437    ModeInfo.hsyncstart := FSavedMode^.hsyncstart;
438    ModeInfo.hsyncend := FSavedMode^.hsyncend;
439    ModeInfo.htotal := FSavedMode^.htotal;
440    ModeInfo.vdisplay := FSavedMode^.vdisplay;
441    ModeInfo.vsyncstart := FSavedMode^.vsyncstart;
442    ModeInfo.vsyncend := FSavedMode^.vsyncend;
443    ModeInfo.vtotal := FSavedMode^.vtotal;
444    ModeInfo.flags := FSavedMode^.flags;
445    ModeInfo.privsize := FSavedMode^.privsize;
446    ModeInfo.c_private := FSavedMode^.c_private;
447
448    XF86VidModeSwitchToMode(FDisplay, FScreen, @ModeInfo);
449  end;
450end;
451
452function TX11ModesXF86VidMode.GetWidth: Integer;
453begin
454  Result := FWidth;
455end;
456
457function TX11ModesXF86VidMode.GetHeight: Integer;
458begin
459  Result := FHeight;
460end;
461{$ENDIF ENABLE_X11_EXTENSION_XF86VIDMODE}