1/*
2 *      Copyright 2011 Julien Lavergne <gilir@ubuntu.com>
3 *
4 *      This program is free software; you can redistribute it and/or modify
5 *      it under the terms of the GNU General Public License as published by
6 *      the Free Software Foundation; either version 2 of the License, or
7 *      (at your option) any later version.
8 *
9 *      This program is distributed in the hope that it will be useful,
10 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *      GNU General Public License for more details.
13 *
14 *      You should have received a copy of the GNU General Public License
15 *      along with this program; if not, write to the Free Software
16 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 *      MA 02110-1301, USA.
18*/
19
20/*
21   TODO packagekit handler (GUI and stuff) ?
22   TODO Use wnck for managing launching applications ?
23*/
24using Posix;
25
26namespace Lxsession
27{
28
29public class AppObject: GLib.Object
30{
31
32    /* Core App Object, all other App objects should inherent from it
33       You should not do an instance of it, use SimpleAppObject if you want
34       a usefull Object
35    */
36
37    public Pid pid;
38
39    public string name { get; set;}
40    public string[] command { get; set;}
41    public bool guard { get; set; default = false;}
42    public string application_type { get; set;}
43    public int crash_count { get; set; default = 0;}
44
45    /* Number of time the application have to crash before stoping to reload */
46    public int stop_reload { get; set; default = 5;}
47
48    public AppObject()
49    {
50        init();
51    }
52
53    public void launch ()
54    {
55        generic_launch (null);
56    }
57
58    public void generic_launch (string? arg1)
59    {
60        if (this.name != null)
61        {
62            if (this.name != "")
63            {
64                try
65                {
66                    string[] spawn_env = Environ.get ();
67                    Process.spawn_async (
68                                 arg1,
69                                 this.command,
70                                 spawn_env,
71                                 SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
72                                 null,
73                                 out this.pid);
74                    ChildWatch.add(this.pid, callback_pid);
75
76                    message ("Launching %s ", this.name);
77
78                    for (int a = 0 ; a <= this.command.length ; a++)
79                    {
80                        GLib.stdout.printf("%s ",this.command[a]);
81                    }
82                    GLib.stdout.printf("\n");
83                }
84                catch (SpawnError err)
85                {
86                    warning (err.message);
87                    warning ("Error when launching %s", this.name);
88                }
89            }
90        }
91    }
92
93    public virtual void read_config_settings()
94    {
95        /* Each object need to implement this, so settings will be read when process is reloaded */
96    }
97
98    public virtual void read_settings()
99    {
100        /* Each object need to implement this, so settings will be read when process is reloaded */
101    }
102
103    public void stop()
104    {
105        if ((int) this.pid != 0)
106        {
107            message("Stopping process with pid %d", (int) this.pid);
108            Posix.kill ((int) this.pid, 15);
109        }
110    }
111
112    public void reload()
113    {
114        message("Reloading process");
115        this.stop();
116        this.launch();
117    }
118
119    public void init()
120    {
121        read_config_settings();
122        read_settings();
123    }
124
125    private void callback_pid(Pid pid, int status)
126    {
127        /* Help :  http://en.wikipedia.org/wiki/Signal_(computing)
128                   http://valadoc.org/glib-2.0/GLib.ProcessSignal.html
129        */
130        message("%s exit with this type of exit: %i", this.name, status);
131
132        Process.close_pid (pid);
133
134        if (this.guard == true)
135        {
136            switch (status)
137            {
138                case 0:
139                    message("Exit normal, don't reload");
140                    break;
141                case 15:
142                    message("Exit by the user, don't reload");
143                    break;
144                case 256:
145                    message("Exit normal, don't reload");
146                    break;
147                default:
148                    message("Exit not normal, try to reload");
149                    this.crash_count = this.crash_count + 1;
150                    if (this.crash_count <= this.stop_reload)
151                    {
152                        this.launch();
153                    }
154                    else
155                    {
156                        message("Application crashed too much, stop reloading");
157                    }
158                    break;
159	        }
160        }
161    }
162}
163
164
165public class SimpleAppObject: AppObject
166{
167
168    public SimpleAppObject()
169    {
170        this.name = "";
171        this.command = {""};
172        this.guard = false;
173        this.application_type = "";
174    }
175}
176
177public class GenericAppObject: AppObject
178{
179
180    public GenericAppObject(AppType app_type)
181    {
182        this.name = app_type.name;
183        this.command = app_type.command;
184        this.guard = app_type.guard;
185        this.application_type = app_type.application_type;
186    }
187}
188
189public class GenericSimpleApp: SimpleAppObject
190{
191    public string settings_command { get; set; default = "";}
192
193    public GenericSimpleApp (string argument)
194    {
195        settings_command = argument;
196        init();
197    }
198
199    public override void read_settings()
200    {
201        string[] create_command = settings_command.split_set(" ",0);
202        this.name = create_command[0];
203        this.command = create_command;
204    }
205}
206
207public class WindowsManagerApp: SimpleAppObject
208{
209    string wm_command;
210    string mode;
211    string session;
212    string extras;
213
214    public WindowsManagerApp ()
215    {
216        init();
217    }
218
219    public override void read_settings()
220    {
221        if (global_settings.get_item_string("Session", "window_manager", null) != null)
222        {
223            mode = "simple";
224            wm_command = global_settings.get_item_string("Session", "window_manager", null);
225            session = "";
226            extras = "";
227        }
228        else
229        {
230            mode = "advanced";
231            wm_command = global_settings.get_item_string("Session", "windows_manager", "command");
232            session = global_settings.get_item_string("Session", "windows_manager", "session");
233            extras = global_settings.get_item_string("Session", "windows_manager", "extras");
234        }
235
236        string session_command;
237
238        if (wm_command == "wm_safe")
239        {
240            this.name = "wm_safe";
241            this.command = {find_window_manager()};
242        }
243        else
244        {
245            if (mode == "simple")
246            {
247                this.name = wm_command;
248                this.command = {wm_command};
249            }
250            else
251            {
252                this.name = wm_command;
253                string create_command;
254                string xdg_config_env = Environment.get_variable("XDG_CONFIG_HOME");
255                switch (wm_command)
256                {
257                    case "openbox":
258                        switch (session)
259                        {
260                            case "LXDE":
261                                session_command = " --config-file " + xdg_config_env + "/openbox/lxde-rc.xml";
262                                break;
263                            case "Lubuntu":
264                                session_command = " --config-file " + xdg_config_env + "/openbox/lubuntu-rc.xml";
265                                break;
266                            default:
267                                session_command = " ";
268                                break;
269                        }
270                        break;
271
272                    case "openbox-custom":
273                        switch (session)
274                        {
275                            default:
276                                session_command = " --config-file " + session;
277                                break;
278                        }
279                        break;
280
281                    default:
282                        session_command = null;
283                        break;
284                }
285
286                switch (extras)
287                {
288                    case null:
289                        create_command = wm_command + session_command;
290                        break;
291                    case "":
292                        create_command = wm_command + session_command;
293                        break;
294                    case " ":
295                        create_command = wm_command + session_command;
296                        break;
297                    default:
298                        create_command = wm_command + session_command + " " + extras;
299                        break;
300                }
301
302                this.command = create_command.split_set(" ",0);
303            }
304        }
305        this.guard = true;
306    }
307
308    private string find_window_manager()
309    {
310
311        var wm_list = new Array<string> ();
312
313        wm_list.append_val("openbox-lxde");
314        wm_list.append_val("openbox-lubuntu");
315        wm_list.append_val("openbox");
316        wm_list.append_val("compiz");
317        wm_list.append_val("kwin");
318        wm_list.append_val("mutter");
319        wm_list.append_val("fluxbox");
320        wm_list.append_val("metacity");
321        wm_list.append_val("xfwin");
322        wm_list.append_val("matchbox");
323
324        string return_value = "";
325
326        for(int i = 0; i < wm_list.length; ++i)
327        {
328			unowned string wm = wm_list.index(i);
329            string test_wm = Environment.find_program_in_path(wm);
330            if ( test_wm != null)
331            {
332                message ("Finding %s",wm);
333                return_value = wm;
334                break;
335            }
336        }
337
338        return return_value;
339
340    }
341
342    private void callback_pid(Pid pid, int status)
343    {
344        /* Help :  http://en.wikipedia.org/wiki/Signal_(computing)
345                   http://valadoc.org/glib-2.0/GLib.ProcessSignal.html
346        */
347        message("%s exit with this type of exit: %i\n", this.name, status);
348
349        if (status == -1)
350        {
351            this.name = "wm_safe";
352            this.command = {find_window_manager()};
353            global_settings.set_generic_default("Session", "windows_manager", "command", "string", "wm_safe");
354        }
355
356        Process.close_pid (pid);
357
358        if (this.guard == true)
359        {
360	        switch (status)
361            {
362                case 0:
363                    message("Exit normal, don't reload");
364                    break;
365                case 15:
366                    message("Exit by the user, don't reload");
367                    break;
368                case 256:
369                    message("Exit normal, don't reload");
370                    break;
371                default:
372                    message("Exit not normal, try to reload");
373                    this.crash_count = this.crash_count + 1;
374                    if (this.crash_count <= this.stop_reload)
375                    {
376                        this.launch();
377                    }
378                    else
379                    {
380                        message("Application crashed too much, stop reloading");
381                    }
382                    break;
383	        }
384        }
385    }
386
387    public new void launch ()
388    {
389        this.read_config_settings();
390        this.read_settings();
391
392        if (this.name != null)
393        {
394            try
395            {
396                string[] spawn_env = Environ.get ();
397                Process.spawn_async (
398                             null,
399                             this.command,
400                             spawn_env,
401                             SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
402                             null,
403                             out pid);
404                ChildWatch.add(pid, this.callback_pid);
405
406                for (int a = 0 ; a <= this.command.length ; a++)
407                {
408                    GLib.stdout.printf("%s ",this.command[a]);
409                }
410                GLib.stdout.printf("\n");
411
412            }
413            catch (SpawnError err)
414            {
415                warning (err.message);
416            }
417        }
418
419    }
420}
421
422public class PanelApp: SimpleAppObject
423{
424    public string panel_command;
425    public string panel_session;
426
427    public PanelApp ()
428    {
429        init();
430    }
431
432    public override void read_config_settings()
433    {
434        panel_command = global_settings.get_item_string("Session", "panel", "command");
435        // message("DEBUG6 : %s", global_settings.get_item_string("Session", "panel", "command"));
436        panel_session = global_settings.get_item_string("Session", "panel", "session");
437        // message("DEBUG6 : %s", global_settings.get_item_string("Session", "panel", "session"));
438    }
439
440    public override void read_settings()
441    {
442        switch (panel_command)
443        {
444            case "lxpanel":
445                this.name = panel_command;
446                if (panel_session != null)
447                {
448                    string create_command = "lxpanel --profile " + panel_session;
449                    this.command = create_command.split_set(" ",0);
450                }
451                else
452                {
453                    this.command = {panel_command};
454                }
455                break;
456            case "awn":
457                this.name = panel_command;
458                string create_command = "avant-window-navigator";
459                this.command = create_command.split_set(" ",0);
460                break;
461            default:
462                string[] create_command = panel_command.split_set(" ",0);
463                this.name = create_command[0];
464                this.command = create_command;
465                break;
466        }
467        this.guard = true;
468    }
469}
470
471public class DockApp: PanelApp
472{
473    public DockApp ()
474    {
475        init();
476    }
477
478    public override void read_config_settings()
479    {
480        panel_command = global_settings.get_item_string("Session", "dock", "command");
481        panel_session = global_settings.get_item_string("Session", "dock", "session");
482    }
483}
484
485public class ScreensaverApp: SimpleAppObject
486{
487    string screensaver_command;
488
489    public ScreensaverApp ()
490    {
491        init();
492    }
493
494    public override void read_settings()
495    {
496        screensaver_command = global_settings.get_item_string("Session", "screensaver", "command");
497
498        switch (screensaver_command)
499        {
500            case "xscreensaver":
501                this.name = screensaver_command;
502                string create_command = "xscreensaver -no-splash";
503                this.command = create_command.split_set(" ",0);
504                break;
505            default:
506                string[] create_command = screensaver_command.split_set(" ",0);
507                this.name = create_command[0];
508                this.command = create_command;
509                break;
510        }
511        this.guard = true;
512    }
513}
514
515public class PowerManagerApp: SimpleAppObject
516{
517    string powermanager_command;
518    string laptop_mode;
519
520    public PowerManagerApp ()
521    {
522        init();
523    }
524
525    public override void read_settings()
526    {
527        powermanager_command = global_settings.get_item_string("Session", "power_manager", "command");
528        laptop_mode = global_settings.get_item_string("State", "laptop_mode", null);
529
530        switch (powermanager_command)
531        {
532            case "auto":
533                /* If we are on a laptop, we need a power manager, try to start xfce one */
534                /* If we are not on a laptop, assume we don't need power management */
535                if (laptop_mode == "yes")
536                {
537                    string create_command = "xfce4-power-manager";
538                    this.name = "xfce4-power-manager";
539                    this.command = create_command.split_set(" ",0);
540                }
541
542                break;
543            case "no":
544                this.name = "power_manager_off";
545                break;
546            default:
547                string[] create_command = powermanager_command.split_set(" ",0);
548                this.name = create_command[0];
549                this.command = create_command;
550                break;
551        }
552        this.guard = true;
553    }
554}
555
556public class FileManagerApp: SimpleAppObject
557{
558    string filemanager_command;
559    string filemanager_session;
560    string filemanager_extras;
561
562    public FileManagerApp ()
563    {
564        init();
565    }
566
567    public override void read_settings()
568    {
569        filemanager_command = global_settings.get_item_string("Session", "file_manager", "command");
570        filemanager_session = global_settings.get_item_string("Session", "file_manager", "session");
571        filemanager_extras = global_settings.get_item_string("Session", "file_manager", "extras");
572
573        switch (filemanager_command)
574        {
575            case "pcmanfm":
576                this.name = filemanager_command;
577                if (filemanager_session != null)
578                {
579                    string create_command = "pcmanfm --profile " + filemanager_session + filemanager_extras;
580                    this.command = create_command.split_set(" ",0);
581                }
582                else
583                {
584                    this.command = {filemanager_command};
585                }
586                break;
587            case "pcmanfm-qt":
588                this.name = filemanager_command;
589                if (filemanager_session != null)
590                {
591                    string create_command = "pcmanfm-qt --profile " + filemanager_session + filemanager_extras;
592                    this.command = create_command.split_set(" ",0);
593                }
594                else
595                {
596                    this.command = {filemanager_command};
597                }
598                break;
599            case "nautilus":
600                this.name = filemanager_command;
601                string create_command = "nautilus" + " -n " + filemanager_extras;
602                this.command = create_command.split_set(" ",0);
603                break;
604            default:
605                string[] create_command = filemanager_command.split_set(" ",0);
606                this.name = create_command[0];
607                this.command = create_command;
608                break;
609        }
610    }
611}
612
613public class DesktopApp: SimpleAppObject
614{
615    string desktop_command;
616    string desktop_wallpaper;
617
618    public DesktopApp ()
619    {
620        init();
621    }
622
623    public override void read_settings()
624    {
625
626        desktop_command = global_settings.get_item_string("Session", "desktop_manager", "command");
627        desktop_wallpaper = global_settings.get_item_string("Session", "desktop_manager", "wallpaper");
628
629        switch (desktop_command)
630        {
631            case "filemanager":
632                string filemanager_session = global_settings.get_item_string("Session", "file_manager", "session");
633                string filemanager_extras = global_settings.get_item_string("Session", "file_manager", "extras");
634
635                if (global_file_manager != null)
636                {
637                    message("File manager needed for desktop manager but doesn't exist, creating it");
638                    var filemanager = new FileManagerApp();
639                    global_file_manager = filemanager;
640                }
641
642                switch (global_settings.get_item_string("Session", "file_manager", "command"))
643                {
644                    case "pcmanfm":
645                        this.name = global_settings.get_item_string("Session", "file_manager", "command");
646                        string create_command = "pcmanfm --desktop --profile " + filemanager_session + filemanager_extras;
647                        this.command = create_command.split_set(" ",0);
648                        break;
649                    case "pcmanfm-qt":
650                        this.name = global_settings.get_item_string("Session", "file_manager", "command");
651                        string create_command = "pcmanfm-qt --desktop --profile " + filemanager_session + filemanager_extras;
652                        this.command = create_command.split_set(" ",0);
653                        break;
654                    case "nautilus":
655                        this.name = global_settings.get_item_string("Session", "file_manager", "command");
656                        string create_command = "nautilus" + " -n " + filemanager_extras;
657                        this.command = create_command.split_set(" ",0);
658                        break;
659                }
660                break;
661            case "feh":
662                this.name = desktop_command;
663                string create_command = "feh" + " --bg-scale " + desktop_wallpaper;
664                this.command = create_command.split_set(" ",0);
665                break;
666            default:
667                string[] create_command = desktop_command.split_set(" ",0);
668                this.name = create_command[0];
669                this.command = create_command;
670                break;
671        }
672        this.guard = true;
673    }
674
675    public void launch_settings()
676    {
677        string[] backup_command = this.command;
678
679        switch (this.name)
680        {
681            case "pcmanfm":
682                string create_settings_command = "pcmanfm --desktop-pref";
683                this.command = create_settings_command.split_set(" ",0);
684                break;
685
686            default:
687                break;
688        }
689        this.launch();
690        this.command = backup_command;
691    }
692
693}
694
695public class PolkitApp: SimpleAppObject
696{
697    string polkit_command;
698
699    public PolkitApp ()
700    {
701        init();
702    }
703
704    public override void read_settings()
705    {
706        polkit_command = global_settings.get_item_string("Session", "polkit", "command");
707
708        switch (polkit_command)
709        {
710            case "gnome":
711                this.name = "polkit-gnome-authentication-agent-1";
712                string create_command = "/usr/local/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1";
713                this.command = create_command.split_set(" ",0);
714                break;
715            case "razorqt":
716                this.name = "razor-policykit-agent";
717                string create_command = "/usr/bin/razor-policykit-agent";
718                this.command = create_command.split_set(" ",0);
719                break;
720            case "lxpolkit":
721                message("polkit separate");
722                this.name = "lxpolkit";
723                string create_command = "lxpolkit";
724                this.command = create_command.split_set(" ",0);
725                break;
726        }
727        this.guard = true;
728
729    }
730
731#if BUILDIN_POLKIT
732    public new void launch ()
733    {
734        policykit_agent_init();
735    }
736#endif
737
738    public void deactivate ()
739    {
740#if BUILDIN_POLKIT
741        policykit_agent_finalize();
742#endif
743    }
744}
745
746public class NetworkGuiApp: SimpleAppObject
747{
748    string network_command;
749    string laptop_mode;
750
751    public NetworkGuiApp ()
752    {
753        init();
754    }
755
756    public override void read_settings()
757    {
758        network_command = global_settings.get_item_string("Session", "network_gui", "command");
759        laptop_mode = global_settings.get_item_string("State", "laptop_mode", null);
760
761        switch (network_command)
762        {
763            case "no":
764                /* Don't start anything */
765                break;
766            case "auto":
767                /* If we are on a laptop, assume we need a GUI, and try to find one, starting with nm-applet */
768                /* If you are not on a laptop, assume we don't need any GUI */
769                if (laptop_mode == "yes")
770                {
771                    string test_nm_applet = Environment.find_program_in_path("nm-applet");
772                     if (test_nm_applet != null)
773                     {
774                         this.name = "nm-applet";
775                         string create_command = "nm-applet";
776                         this.command = create_command.split_set(" ",0);
777                         break;
778                     }
779                     else
780                     {
781                        string test_wicd = Environment.find_program_in_path("wicd");
782                        if (test_wicd != null)
783                        {
784                            this.name = "wicd";
785                            string create_command = "wicd";
786                            this.command = create_command.split_set(" ",0);
787                            break;
788                        }
789                    }
790                }
791                 break;
792            default:
793                string[] create_command = network_command.split_set(" ",0);
794                this.name = create_command[0];
795                this.command = create_command;
796                break;
797        }
798        this.guard = true;
799    }
800}
801
802public class AudioManagerApp: SimpleAppObject
803{
804    string audiomanager_command;
805
806    public AudioManagerApp ()
807    {
808        init();
809    }
810
811    public override void read_settings()
812    {
813        audiomanager_command = global_settings.get_item_string("Session", "audio_manager", "command");
814
815        switch (audiomanager_command)
816        {
817            case "alsamixer":
818                this.name = "alsamixer";
819                string create_command = "xterm -e alsamixer";
820                this.command = create_command.split_set(" ",0);
821                break;
822            default:
823                string[] create_command = audiomanager_command.split_set(" ",0);
824                this.name = create_command[0];
825                this.command = create_command;
826                break;
827        }
828    }
829}
830
831public class QuitManagerApp: SimpleAppObject
832{
833    string quitmanager_command;
834    string quitmanager_image;
835    string quitmanager_layout;
836
837
838    public QuitManagerApp ()
839    {
840        init();
841    }
842
843    public override void read_settings()
844    {
845        quitmanager_command = global_settings.get_item_string("Session", "quit_manager", "command");
846        quitmanager_image = global_settings.get_item_string("Session", "quit_manager", "image");
847        quitmanager_layout = global_settings.get_item_string("Session", "quit_manager", "layout");
848
849        switch (quitmanager_command)
850        {
851            case "lxsession-logout":
852                this.name = "lxsession-logout";
853                string create_command = "lxsession-logout --banner " + quitmanager_image + " --side=" + quitmanager_layout;
854                this.command = create_command.split_set(" ",0);
855                break;
856            default:
857                string[] create_command = quitmanager_command.split_set(" ",0);
858                this.name = create_command[0];
859                this.command = create_command;
860                break;
861        }
862    }
863}
864
865public class WorkspaceManagerApp: SimpleAppObject
866{
867    string workspacemanager_command;
868
869    public WorkspaceManagerApp ()
870    {
871        init();
872    }
873
874    public override void read_settings()
875    {
876        workspacemanager_command = global_settings.get_item_string("Session", "workspace_manager", "command");
877
878        switch (workspacemanager_command)
879        {
880            case "obconf":
881                this.name = "obconf";
882                string create_command = "obconf --tab 6";
883                this.command = create_command.split_set(" ",0);
884                break;
885            default:
886                string[] create_command = workspacemanager_command.split_set(" ",0);
887                this.name = create_command[0];
888                this.command = create_command;
889                break;
890        }
891    }
892}
893
894public class LauncherManagerApp: SimpleAppObject
895{
896    string launchermanager_command;
897
898    public LauncherManagerApp ()
899    {
900        init();
901    }
902
903    public override void read_settings()
904    {
905        launchermanager_command = global_settings.get_item_string("Session", "launcher_manager", "command");
906
907        switch (launchermanager_command)
908        {
909            case "lxpanelctl":
910                this.name = "lxpanelctl";
911                string create_command = "lxpanelctl run";
912                this.command = create_command.split_set(" ",0);
913                break;
914            default:
915                string[] create_command = launchermanager_command.split_set(" ",0);
916                this.name = create_command[0];
917                this.command = create_command;
918                break;
919        }
920    }
921
922    public void autostart_launch()
923    {
924        switch (launchermanager_command)
925        {
926            case "synapse":
927                string create_autostart_command = "synapse --startup";
928                lxsession_spawn_command_line_async(create_autostart_command);
929                break;
930            default:
931                this.launch();
932                break;
933        }
934    }
935}
936
937public class TerminalManagerApp: SimpleAppObject
938{
939    string terminalmanager_command;
940
941    public TerminalManagerApp ()
942    {
943        init();
944    }
945
946    public override void read_config_settings()
947    {
948        terminalmanager_command = global_settings.get_item_string("Session", "terminal_manager", "command");
949    }
950
951    public override void read_settings()
952    {
953        switch (terminalmanager_command)
954        {
955            case "lxterminal":
956                this.name = "lxterminal";
957                string create_command = "lxterminal -e";
958                this.command = create_command.split_set(" ",0);
959                break;
960            default:
961                string[] create_command = terminalmanager_command.split_set(" ",0);
962                this.name = create_command[0];
963                this.command = create_command;
964                break;
965        }
966    }
967
968    public new void launch (string argument)
969    {
970        if (argument == "")
971        {
972            argument = null;
973        }
974
975        generic_launch (argument);
976    }
977}
978
979public class ProxyManagerApp: SimpleAppObject
980{
981    string proxymanager_command;
982    string proxymanager_http;
983
984    public ProxyManagerApp ()
985    {
986        init();
987    }
988
989    public override void read_settings()
990    {
991        proxymanager_command = global_settings.get_item_string("Session", "proxy_manager", "command");
992        proxymanager_http = global_settings.get_item_string("Session", "proxy_manager", "http");
993
994        switch (proxymanager_command)
995        {
996            case "build-in":
997                switch (proxymanager_http)
998                {
999                    case null:
1000                        break;
1001                    case "":
1002                        break;
1003                    case " ":
1004                        break;
1005                    default:
1006                    Environment.set_variable("HTTP_PROXY", proxymanager_http, true);
1007                    break;
1008                }
1009                break;
1010        }
1011    }
1012}
1013
1014public class A11yApp: SimpleAppObject
1015{
1016    string a11y_command;
1017
1018    public A11yApp ()
1019    {
1020        init();
1021    }
1022
1023    public override void read_settings()
1024    {
1025        a11y_command = global_settings.get_item_string("Session", "a11y", "command");
1026
1027        switch (a11y_command)
1028        {
1029            case null:
1030                break;
1031            case "":
1032                break;
1033            case " ":
1034                break;
1035            case "gnome":
1036                string tmp_command = "/usr/local/lib/at-spi2-core/at-spi-bus-launcher --launch-immediately";
1037                string[] create_command = tmp_command.split_set(" ",0);
1038                this.name = create_command[0];
1039                this.command = create_command;
1040                break;
1041            default:
1042                string[] create_command = a11y_command.split_set(" ",0);
1043                this.name = create_command[0];
1044                this.command = create_command;
1045                break;
1046        }
1047    }
1048}
1049
1050public class XrandrApp: SimpleAppObject
1051{
1052    /*  Don't use GenericApp, we may want to implement other option than
1053        reading a xrandr command directly
1054    */
1055    string xrandr_command;
1056
1057    public XrandrApp ()
1058    {
1059        init();
1060    }
1061
1062    public override void read_settings()
1063    {
1064        xrandr_command = global_settings.get_item_string("Session", "xrandr", "command");
1065
1066        switch (xrandr_command)
1067        {
1068            case null:
1069                break;
1070            case "":
1071                break;
1072            case " ":
1073                break;
1074            default:
1075                string[] create_command = xrandr_command.split_set(" ",0);
1076                this.name = create_command[0];
1077                this.command = create_command;
1078                break;
1079        }
1080    }
1081}
1082
1083public class KeyringApp: SimpleAppObject
1084{
1085    string keyring_command;
1086    string keyring_type;
1087
1088    public KeyringApp ()
1089    {
1090        init();
1091    }
1092
1093    public override void read_settings()
1094    {
1095        keyring_command = global_settings.get_item_string("Session", "keyring", "command");
1096        keyring_type = global_settings.get_item_string("Session", "keyring", "type");
1097
1098        switch (keyring_command)
1099        {
1100            case "gnome-all":
1101                string tmp_command = "gnome-keyring-daemon --start --components=pkcs11,secrets,ssh,gpg";
1102                string[] create_command = tmp_command.split_set(" ",0);
1103                this.name = create_command[0];
1104                this.command = create_command;
1105                break;
1106            case "ssh-agent":
1107                string tmp_command = "/usr/bin/ssh-agent -s";
1108                string[] create_command = tmp_command.split_set(" ",0);
1109                this.name = create_command[0];
1110                this.command = create_command;
1111                break;
1112            default:
1113                string[] create_command = keyring_command.split_set(" ",0);
1114                this.name = create_command[0];
1115                this.command = create_command;
1116                break;
1117        }
1118    }
1119}
1120
1121public class ScreenshotManagerApp: SimpleAppObject
1122{
1123    string screenshotmanager_command;
1124
1125    public ScreenshotManagerApp ()
1126    {
1127        init();
1128    }
1129
1130    public override void read_settings()
1131    {
1132        screenshotmanager_command = global_settings.get_item_string("Session", "screenshot_manager", "command");
1133
1134        switch (screenshotmanager_command)
1135        {
1136            default:
1137                string[] create_command = screenshotmanager_command.split_set(" ",0);
1138                this.name = create_command[0];
1139                this.command = create_command;
1140                break;
1141        }
1142    }
1143
1144    public void window_launch()
1145    {
1146        read_settings();
1147
1148        string[] backup_command = this.command;
1149
1150        switch (screenshotmanager_command)
1151        {
1152            case "scrot":
1153                string create_window_command = "scrot -u -b";
1154                this.command = create_window_command.split_set(" ",0);
1155                break;
1156
1157            default:
1158                break;
1159        }
1160
1161        this.launch();
1162        this.command = backup_command;
1163    }
1164}
1165
1166public class UpdatesManagerApp: SimpleAppObject
1167{
1168    string updatesmanager_command;
1169
1170    IconObject updates_icon;
1171    MenuObject icon_menu;
1172
1173    IconObject language_icon;
1174
1175    IconObject reboot_icon;
1176
1177    string apt_update_path = "/var/lib/apt/periodic/update-success-stamp";
1178    GLib.File apt_update_file ;
1179    GLib.FileMonitor apt_update_monitor ;
1180
1181    string dpkg_update_path = "/var/lib/dpkg/status";
1182    GLib.File dpkg_update_file ;
1183    GLib.FileMonitor dpkg_update_monitor ;
1184
1185    string dpkg_run_path = "/var/lib/update-notifier/dpkg-run-stamp";
1186    GLib.File dpkg_run_file ;
1187    GLib.FileMonitor dpkg_run_monitor ;
1188
1189    string apt_lists_update_path = "/var/lib/apt/lists";
1190    GLib.File apt_lists_update_file ;
1191    GLib.FileMonitor apt_lists_update_monitor ;
1192
1193    string reboot_path = "/var/run/reboot-required";
1194    GLib.File reboot_file ;
1195    GLib.FileMonitor reboot_monitor ;
1196
1197    string dpkg_lock_file = "/var/lib/dpkg/lock";
1198
1199    int lock_check = 0;
1200
1201    public UpdatesManagerApp ()
1202    {
1203        init();
1204    }
1205
1206    public override void read_settings()
1207    {
1208        updatesmanager_command = global_settings.get_item_string("Session", "updates_manager", "command");
1209
1210        switch (updatesmanager_command)
1211        {
1212            case null:
1213                break;
1214            case "":
1215                break;
1216            case " ":
1217                break;
1218            case "update-notifier-clone":
1219                setup_apt_config();
1220                setup_reboot_config();
1221                run_check();
1222                break;
1223            default:
1224                string[] create_command = updatesmanager_command.split_set(" ",0);
1225                this.name = create_command[0];
1226                this.command = create_command;
1227                break;
1228        }
1229    }
1230
1231    public void test_inactivate()
1232    {
1233        updates_icon.inactivate();
1234    }
1235
1236    public void test_activate()
1237    {
1238        updates_icon.activate();
1239    }
1240
1241    public void run_check()
1242    {
1243        if (this.lock_check == 0)
1244        {
1245            if (check_lock_file(dpkg_lock_file) == true)
1246            {
1247                this.lock_check = 1;
1248                int timeout = 60;
1249                if (global_settings.get_item_string("Session", "updates_manager", "timeout") != null)
1250                {
1251                    timeout = int.parse(global_settings.get_item_string("Session", "updates_manager", "timeout"));
1252                }
1253                GLib.Timeout.add_seconds(timeout, on_apt_update_file_change);
1254            }
1255        }
1256    }
1257
1258    public void reboot_launch()
1259    {
1260        var session = new SessionObject();
1261        session.lxsession_restart();
1262    }
1263
1264    public void run_check_reboot()
1265    {
1266        string notification_text ="";
1267
1268        if (this.reboot_file.query_exists ())
1269        {
1270            if (this.reboot_icon == null)
1271            {
1272                var reboot_icon_menu = new MenuObject() ;
1273                string line = _("Reboot required");
1274
1275                try
1276                {
1277                    var dis = new DataInputStream (this.reboot_file.read ());
1278                    line = dis.read_line ();
1279                }
1280                catch (GLib.Error e)
1281                {
1282                    message ("Error: %s\n", e.message);
1283                }
1284
1285                if (line != null)
1286                {
1287                    notification_text = line;
1288                }
1289
1290                var menu_item = new MenuItemObject();
1291                menu_item.set_label(notification_text);
1292                menu_item.activate.connect(() => {
1293                    reboot_launch();
1294                });
1295                menu_item.show();
1296                reboot_icon_menu.add(menu_item);
1297
1298                this.reboot_icon = new IconObject("RebootIcon", "system-reboot", notification_text, reboot_icon_menu);
1299                this.reboot_icon.init();
1300                this.reboot_icon.clear_actions ();
1301                this.reboot_icon.add_action ("launch_reboot", _("Reboot"), () =>
1302                {
1303                    reboot_launch();
1304                });
1305                this.reboot_icon.activate();
1306            }
1307        }
1308        else
1309        {
1310            if (this.reboot_icon != null)
1311            {
1312                this.reboot_icon.inactivate();
1313            }
1314        }
1315    }
1316
1317    public void language_launch()
1318    {
1319        if (this.language_icon != null)
1320        {
1321            try
1322            {
1323                Process.spawn_command_line_async("gnome-language-selector");
1324                this.language_icon.inactivate();
1325            }
1326            catch (SpawnError err)
1327            {
1328                warning (err.message);
1329            }
1330        }
1331    }
1332
1333    public void check_language_support()
1334    {
1335        string command = "check-language-support";
1336
1337        string standard_output;
1338        string standard_error;
1339        int exit_status;
1340
1341        string launch_string = _("Launch language support");
1342
1343        try
1344        {
1345            Process.spawn_command_line_sync (command, out standard_output, out standard_error, out exit_status);
1346
1347            message ("Launching %s", command);
1348            message ("Language state: %s", standard_error);
1349            message ("Language exit status: %i", exit_status);
1350            message ("Language output: %s", standard_output);
1351
1352        }
1353        catch (SpawnError err)
1354        {
1355            warning (err.message);
1356        }
1357
1358        if (standard_output != null)
1359        {
1360            if (standard_output.length >= 3)
1361            {
1362                if (this.language_icon == null)
1363                {
1364                    var language_icon_menu = new MenuObject() ;
1365
1366                    var menu_item = new MenuItemObject();
1367                    menu_item.set_label(launch_string);
1368                    menu_item.activate.connect(() => {
1369                        language_launch();
1370                    });
1371                    menu_item.show();
1372                    language_icon_menu.add(menu_item);
1373
1374                    this.language_icon = new IconObject("LanguageIcon", "preferences-desktop-locale", _("Language support missing"), language_icon_menu);
1375                    this.language_icon.init();
1376                    this.language_icon.clear_actions ();
1377                    this.language_icon.add_action ("launch_language_support", launch_string, () =>
1378                    {
1379                        language_launch();
1380                    });
1381                    this.language_icon.activate();
1382                }
1383            }
1384            else if (this.language_icon != null)
1385                {
1386                    this.language_icon.inactivate();
1387                }
1388        }
1389        else if (this.language_icon != null)
1390            {
1391                this.language_icon.inactivate();
1392            }
1393    }
1394
1395    public void upgrade_launch (string upgrade_manager_command)
1396    {
1397        try
1398        {
1399            Process.spawn_command_line_async(upgrade_manager_command);
1400        }
1401        catch (SpawnError err)
1402        {
1403            warning (err.message);
1404        }
1405    }
1406
1407    public bool on_apt_update_file_change()
1408    {
1409        /* Launch something that check if updates are available */
1410        /* For now, use lxsession-apt-check, which is apt-check from update-notifier */
1411
1412        string standard_output;
1413        string standard_error;
1414        int exit_status;
1415
1416        string notification_text = _("Updates available");
1417
1418        string launch_string = _("Launch Update Manager");
1419        string upgrade_manager_command = "";
1420
1421        string[] updates_num;
1422        int updates_urgent = 0;
1423        int updates_normal = 0;
1424        int updates_state = 0;
1425        int number_updates = 0;
1426
1427        /* Lock the check process, to avoid launching the check many times when one is already running */
1428        this.lock_check = 1;
1429
1430        if (this.icon_menu == null)
1431        {
1432            this.icon_menu = new MenuObject();
1433
1434            if (global_settings.get_item_string("Session", "upgrade_manager", "command") != null)
1435            {
1436                upgrade_manager_command = global_settings.get_item_string("Session", "upgrade_manager", "command");
1437
1438                var menu_item = new MenuItemObject();
1439                menu_item.set_label(launch_string);
1440                menu_item.activate.connect(() => {
1441                    upgrade_launch (upgrade_manager_command);
1442                });
1443                menu_item.show();
1444                icon_menu.add(menu_item);
1445            }
1446        }
1447
1448        string command = "/usr/bin/nice" + " " + "/usr/bin/ionice" + " " + "-c3" + " " + "/usr/local/lib/update-notifier/apt-check";
1449
1450        string error_string = "";
1451
1452        try
1453        {
1454            Process.spawn_command_line_sync (command, out standard_output, out standard_error, out exit_status);
1455
1456            message ("Launching %s", command);
1457            message ("Update state: %s", standard_error);
1458            message ("Update exit status: %i", exit_status);
1459
1460        }
1461        catch (SpawnError err)
1462        {
1463            warning (err.message);
1464        }
1465
1466        if (this.updates_icon == null)
1467        {
1468            this.updates_icon = new IconObject("UpdatesIcon", "software-update-available", notification_text, this.icon_menu);
1469            this.updates_icon.init();
1470            if (global_settings.get_item_string("Session", "upgrade_manager", "command") != null)
1471            {
1472                upgrade_manager_command = global_settings.get_item_string("Session", "upgrade_manager", "command");
1473                this.updates_icon.clear_actions ();
1474                this.updates_icon.add_action ("launch_upgrade_manager", launch_string, () =>
1475                {
1476                    upgrade_launch (upgrade_manager_command);
1477                });
1478            }
1479            this.updates_icon.inactivate();
1480        }
1481        else
1482        {
1483            this.updates_icon.inactivate();
1484        }
1485
1486        if (standard_error != "")
1487        {
1488            if (standard_error[0:1] == "E")
1489            {
1490                updates_urgent = 0;
1491                updates_normal = 0;
1492                updates_state = 1;
1493                error_string =   _("An error occurred, please run Package Manager from the left-click menu or apt-get in a terminal to see what is wrong.");
1494                if (standard_error.length > 3)
1495                {
1496                    notification_text = error_string + "\n" + _("The error message was: ") + standard_error;
1497                }
1498                else
1499                {
1500                    notification_text = error_string;
1501                }
1502            }
1503            else
1504                {
1505                    updates_num = standard_error.split_set(";",2);
1506                    message ("Number of upgrades: %s", updates_num[0]);
1507                    message ("Number of security upgrades: %s", updates_num[1]);
1508                    updates_num[2] = "0";
1509
1510                    updates_urgent = int.parse(updates_num[1]);
1511                    updates_normal = int.parse(updates_num[0]);
1512                    number_updates = updates_normal + updates_urgent;
1513
1514                    if (number_updates == 1)
1515                    {
1516                        notification_text = number_updates.to_string() + _(" Update available");
1517                    }
1518                    else if (number_updates > 1)
1519                        {
1520                            notification_text = number_updates.to_string() + (" ") + _("Updates available");
1521                        }
1522                }
1523
1524        }
1525        else
1526        {
1527            updates_state = 1;
1528        }
1529
1530
1531        if (number_updates > 0)
1532        {
1533            message("Activate icon because of updates available");
1534            this.updates_icon.set_notification_body(notification_text);
1535            this.updates_icon.activate();
1536        }
1537
1538        if (updates_urgent > 0)
1539        {
1540            message("Set urgent icon");
1541            this.updates_icon.set_icon("software-update-urgent");
1542            this.updates_icon.set_notification_body(notification_text);
1543        }
1544
1545
1546        if (updates_state > 0)
1547        {
1548            message("Problem in package state");
1549            this.updates_icon.set_icon("software-update-urgent");
1550            this.updates_icon.set_notification_body(notification_text);
1551            this.updates_icon.clear_actions ();
1552            this.updates_icon.add_action ("launch_upgrade_manager", launch_string, () =>
1553            {
1554                upgrade_launch ("synaptic-pkexec");
1555            });
1556            var new_menu = new MenuObject();
1557            var new_menu_item = new MenuItemObject();
1558            new_menu_item.set_label(launch_string);
1559            new_menu_item.activate.connect(() => {
1560                upgrade_launch ("synaptic-pkexec");
1561            });
1562            new_menu_item.show();
1563            new_menu.add(new_menu_item);
1564            this.updates_icon.set_menu(new_menu);
1565            this.updates_icon.activate();
1566        }
1567
1568        /* Check if language support is complete */
1569        check_language_support();
1570
1571        /* Check if a reboot is requiered */
1572        run_check_reboot();
1573
1574        /* Unlock the check */
1575        this.lock_check = 0;
1576
1577        return false;
1578    }
1579
1580    public void setup_apt_config ()
1581    {
1582        /* Note directories monitored by update-notifier :
1583                "/var/lib/apt/lists/" ==> files of meta data of the repositories
1584                "/var/lib/apt/lists/partial/"
1585                "/var/cache/apt/archives/" ==> .deb in cache
1586                "/var/cache/apt/archives/partial/"
1587
1588            Files monitored by update-notifier :
1589              "/var/lib/dpkg/status" => big file of dpkg status
1590              "/var/lib/update-notifier/dpkg-run-stamp" update-notifier stamp for dpkg ?
1591              "/var/lib/apt/periodic/update-success-stamp"
1592        */
1593
1594        try
1595        {
1596            this.apt_update_file = File.new_for_path(this.apt_update_path);
1597            this.apt_update_monitor = apt_update_file.monitor_file(GLib.FileMonitorFlags.NONE);
1598            this.apt_update_monitor.changed.connect(run_check);
1599            message ("Monitoring apt changes");
1600        }
1601        catch (GLib.Error err)
1602        {
1603            message (err.message);
1604        }
1605
1606        try
1607        {
1608            this.dpkg_update_file = File.new_for_path(this.dpkg_update_path);
1609            this.dpkg_update_monitor = dpkg_update_file.monitor_file(GLib.FileMonitorFlags.NONE);
1610            this.dpkg_update_monitor.changed.connect(run_check);
1611            message ("Monitoring dpkg changes");
1612        }
1613        catch (GLib.Error err)
1614        {
1615            message (err.message);
1616        }
1617
1618        try
1619        {
1620            this.dpkg_run_file = File.new_for_path(this.dpkg_run_path);
1621            this.dpkg_run_monitor = dpkg_run_file.monitor_file(GLib.FileMonitorFlags.NONE);
1622            this.dpkg_run_monitor.changed.connect(run_check);
1623            message ("Monitoring dpkg run changes");
1624        }
1625        catch (GLib.Error err)
1626        {
1627            message (err.message);
1628        }
1629
1630        try
1631        {
1632            this.apt_lists_update_file = File.new_for_path(this.apt_lists_update_path);
1633            this.apt_lists_update_monitor = apt_lists_update_file.monitor_directory(GLib.FileMonitorFlags.NONE);
1634            this.apt_lists_update_monitor.changed.connect(run_check);
1635            message ("Monitoring apt_lists changes");
1636        }
1637        catch (GLib.Error err)
1638        {
1639            message (err.message);
1640        }
1641    }
1642
1643    public void setup_reboot_config ()
1644    {
1645        try
1646        {
1647            this.reboot_file = File.new_for_path(this.reboot_path);
1648            this.reboot_monitor = reboot_file.monitor_file(GLib.FileMonitorFlags.NONE);
1649            this.reboot_monitor.changed.connect(run_check_reboot);
1650            message ("Monitoring reboot changes");
1651        }
1652        catch (GLib.Error err)
1653        {
1654            message (err.message);
1655        }
1656    }
1657
1658    /* From https://mail.gnome.org/archives/vala-list/2010-October/msg00036.html */
1659    public bool check_lock_file(string check_file)
1660    {
1661
1662            string lock_file_name = check_file;
1663            int fd = Posix.open (lock_file_name, Posix.O_RDWR);
1664            if (fd == -1)
1665            {
1666              print ("There was an error opening the file '"
1667                + lock_file_name + " (Error number "
1668                + Posix.errno.to_string() + ")\n");
1669              return true;
1670            }
1671
1672            // Try to get a lock
1673            Posix.Flock fl = Posix.Flock();
1674            fl.l_type = Posix.F_WRLCK;
1675            fl.l_whence = Posix.SEEK_SET;
1676            fl.l_start = 100;
1677            fl.l_len = 0;
1678
1679            int fcntl_return = Posix.fcntl (fd, Posix.F_SETLK, fl);
1680            if (fcntl_return == -1)
1681                    return true;
1682
1683            // Release the lock again
1684            fl.l_type = Posix.F_UNLCK;
1685            fl.l_whence = Posix.SEEK_SET;
1686            fl.l_start = 100;
1687            fl.l_len = 0;
1688            fcntl_return = Posix.fcntl (fd, Posix.F_SETLK, fl);
1689
1690            return false;
1691    }
1692
1693}
1694public class CrashManagerApp: SimpleAppObject
1695{
1696    string crash_manager_command;
1697    IconObject crash_icon;
1698
1699    string crash_dir_path = "/var/crash/";
1700    GLib.File crash_dir_file ;
1701    GLib.FileMonitor crash_dir_monitor ;
1702
1703    int lock_crash_check = 0;
1704
1705    public CrashManagerApp ()
1706    {
1707        init();
1708    }
1709
1710    public override void read_settings()
1711    {
1712        crash_manager_command = global_settings.get_item_string("Session", "crash_manager", "command");
1713
1714        switch (crash_manager_command)
1715        {
1716            case null:
1717                break;
1718            case "":
1719                break;
1720            case " ":
1721                break;
1722            case "apport-gtk":
1723                setup_crash_log_config ();
1724                run_crash_check();
1725                break;
1726            default:
1727                string[] create_command = crash_manager_command.split_set(" ",0);
1728                this.name = create_command[0];
1729                this.command = create_command;
1730                break;
1731        }
1732    }
1733
1734    public void test_activate ()
1735    {
1736        if (this.crash_icon != null)
1737        {
1738            this.crash_icon.activate();
1739        }
1740    }
1741
1742    public void test_inactivate ()
1743    {
1744        if (this.crash_icon != null)
1745        {
1746            this.crash_icon.inactivate();
1747        }
1748    }
1749
1750    public void setup_crash_log_config ()
1751    {
1752        try
1753        {
1754            this.crash_dir_file = File.new_for_path(this.crash_dir_path);
1755            this.crash_dir_monitor = crash_dir_file.monitor_directory(GLib.FileMonitorFlags.NONE);
1756            this.crash_dir_monitor.changed.connect(run_crash_check);
1757            message ("Monitoring crash dir changes");
1758        }
1759        catch (GLib.Error err)
1760        {
1761            message (err.message);
1762        }
1763    }
1764
1765    public void run_crash_check()
1766    {
1767        if (this.lock_crash_check == 0)
1768        {
1769            this.lock_crash_check = 1;
1770            int timeout = 60;
1771            if (global_settings.get_item_string("Session", "crash_manager", "timeout") != null)
1772            {
1773                timeout = int.parse(global_settings.get_item_string("Session", "crash_manager", "timeout"));
1774            }
1775            GLib.Timeout.add_seconds(timeout, on_crash_file_change);
1776        }
1777    }
1778
1779    public List<string> check_crash_file()
1780    {
1781        List<string> crash_list = new List<string> ();
1782        List<string> final_crash_list = new List<string> ();
1783        string[] uploaded_list = {};
1784        string file_name;
1785
1786        if (this.crash_dir_file != null)
1787        {
1788            try
1789            {
1790                var directory = File.new_for_path (crash_dir_path);
1791                var enumerator = directory.enumerate_children (FileAttribute.STANDARD_NAME, 0);
1792
1793                FileInfo file_info;
1794                while ((file_info = enumerator.next_file ()) != null)
1795                {
1796                    file_name = file_info.get_name();
1797                    if (file_name != ".lock")
1798                    {
1799                        if (file_name.has_suffix(".crash"))
1800                        {
1801                            message("Add to crash_list: %s", file_name);
1802                            crash_list.append(file_name);
1803                        }
1804                        else if (file_name.has_suffix(".uploaded"))
1805                        {
1806                            uploaded_list += file_name.replace(".uploaded", ".crash");
1807                            message("Added to upload_list: %s", file_name.replace(".uploaded", ".crash"));
1808                        }
1809                    }
1810                }
1811            }
1812            catch (Error e)
1813            {
1814                message ("Error: %s\n", e.message);
1815            }
1816        }
1817
1818        foreach (string element in crash_list)
1819        {
1820            message("Check element in crash_list: %s", element);
1821            if (uploaded_list != null)
1822            {
1823                if (element in uploaded_list)
1824                {
1825                    message("Remove element in crash_list: %s", element);
1826                }
1827                else
1828                {
1829                    final_crash_list.append(element);
1830                }
1831            }
1832            else
1833            {
1834                final_crash_list.append(element);
1835            }
1836        }
1837
1838        return final_crash_list;
1839    }
1840
1841    public void crash_report_launch (string command)
1842    {
1843        try
1844        {
1845            Process.spawn_command_line_async(command);
1846            message ("Launching crash command : %s", command);
1847        }
1848        catch (SpawnError err)
1849        {
1850            warning (err.message);
1851        }
1852    }
1853
1854    public MenuObject build_menu(List<string> crash_list)
1855    {
1856        uint len = crash_list.length();
1857        var menu = new MenuObject();
1858
1859        if (len >= 1)
1860        {
1861            foreach (string element in crash_list)
1862            {
1863                string command = "/usr/local/bin/pkexec /usr/local/share/apport/apport-gtk" + " " + this.crash_dir_path + element;
1864
1865                var menu_item = new MenuItemObject();
1866                menu_item.set_label(_("Report ") + element);
1867                menu_item.activate.connect(() => {
1868                        crash_report_launch(command);
1869                });
1870                menu_item.show();
1871                menu.add(menu_item);
1872            }
1873        }
1874
1875        return menu;
1876
1877    }
1878
1879    public bool on_crash_file_change ()
1880    {
1881        List<string> crash_list;
1882        uint len;
1883        MenuObject crash_menu;
1884
1885        /* Lock the check process, to avoid launching the check many times when one is already running */
1886        this.lock_crash_check = 1;
1887
1888        crash_list = check_crash_file();
1889        len = crash_list.length();
1890        uint last_item = len - 1;
1891
1892        if (len >= 1)
1893        {
1894            crash_menu = build_menu(crash_list);
1895            string command =  "/usr/local/bin/pkexec /usr/local/share/apport/apport-gtk" + " " + this.crash_dir_path + crash_list.nth_data(last_item) ;
1896            string remove_command = "/usr/local/bin/pkexec rm -f " + this.crash_dir_path + crash_list.nth_data(last_item);
1897
1898            string launch_string = "Report last crash";
1899            string remove_string = "Remove last crash";
1900
1901            if (this.crash_icon == null)
1902            {
1903                this.crash_icon = new IconObject("CrashIcon", "apport", _("Crash files available for report"), crash_menu);
1904                this.crash_icon.init();
1905            }
1906            this.crash_icon.set_menu(crash_menu);
1907            /* TODO Make a window dialog to be able to really report bug on notification screen (and also add the remove mode)
1908
1909            this.crash_icon.clear_actions ();
1910            this.crash_icon.add_action ("launch_crash_report", launch_string, () =>
1911            {
1912                crash_report_launch (command);
1913            });
1914            */
1915            if (global_settings.get_item_string("Session", "crash_manager", "dev_mode") == "yes")
1916            {
1917                this.crash_icon.add_action ("remove_crash_report", remove_string, () =>
1918                {
1919                    crash_report_launch (remove_command);
1920                });
1921            }
1922            this.crash_icon.activate();
1923        }
1924        /* Unlock the check */
1925        this.lock_crash_check = 0;
1926        return false;
1927    }
1928}
1929}
1930