/[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 391 - (show annotations) (download)
Thu Feb 3 13:54:58 2011 UTC (13 years, 2 months ago) by dmorgan
File size: 11609 byte(s)
Import cleaned drakx-kbd-mouse-x11
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() || ($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 { VendorName => "Plug'n Play" };
28 } else {
29 good_default_monitor() =~ /(.*)\|(.*)/ or internal_error("bad good_default_monitor");
30 { VendorName => $1, ModelName => $2 };
31 }
32 }
33
34 my @VertRefresh_ranges = ("50-70", "50-90", "50-100", "40-150");
35
36 my @HorizSync_ranges = (
37 "31.5",
38 "31.5-35.1",
39 "31.5-37.9",
40 "31.5-48.5",
41 "31.5-57.0",
42 "31.5-64.3",
43 "31.5-79.0",
44 "31.5-82.0",
45 "31.5-88.0",
46 "31.5-94.0",
47 );
48
49 sub configure {
50 my ($in, $raw_X, $nb_monitors, $o_probed_info, $b_auto) = @_;
51
52 my $monitors = [ $raw_X->get_or_new_monitors($nb_monitors) ];
53 if ($o_probed_info) {
54 put_in_hash($monitors->[0], $o_probed_info);
55 }
56 my $head_nb = 1;
57 foreach my $monitor (@$monitors) {
58 choose($in, $raw_X, $monitor, @$monitors > 1 ? $head_nb++ : 0, $b_auto) or return;
59 }
60 $raw_X->set_monitors(@$monitors);
61 $monitors;
62 }
63
64 sub configure_auto_install {
65 my ($raw_X, $old_X) = @_;
66
67 if ($old_X->{monitor}) {
68 #- keep compatibility
69 $old_X->{monitor}{VertRefresh} = $old_X->{monitor}{vsyncrange};
70 $old_X->{monitor}{HorizSync} = $old_X->{monitor}{hsyncrange};
71
72 #- new name
73 $old_X->{monitors} = [ delete $old_X->{monitor} ];
74 }
75
76 my $monitors = [ $raw_X->get_or_new_monitors($old_X->{monitors} ? int @{$old_X->{monitors}} : 1) ];
77 mapn {
78 my ($monitor, $auto_install_monitor) = @_;
79 put_in_hash($monitor, $auto_install_monitor);
80 configure_automatic($monitor);
81 } $monitors, $old_X->{monitors} if $old_X->{monitors};
82
83 my $card_Driver;
84 if (!is_valid($monitors->[0])) {
85 my ($first_card) = Xconfig::card::probe();
86 $card_Driver = $first_card->{Driver} if $first_card;
87 put_in_hash($monitors->[0], probe($card_Driver));
88 }
89
90 foreach my $monitor (@$monitors) {
91 if (!is_valid($monitor)) {
92 put_in_hash($monitor, default_monitor($card_Driver));
93 configure_automatic($monitor) or internal_error("good_default_monitor (" . good_default_monitor() . ") is unknown in MonitorsDB");
94 }
95 }
96 $raw_X->set_monitors(@$monitors);
97 $monitors;
98 }
99
100 sub choose {
101 my ($in, $raw_X, $monitor, $head_nb, $b_auto) = @_;
102
103 my $ok = is_valid($monitor);
104 if ($b_auto && $ok) {
105 return $ok;
106 }
107
108 my (@l_monitors, %h_monitors);
109 foreach (monitors_db()) {
110 my $s = "$_->{VendorName}|$_->{ModelName}";
111 push @l_monitors, $s;
112 $h_monitors{$s} = $_;
113 }
114 $h_monitors{"Plug'n Play"} = {};
115
116 ask_monitor:
117 my $merge_name = sub {
118 my ($monitor) = @_;
119 $monitor->{ModelName} ? $monitor->{VendorName} . '|' . $monitor->{ModelName} : $monitor->{VendorName};
120 };
121 my $merged_name = do {
122 my $merged_name = $merge_name->($monitor);
123 if (!exists $h_monitors{$merged_name}) {
124 $merged_name = is_valid($monitor) ? 'Custom' :
125 $merge_name->(default_monitor($raw_X->get_Driver));
126 }
127 $merged_name;
128 };
129
130 $in->ask_from_({ title => N("_: This is a display device\nMonitor"),
131 messages => $head_nb ? N("Choose a monitor for head #%d", $head_nb) : N("Choose a monitor"),
132 interactive_help_id => 'configureX_monitor'
133 },
134 [ { val => \$merged_name, separator => '|',
135 list => ['Custom', "Plug'n Play", uniq(@l_monitors)],
136 format => sub { $_[0] eq 'Custom' ? N("Custom") :
137 $_[0] eq "Plug'n Play" ? N("Plug'n Play") . ($monitor->{VendorName} eq "Plug'n Play" ? " ($monitor->{ModelName})" : '') :
138 $_[0] =~ /^Generic\|(.*)/ ? N("Generic") . "|$1" :
139 N("Vendor") . "|$_[0]" },
140 sort => !$in->isa('interactive::gtk') } ]) or return;
141
142 if ($merged_name eq "Plug'n Play") {
143 local $::noauto = 0; #- hey, you asked for plug'n play, so i do probe!
144 delete @$monitor{'VendorName', 'ModelName', 'EISA_ID', 'HorizSync', 'VertRefresh'};
145 if ($head_nb <= 1) {
146 if (my $probed_info = probe($raw_X->get_Driver)) {
147 put_in_hash($monitor, $probed_info);
148 } else {
149 log::l("Plug'n Play probing failed, but Xorg may do better");
150 $monitor->{VendorName} = "Plug'n Play";
151 }
152 } else {
153 $monitor->{VendorName} = "Plug'n Play";
154 }
155 } elsif ($merged_name eq 'Custom') {
156 $in->ask_from('',
157 N("The two critical parameters are the vertical refresh rate, which is the rate
158 at which the whole screen is refreshed, and most importantly the horizontal
159 sync rate, which is the rate at which scanlines are displayed.
160
161 It is VERY IMPORTANT that you do not specify a monitor type with a sync range
162 that is beyond the capabilities of your monitor: you may damage your monitor.
163 If in doubt, choose a conservative setting."),
164 [ { val => \$monitor->{HorizSync}, list => \@HorizSync_ranges, label => N("Horizontal refresh rate"), not_edit => 0 },
165 { val => \$monitor->{VertRefresh}, list => \@VertRefresh_ranges, label => N("Vertical refresh rate"), not_edit => 0 } ]) or goto &choose;
166 delete @$monitor{'VendorName', 'ModelName', 'EISA_ID'};
167 } else {
168 put_in_hash($monitor, $h_monitors{$merged_name});
169 }
170 $monitor->{manually_chosen} = 1;
171 1;
172 }
173
174 sub _configure_automatic_LCD {
175 my ($monitor) = @_;
176
177 $monitor->{HorizSync} && $monitor->{VertRefresh} and return;
178
179 $monitor->{preferred_resolution}
180 && Xconfig::xfree::resolution2ratio($monitor->{preferred_resolution}) eq '16/10' or return;
181
182 log::l("no HorizSync nor VertRefresh, using preferred resolution (hopefully this is a flat panel)");
183 add2hash($monitor, generic_flat_panel($monitor->{preferred_resolution}));
184 1;
185 }
186
187 sub configure_automatic {
188 my ($monitor) = @_;
189
190 if ($monitor->{EISA_ID}) {
191 log::l("EISA_ID: $monitor->{EISA_ID}");
192 if (my $mon = find { lc($_->{EISA_ID}) eq $monitor->{EISA_ID} } monitors_db()) {
193 add2hash($monitor, $mon);
194 log::l("EISA_ID corresponds to: $monitor->{ModelName}");
195 } elsif (!$monitor->{HorizSync} || !$monitor->{VertRefresh}) {
196 log::l("unknown EISA_ID and partial DDC probe, so unknown monitor");
197 delete @$monitor{'VendorName', 'ModelName', 'EISA_ID'};
198 }
199 } elsif ($monitor->{VendorName}) {
200 if (my $mon = find { $_->{VendorName} eq $monitor->{VendorName} && $_->{ModelName} eq $monitor->{ModelName} } monitors_db()) {
201 put_in_hash($monitor, $mon);
202 }
203 }
204
205 _configure_automatic_LCD($monitor);
206
207 is_valid($monitor);
208 }
209
210 sub is_valid {
211 my ($monitor) = @_;
212 $monitor->{HorizSync} && $monitor->{VertRefresh} || $monitor->{VendorName} eq "Plug'n Play";
213 }
214
215 sub probe {
216 my ($o_card_Driver) = @_;
217 probe_DDC() || probe_DMI() || probe_using_X($o_card_Driver);
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_using_X {
289 my ($card_Driver) = @_;
290
291 detect_devices::isLaptop() or return;
292
293 $card_Driver ||= do {
294 require Xconfig::card;
295 my @cards = Xconfig::card::probe();
296 $cards[0]{Driver};
297 } or return;
298
299 require modules;
300 my @old_modules = modules::loaded_modules();
301 my $resolution = run_program::rooted_get_stdout($::prefix, 'monitor-probe-using-X', '--perl', $card_Driver);
302 modules::unload(difference2([ modules::loaded_modules() ], \@old_modules));
303
304 $resolution = eval($resolution) or return;
305
306 if (my $res = $resolution->[0]{preferred_resolution}) {
307 generic_flat_panel($res);
308 } else {
309 log::l("at least one EDID was found in Xorg.log, so let Xorg autodetect the monitor");
310 { VendorName => "Plug'n Play" };
311 }
312 }
313
314 sub probe_DMI() {
315 my $res = detect_devices::probe_unique_name('Resolution');
316 $res && generic_flat_panel_txt($res);
317 }
318
319 sub generic_flat_panel {
320 my ($resolution) = @_;
321 generic_flat_panel_($resolution->{X}, $resolution->{Y});
322 }
323 sub generic_flat_panel_txt {
324 my ($resolution) = @_;
325 my ($X, $Y) = $resolution =~ /(\d+)x(\d+)/ or log::l("bad resolution $resolution"), return;
326 generic_flat_panel_($X, $Y);
327 }
328 sub generic_flat_panel_ {
329 my ($X, $Y) = @_;
330 {
331 VendorName => 'Generic',
332 ModelName => "Flat Panel ${X}x${Y}",
333 HorizSync => '28.8-' . ($X > 1920 ? '100' : '90'), VertRefresh => '60',
334 preferred_resolution => { X => $X, Y => $Y },
335 };
336 }
337
338 my $monitors_db;
339 sub monitors_db() {
340 $monitors_db ||= readMonitorsDB("$ENV{SHARE_PATH}/ldetect-lst/MonitorsDB");
341 @$monitors_db;
342 }
343 sub readMonitorsDB {
344 my ($file) = @_;
345
346 my @monitors_db;
347 my $F = openFileMaybeCompressed($file);
348 local $_;
349 my $lineno = 0; while (<$F>) {
350 $lineno++;
351 s/\s+$//;
352 /^#/ and next;
353 /^$/ and next;
354
355 my @fields = qw(VendorName ModelName EISA_ID HorizSync VertRefresh dpms);
356 my %l; @l{@fields} = split /\s*;\s*/;
357 push @monitors_db, \%l;
358 }
359 \@monitors_db;
360 }
361
362
363 1;
364

  ViewVC Help
Powered by ViewVC 1.1.30