d349a84a855590addb0264c56dd41efa35ebe286
[moonshot-ui.git] / src / moonshot-window.vala
1 using Gtk;
2
3 class MainWindow : Window
4 {
5     private const int WINDOW_WIDTH = 400;
6     private const int WINDOW_HEIGHT = 500;
7
8     private UIManager ui_manager = new UIManager();
9     private Entry search_entry;
10     private VBox vbox_right;
11     private CustomVBox custom_vbox;
12     private VBox services_internal_vbox;
13
14     private Entry username_entry;
15     private Entry password_entry;
16
17     private ListStore listmodel;
18     private TreeModelFilter filter;
19
20     public IdentitiesManager identities_manager;
21
22     private MoonshotServer ipc_server;
23
24     private IdCard default_id_card;
25     public Queue<IdentityRequest> request_queue;
26
27     private HashTable<Gtk.Button, string> service_button_map;
28
29     private enum Columns
30     {
31         IDCARD_COL,
32         LOGO_COL,
33         ISSUER_COL,
34         USERNAME_COL,
35         PASSWORD_COL,
36         N_COLUMNS
37     }
38
39     private const string layout =
40 "
41 <menubar name='MenuBar'>
42         <menu name='FileMenu' action='FileMenuAction'>
43             <menuitem name='AddIdCard' action='AddIdCardAction' />
44             <separator />
45             <menuitem name='Quit' action='QuitAction' />
46         </menu>
47
48         <menu name='HelpMenu' action='HelpMenuAction'>
49              <menuitem name='About' action='AboutAction' />
50         </menu>
51 </menubar>
52 ";
53
54     public MainWindow()
55     {
56         request_queue = new Queue<IdentityRequest>();
57         
58         service_button_map = new HashTable<Gtk.Button, string> (direct_hash, direct_equal);
59
60         this.title = "Moonshoot";
61         this.set_position (WindowPosition.CENTER);
62         set_default_size (WINDOW_WIDTH, WINDOW_HEIGHT);
63
64         build_ui();
65         setup_identities_list();
66         load_id_cards();
67         connect_signals();
68         init_ipc_server();
69     }
70
71     private bool visible_func (TreeModel model, TreeIter iter)
72     {
73         string issuer;
74         string search_text;
75         string issuer_casefold;
76         string search_text_casefold;
77
78         model.get (iter,
79                    Columns.ISSUER_COL, out issuer);
80         search_text = this.search_entry.get_text ();
81
82         if (issuer == null || search_text == null)
83             return false;
84
85         issuer_casefold = issuer.casefold ();
86         search_text_casefold = search_text.casefold ();
87
88         if (issuer_casefold.contains (search_text_casefold))
89             return true;
90
91         return false;
92     }
93
94     private void setup_identities_list ()
95     {
96        this.listmodel = new ListStore (Columns.N_COLUMNS, typeof (IdCard),
97                                                           typeof (Gdk.Pixbuf),
98                                                           typeof (string),
99                                                           typeof (string),
100                                                           typeof (string));
101       this.filter = new TreeModelFilter (listmodel, null);
102
103       filter.set_visible_func (visible_func);
104     }
105
106     private void search_entry_icon_press_cb (EntryIconPosition pos, Gdk.Event event)
107     {
108         if (pos == EntryIconPosition.PRIMARY)
109         {
110             print ("Search entry icon pressed\n");
111         }
112         else
113         {
114             this.search_entry.set_text ("");
115         }
116     }
117
118     private void search_entry_text_changed_cb ()
119     {
120         this.filter.refilter ();
121         redraw_id_card_widgets ();
122
123         var has_text = this.search_entry.get_text_length () > 0;
124         this.search_entry.set_icon_sensitive (EntryIconPosition.PRIMARY, has_text);
125         this.search_entry.set_icon_sensitive (EntryIconPosition.SECONDARY, has_text);
126
127         this.vbox_right.set_visible (false);
128         this.resize (WINDOW_WIDTH, WINDOW_HEIGHT);
129     }
130
131     private bool search_entry_key_press_event_cb (Gdk.EventKey e)
132     {
133         if(Gdk.keyval_name(e.keyval) == "Escape")
134            this.search_entry.set_text("");
135
136         // Continue processing this event, since the
137         // text entry functionality needs to see it too.
138         return false;
139     }
140
141     private void load_id_cards ()
142     {
143         identities_manager = new IdentitiesManager ();
144         
145         if (identities_manager.id_card_list == null)
146           return;
147
148         foreach (IdCard id_card in identities_manager.id_card_list)
149         {
150             add_id_card_data (id_card);
151             add_id_card_widget (id_card);
152         }
153
154         this.default_id_card = identities_manager.id_card_list.data;
155     }
156
157     private void fill_details (IdCardWidget id_card_widget)
158     {
159        var id_card = id_card_widget.id_card;
160        this.username_entry.set_text (id_card.username);
161        this.password_entry.set_text (id_card.password ?? "");
162
163        var children = this.services_internal_vbox.get_children ();
164        foreach (var hbox in children)
165            hbox.destroy();
166        fill_services_vbox (id_card_widget.id_card);
167        identities_manager.store_id_cards();
168     }
169
170     private void show_details (IdCard id_card)
171     {
172        this.vbox_right.set_visible (!vbox_right.get_visible ());
173
174        if (this.vbox_right.get_visible () == false)
175        {
176            this.resize (WINDOW_WIDTH, WINDOW_HEIGHT);
177        }
178     }
179
180     private void details_identity_cb (IdCardWidget id_card_widget)
181     {
182        fill_details (id_card_widget);
183        show_details (id_card_widget.id_card);
184     }
185
186     private IdCard get_id_card_data (AddIdentityDialog dialog)
187     {
188         var id_card = new IdCard ();
189
190         id_card.display_name = dialog.display_name;
191         id_card.issuer = dialog.issuer;
192         if (id_card.issuer == "")
193             id_card.issuer = "Issuer";
194         id_card.username = dialog.username;
195         id_card.password = dialog.password;
196         id_card.pixbuf = find_icon ("avatar-default", 48);
197         id_card.services = {};
198
199         return id_card;
200     }
201
202     private void add_id_card_data (IdCard id_card)
203     {
204         TreeIter iter;
205
206         this.listmodel.append (out iter);
207         listmodel.set (iter,
208                        Columns.IDCARD_COL, id_card,
209                        Columns.LOGO_COL, id_card.pixbuf,
210                        Columns.ISSUER_COL, id_card.issuer,
211                        Columns.USERNAME_COL, id_card.username,
212                        Columns.PASSWORD_COL, id_card.password);
213     }
214
215     private void remove_id_card_data (IdCard id_card)
216     {
217         TreeIter iter;
218         string issuer;
219
220         if (listmodel.get_iter_first (out iter))
221         {
222             do
223             {
224                 listmodel.get (iter,
225                                Columns.ISSUER_COL, out issuer);
226
227                 if (id_card.issuer == issuer)
228                 {
229                     listmodel.remove (iter);
230                     break;
231                 }
232             }
233             while (listmodel.iter_next (ref iter));
234         }
235     }
236
237     private void add_id_card_widget (IdCard id_card)
238     {
239         var id_card_widget = new IdCardWidget (id_card);
240
241         this.custom_vbox.add_id_card_widget (id_card_widget);
242
243         id_card_widget.details_id.connect (details_identity_cb);
244         id_card_widget.remove_id.connect (remove_identity_cb);
245         id_card_widget.send_id.connect ((w) => send_identity_cb (w.id_card));
246         id_card_widget.expanded.connect (this.custom_vbox.receive_expanded_event);
247         id_card_widget.expanded.connect (fill_details);
248     }
249
250     private void add_identity (AddIdentityDialog dialog)
251     {
252         insert_id_card (get_id_card_data (dialog));
253     }
254     
255     /* This method finds a valid display name */
256     public bool display_name_is_valid (string name,
257                                        out string? candidate)
258     {
259         foreach (IdCard id_card in identities_manager.id_card_list)
260         {
261           if (id_card.display_name == name)
262           {
263             if (&candidate != null)
264             {
265               for (int i=0; i<1000; i++)
266               {
267                 string tmp = "%s %d".printf (name, i);
268                 if (display_name_is_valid (tmp, null))
269                 {
270                   candidate = tmp;
271                   break;
272                 }
273               }
274             }
275             return false;
276           }
277         }
278         
279         return true;
280     }
281     
282     public void insert_id_card (IdCard id_card)
283     {
284         string candidate;
285         
286         if (!display_name_is_valid (id_card.display_name, out candidate))
287         {
288           id_card.display_name = candidate;
289         }
290     
291         this.identities_manager.id_card_list.prepend (id_card);
292         this.identities_manager.store_id_cards ();
293
294         add_id_card_data (id_card);
295         add_id_card_widget (id_card);
296     }
297
298     private void add_identity_cb ()
299     {
300         var dialog = new AddIdentityDialog ();
301         var result = dialog.run ();
302
303         switch (result) {
304         case ResponseType.OK:
305             add_identity (dialog);
306             break;
307         default:
308             break;
309         }
310         dialog.destroy ();
311     }
312
313     private void remove_id_card_widget (IdCardWidget id_card_widget)
314     {
315         remove_id_card_data (id_card_widget.id_card);
316
317         this.custom_vbox.remove_id_card_widget (id_card_widget);
318     }
319
320     private void remove_identity (IdCardWidget id_card_widget)
321     {
322         var id_card = id_card_widget.id_card;
323
324         this.identities_manager.id_card_list.remove (id_card);
325         this.identities_manager.store_id_cards ();
326
327         remove_id_card_widget (id_card_widget);
328     }
329
330     private void redraw_id_card_widgets ()
331     {
332         TreeIter iter;
333         IdCard id_card;
334
335         var children = this.custom_vbox.get_children ();
336         foreach (var id_card_widget in children)
337             id_card_widget.destroy();
338
339         if (filter.get_iter_first (out iter))
340         {
341             do
342             {
343                 filter.get (iter,
344                             Columns.IDCARD_COL, out id_card);
345
346                 add_id_card_widget (id_card);
347             }
348             while (filter.iter_next (ref iter));
349         }
350     }
351
352     private void remove_identity_cb (IdCardWidget id_card_widget)
353     {
354         var id_card = id_card_widget.id_card;
355
356         var dialog = new MessageDialog (null,
357                                         DialogFlags.DESTROY_WITH_PARENT,
358                                         MessageType.INFO,
359                                         Gtk.ButtonsType.YES_NO,
360                                         _("Are you sure you want to delete %s ID Card?"), id_card.issuer);
361         var result = dialog.run ();
362         switch (result) {
363         case ResponseType.YES:
364             remove_identity (id_card_widget);
365             break;
366         default:
367             break;
368         }
369         dialog.destroy ();
370     }
371
372     public void select_identity (IdentityRequest request)
373     {
374         IdCard identity = null;
375
376         this.request_queue.push_tail (request);
377         
378         if (custom_vbox.current_idcard != null &&
379             custom_vbox.current_idcard.send_button != null)
380           custom_vbox.current_idcard.send_button.set_sensitive (true);
381
382         if (request.select_default)
383         {
384             identity = this.default_id_card;
385         }
386
387         /* Automatic service matching rules can go here */
388
389         if (identity == null)
390         {
391             // Resort to manual selection
392             this.show ();
393         }
394         else
395         {
396             // Send back the identity (we can't directly run the
397             // callback because we may be being called from a 'yield')
398             Idle.add (() => { send_identity_cb (identity); return false; });
399             return;
400         }
401     }
402
403     public void send_identity_cb (IdCard identity)
404     {
405         return_if_fail (request_queue.length > 0);
406
407         var request = this.request_queue.pop_head ();
408         bool reset_password = false;
409
410         if (identity.password == null)
411         {
412             var dialog = new AddPasswordDialog ();
413             var result = dialog.run ();
414
415             switch (result) {
416             case ResponseType.OK:
417                 identity.password = dialog.password;
418                 reset_password = ! dialog.remember;
419                 break;
420             default:
421                 identity = null;
422                 break;
423             }
424
425             dialog.destroy ();
426         }
427
428         if (this.request_queue.is_empty())
429             this.hide ();
430
431         if (identity != null)
432             this.default_id_card = identity;
433
434         request.return_identity (identity);
435
436         if (reset_password)
437             identity.password = null;
438     }
439
440     private void label_make_bold (Label label)
441     {
442         var font_desc = new Pango.FontDescription ();
443
444         font_desc.set_weight (Pango.Weight.BOLD);
445
446         /* This will only affect the weight of the font, the rest is
447          * from the current state of the widget, which comes from the
448          * theme or user prefs, since the font desc only has the
449          * weight flag turned on.
450          */
451         label.modify_font (font_desc);
452     }
453
454     private void fill_services_vbox (IdCard id_card)
455     {
456         int i = 0;
457         var n_columns = id_card.services.length;
458
459         var services_table = new Table (n_columns, 2, false);
460         services_table.set_col_spacings (10);
461         services_table.set_row_spacings (10);
462         this.services_internal_vbox.add (services_table);
463         
464         service_button_map.remove_all ();
465
466         foreach (string service in id_card.services)
467         {
468             var label = new Label (service);
469             label.set_alignment (0, (float) 0.5);
470 #if VALA_0_12
471             var remove_button = new Button.from_stock (Stock.REMOVE);
472 #else
473             var remove_button = new Button.from_stock (STOCK_REMOVE);
474 #endif
475
476
477             service_button_map.insert (remove_button, service);
478             
479             remove_button.clicked.connect ((remove_button) =>
480             {
481               var dialog = new Gtk.MessageDialog (this,
482                                       Gtk.DialogFlags.DESTROY_WITH_PARENT,
483                                       Gtk.MessageType.QUESTION,
484                                       Gtk.ButtonsType.YES_NO,
485                                       _("Are you sure you want to stop '%s' ID Card to use %s?"),
486                                       custom_vbox.current_idcard.id_card.display_name);
487               var ret = dialog.run();
488               dialog.hide();
489               
490               if (ret == Gtk.ResponseType.YES)
491               {
492                 IdCard idcard = custom_vbox.current_idcard.id_card;
493                 var candidate = service_button_map.lookup (remove_button);
494
495                 SList<string> services = new SList<string>();
496                 
497                 foreach (string srv in id_card.services)
498                 {
499                   if (srv == candidate)
500                     continue;
501                   services.append (srv);
502                 }
503                 
504                 id_card.services = new string[services.length()];
505                 for (int j=0; j<id_card.services.length; j++)
506                 {
507                   id_card.services[j] = services.nth_data(j);
508                 }
509                 
510                 var children = services_internal_vbox.get_children ();
511                 foreach (var hbox in children)
512                   hbox.destroy();
513                 
514                 fill_services_vbox (id_card);
515                 custom_vbox.current_idcard.update_id_card_label ();
516               }
517               
518             });
519             services_table.attach_defaults (label, 0, 1, i, i+1);
520             services_table.attach_defaults (remove_button, 1, 2, i, i+1);
521             i++;
522         }
523         this.services_internal_vbox.show_all ();
524     }
525
526     private void on_about_action ()
527     {
528         string[] authors = {
529             "Javier Jardón <jjardon@codethink.co.uk>",
530             "Sam Thursfield <samthursfield@codethink.co.uk>",
531             "Alberto Ruiz <alberto.ruiz@codethink.co.uk>",
532             null
533         };
534
535         string copyright = "Copyright 2011 JANET";
536
537         string license =
538 """
539 Copyright (c) 2011, JANET(UK)
540 All rights reserved.
541
542 Redistribution and use in source and binary forms, with or without
543 modification, are permitted provided that the following conditions
544 are met:
545
546 1. Redistributions of source code must retain the above copyright
547    notice, this list of conditions and the following disclaimer.
548
549 2. Redistributions in binary form must reproduce the above copyright
550    notice, this list of conditions and the following disclaimer in the
551    documentation and/or other materials provided with the distribution.
552
553 3. Neither the name of JANET(UK) nor the names of its contributors
554    may be used to endorse or promote products derived from this software
555    without specific prior written permission.
556
557 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"
558 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
559 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
560 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
561 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
562 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
563 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
564 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
565 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
566 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
567 SUCH DAMAGE.
568 """;
569
570         Gtk.show_about_dialog (this,
571             "comments", _("Moonshot project UI"),
572             "copyright", copyright,
573             "website", "http://www.project-moonshot.org/",
574             "license", license,
575             "website-label", _("Visit the Moonshot project web site"),
576             "authors", authors,
577             "translator-credits", _("translator-credits"),
578             null
579         );
580     }
581
582     private Gtk.ActionEntry[] create_actions() {
583         Gtk.ActionEntry[] actions = new Gtk.ActionEntry[0];
584
585         Gtk.ActionEntry filemenu = { "FileMenuAction",
586                                      null,
587                                      N_("_File"),
588                                      null, null, null };
589         actions += filemenu;
590         Gtk.ActionEntry add = { "AddIdCardAction",
591 #if VALA_0_12
592                                 Stock.ADD,
593 #else
594                                 STOCK_ADD,
595 #endif
596                                 N_("Add ID Card"),
597                                 null,
598                                 N_("Add a new ID Card"),
599                                 add_identity_cb };
600         actions += add;
601         Gtk.ActionEntry quit = { "QuitAction",
602 #if VALA_0_12
603                                  Stock.QUIT,
604 #else
605                                  STOCK_QUIT,
606 #endif
607                                  N_("Quit"),
608                                  "<control>Q",
609                                  N_("Quit the application"),
610                                  Gtk.main_quit };
611         actions += quit;
612
613         Gtk.ActionEntry helpmenu = { "HelpMenuAction",
614                                      null,
615                                      N_("_Help"),
616                                      null, null, null };
617         actions += helpmenu;
618         Gtk.ActionEntry about = { "AboutAction",
619 #if VALA_0_12
620                                   Stock.ABOUT,
621 #else
622                                   STOCK_ABOUT,
623 #endif
624                                   N_("About"),
625                                   null,
626                                   N_("About this application"),
627                                   on_about_action };
628         actions += about;
629
630         return actions;
631     }
632
633
634     private void create_ui_manager ()
635     {
636         Gtk.ActionGroup action_group = new Gtk.ActionGroup ("GeneralActionGroup");
637         action_group.add_actions (create_actions (), this);
638         ui_manager.insert_action_group (action_group, 0);
639         try
640         {
641             ui_manager.add_ui_from_string (layout, -1);
642         }
643         catch (Error e)
644         {
645             stderr.printf ("%s\n", e.message);
646         }
647         ui_manager.ensure_update ();
648     }
649
650     private void build_ui()
651     {
652         create_ui_manager ();
653
654         this.search_entry = new Entry();
655
656         set_atk_name_description (search_entry, _("Search entry"), _("Search for a specific ID Card"));
657         this.search_entry.set_icon_from_pixbuf (EntryIconPosition.PRIMARY,
658                                                 find_icon_sized ("edit-find-symbolic", Gtk.IconSize.MENU));
659         this.search_entry.set_icon_tooltip_text (EntryIconPosition.PRIMARY,
660                                                  _("Search identity or service"));
661         this.search_entry.set_icon_sensitive (EntryIconPosition.PRIMARY, false);
662
663         this.search_entry.set_icon_from_pixbuf (EntryIconPosition.SECONDARY,
664                                                 find_icon_sized ("edit-clear-symbolic", Gtk.IconSize.MENU));
665         this.search_entry.set_icon_tooltip_text (EntryIconPosition.SECONDARY,
666                                                  _("Clear the current search"));
667         this.search_entry.set_icon_sensitive (EntryIconPosition.SECONDARY, false);
668
669
670         this.search_entry.icon_press.connect (search_entry_icon_press_cb);
671         this.search_entry.notify["text"].connect (search_entry_text_changed_cb);
672         this.search_entry.key_press_event.connect(search_entry_key_press_event_cb);
673
674         this.custom_vbox = new CustomVBox (this, false, 6);
675
676         var viewport = new Viewport (null, null);
677         viewport.set_border_width (6);
678         viewport.set_shadow_type (ShadowType.NONE);
679         viewport.add (custom_vbox);
680         var scroll = new ScrolledWindow (null, null);
681         scroll.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC);
682         scroll.set_shadow_type (ShadowType.IN);
683         scroll.add_with_viewport (viewport);
684
685         var vbox_left = new VBox (false, 0);
686         vbox_left.pack_start (search_entry, false, false, 6);
687         vbox_left.pack_start (scroll, true, true, 0);
688         vbox_left.set_size_request (WINDOW_WIDTH, 0);
689
690         var login_vbox_title = new Label (_("Login: "));
691         label_make_bold (login_vbox_title);
692         login_vbox_title.set_alignment (0, (float) 0.5);
693         var username_label = new Label (_("Username:"));
694         username_label.set_alignment (1, (float) 0.5);
695         this.username_entry = new Entry ();
696         var password_label = new Label (_("Password:"));
697         password_label.set_alignment (1, (float) 0.5);
698         this.password_entry = new Entry ();
699         password_entry.set_invisible_char ('*');
700         password_entry.set_visibility (false);
701         var remember_checkbutton = new CheckButton.with_label (_("Remember password"));
702         var login_table = new Table (3, 3, false);
703         login_table.set_col_spacings (10);
704         login_table.set_row_spacings (10);
705         login_table.attach_defaults (username_label, 0, 1, 0, 1);
706         login_table.attach_defaults (username_entry, 1, 2, 0, 1);
707         login_table.attach_defaults (password_label, 0, 1, 1, 2);
708         login_table.attach_defaults (password_entry, 1, 2, 1, 2);
709         login_table.attach_defaults (remember_checkbutton,  1, 2, 2, 3);
710         var login_vbox_alignment = new Alignment (0, 0, 0, 0);
711         login_vbox_alignment.set_padding (0, 0, 12, 0);
712         login_vbox_alignment.add (login_table);
713         var login_vbox = new VBox (false, 6);
714         login_vbox.pack_start (login_vbox_title, false, true, 0);
715         login_vbox.pack_start (login_vbox_alignment, false, true, 0);
716
717         var services_vbox_title = new Label (_("Services:"));
718         label_make_bold (services_vbox_title);
719         services_vbox_title.set_alignment (0, (float) 0.5);
720         var services_vbox_alignment = new Alignment (0, 0, 0, 0);
721         services_vbox_alignment.set_padding (0, 0, 12, 0);
722         this.services_internal_vbox = new VBox (true, 6);
723         services_vbox_alignment.add (services_internal_vbox);
724         var services_vbox = new VBox (false, 6);
725         services_vbox.pack_start (services_vbox_title, false, true, 0);
726         services_vbox.pack_start (services_vbox_alignment, false, true, 0);
727
728         this.vbox_right = new VBox (false, 18);
729         vbox_right.pack_start (login_vbox, false, true, 0);
730         vbox_right.pack_start (services_vbox, false, true, 0);
731
732         var hbox = new HBox (false, 12);
733         hbox.pack_start (vbox_left, true, true, 0);
734         hbox.pack_start (vbox_right, false, false, 0);
735
736         var main_vbox = new VBox (false, 0);
737         main_vbox.set_border_width (12);
738         var menubar = this.ui_manager.get_widget ("/MenuBar");
739         main_vbox.pack_start (menubar, false, false, 0);
740         main_vbox.pack_start (hbox, true, true, 0);
741         add (main_vbox);
742
743         main_vbox.show_all();
744         this.vbox_right.hide ();
745     }
746
747     private void set_atk_name_description (Widget widget, string name, string description)
748     {
749        var atk_widget = widget.get_accessible ();
750
751        atk_widget.set_name (name);
752        atk_widget.set_description (description);
753     }
754
755     private void connect_signals()
756     {
757         this.destroy.connect (Gtk.main_quit);
758     }
759
760     private void init_ipc_server ()
761     {
762 #if IPC_MSRPC
763         /* Errors will currently be sent via g_log - ie. to an
764          * obtrusive message box, on Windows
765          */
766         this.ipc_server = MoonshotServer.get_instance ();
767         MoonshotServer.start (this);
768 #else
769         try {
770             var conn = DBus.Bus.get (DBus.BusType.SESSION);
771             dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus",
772                                                        "/org/freedesktop/DBus",
773                                                        "org.freedesktop.DBus");
774
775             // try to register service in session bus
776             uint reply = bus.request_name ("org.janet.Moonshot", (uint) 0);
777             assert (reply == DBus.RequestNameReply.PRIMARY_OWNER);
778
779             this.ipc_server = new MoonshotServer (this);
780             conn.register_object ("/org/janet/moonshot", ipc_server);
781
782         }
783         catch (DBus.Error e)
784         {
785             stderr.printf ("%s\n", e.message);
786         }
787 #endif
788     }
789
790     public static int main(string[] args)
791     {
792         Gtk.init(ref args);
793
794 #if OS_WIN32
795         // Force specific theme settings on Windows without requiring a gtkrc file
796         Gtk.Settings settings = Gtk.Settings.get_default ();
797         settings.set_string_property ("gtk-theme-name", "ms-windows", "moonshot");
798         settings.set_long_property ("gtk-menu-images", 0, "moonshot");
799 #endif
800
801         Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
802         Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
803         Intl.textdomain (Config.GETTEXT_PACKAGE);
804
805         var window = new MainWindow();
806         window.show ();
807
808         Gtk.main();
809
810         return 0;
811     }
812 }