/[soft]/drakx-kbd-mouse-x11/trunk/lib/Xconfig/monitor.pm
ViewVC logotype

Contents of /drakx-kbd-mouse-x11/trunk/lib/Xconfig/monitor.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3720 - (show annotations) (download)
Sat Mar 24 06:29:49 2012 UTC (12 years, 1 month ago) by tv
File size: 10862 byte(s)
perl_checker cleanups
1 package Xconfig::monitor; #- $Id: monitor.pm 261588 2009-10-08 17:02:40Z blino $
2
3 use diagnostics;
4 use strict;
5
6 use Xconfig::xfree;
7 use detect_devices;
8 use common;
9 use any;
10 use log;
11
12
13 sub good_default_monitor() {
14 detect_devices::is_xbox() ? 'Generic|640x480 @ 60 Hz' :
15 arch() =~ /ppc/ ?
16 (detect_devices::get_mac_model() =~ /^iBook/ ? 'Apple|iBook 800x600' : 'Apple|iMac/PowerBook 1024x768') :
17 (detect_devices::isLaptop() ? 'Generic|Flat Panel 1024x768' : 'Generic|1024x768 @ 60 Hz');
18 }
19
20 sub default_monitor {
21 my ($card_Driver) = @_;
22 if (detect_devices::is_virtualbox() || detect_devices::isLaptop() || $card_Driver eq 'siliconmotion' && arch() =~ /mips/) {
23 # HACK: since there is no way to get the EDID on gdium, the resolution is passed to the kernel
24 # so we can rely on it
25 # in vbox, we return Plug'n'Play because the vbox integration addons
26 # will take care of everything for us
27 # On laptops the X server should usually be able to autodetect everything.
28 { VendorName => "Plug'n Play" };
29 } else {
30 good_default_monitor() =~ /(.*)\|(.*)/ or internal_error("bad good_default_monitor");
31 { VendorName => $1, ModelName => $2 };
32 }
33 }
34
35 my @VertRefresh_ranges = ("50-70", "50-90", "50-100", "40-150");
36
37 my @HorizSync_ranges = (
38 "31.5",
39 "31.5-35.1",
40 "31.5-37.9",
41 "31.5-48.5",
42 "31.5-57.0",
43 "31.5-64.3",
44 "31.5-79.0",
45 "31.5-82.0",
46 "31.5-88.0",
47 "31.5-94.0",
48 );
49
50 sub configure {
51 my ($in, $raw_X, $nb_monitors, $o_probed_info, $b_auto) = @_;
52
53 my $monitors = [ $raw_X->get_or_new_monitors($nb_monitors) ];
54 if ($o_probed_info) {
55 put_in_hash($monitors->[0], $o_probed_info);
56 }
57 my $head_nb = 1;
58 foreach my $monitor (@$monitors) {
59 choose($in, $raw_X, $monitor, @$monitors > 1 ? $head_nb++ : 0, $b_auto) or return;
60 }
61 $raw_X->set_monitors(@$monitors);
62 $monitors;
63 }
64
65 sub configure_auto_install {
66 my ($raw_X, $old_X) = @_;
67
68 if ($old_X->{monitor}) {
69 #- keep compatibility
70 $old_X->{monitor}{VertRefresh} = $old_X->{monitor}{vsyncrange};
71 $old_X->{monitor}{HorizSync} = $old_X->{monitor}{hsyncrange};
72
73 #- new name
74 $old_X->{monitors} = [ delete $old_X->{monitor} ];
75 }
76
77 my $monitors = [ $raw_X->get_or_new_monitors($old_X->{monitors} ? int @{$old_X->{monitors}} : 1) ];
78 mapn {
79 my ($monitor, $auto_install_monitor) = @_;
80 put_in_hash($monitor, $auto_install_monitor);
81 configure_automatic($monitor);
82 } $monitors, $old_X->{monitors} if $old_X->{monitors};
83
84 my $card_Driver;
85 if (!is_valid($monitors->[0])) {
86 my ($first_card) = Xconfig::card::probe();
87 $card_Driver = $first_card->{Driver} if $first_card;
88 put_in_hash($monitors->[0], probe());
89 }
90
91 foreach my $monitor (@$monitors) {
92 if (!is_valid($monitor)) {
93 put_in_hash($monitor, default_monitor($card_Driver));
94 configure_automatic($monitor) or internal_error("good_default_monitor (" . good_default_monitor() . ") is unknown in MonitorsDB");
95 }
96 }
97 $raw_X->set_monitors(@$monitors);
98 $monitors;
99 }
100
101 sub choose {
102 my ($in, $raw_X, $monitor, $head_nb, $b_auto) = @_;
103
104 my $ok = is_valid($monitor);
105 if ($b_auto && $ok) {
106 return $ok;
107 }
108
109 my (@l_monitors, %h_monitors);
110 foreach (monitors_db()) {
111 my $s = "$_->{VendorName}|$_->{ModelName}";
112 push @l_monitors, $s;
113 $h_monitors{$s} = $_;
114 }
115 $h_monitors{"Plug'n Play"} = {};
116
117 ask_monitor:
118 my $merge_name = sub {
119 my ($monitor) = @_;
120 $monitor->{ModelName} ? $monitor->{VendorName} . '|' . $monitor->{ModelName} : $monitor->{VendorName};
121 };
122 my $merged_name = do {
123 my $merged_name = $merge_name->($monitor);
124 if (!exists $h_monitors{$merged_name}) {
125 $merged_name = is_valid($monitor) ? 'Custom' :
126 $merge_name->(default_monitor($raw_X->get_Driver));
127 }
128 $merged_name;
129 };
130
131 $in->ask_from_({ title => N("_: This is a display device\nMonitor"),
132 messages => $head_nb ? N("Choose a monitor for head #%d", $head_nb) : N("Choose a monitor"),
133 interactive_help_id => 'configureX_monitor'
134 },
135 [ { val => \$merged_name, separator => '|',
136 list => ['Custom', "Plug'n Play", uniq(@l_monitors)],
137 format => sub { $_[0] eq 'Custom' ? N("Custom") :
138 $_[0] eq "Plug'n Play" ? N("Plug'n Play") . ($monitor->{VendorName} eq "Plug'n Play" ? " ($monitor->{ModelName})" : '') :
139 $_[0] =~ /^Generic\|(.*)/ ? N("Generic") . "|$1" :
140 N("Vendor") . "|$_[0]" },
141 sort => !$in->isa('interactive::gtk') } ]) or return;
142
143 if ($merged_name eq "Plug'n Play") {
144 local $::noauto = 0; #- hey, you asked for plug'n play, so i do probe!
145 delete @$monitor{'VendorName', 'ModelName', 'EISA_ID', 'HorizSync', 'VertRefresh'};
146 if ($head_nb <= 1) {
147 if (my $probed_info = probe()) {
148 put_in_hash($monitor, $probed_info);
149 } else {
150 log::l("Plug'n Play probing failed, but Xorg may do better");
151 $monitor->{VendorName} = "Plug'n Play";
152 }
153 } else {
154 $monitor->{VendorName} = "Plug'n Play";
155 }
156 } elsif ($merged_name eq 'Custom') {
157 $in->ask_from('',
158 N("The two critical parameters are the vertical refresh rate, which is the rate
159 at which the whole screen is refreshed, and most importantly the horizontal
160 sync rate, which is the rate at which scanlines are displayed.
161
162 It is VERY IMPORTANT that you do not specify a monitor type with a sync range
163 that is beyond the capabilities of your monitor: you may damage your monitor.
164 If in doubt, choose a conservative setting."),
165 [ { val => \$monitor->{HorizSync}, list => \@HorizSync_ranges, label => N("Horizontal refresh rate"), not_edit => 0 },
166 { val => \$monitor->{VertRefresh}, list => \@VertRefresh_ranges, label => N("Vertical refresh rate"), not_edit => 0 } ]) or goto &choose;
167 delete @$monitor{'VendorName', 'ModelName', 'EISA_ID'};
168 } else {
169 put_in_hash($monitor, $h_monitors{$merged_name});
170 }
171 $monitor->{manually_chosen} = 1;
172 1;
173 }
174
175 sub _configure_automatic_LCD {
176 my ($monitor) = @_;
177
178 $monitor->{HorizSync} && $monitor->{VertRefresh} and return;
179
180 $monitor->{preferred_resolution}
181 && Xconfig::xfree::resolution2ratio($monitor->{preferred_resolution}) eq '16/10' or return;
182
183 log::l("no HorizSync nor VertRefresh, using preferred resolution (hopefully this is a flat panel)");
184 add2hash($monitor, generic_flat_panel($monitor->{preferred_resolution}));
185 1;
186 }
187
188 sub configure_automatic {
189 my ($monitor) = @_;
190
191 if ($monitor->{EISA_ID}) {
192 log::l("EISA_ID: $monitor->{EISA_ID}");
193 if (my $mon = find { lc($_->{EISA_ID}) eq $monitor->{EISA_ID} } monitors_db()) {
194 add2hash($monitor, $mon);
195 log::l("EISA_ID corresponds to: $monitor->{ModelName}");
196 } elsif (!$monitor->{HorizSync} || !$monitor->{VertRefresh}) {
197 log::l("unknown EISA_ID and partial DDC probe, so unknown monitor");
198 delete @$monitor{'VendorName', 'ModelName', 'EISA_ID'};
199 }
200 } elsif ($monitor->{VendorName}) {
201 if (my $mon = find { $_->{VendorName} eq $monitor->{VendorName} && $_->{ModelName} eq $monitor->{ModelName} } monitors_db()) {
202 put_in_hash($monitor, $mon);
203 }
204 }
205
206 _configure_automatic_LCD($monitor);
207
208 is_valid($monitor);
209 }
210
211 sub is_valid {
212 my ($monitor) = @_;
213 $monitor->{HorizSync} && $monitor->{VertRefresh} || $monitor->{VendorName} eq "Plug'n Play";
214 }
215
216 sub probe() {
217 probe_DDC() || probe_DMI();
218 }
219
220 #- some EDID are much too strict:
221 #- the HorizSync range is too small to allow smaller resolutions
222 sub adjust_HorizSync_from_edid {
223 my ($monitor) = @_;
224
225 my ($hmin, $hmax) = $monitor->{HorizSync} =~ /(\d+)-(\d+)/ or return;
226 if ($hmin > 45) {
227 log::l("replacing HorizSync $hmin-$hmax with 28.8-$hmax (allow 800x480)");
228 $monitor->{HorizSync} = "28.8-$hmax";
229 }
230 }
231 #- the VertRefresh range is too weird
232 sub adjust_VertRefresh_from_edid {
233 my ($monitor) = @_;
234
235 my ($vmin, $vmax) = $monitor->{VertRefresh} =~ /(\d+)-(\d+)/ or return;
236 if ($vmin > 60) {
237 log::l("replacing VertRefresh $vmin-$vmax with 60-$vmax");
238 $monitor->{VertRefresh} = "60-$vmax";
239 }
240 }
241
242 sub probe_DDC() {
243 my ($edid, $vbe) = any::monitor_full_edid() or return;
244 my $monitor = eval($edid);
245
246 if ($vbe =~ /Memory: (\d+)k/) {
247 $monitor->{VideoRam_probed} = $1;
248 }
249 use_EDID($monitor);
250 }
251
252 sub use_EDID {
253 my ($monitor) = @_;
254
255 adjust_HorizSync_from_edid($monitor);
256 adjust_VertRefresh_from_edid($monitor);
257
258 $monitor->{ModeLine} = Xconfig::xfree::default_ModeLine();
259 my $detailed_timings = $monitor->{detailed_timings} || [];
260 my @different_timings = uniq_ { $_->{horizontal_active} . 'x' . $_->{vertical_active} } @$detailed_timings;
261 foreach (grep { !$_->{bad_ratio} } @$detailed_timings) {
262 if (Xconfig::xfree::xorg_builtin_resolution($_->{horizontal_active}, $_->{vertical_active})) {
263 #- we don't want the 4/3 modelines otherwise they conflict with the Xorg builtin vesamodes
264 } else {
265 unshift @{$monitor->{ModeLine}},
266 { val => $_->{ModeLine}, pre_comment => $_->{ModeLine_comment} . "\n" };
267 }
268
269 if (@different_timings == 1 && $_->{horizontal_active} >= 1024) {
270 #- we don't use detailed_timing when it is 640x480 or 800x600,
271 #- since 14" CRTs often give this even when they handle 1024x768 correctly (and desktop is no good in poor resolutions)
272
273 #- should we care about {has_preferred_timing} ?
274 $monitor->{preferred_resolution} = { X => $_->{horizontal_active}, Y => $_->{vertical_active} };
275 }
276 }
277
278 if ($monitor->{EISA_ID}) {
279 $monitor->{VendorName} = "Plug'n Play";
280 $monitor->{ModelName} = $monitor->{monitor_name};
281 $monitor->{ModelName} =~ s/"/''/g;
282 $monitor->{ModelName} =~ s/[\0-\x20]/ /g;
283 }
284 configure_automatic($monitor) or return;
285 $monitor;
286 }
287
288 sub probe_DMI() {
289 my $res = detect_devices::probe_unique_name('Resolution');
290 $res && generic_flat_panel_txt($res);
291 }
292
293 sub generic_flat_panel {
294 my ($resolution) = @_;
295 generic_flat_panel_($resolution->{X}, $resolution->{Y});
296 }
297 sub generic_flat_panel_txt {
298 my ($resolution) = @_;
299 my ($X, $Y) = $resolution =~ /(\d+)x(\d+)/ or log::l("bad resolution $resolution"), return;
300 generic_flat_panel_($X, $Y);
301 }
302 sub generic_flat_panel_ {
303 my ($X, $Y) = @_;
304 {
305 VendorName => 'Generic',
306 ModelName => "Flat Panel ${X}x${Y}",
307 HorizSync => '28.8-' . ($X > 1920 ? '100' : '90'), VertRefresh => '60',
308 preferred_resolution => { X => $X, Y => $Y },
309 };
310 }
311
312 my $monitors_db;
313 sub monitors_db() {
314 $monitors_db ||= readMonitorsDB("$ENV{SHARE_PATH}/ldetect-lst/MonitorsDB");
315 @$monitors_db;
316 }
317 sub readMonitorsDB {
318 my ($file) = @_;
319
320 my @monitors_db;
321 my $F = openFileMaybeCompressed($file);
322 local $_;
323 my $lineno = 0; while (<$F>) {
324 $lineno++;
325 s/\s+$//;
326 /^#/ and next;
327 /^$/ and next;
328
329 my @fields = qw(VendorName ModelName EISA_ID HorizSync VertRefresh dpms);
330 my %l; @l{@fields} = split /\s*;\s*/;
331 push @monitors_db, \%l;
332 }
333 \@monitors_db;
334 }
335
336
337 1;
338

  ViewVC Help
Powered by ViewVC 1.1.30