/[soft]/control-center/trunk/control-center
ViewVC logotype

Contents of /control-center/trunk/control-center

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1079 - (show annotations) (download)
Tue May 3 13:23:38 2011 UTC (12 years, 11 months ago) by obgr_seneca
File size: 58756 byte(s)
- fixed typo (Bug #959)
- corrected pot file so it will pass msgfmt -c

1 #!/usr/bin/perl
2 # $Id: control-center 269021 2010-05-19 16:37:57Z eugeni $
3
4 # Copyright (C) 1999-2008 Mandriva
5 # Daouda Lo
6 # Damien Krotkine
7 # Thierry Vignaud <tvignaud@mandriva.com>
8 # Yves Duret
9 #
10 # This program is free software; you can redistribute it and/or modify it under
11 # the terms of the GNU General Public License as published by the Free Software
12 # Foundation; either version 2, or (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program; if not, write to the Free Software
21 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23
24 use strict;
25 use diagnostics;
26 use lib qw(/usr/lib/libDrakX);
27 use c;
28 use standalone;
29 use common;
30 use detect_devices;
31 use lang;
32
33 # i18n: IMPORTANT: to get correct namespace (drakconf instead of libDrakX)
34 BEGIN { unshift @::textdomains, 'drakconf' }
35 use mygtk2 qw(gtknew);
36 use ugtk2 qw(:create :dialogs :helpers :wrappers);
37 use Gtk2::WebKit;
38
39 use MDV::Control_Center;
40
41
42 my (%tool_pids, %tool_feedback, $gurpmi_pid);
43
44 my ($conffile, $class_install) = ('/etc/mcc.conf', '/etc/sysconfig/system');
45
46 my ($rootwin_width, $rootwin_height) = gtkroot()->get_size;
47 my $default_width = $rootwin_width <= 800 ? 720 : 800;
48 my $default_height = $rootwin_height <= 480 ? 420 : $rootwin_height <= 600 ? 523 : 600;
49
50 my $min_width = $rootwin_width == 640 ? 620 : 680;
51 my $min_height = $rootwin_height == 480 ? 420 : 500;
52
53 require_root_capability() if !$::testing; # just to get root capabilities
54
55
56 #-------------------------------------------------------------
57 # read configuration, set themes, ...
58 my %h = getVarsFromSh($conffile);
59 my %class = getVarsFromSh($class_install);
60 $h{THEME} ||= 'default';
61 $h{LOGS} ||= bool2text($class{CLASS} eq 'expert' ? 1 : 0);
62 $h{EXPERT_WIZARD} ||= 0;
63 $h{HEIGTH} ||= $default_height;
64 $h{WIDTH} ||= $default_width;
65
66 my %option_values;
67 $option_values{show_log} = text2bool($h{LOGS});
68 my $theme = $h{THEME};
69 my $program;
70 my ($i, $geometry, $save_html);
71 foreach (@ARGV) {
72 $i++;
73 $theme = $1 if /--theme (\w+)/;
74 $program = $1 if /--start-with=(.*)/;
75 if (/^--geometry$/) {
76 $geometry = splice @ARGV, $i, 1;
77 last;
78 }
79 $save_html = 1 if /--save-html-pages/;
80 }
81
82 -d "$themes_dir/$theme" or $theme = 'default';
83 add_icon_path("$themes_dir/$theme/");
84 add_icon_path("$themes_dir/default") if $theme ne 'default'; # fall back if theme miss some icons
85
86 mygtk2::import_style_ressources();
87 my $rc = find { -r $_ } ("$themes_dir/$theme/gtkrc", if_($theme ne 'default', "$themes_dir/default/gtkrc"));
88 Gtk2::Rc->parse($rc) if -r $rc;
89
90 my $branding = N("Mageia");
91 my $product_id = common::parse_LDAP_namespace_structure(cat_('/etc/product.id'));
92 # allow OEM branding:
93 $branding = translate($product_id->{distribution});
94
95
96 #-------------------------------------------------------------
97 # Splash window: please wait ...
98 my $window_splash = Gtk2::Window->new('popup');
99 $window_splash->signal_connect(delete_event => \&quit_global);
100 $window_splash->set_title(N("%s Control Center", $branding));
101 $window_splash->set_position('center_always');
102 $window_splash->add(gtknew('Fixed', widget_name => 'Steps',
103 children => [
104 [ gtknew('Image_using_pixbuf', file => 'splash_screen'), 0, 0 ],
105 [ gtknew('Label', text => N("%s Control Center", $branding)), 21, 60 ],
106 [ gtknew('Label', text => N("Loading... Please wait")), 21, 175 ],
107 ]),
108 );
109 $window_splash->show_all;
110 gtkflush();
111
112
113 #-------------------------------------------------------------
114 # Data structures
115 my $more_wizard_dir = "/etc/wizard.d/";
116
117 my $isWiz = -e "/usr/sbin/drakwizard";
118 my $isRpmDrake = -e "/usr/sbin/rpmdrake";
119 my $isParkRpmDrake = -e "/usr/sbin/park-rpmdrake";
120 my $isWebAdmin = -e "/usr/bin/mdkwebadmin";
121 my $isRfbDrake = -e "/usr/bin/rfbdrake";
122 my $isDrakStats = -e "/usr/sbin/drakstats";
123
124 my $application_driven_menu;
125
126 sub is_wizard_installed { -f top(glob("/usr/lib/perl5/vendor_perl/*/MDK/Wizard/$_[0]")) }
127
128 my $is_auth_wizard_installed = is_wizard_installed('Nisautofs.pm');
129
130
131 sub wizard_format {
132 map {
133 my ($id, $wizard, $icon, $description, $long_description, $file) = @$_;
134 $programs{$id} =
135 {
136 binary => "$sbindir/drakwizard $wizard",
137 embedded => 1,
138 description => $description,
139 long_description => $long_description,
140 icon => $icon,
141 };
142 if_(is_wizard_installed($file), $id);
143 } @_;
144 }
145
146 # [ [ class_label, class icon name, [ program_label, ... ] ]
147 my @tree = (
148 if_($isRpmDrake || $isParkRpmDrake,
149 [
150 #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
151 N("Software Management"), 'software', 'software-management',
152 [
153 if_($isRpmDrake,
154 {
155 title => N("Software Management"),
156 list => [
157 "Install Software",
158 "Mageia Update",
159 if_(0, "Mageia Online"),
160 "Updates Configuration",
161 "Software Media Manager",
162 ]
163 },
164 ),
165 {
166 title => N("Others"),
167 list => [
168 if_($isParkRpmDrake, "Manage park"),
169 if_($isDrakStats, "Package stats"),
170 ]
171 },
172 ]
173 ]
174 ),
175
176 if_(0, [ N("Server wizards"), 'wizard-mdk' ]),
177 [
178 #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
179 N("Sharing"), 'file-sharing-mdk', 'wiz-client',
180 [
181 {
182 title => N("Sharing"),
183 list => [
184 (wizard_format( # [ id, wizard file name, icon, description ]
185 [ "FTP wizard", "proftpd", 'ftp-mdk', N("Configure FTP"),
186 N("Set up an FTP server"), 'Proftpd.pm',
187 ],
188 [ "Samba wizard", "samba", 'samba_server-mdk', N("Configure Samba"),
189 N("Set up a file and print server for workstations running Linux and non-Linux systems"), 'Samba.pm',
190 ],
191 [ "Manage Samba share", "sambashare", 'wizard-mdk', N("Manage Samba share"),
192 N("Manage, create special share, create public/user share"), 'Sambashare.pm', 1,
193 ],
194 [ "Web wizard", "apache2", 'web_server-mdk', N("Configure web server"),
195 N("Set up a web server"), 'Apache.pm',
196 ],
197 [ "Installation server wizard", "installsrv", 'wizard-mdk', N("Configure installation server"),
198 N("Set up server for network installations of %s", $branding), 'Installsrv.pm', 1,
199 ],
200 ),
201 ),
202 ]
203 },
204 ]
205 ],
206 [
207 #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
208 N("Network Services"), 'network-services-mdk', 'mcc-network',
209 [
210 {
211 title => N("Network Services"),
212 list => [
213 (wizard_format( # [ id, wizard file name, icon, description ]
214 [ "DHCP wizard", "dhcp", 'dhcp_server-mdk', N("Configure DHCP"),
215 N("Set up a DHCP server"), 'Dhcp.pm',
216 ],
217 [ "DNS wizard", "bind", 'dns_server-mdk', N("Configure DNS"),
218 N("Set up a DNS server (network name resolution)"), 'Bind.pm',
219 ],
220 [ "Squid wizard", "squid", 'drakproxy-mdk', N("Configure proxy"),
221 N("Configure a web caching proxy server"), 'Squid.pm',
222 ],
223 [ "Time wizard", "ntp", 'ntp_server-mdk', N("Configure time"),
224 N("Set the time of the server to be synchronized with an external time server"), 'Ntp.pm',
225 ],
226 [ "SSHD wizard", "sshd", 'wizard-sshd', N("OpenSSH daemon configuration"),
227 N("OpenSSH daemon configuration"), 'Sshd.pm',
228 ],
229 ),
230 ),
231 ]
232 },
233 ]
234 ],
235
236 [
237 #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
238 N("Authentication"), 'drakauth-mdk', '',
239 [
240 {
241 title => N("Authentication"),
242 list => [
243 if_($is_auth_wizard_installed, "Authentication"),
244 (wizard_format( # [ id, wizard file name, icon, description ]
245 [ 'Nis+autofs wizard', "nisautofs", 'nisautofs', N("Configure NIS and Autofs"),
246 N("Configure the NIS and Autofs services"), 'Nisautofs.pm',
247 ],
248 [ "LDAP wizard", "ldap", "ldap-mdk", N("Configure LDAP"),
249 N("Configure the LDAP directory services"), 'Ldap.pm',
250 ],
251 ),
252 ),
253 ]
254 },
255 ]
256 ],
257
258 [
259 #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
260 N("Groupware"), 'groupware-mdk', '',
261 [
262 {
263 title => N("Groupware"),
264 list => [
265 (wizard_format( # [ id, wizard file name, icon, description ]
266 if_(0, [ "News wizard", "inn", 'news-mdk', N("Configure news"),
267 N("Configure a newsgroup server"), 'Inn.pm',
268 ],
269 [ "Kolab wizard", "kolab", "kolab-mdk", N("Configure groupware"),
270 N("Configure a groupware server"), 'Kolab.pm',
271 ]),
272 [ "Postfix wizard", "postfix", 'postfix-mdk', N("Configure mail"),
273 N("Configure the Internet Mail services"), 'Postfix.pm'
274 ],
275 ),
276 ),
277 ]
278 },
279 ]
280 ],
281
282 if_($isWebAdmin || $isRfbDrake,
283 [
284 #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
285 N("Online Administration"), 'online-administration-mdk', '',
286 [
287 {
288 title => N("Online Administration"),
289 list => [
290 if_($isWebAdmin,
291 (map {
292 my ($id, $icon, $op, $description, $long_description) = @$_;
293 $programs{$id} =
294 {
295 binary => "$bindir/mdkwebadmin.pl $op",
296 embedded => -1, # too big
297 description => $description,
298 long_description => $long_description,
299 icon => $icon,
300 };
301
302 $id;
303 } ( # [ id, wizard file name, icon, description ]
304 [ "Local Admin", 'local-administration-mdk', '--direct', N("Local administration"),
305 (-e "/usr/bin/webmin" ? N("Configure the local machine via web interface") : N("You don't seem to have webmin installed. Local config is disabled"))
306 ],
307 [ "Remote Admin", 'remote-administration-mdk', '--link', N("Remote administration"),
308 N("Click here if you want to configure a remote box via Web interface"),
309 ])
310 )
311 ),
312 if_($isRfbDrake,
313 "Remote Control",
314 )
315 ]
316 },
317 ]
318 ]),
319
320 [
321 #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
322 N("Hardware"), 'drakhard-mdk', 'mcc-hardware',
323 [
324 {
325 title => N("Manage your hardware"),
326 list => [
327 "Hardware List",
328 "Sound",
329 ]
330 },
331 {
332 title => N("Configure graphics"),
333 list => [
334 "3D",
335 "Graphical server configuration",
336 ]
337 },
338 {
339 title => N("Configure mouse and keyboard"),
340 list => [
341 "Keyboard",
342 "Mouse",
343 ]
344 },
345 {
346 title => N("Configure printing and scanning"),
347 list => [
348 "Printer",
349 "Scanner",
350 if_(-x "$bindir/drakfax", "Fax"),
351 ]
352 },
353 {
354 title => N("Others"),
355 list => [
356 "UPS",
357 ]
358 },
359 ]
360 ],
361
362 [
363 #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
364 N("Network & Internet"), 'net-mdk', 'mcc-network',
365 [
366 {
367 title => N("Manage your network devices"),
368 list => [
369 "Network Center",
370 "Add Connection",
371 if_(!-x "$sbindir/draknetcenter",
372 "Configure Internet",
373 "Manage Connection",
374 "Monitor Connection",
375 ),
376 "Remove Interface",
377 ]
378 },
379 {
380 title => N("Personalize and Secure your network"),
381 list => [
382 "Proxy Configuration",
383 "Connection Sharing",
384 "Network Profiles",
385 "VPN",
386 ]
387 },
388 {
389 title => N("Others"),
390 list => [
391 "Hosts",
392 ]
393 },
394 ],
395 ],
396
397 [
398 #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
399 N("System"), 'system-mdk', 'mcc-system',
400 [
401 {
402 title => N("Manage system services"),
403 list => [
404 if_(!$is_auth_wizard_installed, "Authentication"),
405 "Menus",
406 "Services",
407 "Fonts",
408 ]
409 },
410 {
411 title => N("Localization"),
412 list => [
413 "Date & Time",
414 "Localization",
415 ]
416 },
417 {
418 title => N("Administration tools"),
419 list => [
420 "Logs",
421 if_($ENV{LANGUAGE} !~ /^zh/, "Console"),
422 "Users",
423 "Migration",
424 if_(-x "$xbindir/drakcronat", "Programs scheduling"),
425 "Backups",
426 'Snapshots',
427 "Virtualization",
428 ]
429 },
430 ]
431 ],
432
433 [
434 #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
435 N("Network Sharing"), 'network-sharing-mdk', '',
436 [
437 {
438 title => N("Configure Windows(R) shares"),
439 list => [
440 "Access Windows shares",
441 "Samba configuration",
442 ]
443 },
444 {
445 title => N("Configure NFS shares"),
446 list => [
447 "NFS mount points",
448 "NFS exports",
449 ]
450 },
451 {
452 title => N("Configure WebDAV shares"),
453 list => [
454 "WebDAV mount points",
455 ]
456 },
457 ],
458 ],
459
460 [
461 #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
462 N("Local disks"), 'partition-mdk', 'mcc-localdisks',
463 [
464 {
465 title => N("Local disks"),
466 list => [
467 "Hard Drives",
468 (map {
469 my ($type, $scan, $text_orig, $long_text) = @$_;
470 map_index {
471 my $text = sprintf(translate($text_orig), $_->{info});
472 my $full_name = $text . ($::i ? $::i + 1 : '');
473 $programs{$full_name} =
474 {
475 binary => "$sbindir/diskdrake --removable=$_->{device}",
476 embedded => 1,
477 description => $text,
478 long_description => sprintf(translate($long_text), $_->{info}),
479 icon => "diskdrake_$type",
480 };
481 $full_name;
482 } $scan->();
483 } do {
484 my %cdroms_by_type;
485 foreach (detect_devices::cdroms()) {
486 my $type = detect_devices::isBurner($_) ? 'burner' : detect_devices::isDvdDrive($_) ? 'DVD' : 'cdrom';
487 push @{$cdroms_by_type{$type}}, $_;
488 }
489 ([ 'cdrom', sub { @{$cdroms_by_type{cdrom} || []} }, N_("CD-ROM (%s)",),
490 N_("Set where your \"%s\" CD-ROM drive is mounted"),
491 ],
492 [ 'dvd', sub { @{$cdroms_by_type{DVD} || []} }, N_("DVD-ROM (%s)"),
493 N_("Set where your \"%s\" DVD-ROM drive is mounted"),
494 ],
495 [ 'cdwriter', sub { @{$cdroms_by_type{burner} || []} }, N_("CD/DVD burner (%s)"),
496 N_("Set where your \"%s\" CD/DVD burner is mounted"),
497 ],
498 [ 'zip', \&detect_devices::zips, N_("ZIP drive"),
499 N_("Set where your ZIP drive is mounted"),
500 ],
501 );
502 }),
503 "Partition Sharing",
504 ]
505 },
506 ]
507 ],
508
509 [
510 #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
511 N("Security"), 'security-mdk', 'mcc-security',
512 [
513 {
514 title => N("Security"),
515 list => [
516 "Security Level",
517 "Tomoyo Policy",
518 "Firewall",
519 "Mageia Tools Authentication",
520 "Invictus Firewall",
521 "Parental Controls",
522 ]
523 },
524 ]
525 ],
526
527 [
528 #-PO: please keep the following message very short: it must fit in the left list of MCC!!!
529 N("Boot"), 'drakboot-mdk', 'mcc-boot',
530 [
531 {
532 title => N("Configure boot steps"),
533 list => [
534 #if_(detect_devices::floppies, "Boot Disk"), # kernel is too big
535 "Auto login Config",
536 "Boot Config",
537 "Display Manager chooser",
538 ]
539 },
540 {
541 title => N("Boot look'n feel"),
542 list => [
543 #"Boot Theme",
544 ]
545 },
546 {
547 title => N("Others"),
548 list => [
549 if_(0, "Auto Install"),
550 ]
551 },
552 ]
553 ],
554 );
555
556 if (scalar glob_("$more_wizard_dir/*.conf")) {
557 my @leaf = (
558 N("Additional wizards"),
559 'wizard-mdk',
560 []
561 );
562
563 foreach my $file (glob_("$more_wizard_dir/*.conf")) {
564 next unless -f $file;
565 my %tmp = getVarsFromSh($file);
566 $programs{$tmp{NAME}} = {
567 binary => "$sbindir/drakwizard " . lc($file),
568 embedded => 1,
569 description => $tmp{DESCRIPTION},
570 icon => $tmp{ICON} || 'wizard-mdk',
571 long_description => $tmp{LONG_DESCRIPTION},
572 };
573 push(@{$leaf[2]}, $tmp{NAME});
574 }
575 push(@tree, \@leaf);
576 }
577
578 #-------------------------------------------------------------
579 # let build the GUI
580
581
582 my $align = mygtk2::text_direction_rtl() ? "right" : "left";
583 my $align2 = mygtk2::text_direction_rtl() ? "right" : "left";
584
585
586 # main window :
587
588 my ($timeout, %check_boxes, $emb_socket);
589
590 # set default size:
591
592 my $window_global = gtkset_size_request(Gtk2::Window->new('toplevel'), $min_width, $min_height);
593 $::main_window = $window_global;
594
595 if ($geometry) {
596 @h{qw(HEIGTH WIDTH)} = $geometry =~ /(\d+)x(\d+)/;
597 my ($x, $y) = $geometry =~ /([+-]\d+)([+-]\d+)/;
598 $window_global->set_uposition($x, $y) if $x || $y;
599 } else {
600 }
601 $window_global->resize(max($default_width, $h{WIDTH}, $min_width), max($h{HEIGTH}, $default_height, $min_height));
602
603 $window_global->set_icon(gtkcreate_pixbuf("/usr/share/icons/drakconf.png"));
604
605 my $pending_app = 0;
606
607 my $help_on_context = 'drakconf-intro';
608
609 my @themes = grep { -d "$themes_dir/$_" } all($themes_dir);
610
611 #-PO Translators, please keep all "/" charaters !!!
612 my %options = (
613 'show_log' => [ N("/_Options"), N("/Display _Logs") ],
614 'embedded_mode' => [ N("/_Options"), N("/_Embedded Mode") ],
615 'wiz_expert' => [ N("/_Options"), N("/Expert mode in _wizards") ],
616 );
617
618 my $mga_rel = common::mageia_release();
619
620 my ($steps, $view);
621
622 my $release = mageia_release_info();
623
624 my @menu_items = (
625 [ N("/_File"), undef, undef, undef, '<Branch>' ],
626 [ N("/_File") . N("/_Quit"), N("<control>Q"), \&quit_global, undef, '<Item>', N("Quit") ],
627 [ N("/_Options"), undef, undef, undef, '<Branch>' ],
628 [ join('', @{$options{show_log}}), undef,
629 sub {
630 $option_values{show_log} = $check_boxes{show_log}->get_active;
631 if ($option_values{show_log}) {
632 start_logdrake();
633 } else {
634 kill_logdrake();
635 }
636 },
637 undef, '<CheckItem>'
638 ],
639
640 if_(0 && $isWiz,
641 [ join('', @{$options{wiz_expert}}), undef,
642 sub { $option_values{expert_wizard} = $check_boxes{wiz_expert}->get_active },
643 undef, '<CheckItem>',
644 ],
645 ),
646 if_(@themes > 1,
647 [ N("/_Themes"), undef, undef, undef, '<Branch>' ],
648 (map {
649 my $name = $_;
650 [ N("/_Themes") . "/" . ($name eq $theme ? " O " : " ") . "_$_", undef,
651 sub {
652 return if $theme eq $name;
653 !$pending_app || splash_warning(N("This action will restart the control center.\nAny change not applied will be lost."), 1) and do {
654 # embedded app must be killed
655 kill_children();
656 kill_logdrake();
657 child_just_exited();
658 exec "$0 --theme $name";
659 };
660 }, undef, '<CheckItem>'
661 ];
662 } @themes),
663 [ N("/_Themes") . N("/_More themes"), undef, \&more_themes, undef, '<Item>' ]
664 ),
665 [ N("/_Help"), undef, undef, undef, '<Branch>' ],
666 [ N("/_Help") . N("/_Help"), undef, \&run_help, undef, '<Item>', N("Help") ],
667 [ N("/_Help") . N("/_Release notes"), undef, sub { run_browser('Notes') }, undef, '<Item>', N("Help") ],
668 [ N("/_Help") . N("/What's _New?"), undef, sub { run_browser("What's New?") }, undef, '<Item>', N("Help") ],
669 [ N("/_Help") . N("/_Errata"), undef, sub { run_browser('Errata') }, undef, '<Item>', N("Help") ],
670 [ N("/_Help") . N("/_Report Bug"), undef, sub {
671 run_program::raw({ detach => 1, as_user => 1 }, 'drakbug', '--report', (split(/\s/, $pending_app))[0] || 'drakconf');
672 }, undef, '<Item>' ],
673 [ N("/_Help") . N("/_About..."), undef, \&about_mga_cc, undef, '<Item>' ]
674 );
675
676
677 sub run_help() {
678 run_program::raw({ detach => 1, as_user => 1 }, 'drakhelp', '--id', $help_on_context);
679 }
680
681 sub run_browser {
682 my ($url) = @_;
683 # Enable back $url when we will have our first release and our first release wiki page
684 #$url = "http://wiki.mageia.org/en/$release->{version}_$url" if $url !~ m!^http://!;
685 $url = "http://www.mageia.org/" if $url !~ m!^http://!;
686 run_program::raw({ detach => 1, as_user => 1 }, '/usr/bin/www-browser', $url);
687 }
688
689 my ($menu, $factory) = create_factory_menu($window_global, @menu_items);
690
691 # to retrieve a path, one must prevent "accelerators completion":
692 sub get_path { join('', map { my $i = $_; $i =~ s/_//g; $i } @_) }
693
694 %check_boxes = map {
695 $_ => $factory->get_widget("<main>" . get_path(@{$options{$_}}));
696 } ('show_log', if_(0 && $isWiz, "wiz_expert"));
697
698 my @buttons;
699 my $offset = 15;
700
701 $view = gtknew('WebKit_View', no_popup_menu => 1);
702 # so that it exists when building steps:
703 my $banner_notebook = Gtk2::Notebook->new;
704 build_list();
705
706 gtkadd($window_global,
707 gtkpack_(Gtk2::VBox->new(0, 0),
708 0, $menu,
709 #0, $banner_notebook,
710 0, Gtk2::HSeparator->new,
711 # 0, gtkset_size_request(Gtk2::VBox->new(10, 10), -1, 2),
712 1, gtkpack_(Gtk2::HBox->new(0, 0),
713 1, $steps = gtknew('MDV_Notebook', parent_window => $window_global, children => [ #Layout Fixed
714 # 145 is the vertical offset in order to be below the actual logo:
715 [ gtknew('VBox', widget_name => 'Steps', spacing => 0, width => (192 - $offset),
716 children_tight => [ map {
717 gtknew('HBox', spacing => 0, children => [
718 1, $_,
719 0, gtknew('Alignment', width => 12),
720 ]);
721 } @buttons ]), 0, 100 ],
722 ], right_child => gtknew('ScrolledWindow', child => gtkset_border_width($view, 5),
723 no_shadow => 1, h_policy => 'never')),
724 1, gtkpack(my $emb_box = Gtk2::VBox->new(0, 0),
725 my $wait_darea = gtkset_size_request(Gtk2::DrawingArea->new, -1, -1),
726 ),
727 ),
728 0, Gtk2::HSeparator->new,
729 0, my $buttons = gtkadd(gtkset_layout(Gtk2::HButtonBox->new, 'start'),
730 map { gtkset_border_width($_, 3) }
731 gtksignal_connect(my $cancel = Gtk2::Button->new(N("Cancel")),
732 clicked => sub {
733 stop_wait_area();
734 kill_children();
735 child_just_exited();
736 }),
737 ),
738 )
739 );
740
741 $view->set_size_request(-1, -1);
742
743 $window_global->signal_connect(delete_event => \&quit_global);
744
745 my $accel = Gtk2::AccelGroup->new;
746 $accel->connect(Gtk2::Gdk->keyval_from_name('F1'), [], ['visible'], \&run_help);
747 $window_global->add_accel_group($accel);
748
749 use POSIX qw(:sys_utsname_h :math_h :sys_wait_h :unistd_h);
750 my (undef, $nodename) = POSIX::uname();
751 $window_global->set_title(N("%s Control Center %s [on %s]", $branding, $version, $nodename));
752 $window_global->set_position('center');
753
754 foreach my $notebook ($banner_notebook) {
755 $notebook->set_property('show-border', 0);
756 $notebook->set_property('show-tabs', 0);
757 }
758
759
760 # banner :
761
762 #add2notebook($banner_notebook, "", Gtk2::Banner->new("/usr/share/icons/large/drakconf.png",
763 # N("Welcome to the %s Control Center", $branding)));
764
765
766 my ($_hand_cursor, $wait_cursor) = map { Gtk2::Gdk::Cursor->new($_) } qw(hand2 watch);
767
768 my $left_locked = 0;
769
770 #my $spacing = 25;
771
772 my %tool_callbacks;
773
774 my ($page_count);
775
776
777 my $conf_file = '/etc/sysconfig/mcc.conf';
778 foreach (cat_($conf_file)) {
779 #s/^ENABLE_//;
780 #my ($key, $val) = /^(.*)=(.*)/;
781 if (my ($key, $val) = /^ENABLE_(.*)=(.*)/) {
782 $key =~ s/_/ /g;
783 #warn "--> ($key, $val)\n";
784 $programs{$key}{disabled} = 1 if $val ne 'yes';
785 warn ">> disabling $key\n" if $val ne 'yes';
786 } else {
787 warn "bogus line in $conf_file: $_\n";
788 next;
789 }
790 }
791
792 sub load_packages2install() {
793 my $progs_conf_file = '/usr/share/mcc/progs.conf';
794 foreach (cat_($progs_conf_file)) {
795 #if (my ($key, $val) = /^USE_WRAPPER_FOR_(.*)=(.*)/) {
796 if (my ($key, $val) = /^INSTALL_FOR_(.*)=(.*)/) {
797 $key =~ s/_/ /g;
798 # we'll use gurpmi in order to install missing packages if needed;
799 $programs{$key}{packages2install} = $val if $val;
800 } else {
801 warn "bogus line in $conf_file: $_\n";
802 next;
803 }
804 }
805 }
806
807 sub clean_list {
808 my ($subtree) = @_;
809 grep {
810 my $stuff = $_;
811 my $exec = real_bin_path($programs{$stuff}{binary});
812 my $is_present = -x $exec;
813 if (!$is_present && $programs{$stuff}{packages2install}) {
814 $is_present = 1;
815 # override missing icon:
816 $programs{$stuff}{real_icon} ||= $programs{$stuff}{icon};
817 $programs{$stuff}{icon} = 'installremoverpm';
818 } elsif ($programs{$stuff}{real_icon}) {
819 $programs{$stuff}{icon} = $programs{$stuff}{real_icon};
820 }
821 # do not complain about missing entries in move:
822 warn qq("$exec" is not executable [$stuff]) if $mga_rel !~ /Move/ && !$is_present && !$programs{$stuff}{disabled};
823 !$programs{$stuff}{hidden} && $is_present && !$programs{$stuff}{disabled};
824 } @$subtree;
825 }
826
827 sub build_widget_element {
828 my ($label) = @_;
829 my $icon = $programs{$label}{icon};
830
831 die "$label 's icon is missing" if !$programs{$label} && $::testing;
832 $tool_callbacks{$label} = sub {
833 run_tool($label, undef, #$event_box,
834 $icon, $programs{$label}{description}, $programs{$label});
835 };
836 # FIX ME: DO THIS AGAIN:
837 $tool_feedback{$label} = sub {}; #sub { $event_box->window && $event_box->window->set_cursor($hand_cursor) };
838 my $real_icon = $icon ? '<IMG SRC="' . mygtk2::_find_imgfile($icon) . '">' : '';
839 my @widgets = (
840 qq(<TD class="img">$real_icon</TD>),
841 qq(<TD style="text-align: $align"><DIV>)
842 . escape_text_for_TextView_markup_format($programs{$label}{description})
843 . qq(</DIV></TD>)
844 );
845 qq(<TD WIDTH="49%">
846 <A HREF="$label"><TABLE align="$align2" ID="subtable"><TR>
847 @widgets
848 </TR></TABLE></A></TD>
849 );
850 }
851
852 my (@strings, $current_string_idx);
853 sub load_view() {
854 $view->load_html_string($strings[$current_string_idx], 'file:///');
855 }
856
857 sub build_list() {
858 my $index = 0;
859 load_packages2install();
860 my $i;
861 foreach (@tree) {
862 my ($text, $icon, $help, $subtrees) = @$_;
863
864 my @subtrees = grep { $_->{list} = [ clean_list($_->{list}) ]; !is_empty_array_ref($_->{list}) } @$subtrees;
865
866
867 # Skip empty classes:
868 next if !@subtrees;
869 $i++;
870
871
872 my $my_index = $index++;
873 my $square_icon_uri = mygtk2::_find_imgfile('cadre-ic');
874 my $back_img = mygtk2::_find_imgfile('right-white-background_right_part_768.png');
875 my $string = join("\n", qq(<HTML>
876 <HEAD>
877 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
878 <style type="text/css">
879 body {
880 // background-color: #ecf0f2;
881 // background-image: url($back_img);
882 background-repeat: no-repeat; /*pas de répition de l'image*/
883 background-attachment: fixed;
884 background-position: top left
885 }
886 p {text-align: $align}
887 td {text-align: $align}
888 #title {
889 text-align: $align;
890 color: #grey;
891 font-weight: bold;
892 margin-left: 13px;
893 margin-top: 16px;
894 margin-bottom: 8px;
895 }
896 #top_margin {
897 margin-top: 30px;
898 }
899 #block {
900 margin-left: 4px;
901 margin-bottom: 24px;
902 border-spacing: 8px 0px;
903 }
904 #subtable {
905 border-spacing: 8px 8px;
906 }
907 td.img {
908 background-image: url($square_icon_uri);
909 background-repeat: no-repeat;
910 background-position: center center;
911 width: 60; height: 60;
912 text-align: center;
913 }
914 hr {
915 background-color: #eef2f6;
916 margin-left: 21px;
917 margin-right: 22px;
918 height: 1;
919 border: 0;
920 }
921 tr {text-align: $align}
922 td {
923 margin-left: 10px;
924 margin-right: 10px;
925 }
926 ),
927 if_(mygtk2::text_direction_rtl(), " a { direction: rtl; unicode-bidi: embed }"), qq(
928 a:link {color:black; text-decoration:none }
929 a:visited {color:black; text-decoration:none }
930 a:hover {color:grey }
931 // a:active {color:black; text-decoration:none }
932 </style>
933
934 </HEAD>
935 <BODY>
936 ));
937
938
939
940 # Create right notebook pages :
941
942 my $section;
943 foreach my $subtree (@subtrees) {
944 $string .= $section++ ? "<hr NOSHADE>\n" : '<div ID="top_margin"></div>';
945 my $title = mygtk2::asteriskize($subtree->{title});
946 $string .= qq(
947 <div ID="title">$title</div>
948 <TABLE BORDER=0 WIDTH="100%" ID="block">
949 );
950 if (@{$subtree->{list}} % 2) {
951 my @widgets = (pop @{$subtree->{list}}, "");
952 @widgets = reverse @widgets if mygtk2::text_direction_rtl();
953 push @{$subtree->{list}}, @widgets;
954 }
955 $string .= join("\n",
956 map {
957 "<TR>" . join("\n", grep { defined $_ } @$_) . "</TR>" }
958 # "<TR>" . join("\n<TD> </TD>\n", grep { defined $_ } @$_) . "</TR>" }
959 group_by(2, map { $_ ? build_widget_element($_) : '<TD></TD>' } @{$subtree->{list}})
960 );
961
962 $string .= "</TABLE>\n";
963 }
964 my $text_orig = $text;
965 # b/c we use Pango text markup language, we've to protect '&' caracter:
966 $text =~ s/&/&amp;/g;
967 $page_count++;
968
969 $string .= qq(</BODY></HTML>);
970 if ($save_html) {
971 mkdir_p('/tmp/mcc');
972 MDK::Common::File::output_utf8("/tmp/mcc/$i.html", $string);
973 }
974
975 $strings[$my_index] = $string;
976 push @buttons, gtknew('Button', relief => 'none', child =>
977 gtknew('Label_Right', text_markup => qq(<small>$text</small>), ellipsize => 'end'),
978 clicked => sub {
979 $current_string_idx = $my_index;
980 load_view();
981 $steps->move_selection($_[0]->child);
982 $banner_notebook->set_current_page($my_index);
983 $help_on_context = $help;
984 },
985 );
986
987 #add2notebook($banner_notebook, "", Gtk2::Banner->new($icon, $text_orig));
988 }
989 }
990
991 $view->signal_connect('navigation-requested' =>
992 sub {
993 my (undef, undef, $request) = @_;
994 my $res = 'ignore';
995
996 # get the actual program ID:
997 my $url = Glib::filename_from_uri($request->get_uri);
998 $url =~ s!^/*!!; # not a path
999
1000 # workaround wekbit calling navigation-requested with "/":
1001 if (!$url) {
1002 return 'accept';
1003 }
1004
1005 # url can be a translated UTF-8 string (eg: for CD/DVD entries):
1006 c::set_tagged_utf8($url);
1007
1008 # do not crash on eg: "reload":
1009 if (!$tool_callbacks{$url}) {
1010 warn "Warning: invalid tool name: $url\n";
1011 return $res;
1012 }
1013 $tool_callbacks{$url}->();
1014 # FIXME: the following code is currently useless:
1015 # should we provide a way to kill buggy embedded programs ?
1016 return $res if $left_locked;
1017 warn_on_startup();
1018 return $res;
1019 });
1020
1021 my %icons = (
1022 );
1023
1024 # manage tools not present in MCC (localedrake, drakauth, ...):
1025 foreach my $label (difference2([ keys %programs ], [ keys %tool_callbacks ])) {
1026 my $text = $programs{$label}{description};
1027 $tool_callbacks{$label} = sub { run_tool($label, undef, $icons{$label} || 'wizard-mdk', $text, $programs{$label}) };
1028 $tool_feedback{$label} = sub {};
1029 }
1030
1031
1032 foreach (keys %check_boxes) {
1033 my $widget = $check_boxes{$_};
1034 if (defined $widget) {
1035 $widget->set_active($option_values{$_});
1036 } else {
1037 print STDERR qq(BUG with LANGUAGE "$ENV{LANGUAGE}" for "$_"\n);
1038 err_dialog(N("Error"), N("There's a bug in translations of your language (%s)
1039
1040 Please report that bug.", $ENV{LANGUAGE}));
1041 }
1042 }
1043
1044 # "wait while launching a program" area :
1045
1046 my ($run_pixbuf, $run_counter, $run_counter_add, %run_pixbufs);
1047
1048 sub stop_wait_area() {
1049 $wait_darea->hide;
1050 Glib::Source->remove($timeout) if $timeout;
1051 undef %run_pixbufs;
1052 }
1053
1054 $wait_darea->signal_connect(expose_event => sub {
1055 my ($w) = @_;
1056 return if !$wait_darea->realized;
1057 return unless $run_pixbuf; # some people got an expose event before we start an embedded tool
1058 return unless $wait_darea->{size};
1059 $wait_darea->{layout} ||= $wait_darea->create_pango_layout(N("Loading... Please wait"));
1060 my $pixbuf = $run_pixbufs{$run_counter} ||= mygtk2::_pixbuf_render_alpha($run_pixbuf, $run_counter);
1061 if (!$wait_darea->{first_expose}) {
1062 $wait_darea->{first_expose} = 1;
1063 my $size = $wait_darea->{size};
1064 my ($d_width, $d_height) = ($size->width, $size->height);
1065 ($w->{pix_width}, $w->{pix_height}) = ($pixbuf->get_width, $pixbuf->get_height);
1066 my ($txt_width, $txt_height) = $wait_darea->{layout}->get_pixel_size;
1067 $w->{pix_yy} = ($d_width - $w->{pix_width})/2;
1068 $w->{pix_xx} = ($d_height - $w->{pix_height} - $txt_height)/2;
1069 $w->{text_yy} = $w->{pix_yy} + ($w->{pix_width} - $txt_width)/2;
1070 $w->{text_xx} = $w->{pix_xx} + $w->{pix_height} + 5;
1071 }
1072 $pixbuf->render_to_drawable($w->window, $w->style->fg_gc('normal'), 0, 0, $w->{pix_yy}, $w->{pix_xx}, $w->{pix_width}, $w->{pix_height}, 'normal', 0, 0);
1073 my $style = $wait_darea->{style} ||= $wait_darea->get_style;
1074 $wait_darea->window->draw_layout($style->text_gc('normal'), $w->{text_yy}, $w->{text_xx}, $w->{layout});
1075 $run_counter += $run_counter_add;
1076 $run_counter_add = -$run_counter_add if $run_counter < 100 || 255-$run_counter_add < $run_counter;
1077 });
1078
1079 gtkflush();
1080
1081 # display first page (we use a timeout so that Y position of widgets is know):
1082 Glib::Timeout->add(100, sub { $buttons[0]->signal_emit('clicked'); 0 });
1083
1084 $window_global->show_all;
1085
1086 hide_buttons();
1087 $emb_box->hide;
1088 $wait_darea->realize;
1089
1090 $SIG{USR1} = 'IGNORE';
1091 $SIG{USR2} = 'IGNORE';
1092 $SIG{TERM} = \&quit_global;
1093 $SIG{CHLD} = \&sig_child;
1094
1095 $window_splash->destroy;
1096 undef $window_splash;
1097 Glib::Timeout->add(200, sub { sig_child('CHLD', 1); 1 });
1098
1099 if ($program) {
1100 if (my $sub = $tool_callbacks{$program}) {
1101 Glib::Timeout->add(500, sub { $sub->(); 0 });
1102 } else {
1103 err_dialog(N("Error"), N("Impossible to run unknown '%s' program", $program));
1104
1105 }
1106 }
1107
1108 Gtk2->main;
1109
1110
1111 sub group_by {
1112 my $nb = shift @_;
1113 my @l;
1114 for (my $i = 0; $i < @_; $i += $nb) {
1115 push @l, [ map { $_[$_] } $i..$i+$nb-1 ]; # $_[$i], $_[$i+1], $_[$i+2] ];
1116 }
1117 @l;
1118 }
1119
1120 sub warn_on_startup() {
1121 if ($pending_app) {
1122 return if !splash_warning(N("The modifications done in the current module won't be saved."), 1);
1123 kill_children();
1124 child_just_exited();
1125 }
1126 }
1127
1128 #-------------------------------------------------------------
1129 # socket/plug managment
1130
1131 # called once embedded tool has exited
1132 sub child_just_exited() {
1133 $pending_app = 0;
1134 $left_locked = 0;
1135 if ($emb_socket) {
1136 $emb_socket->destroy;
1137 undef $emb_socket;
1138 }
1139 $emb_box->hide;
1140 hide_buttons();
1141 $cancel->hide;
1142 gtkset_mousecursor_normal();
1143 foreach my $w ($steps, $banner_notebook) {
1144 $w->show;
1145 }
1146
1147 stop_wait_area();
1148 }
1149
1150 sub hide_socket_and_clean() {
1151 $emb_box->hide;
1152 $pending_app = 0;
1153 }
1154
1155 sub create_hidden_socket {
1156 my ($icon, $label) = @_;
1157 my $banner;
1158 gtkpack_($emb_box,
1159 0, $banner = gtkpack__(Gtk2::VBox->new(0, 0), Gtk2::Banner->new($icon, $label),
1160 Gtk2::HSeparator->new,
1161 ),
1162 1, gtksignal_connect($emb_socket = Gtk2::Socket->new, 'plug-removed' => sub {
1163 $menu->show if $application_driven_menu;
1164 $banner->destroy;
1165 child_just_exited();
1166 }));
1167 $banner->hide;
1168 # signal emitted when embedded apps begin to draw:
1169 $emb_socket->signal_connect('plug-added' => sub {
1170 $banner_notebook->hide;
1171 if ($application_driven_menu) {
1172 $menu->hide;
1173 } else {
1174 $banner->show;
1175 }
1176 stop_wait_area();
1177 $left_locked = 0;
1178 hide_buttons();
1179 $buttons->hide;
1180 return if !$emb_socket;
1181 $emb_socket->show;
1182 $emb_socket->can_focus(1);
1183 $emb_socket->grab_focus;
1184 #$emb_socket->window->XSetInputFocus; #only need by console (no more embedded until we've vte/zvt binding)
1185 });
1186 $emb_box->set_focus_child($emb_socket);
1187 $emb_socket->hide;
1188 }
1189
1190
1191 #-------------------------------------------------------------
1192 # processes managment
1193
1194 # embedded processes pid will be stocked there
1195 my @pid_launched;
1196
1197 # logdrake pid are stocked here
1198 my $pid_exp;
1199
1200 sub fork_ {
1201 my ($prog, $o_pid_table) = @_;
1202 $o_pid_table ||= \@pid_launched;
1203 my $pid = fork();
1204 if (defined $pid) {
1205 !$pid and do { exec($prog) or POSIX::_exit(1) }; # immediate exit, else forked gtk+ object destructors will badly catch up parent mcc
1206 push @$o_pid_table, $pid;
1207 return $pid;
1208 } else {
1209 splash_warning(N("cannot fork: %s", "$!"));
1210 child_just_exited();
1211 }
1212 }
1213
1214 sub real_bin_path {
1215 my ($prog) = @_;
1216 first(split /\s+/, $prog);
1217 }
1218
1219 sub run_tool {
1220 my ($label, $box, $icon, $text, $tool) = @_;
1221 my ($exec, $gtkplug) = @$tool{qw(binary embedded)};
1222 $application_driven_menu = $tool->{application_driven_menu};
1223 return if $tool_pids{$label};
1224 my $will_run_gurpmi;
1225 if (! -x real_bin_path($exec)) {
1226 if ($tool->{packages2install}) {
1227 # gurpmi doesn't support being embedded yet:
1228 $gtkplug = -1;
1229 $exec = join(' ', "$bindir/gurpmi", split(/\s/, $tool->{packages2install}));
1230 $will_run_gurpmi = 1;
1231 } else {
1232 splash_warning(N("cannot fork and exec \"%s\" since it is not executable", $exec));
1233 return;
1234 }
1235 }
1236 $exec .= " --summary" if $option_values{expert_wizard} && $exec =~ /drakwizard/;
1237 my $embedded = $gtkplug != -1; # not "explicitely not embedded"
1238 if ($embedded) {
1239 $steps->hide;
1240 create_hidden_socket($icon, $text);
1241 $emb_box->show;
1242 $emb_socket->realize;
1243 $pending_app = $tool->{binary};
1244 if ($gtkplug > 0) {
1245 $buttons->show;
1246 $exec .= " --embedded " . $emb_socket->get_id;
1247 $wait_darea->show;
1248 $cancel->show;
1249 $run_pixbuf = eval { gtkcreate_pixbuf($icon . "_128") };
1250 $run_counter = 255;
1251 $run_counter_add = -5;
1252 undef $wait_darea->{color};
1253 undef $wait_darea->{size};
1254 undef $wait_darea->{first_expose};
1255 $wait_darea->{not_yet_complete} = 1;
1256 $timeout = Glib::Timeout->add(35, sub {
1257 $wait_darea->{size} ||= $wait_darea->allocation;
1258 my $style = $wait_darea->{style} ||= $wait_darea->get_style;
1259 my $bg = $wait_darea->{bg} ||= $style->bg('normal');
1260 my $base = $wait_darea->{base} ||= $style->base('normal');
1261 my $color = $wait_darea->{color} ||= $base;
1262 # $base -> $bg
1263 my @colors = ([ $color->red, $bg->red ],
1264 [ $color->green, $bg->green ],
1265 [ $color->blue, $bg->blue ]);
1266 if ($wait_darea->{not_yet_complete} && any { $_->[0] != $_->[1] } @colors) {
1267 $wait_darea->window->set_background($color);
1268 $wait_darea->{color} = gtkcolor(map { $_->[0] - min(300, $_->[0] - $_->[1]) } @colors);
1269 $wait_darea->queue_draw;
1270 } elsif ($wait_darea->{not_yet_complete}) {
1271 # set exact color
1272 $wait_darea->window->set_background($bg);
1273 $wait_darea->queue_draw;
1274 $wait_darea->{not_yet_complete} = 0;
1275 } else {
1276 my $w = $wait_darea;
1277 $wait_darea->queue_draw_area($w->{pix_yy}, $w->{pix_xx}, $w->{pix_width}, $w->{pix_height});
1278 }
1279 1;
1280 });
1281 $left_locked = 1;
1282 $buttons->show;
1283 $tool_pids{$label} = fork_($exec);
1284 }
1285 } else { # not embedded
1286 # fix #3415 when $gtkplug eq -1
1287 local $option_values{embedded} = 0;
1288 $tool_pids{$label} = fork_($exec);
1289 $gurpmi_pid = $tool_pids{$label} if $will_run_gurpmi;
1290 }
1291 start_logdrake();
1292 $box->window->set_cursor($wait_cursor) if $box;
1293 }
1294
1295 sub start_logdrake() {
1296 # (re)start logdrake if needed
1297 if ($option_values{show_log} && !$pid_exp) {
1298 my $exec_log = "logdrake --explain=drakxtools";
1299 $pid_exp = fork_($exec_log, []);
1300 }
1301
1302 }
1303
1304 sub kill_them_all {
1305 foreach my $pid (@_) {
1306 kill('TERM', $pid) if $pid;
1307 }
1308 }
1309
1310 sub kill_children() {
1311 kill_them_all(@pid_launched);
1312 }
1313
1314 sub kill_logdrake() {
1315 kill_them_all($pid_exp) if $pid_exp;
1316 }
1317
1318 sub quit_global() {
1319 if (@pid_launched) {
1320 &kill_children();
1321 return 1; # tell gtk+ not to quit
1322 }
1323 &kill_children();
1324 &kill_logdrake();
1325 my ($x, $y) = $window_global->get_size;
1326 setVarsInSh($conffile, {
1327 LOGS => bool2text($option_values{show_log}),
1328 EXPERT_WIZARD => bool2text($option_values{expert_wizard}),
1329 HEIGTH => $y,
1330 WIDTH => $x,
1331 THEME => $theme,
1332 });
1333 gtkset_mousecursor_normal();
1334 Gtk2::exit(0);
1335 standalone::exit(0);
1336 }
1337
1338
1339 #-------------------------------------------------------------
1340 # signals managment
1341
1342 # got when child died and gone in zombie state
1343 sub sig_child {
1344 my ($_sig, $o_is_cleaner) = @_;
1345 my $child_pid;
1346 do {
1347 $child_pid = waitpid(-1, POSIX::WNOHANG);
1348 if (my $tool = find { $tool_pids{$_} eq $child_pid } keys %tool_pids) {
1349 $tool_feedback{$tool}->();
1350 delete $tool_pids{$tool};
1351 @pid_launched = grep { $_ ne $child_pid } @pid_launched;
1352 if ($child_pid == $gurpmi_pid) {
1353 undef $gurpmi_pid;
1354
1355 my @services;
1356 if ($programs{$tool}{services_to_start_after_install}) {
1357 @services = @{$programs{$tool}{services_to_start_after_install}};
1358 run_program::raw({ detach => 1 }, 'service', $_, 'restart') foreach @services;
1359 }
1360
1361 # refresh the icon list if some package got installed (eg: system-config-printer)
1362 build_list();
1363 load_view();
1364 }
1365 }
1366 undef $pid_exp if $pid_exp eq $child_pid;
1367 } while $child_pid > 0;
1368 # child unexpectedly died (cleanup since child_just_exited won't be called by plug-removed since plug never was added)
1369 return if $o_is_cleaner || !$left_locked;
1370 child_just_exited();
1371 splash_warning(N("This program has exited abnormally"));
1372 }
1373
1374
1375 #-------------------------------------------------------------
1376 # mcc dialog specific functions
1377
1378 sub splash_warning {
1379 my ($label, $o_cancel_button) = @_;
1380 warn_dialog(N("Warning"), $label, { cancel => $o_cancel_button });
1381 }
1382
1383 sub new_dialog {
1384 my ($title, $o_no_button) = @_;
1385 my $dialog = gtkset_border_width(Gtk2::Dialog->new, 10);
1386 $dialog->set_transient_for($window_global);
1387 $dialog->set_position('center-on-parent');
1388 $dialog->set_title($title);
1389 $dialog->action_area->pack_start(gtkadd(Gtk2::HButtonBox->new,
1390 gtksignal_connect(Gtk2::Button->new(N("Close")), clicked => sub { $dialog->destroy })
1391 ),
1392 0,0,0) unless $o_no_button;
1393 gtkset_modal($dialog, 1);
1394 }
1395
1396 sub more_themes() {
1397 my $window_about = new_dialog(N("More themes"));
1398 gtkpack_($window_about->vbox,
1399 0, Gtk2::Label->new(N("Getting new themes")),
1400 0, gtkadd(gtkset_shadow_type(gtkset_border_width(Gtk2::Frame->new(N("Additional themes")), 10), 'etched_out'),
1401 gtkpack(Gtk2::HBox->new(0, 5),
1402 N("Get additional themes on www.damz.net"),
1403 )
1404 )
1405 );
1406 $window_about->show_all;
1407 }
1408
1409 sub about_mga_cc() {
1410 my $window_about = new_dialog(N("About - %s Control Center", $branding));
1411 my $tree_model = Gtk2::TreeStore->new("Glib::String", "Glib::String", "Glib::String");
1412 my $credits = Gtk2::TextView->new;
1413 my $list = Gtk2::TreeView->new_with_model($tree_model);
1414 $list->can_focus(0);
1415 each_index { $list->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => $::i)) } 0..1;
1416 $list->set_headers_visible(0);
1417
1418 foreach my $row ([ N("Authors: "), '' ],
1419 [ '', 'Chmouel Boudjnah' ],
1420 [ '', 'Damien "dam\'s" Krotkine',
1421 #-PO "perl" here is the programming language
1422 N("(perl version)") ],
1423 [ '', 'Daouda Lo' ],
1424 [ '', 'Thierry Vignaud' ],
1425 [ '', 'Yves Duret' ],
1426 [ '', '' ],
1427 [ N("Artwork: "), '', '' ],
1428 [ '', 'Anh-Van Nguyen' ],
1429
1430 [ '',
1431 #-PO If your language allows it, use eacute for first "e" and egrave for 2nd one.
1432 N("Helene Durosini"), '<ln@mandriva.com>' ],
1433 ) {
1434 $tree_model->append_set(undef, [ map_index { $::i => $_ } @$row ]);
1435 }
1436
1437 my ($previous_type, $not_first_title, $not_first_block);
1438 my $locale = lang::read;
1439 require Gtk2::Pango;
1440 foreach my $line (grep { $_ ne "\n" && !/^#/ } cat_(top(glob("/usr/share/doc/mageia-release-*/CREDITS.$locale->{lang}")))) {
1441 if (my ($type, $comment, $contributor) = split(/\|/, $line, 3)) {
1442 last if !$type;
1443 $comment =~ s/^ //; # fix initial space of first section (CREDITS format should be enhanced to specify lines that really are sections)
1444 chomp($contributor);
1445 if ($previous_type ne $type) {
1446 gtktext_append($credits, [ [ join('', if_($not_first_title, "\n"), translate(common::to_utf8($type)), "\n"),
1447 { 'weight' => Gtk2::Pango->PANGO_WEIGHT_BOLD, scale => Gtk2::Pango->scale_large } ] ]);
1448 $previous_type = $type;
1449 $not_first_title = 1;
1450 }
1451 if ($contributor) {
1452 gtktext_append($credits,
1453 #-PO: this is used as "language: translator" in credits part of the about dialog:
1454 N("- %s: %s\n", map { translate($_) } $comment, $contributor)
1455 );
1456 } else {
1457 $comment = $comment . "\n" if !$not_first_block; # fix spacing before second title;
1458 gtktext_append($credits, join('', if_($not_first_block, "- "), translate($comment)));
1459 $not_first_block = 1;
1460 }
1461 }
1462 }
1463
1464
1465 # Give our translators the ability to show their family and
1466 # friends that thez participated ...
1467
1468 #-PO Add your Name here to find it in the About section in your language.
1469 my $translator_name = N("_: NAME OF TRANSLATORS\nYour names");
1470 #-PO Add your E-Mail address here if you want to show it in the about doialog.
1471 my $translator_email = N("_: EMAIL OF TRANSLATORS\nYour emails");
1472 if ($translator_name ne "Your names" && 0) {
1473 $tree_model->append_set(undef, [ 0 => $_->[0], 1 => $_->[1] ]) foreach [ '', '' ], [ N("Translator: ") ];
1474 $tree_model->append_set(undef, [ 0 => $_->[0], 1 => $_->[1] ]) foreach [ '', $translator_name, $translator_email ];
1475 }
1476 $list->get_selection->set_mode('none');
1477
1478 gtkpack_($window_about->vbox,
1479 (0, Gtk2::Banner->new('/usr/share/icons/large/drakconf.png',
1480 #-PO: Here, first %s will be replaced by 'Mageia'
1481 #-PO: second %s will be replaced by the version (eg: "Mageia 1 (Free) Control Center")
1482 N("%s %s (%s) Control Center",
1483 $branding, @$release{qw(version product)}))),
1484 0, Gtk2::Label->new(""),
1485 0, Gtk2::Label->new(
1486 #-PO: here %s is eg: "1999-2008"
1487 N("Copyright (C) %s Mandriva SA", '1999-2008') . "\n" . N("Copyright (C) %s Mageia", '2011') . "\n" ),
1488 0, Gtk2::HSeparator->new,
1489 0, Gtk2::Label->new(""),
1490 1, my $n = Gtk2::Notebook->new,
1491 );
1492
1493 add2notebook($n, N("Authors"), $list);
1494 add2notebook($n, N("Mageia Contributors"), gtkset_size_request(create_scrolled_window($credits), 650, 50));
1495 $n->set_current_page(0);
1496
1497 $window_about->show_all;
1498 }
1499
1500
1501 #-------------------------------------------------------------
1502 # mcc specific graphic functions:
1503
1504
1505 sub set_page {
1506 my ($index) = @_;
1507 start_logdrake();
1508 set_page_raw($index);
1509 hide_buttons();
1510 }
1511
1512 sub hide_buttons() {
1513 $buttons->hide;
1514 $cancel->hide;
1515 }
1516
1517
1518 sub create_packtable2 {
1519 my ($options, @l) = @_;
1520 my $w = Gtk2::Table->new(0, 0, 1);
1521 add2hash_($options, { xpadding => 5, ypadding => 0 });
1522 each_index {
1523 my ($i, $l) = ($::i, $_);
1524 each_index {
1525 my $j = $::i;
1526 if ($_) {
1527 ref $_ or $_ = gtknew('WrappedLabel', text => $_);
1528 $w->attach($_, $j, $j + 1, $i, $i + 1, ['expand', 'fill'], ['expand', 'fill'], $options->{xpadding}, $options->{ypadding});
1529 $_->show;
1530 }
1531 } @$l;
1532 } @l;
1533 $w->set_col_spacings($options->{col_spacings} || 0);
1534 $w->set_row_spacings($options->{row_spacings} || 0);
1535 gtkset_border_width($w, $::isInstall ? 3 : 10);
1536 }
1537
1538 #-------------------------------------------------------------
1539 # mcc specific graphic functions:
1540
1541 sub render_shiner {
1542 my ($pixbuf, $shine_value) = @_;
1543 my $new_pixbuf = (mygtk2::_new_alpha_pixbuf($pixbuf))[2];
1544 $pixbuf->saturate_and_pixelate($new_pixbuf, $shine_value, 0);
1545 $new_pixbuf;
1546 }
1547
1548 sub scale {
1549 my ($pixbuf, $gain) = @_;
1550 my ($width, $height) = ($pixbuf->get_height, $pixbuf->get_width);
1551 $pixbuf->scale_simple($height+$gain, $width+$gain, 'hyper');
1552 }
1553
1554
1555 1;

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.30