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