File Coverage

blib/lib/Config/Model/Backend/Xorg/Read.pm
Criterion Covered Total %
statement 193 203 95.0
branch 60 72 83.3
condition 9 9 100.0
subroutine 18 18 100.0
pod 0 13 0.0
total 280 315 88.8


line stmt bran cond sub pod time code
1             #
2             # This file is part of Config-Model-Xorg
3             #
4             # This software is Copyright (c) 2007-2018 by Dominique Dumont.
5             #
6             # This is free software, licensed under:
7             #
8             # The GNU Lesser General Public License, Version 2.1, February 1999
9             #
10             package Config::Model::Backend::Xorg::Read ;
11             $Config::Model::Backend::Xorg::Read::VERSION = '1.114';
12 1     1   626 use Mouse::Role;
  1         3  
  1         10  
13              
14 1     1   362 use Carp ;
  1         4  
  1         66  
15 1     1   487 use IO::File ;
  1         2111  
  1         132  
16 1     1   8 use Log::Log4perl;
  1         3  
  1         7  
17 1     1   49 use Data::Dumper ;
  1         12  
  1         3379  
18              
19             my $logger = Log::Log4perl::get_logger('Backend::Xorg::Read');
20              
21             # return a data structure in the form :
22             # hash_ref->array_ref->hash_ref->array_ref
23             #
24             # { section_name => [
25             # # section_a
26             # { element_name => [ [ value_a ] , [ va, lue, _b ] },
27             # ...
28             # # section_b
29             # ...
30             # ],
31             # },
32             # ...
33             sub parse_raw_xorg {
34 10     10 0 26 my $xorg_lines = shift ;
35              
36 10         23 my %data ;
37              
38 10         49 while (@$xorg_lines) {
39 112         197 my $line_data = shift @$xorg_lines ;
40 112         277 my ($line_nb,$line) = @$line_data ;
41 112         421 my ($raw_key,$value) = split /\s+/,$line,2;
42 112         262 my $key = lc($raw_key) ;
43 112 50       279 if ($key eq 'section') {
44             # Section names are insensitive to '_' and ' '
45 112         498 $value =~ s/["_ ]+//g;
46 112         225 push @{$data{lc($value)}},
  112         488  
47             [ $line_nb, parse_raw_section($xorg_lines) ] ;
48             }
49             }
50              
51 10         46 return \%data ;
52             }
53              
54             sub parse_raw_section {
55 143     143 0 255 my $xorg_lines = shift ;
56              
57 143         199 my %data ;
58 143         568 $logger->debug( "parse_raw_section: called on xorg file $xorg_lines->[0][0]");
59              
60 143         1857 while (@$xorg_lines) {
61 803         1317 my $line_data = shift @$xorg_lines ;
62 803         1484 my ($line_nb,$line) = @$line_data ;
63 803         2690 my ($raw_key,$value) = split /\s+/,$line,2;
64              
65 803         1680 my $key = lc($raw_key) ; # keys are case insensitive
66 803         1417 $key =~ s/_+//g; # keys are insensitive to '_'
67              
68 803 100       1982 if ($key =~ /end(sub)?section/) {
    100          
69 143         683 return \%data ;
70             }
71             elsif ($key eq 'subsection') {
72 31         118 $value =~ s/["_ ]//g;
73 31         75 my $store = lc($value) ; # subsection name is case insensitive
74 31         150 $logger->debug("parse_raw_section: SubSection $value $line_nb");
75 31         374 push @{$data{$store}}, [ $line_nb, parse_raw_section($xorg_lines) ];
  31         123  
76             }
77             else {
78 629         1281 my @store = ( $line_nb ) ;
79 629         1528 while (length($value)) {
80 1401 100       4373 if ($value =~ /^"([^"]+)"/) {
    50          
81 817         1902 push @store,$1 ;
82 817         3966 $value =~ s/^"[^"]+"\s*//g;
83             }
84             elsif ($value =~ /^([^"\s]+)/) {
85 584         1319 push @store,$1 ;
86 584         2715 $value =~ s/^([^"\s]+)\s*//g;
87             }
88             else {
89 0         0 die "parse_raw_section: unexpected value $value";
90             }
91              
92             }
93 629         977 push @{$data{$key}}, \@store ;
  629         2770  
94             }
95             }
96             }
97              
98             # Need to update functions beloow
99             sub parse_all {
100 10     10 0 21 my $xorg_conf = shift;
101 10         26 my $root = shift ;
102 10         125 $logger->debug("parse_all: called on ".join(' ', keys %$xorg_conf));
103              
104             # parse section data according to model elements order
105 10         169 foreach my $section_name ($root->get_element_name) {
106 140         239489 my $lc_section_name = lc($section_name) ;
107              
108 140         384 my $section_data_ref = delete $xorg_conf->{$lc_section_name} ;
109 140 100       433 next unless defined $section_data_ref ;
110              
111 74         248 foreach my $section_data (@$section_data_ref) {
112 112         20150 $logger->debug( "parse_all: section '$section_name'");
113 112         1761 parse_section($section_data,$root->fetch_element($section_name)) ;
114             }
115             }
116              
117 10 50       117 if (keys %$xorg_conf) {
118 0         0 die "can't handle section ", join(' ',keys %$xorg_conf),
119             ": Error in input file or Xorg model is incomplete";
120             }
121             }
122              
123             sub parse_option {
124 148     148 0 598 my ($obj, $trash, $line, @args) = @_ ;
125 148         415 my $opt = shift @args;
126 148         861 $logger->debug( "parse_option: called on option $opt $line");
127              
128 148 100 100     3458 if ($obj->config_class_name eq 'Xorg::ServerFlags') {
    100 100        
    100          
    100          
129 6         23 $logger->debug( "parse_option: obj ",$obj->name, " ($line) load option '$opt' ");
130 6         121 my $opt_obj = $obj->fetch_element($opt) ;
131 6 50       418 $opt_obj->store ( @args ? $args[0] : 1 ) ;
132             }
133             elsif ($opt =~ /Core(Keyboard|Pointer)/ ) {
134 14         61 my $id = $obj -> index_value ;
135 14         87 $logger->debug( "parse_option: ($line) Load top level $opt to '$id'");
136 14         247 $obj->load( qq(! $opt="$id") ) ;
137             }
138             elsif ( $obj->config_class_name eq 'Xorg::InputDevice'
139             and $opt eq 'AutoRepeat') {
140 2         11 $logger->debug( "parse_option: obj ",$obj->name, " ($line) load option '$opt' with '",
141             join('+',@args),"' ");
142 2         56 my @v = split / /,$args[0] ;
143 2         13 my $load = sprintf ( "Option AutoRepeat delay=%s rate=%s", @v);
144 2         10 $logger->debug( "parse_option: ",$obj->name," load '$load'");
145 2         41 $obj->load($load) ;
146             }
147             elsif ( $obj->config_class_name eq 'Xorg::InputDevice'
148             and $opt eq 'XkbOptions' ) {
149 2         14 $logger->debug( "parse_option: obj ",$obj->name, " ($line) load option '$opt' with '",
150             join('+',@args),"' ");
151 2         59 my @v = split /:/,$args[0] ;
152 2         19 my $load = sprintf ( "Option XkbOptions %s=%s", @v);
153 2         11 $logger->debug( "parse_option: ",$obj->name," load '$load'");
154 2         43 $obj->load($load) ;
155             }
156             else {
157             # dont' work for ServerFlags
158 124         420 my $opt_p_obj = $obj->fetch_element("Option") ;
159 124         7516 my $opt_obj;
160 124 50       469 if ($opt_p_obj->has_element($opt)) {
    0          
161 124         4178 $logger->debug( "parse_option: obj ",$obj->name, " ($line) load option '$opt' ");
162 124         2895 $opt_obj= $opt_p_obj->fetch_element($opt) ;
163 124 100       213856 $opt_obj->store ( @args ? $args[0] : 1 ) if defined $opt_obj ;
    50          
164             }
165             elsif ($opt_p_obj->instance->get_value_check('fetch_or_store')) {
166 0         0 Config::Model::Exception::UnknownElement
167             -> throw(
168             object => $opt_p_obj,
169             where => $opt_p_obj->location ,
170             element => $opt,
171             );
172             }
173             else {
174 0         0 $logger->warn( "parse_option: obj ",$obj->name, " ($line) option '$opt' is unknown");
175             }
176             }
177             }
178              
179             my %mode_flags = (
180             '+hsync' => "HSyncPolarity=positive",
181             '-hsync' => "HSyncPolarity=negative",
182             '+vsync' => "VSyncPolarity=positive",
183             '-vsync' => "VSyncPolarity=negative",
184             '+csync' => "CSyncPolarity=positive",
185             '-csync' => "CSyncPolarity=negative",
186             );
187              
188             sub parse_mode_line {
189 50     50 0 347 my ($obj, $trash, $line, $mode, @m) = @_ ;
190              
191             # force @v content to be numerical instead of strings
192 50         162 my @v = map { 0 + $_ } splice @m,0,9 ;
  450         950  
193              
194 50         670 my $load = qq!Mode:"$mode" DotClock=$v[0] !;
195 50         285 $load .= "HTimings disp=$v[1] syncstart=$v[2] syncend=$v[3] total=$v[4] - ";
196 50         221 $load .= "VTimings disp=$v[5] syncstart=$v[6] syncend=$v[7] total=$v[8] - ";
197              
198 50 100       205 $load .= "Flags " . join (' ', map {$mode_flags{lc($_)} || "$_=1" } @m ) . ' - '
  18 100       215  
199             if @m ;
200              
201 50         287 $logger->debug( "parse_mode_line: ($line) load '$load'");
202 50         788 $obj->load($load) ;
203             }
204              
205             sub parse_modes_list {
206 28     28 0 177 my ($obj, $trash, $line_nb, @modes) = @_ ;
207              
208 28         173 my $load = 'Modes="'.join('","',@modes).'"';
209 28         186 $logger->debug( "parse_modes_list: ($line_nb)) load '$load'");
210 28         433 $obj->load($load) ;
211             }
212              
213             # called while parsing ServerLayout or Device
214             # key is always 'Screen'
215             sub parse_layout_screen {
216 20     20 0 113 my ($obj, $key, $line, $value, @args) = @_ ;
217              
218 20         50 my $load;
219              
220 20 100       109 if ($obj->config_class_name eq 'Xorg::Device') {
221 8         24 $load = "Screen=$value";
222             }
223             else {
224 12         27 my ($num, $screen_id);
225 12 100       100 if ($value =~ /^(\d+)$/) {
226 10         34 $num = $value ;
227 10         32 $screen_id = shift @args ;
228             }
229             else {
230 2         7 $num = 0;
231 2         8 $screen_id = $value ;
232             }
233              
234 12         57 $load = "Screen:$num screen_id=\"$screen_id\" ";
235              
236 12         70 $logger->debug( "parse_layout_screen: screen load '$load'");
237              
238 12 100       232 if (@args) {
239             # there's a position information
240 8         25 my ($relative_spec, $pos );
241              
242 8 100       66 if ( $args[0] =~ /^\d+$/ ) {
    100          
    50          
243 3         10 $pos = 'Absolute' ;
244 3         26 $relative_spec = sprintf("x=%s y=%s",@args) ;
245             }
246             elsif ($args[0] eq 'Absolute') {
247 3         10 $pos = shift @args ;
248 3         27 $relative_spec = sprintf("x=%s y=%s",@args) ;
249             }
250             elsif ($args[0] eq 'Relative') {
251 0         0 $pos = shift @args ;
252 0         0 $relative_spec = sprintf("screen_id=\"%s\" x=%s y=%s",@args) ;
253             }
254             else {
255 2         7 $pos = shift @args;
256 2         17 $relative_spec = sprintf("screen_id=\"%s\"",@args) ;
257             }
258 8         45 $load .= "position relative_screen_location=$pos $relative_spec ";
259             }
260 12         65 $logger->debug( "parse_layout_screen: Screen ($line) load '$load' ");
261             }
262              
263 20         257 $logger->debug( "parse_layout_screen:", $obj->config_class_name," load '$load'");
264 20         300 $obj->load($load) ;
265             }
266              
267             # called when parsing section ServerLayout
268             sub parse_input_device {
269 24     24 0 85 my ($obj, $trash, $line ,$id, @opt) = @_ ;
270              
271 24         164 $logger->debug( "$trash id:'$id' option '".join("' '",@opt)."'");
272              
273 24         350 my $dev = $obj->fetch_element('InputDevice') -> fetch_with_id($id) ;
274              
275 24         27815 foreach my $opt (@opt) {
276 3 50       41 if ($opt eq 'SendCoreEvents') {
    50          
277 0         0 $dev->fetch_element($opt)->store(1) ;
278             }
279             elsif ($opt =~ /Core(Keyboard|Pointer)/) {
280 3         27 $logger->debug( "parse_input_device: Load '! $opt=\"$id\"'");
281 3         60 $obj->load("! $opt=\"$id\"") ;
282             }
283             else {
284 0         0 die "parse_input_device ($line): Unexpected ServerLayout->InputDevice ",
285             "option: $opt. Error in input file or Xorg model is incomplete";
286             }
287             }
288             }
289              
290             sub parse_display_size {
291 4     4 0 19 my ($obj, $tag_name, $line ,$w, $h) = @_ ;
292 4         28 $logger->debug( "$tag_name width:'$w' height:$h");
293 4         67 my $load = "DisplaySize width=$w height=$h";
294 4         33 $logger->debug( $obj->config_class_name," load '$load'");
295 4         59 $obj->load($load) ;
296             }
297              
298             sub parse_view_port {
299 2     2 0 12 my ($obj, $tag_name, $line ,$x0, $y0) = @_ ;
300 2         15 $logger->debug( "$tag_name x0:'$x0' y0:$y0");
301 2         30 my $load = "ViewPort x0=$x0 y0=$y0";
302 2         18 $logger->debug( $obj->config_class_name," load '$load'");
303 2         28 $obj->load($load) ;
304             }
305              
306             sub parse_virtual {
307 4     4 0 25 my ($obj, $tag_name, $line ,$xdim, $ydim) = @_ ;
308 4         30 $logger->debug( "$tag_name xdim:'$xdim' ydim:$ydim");
309 4         61 my $load = "Virtual xdim=$xdim ydim=$ydim";
310 4         43 $logger->debug( $obj->config_class_name," load '$load'");
311 4         68 $obj->load($load) ;
312             }
313              
314             sub parse_gamma {
315 4     4 0 28 my ($obj, $tag_name, $line ,@g) = @_ ;
316 4         29 $logger->debug( "$tag_name @g");
317 4 100       61 my $global = @g == 1 ? 1 : 0 ;
318 4         18 my $load = "Gamma use_global_gamma=$global ";
319 4 100       41 $load .= $global ? "gamma=$g[0]"
320             : sprintf("red_gamma=%s green_gamma=%s blue_gamma=%s",@g) ;
321 4         32 $logger->debug( $obj->config_class_name," load '$load'");
322 4         62 $obj->load($load) ;
323             }
324              
325             my %parse_line = (
326             'fontpath' => sub { $_[0]->fetch_element($_[1])->push($_[3]) ;} ,
327             'load' => sub { $_[0]->fetch_element($_[3])->store(1) ;} ,
328             'modeline' => \&parse_mode_line,
329             'option' => \&parse_option ,
330             'modes' => \&parse_modes_list,
331             'screen' => \&parse_layout_screen,
332             'inputdevice' => \&parse_input_device,
333             'displaysize' => \&parse_display_size ,
334             'viewport' => \&parse_view_port ,
335             'virtual' => \&parse_virtual ,
336             'gamma' => \&parse_gamma ,
337             ) ;
338              
339             sub parse_section {
340 143     143 0 8999 my $section_line_data = shift ; # [ line_nb, hash ref ]
341 143         307 my $obj = shift ;
342              
343 143         426 my ($sect_line_nb, $section_data) = @$section_line_data ;
344              
345             # section like InputDevice have an identifier which must be extracted first
346 143         693 my $obj_type = $obj->get_type ;
347 143 100       1702 my $has_id = $obj_type =~ /list|hash/ ? 1 : 0 ;
348 143         299 my $tmp_obj = $obj ;
349              
350 143         723 $logger->debug( "parse_section ($sect_line_nb) called on ",
351             $obj->name," (has_id: $has_id)");
352              
353             # first get the identifier and create the object.
354 143 100       4546 if ($has_id) {
355             my $id_rr = delete $section_data->{identifier}
356 117   100     688 || delete $section_data->{depth} ;
357 117 100       423 if (not defined $id_rr) {
358 1         4 $logger->debug( "parse_section can't find identifier for ",$obj->name );
359 1         25 return ;
360             }
361              
362 116         234 my ($line,$id) = @{$id_rr->[0]} ;
  116         457  
363 116         604 $logger->debug( "parse_section $line: found id '$id' for '",
364             $obj->name,"'");
365 116         2920 $tmp_obj = $obj->fetch_with_id($id) ;
366             }
367              
368             # parse special cases and section data according to model elements order
369             # special case: modeline must be parsed first
370 142         146545 foreach my $elt_name ('modeline',$tmp_obj->get_element_name) {
371 1052         4283118 my $lc_name = lc($elt_name) ;
372 1052         2300 my $a2_r = delete $section_data->{$lc_name}; # array of array ref ;
373              
374 1052 100       2561 next unless defined $a2_r ;
375              
376 226         1368 $logger->debug( "parse_section: parse section data key '$lc_name'");
377              
378 226         2995 foreach my $arg (@$a2_r) {
379 348 100       875529 if (defined $parse_line{$lc_name}) {
    100          
380 203         876 $parse_line{$lc_name} -> ($tmp_obj, $elt_name, @$arg) ;
381             }
382             elsif (ref $arg->[1] eq 'HASH') {
383             # we have a subsection
384 31         161 $logger->debug( $tmp_obj->name, " subsection $elt_name ");
385 31         708 parse_section($arg,$tmp_obj->fetch_element($elt_name)) ;
386             }
387             else {
388 114         332 my $line = shift @$arg ;
389 114         377 my $val = "@$arg" ;
390 114         379 $logger->debug( $tmp_obj->name,
391             " ($line) store $elt_name = '$val'");
392 114         2418 $tmp_obj->fetch_element($elt_name)->store($val);
393             }
394             }
395             }
396              
397 142 100       20574 if ( %$section_data ) {
398 45         233 foreach my $lc_name (keys %$section_data) {
399 45 50       229 if (defined $parse_line{$lc_name}) {
400 45         167 my $a2_r = delete $section_data->{$lc_name};
401 45         133 foreach my $arg (@$a2_r) {
402 195         196469 $parse_line{$lc_name} -> ($tmp_obj, $lc_name, @$arg) ;
403             }
404             }
405             else {
406 0           $logger->warn( "parse_section: unexpected '$lc_name' "
407             ."element for ", $tmp_obj->name) ;
408 0           die ;
409             }
410             }
411             }
412             }
413              
414             1;