4 public class IdentityManagerView : Window {
5 private const int WINDOW_WIDTH = 400;
6 private const int WINDOW_HEIGHT = 500;
7 protected IdentityManagerApp parent_app;
9 public OSXApplication osxApp;
11 private UIManager ui_manager = new UIManager();
12 private Entry search_entry;
13 private VBox vbox_right;
14 private VBox login_vbox;
15 private VBox services_vbox;
16 private CustomVBox custom_vbox;
17 private VBox services_internal_vbox;
19 private Entry issuer_entry;
20 private Entry username_entry;
21 private Entry password_entry;
22 private Label prompting_service;
23 private Label no_identity_title;
24 private CheckButton remember_checkbutton;
25 private Button update_password_button;
27 private ListStore* listmodel;
28 private TreeModelFilter filter;
30 public IdentityManagerModel identities_manager;
31 private unowned SList<IdCard> candidates;
33 public GLib.Queue<IdentityRequest> request_queue;
35 private HashTable<Gtk.Button, string> service_button_map;
47 private const string layout =
48 "<menubar name='MenuBar'>" +
49 " <menu name='FileMenu' action='FileMenuAction'>" +
50 " <menuitem name='AddIdCard' action='AddIdCardAction' />" +
52 " <menuitem name='Quit' action='QuitAction' />" +
55 " <menu name='HelpMenu' action='HelpMenuAction'>" +
56 " <menuitem name='About' action='AboutAction' />" +
60 public IdentityManagerView(IdentityManagerApp app) {
63 osxApp = OSXApplication.get_instance();
65 identities_manager = parent_app.model;
66 request_queue = new GLib.Queue<IdentityRequest>();
67 service_button_map = new HashTable<Gtk.Button, string> (direct_hash, direct_equal);
68 this.title = "Moonshot Identity Selector";
69 this.set_position (WindowPosition.CENTER);
70 set_default_size (WINDOW_WIDTH, WINDOW_HEIGHT);
77 public void on_card_list_changed () {
81 private bool visible_func (TreeModel model, TreeIter iter)
86 Columns.IDCARD_COL, out id_card);
91 if (candidates != null)
93 bool is_candidate = false;
94 foreach (IdCard candidate in candidates)
96 if (candidate == id_card)
103 string entry_text = search_entry.get_text ();
104 if (entry_text == null || entry_text == "")
109 foreach (string search_text in entry_text.split(" "))
111 if (search_text == "")
115 string search_text_casefold = search_text.casefold ();
117 if (id_card.issuer != null)
119 string issuer_casefold = id_card.issuer;
121 if (issuer_casefold.contains (search_text_casefold))
125 if (id_card.display_name != null)
127 string display_name_casefold = id_card.display_name.casefold ();
129 if (display_name_casefold.contains (search_text_casefold))
133 if (id_card.services.length > 0)
135 foreach (string service in id_card.services)
137 string service_casefold = service.casefold ();
139 if (service_casefold.contains (search_text_casefold))
147 private void setup_list_model ()
149 this.listmodel = new ListStore (Columns.N_COLUMNS, typeof (IdCard),
154 this.filter = new TreeModelFilter (listmodel, null);
156 filter.set_visible_func (visible_func);
159 private void search_entry_icon_press_cb (EntryIconPosition pos, Gdk.Event event)
161 if (pos == EntryIconPosition.PRIMARY)
163 print ("Search entry icon pressed\n");
167 this.search_entry.set_text ("");
171 private void search_entry_text_changed_cb ()
173 this.filter.refilter ();
174 redraw_id_card_widgets ();
176 var has_text = this.search_entry.get_text_length () > 0;
177 this.search_entry.set_icon_sensitive (EntryIconPosition.PRIMARY, has_text);
178 this.search_entry.set_icon_sensitive (EntryIconPosition.SECONDARY, has_text);
180 this.vbox_right.set_visible (false);
183 private bool search_entry_key_press_event_cb (Gdk.EventKey e)
185 if(Gdk.keyval_name(e.keyval) == "Escape")
186 this.search_entry.set_text("");
188 // Continue processing this event, since the
189 // text entry functionality needs to see it too.
193 private void update_password_cb()
195 if (this.custom_vbox.current_idcard != null) {
196 var identity = this.custom_vbox.current_idcard.id_card;
197 var dialog = new AddPasswordDialog(identity, null);
198 var result = dialog.run ();
201 case ResponseType.OK:
202 identity.password = dialog.password;
203 identity.store_password = dialog.remember;
205 identity.temporary = false;
206 identity = identities_manager.update_card(identity);
215 private void load_id_cards () {
216 string current_idcard_nai = null;
217 if (this.custom_vbox.current_idcard != null) {
218 current_idcard_nai = custom_vbox.current_idcard.id_card.nai;
219 custom_vbox.current_idcard = null;
221 var children = this.custom_vbox.get_children ();
222 foreach (var id_card_widget in children) {
223 remove_id_card_widget((IdCardWidget)id_card_widget);
225 this.listmodel->clear();
226 LinkedList<IdCard> card_list = identities_manager.get_card_list() ;
227 if (card_list == null) {
231 foreach (IdCard id_card in card_list) {
232 add_id_card_data (id_card);
233 IdCardWidget id_card_widget = add_id_card_widget (id_card);
234 if (id_card_widget.id_card.nai == current_idcard_nai) {
235 fill_details(id_card_widget);
236 id_card_widget.expand();
239 if (custom_vbox.current_idcard == null)
243 private void fill_details (IdCardWidget? id_card_widget)
245 var vr_children = this.vbox_right.get_children();
246 foreach (var vr_child in vr_children)
247 this.vbox_right.remove(vr_child);
248 if (id_card_widget != null) {
249 var id_card = id_card_widget.id_card;
250 if (id_card.display_name == IdCard.NO_IDENTITY) {
251 this.vbox_right.pack_start(no_identity_title, false, true, 0);
253 this.issuer_entry.set_text (id_card.issuer);
254 this.username_entry.set_text (id_card.username);
255 this.password_entry.set_text (id_card.password ?? "");
256 this.vbox_right.pack_start(login_vbox, false, true, 0);
257 this.remember_checkbutton.active = id_card.store_password;
259 this.vbox_right.pack_start (services_vbox, false, true, 0);
261 var children = this.services_internal_vbox.get_children ();
262 foreach (var hbox in children)
263 services_internal_vbox.remove(hbox);
264 fill_services_vbox (id_card_widget.id_card);
268 private void show_details (IdCard id_card)
270 this.vbox_right.set_visible (!vbox_right.get_visible ());
272 if (this.vbox_right.get_visible () == false)
274 this.resize (WINDOW_WIDTH, WINDOW_HEIGHT);
278 private void details_identity_cb (IdCardWidget id_card_widget)
280 fill_details (id_card_widget);
281 show_details (id_card_widget.id_card);
284 private IdCard get_id_card_data (AddIdentityDialog dialog)
286 var id_card = new IdCard ();
288 id_card.display_name = dialog.display_name;
289 id_card.issuer = dialog.issuer;
290 id_card.username = dialog.username;
291 id_card.password = dialog.password;
292 id_card.store_password = dialog.store_password;
293 id_card.services = {};
298 private void add_id_card_data (IdCard id_card)
302 this.listmodel->append (out iter);
303 pixbuf = get_pixbuf(id_card);
304 listmodel->set (iter,
305 Columns.IDCARD_COL, id_card,
306 Columns.LOGO_COL, pixbuf,
307 Columns.ISSUER_COL, id_card.issuer,
308 Columns.USERNAME_COL, id_card.username,
309 Columns.PASSWORD_COL, id_card.password);
312 private void remove_id_card_data (IdCard id_card)
317 if (listmodel->get_iter_first (out iter))
321 listmodel->get (iter,
322 Columns.ISSUER_COL, out issuer);
324 if (id_card.issuer == issuer)
326 listmodel->remove (iter);
330 while (listmodel->iter_next (ref iter));
334 private IdCardWidget add_id_card_widget (IdCard id_card)
336 var id_card_widget = new IdCardWidget (id_card);
337 this.custom_vbox.add_id_card_widget (id_card_widget);
338 id_card_widget.details_id.connect (details_identity_cb);
339 id_card_widget.remove_id.connect (remove_identity_cb);
340 id_card_widget.send_id.connect ((w) => send_identity_cb (w.id_card));
341 id_card_widget.expanded.connect (this.custom_vbox.receive_expanded_event);
342 id_card_widget.expanded.connect (fill_details);
343 return id_card_widget;
346 public bool add_identity (IdCard id_card, bool force_flat_file_store)
350 * TODO: We should have a confirmation dialog, but currently it will crash on Mac OS
351 * so for now we will install silently
353 var ret = Gtk.ResponseType.YES;
355 Gtk.MessageDialog dialog;
356 IdCard? prev_id = identities_manager.find_id_card(id_card.nai, force_flat_file_store);
358 int flags = prev_id.Compare(id_card);
360 return false; // no changes, no need to update
361 } else if ((flags & (1<<IdCard.DiffFlags.DISPLAY_NAME)) != 0) {
362 dialog = new Gtk.MessageDialog (this,
363 Gtk.DialogFlags.DESTROY_WITH_PARENT,
364 Gtk.MessageType.QUESTION,
365 Gtk.ButtonsType.YES_NO,
366 _("Would you like to replace ID Card '%s' using nai '%s' with the new ID Card '%s'?"),
367 prev_id.display_name,
369 id_card.display_name);
371 dialog = new Gtk.MessageDialog (this,
372 Gtk.DialogFlags.DESTROY_WITH_PARENT,
373 Gtk.MessageType.QUESTION,
374 Gtk.ButtonsType.YES_NO,
375 _("Would you like to update ID Card '%s' using nai '%s'?"),
376 id_card.display_name,
380 dialog = new Gtk.MessageDialog (this,
381 Gtk.DialogFlags.DESTROY_WITH_PARENT,
382 Gtk.MessageType.QUESTION,
383 Gtk.ButtonsType.YES_NO,
384 _("Would you like to add '%s' ID Card to the ID Card Organizer?"),
385 id_card.display_name);
387 var ret = dialog.run ();
391 if (ret == Gtk.ResponseType.YES) {
392 this.identities_manager.add_card (id_card, force_flat_file_store);
399 private void add_identity_manual_cb ()
401 var dialog = new AddIdentityDialog ();
402 int result = ResponseType.CANCEL;
403 while (!dialog.complete)
404 result = dialog.run ();
407 case ResponseType.OK:
408 this.identities_manager.add_card (get_id_card_data (dialog), false);
416 private void remove_id_card_widget (IdCardWidget id_card_widget) {
417 this.custom_vbox.remove_id_card_widget (id_card_widget);
420 private void remove_identity (IdCardWidget id_card_widget)
422 var id_card = id_card_widget.id_card;
423 remove_id_card_widget (id_card_widget);
425 this.identities_manager.remove_card(id_card);
428 private void redraw_id_card_widgets ()
433 var children = this.custom_vbox.get_children ();
434 foreach (var id_card_widget in children)
435 remove_id_card_widget((IdCardWidget )id_card_widget); //id_card_widget.destroy();
437 if (filter.get_iter_first (out iter))
442 Columns.IDCARD_COL, out id_card);
444 add_id_card_widget (id_card);
446 while (filter.iter_next (ref iter));
450 private void remove_identity_cb (IdCardWidget id_card_widget)
452 var id_card = id_card_widget.id_card;
454 var dialog = new MessageDialog (this,
455 DialogFlags.DESTROY_WITH_PARENT,
456 MessageType.QUESTION,
457 Gtk.ButtonsType.YES_NO,
458 _("Are you sure you want to delete %s ID Card?"), id_card.issuer);
459 var result = dialog.run ();
461 case ResponseType.YES:
462 remove_identity (id_card_widget);
470 public void set_prompting_service(string service)
472 prompting_service.set_label( _("Identity requested for service: %s").printf(service) );
475 public void queue_identity_request(IdentityRequest request)
477 if (this.request_queue.is_empty())
478 { /* setup widgets */
479 candidates = request.candidates;
481 redraw_id_card_widgets ();
482 set_prompting_service(request.service);
485 this.request_queue.push_tail (request);
488 public IdCard check_add_password(IdCard identity, IdentityRequest request, IdentityManagerModel model)
490 IdCard retval = identity;
491 bool idcard_has_pw = (identity.password != null) && (identity.password != "");
492 bool request_has_pw = (request.password != null) && (request.password != "");
493 if ((!idcard_has_pw) && (!identity.IsNoIdentity())) {
494 if (request_has_pw) {
495 identity.password = request.password;
496 retval = model.update_card(identity);
498 var dialog = new AddPasswordDialog (identity, request);
499 var result = dialog.run ();
502 case ResponseType.OK:
503 identity.password = dialog.password;
504 identity.store_password = dialog.remember;
506 identity.temporary = false;
507 retval = model.update_card(identity);
519 public void send_identity_cb (IdCard id)
521 IdCard identity = id;
522 return_if_fail (request_queue.length > 0);
525 var request = this.request_queue.pop_head ();
526 identity = check_add_password(identity, request, identities_manager);
527 if (this.request_queue.is_empty())
530 prompting_service.set_label(_(""));
531 if (!parent_app.explicitly_launched) {
532 // The following occasionally causes the app to exit without sending the dbus
533 // reply, so for now we just don't exit
539 IdentityRequest next = this.request_queue.peek_head();
540 candidates = next.candidates;
541 set_prompting_service(next.service);
544 redraw_id_card_widgets ();
546 if ((identity != null) && (!identity.IsNoIdentity()))
547 parent_app.default_id_card = identity;
549 request.return_identity (identity);
552 private void label_make_bold (Label label)
554 var font_desc = new Pango.FontDescription ();
556 font_desc.set_weight (Pango.Weight.BOLD);
558 /* This will only affect the weight of the font, the rest is
559 * from the current state of the widget, which comes from the
560 * theme or user prefs, since the font desc only has the
561 * weight flag turned on.
563 label.modify_font (font_desc);
566 private void fill_services_vbox (IdCard id_card)
569 var n_columns = id_card.services.length;
571 var services_table = new Table (n_columns, 2, false);
572 services_table.set_col_spacings (10);
573 services_table.set_row_spacings (10);
574 this.services_internal_vbox.add (services_table);
576 service_button_map.remove_all ();
578 foreach (string service in id_card.services)
580 var label = new Label (service);
581 label.set_alignment (0, (float) 0.5);
583 var remove_button = new Button.from_stock (Stock.REMOVE);
585 var remove_button = new Button.from_stock (STOCK_REMOVE);
589 service_button_map.insert (remove_button, service);
591 remove_button.clicked.connect ((remove_button) =>
593 var candidate = service_button_map.lookup (remove_button);
594 if (candidate == null)
596 var dialog = new Gtk.MessageDialog (this,
597 Gtk.DialogFlags.DESTROY_WITH_PARENT,
598 Gtk.MessageType.QUESTION,
599 Gtk.ButtonsType.YES_NO,
600 _("Are you sure you want to stop '%s' ID Card from being used with %s?"),
601 custom_vbox.current_idcard.id_card.display_name,
603 var ret = dialog.run();
606 if (ret == Gtk.ResponseType.YES)
608 IdCard idcard = custom_vbox.current_idcard.id_card;
609 if (idcard != null) {
610 SList<string> services = new SList<string>();
612 foreach (string srv in idcard.services)
614 if (srv == candidate)
616 services.append (srv);
619 idcard.services = new string[services.length()];
620 for (int j=0; j<idcard.services.length; j++)
622 idcard.services[j] = services.nth_data(j);
625 identities_manager.update_card(idcard);
630 services_table.attach_defaults (label, 0, 1, i, i+1);
631 services_table.attach_defaults (remove_button, 1, 2, i, i+1);
634 this.services_internal_vbox.show_all ();
637 private void on_about_action ()
640 "Javier Jardón <jjardon@codethink.co.uk>",
641 "Sam Thursfield <samthursfield@codethink.co.uk>",
642 "Alberto Ruiz <alberto.ruiz@codethink.co.uk>",
646 string copyright = "Copyright 2011 JANET";
650 Copyright (c) 2011, JANET(UK)
653 Redistribution and use in source and binary forms, with or without
654 modification, are permitted provided that the following conditions
657 1. Redistributions of source code must retain the above copyright
658 notice, this list of conditions and the following disclaimer.
660 2. Redistributions in binary form must reproduce the above copyright
661 notice, this list of conditions and the following disclaimer in the
662 documentation and/or other materials provided with the distribution.
664 3. Neither the name of JANET(UK) nor the names of its contributors
665 may be used to endorse or promote products derived from this software
666 without specific prior written permission.
668 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"
669 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
670 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
671 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
672 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
673 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
674 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
675 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
676 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
677 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
681 Gtk.show_about_dialog (this,
682 "comments", _("Moonshot project UI"),
683 "copyright", copyright,
684 "website", Config.PACKAGE_URL,
685 "version", Config.PACKAGE_VERSION,
687 "website-label", _("Visit the Moonshot project web site"),
689 "translator-credits", _("translator-credits"),
694 private Gtk.ActionEntry[] create_actions() {
695 Gtk.ActionEntry[] actions = new Gtk.ActionEntry[0];
697 Gtk.ActionEntry filemenu = { "FileMenuAction",
702 Gtk.ActionEntry add = { "AddIdCardAction",
710 N_("Add a new ID Card"),
711 add_identity_manual_cb };
713 Gtk.ActionEntry quit = { "QuitAction",
721 N_("Quit the application"),
725 Gtk.ActionEntry helpmenu = { "HelpMenuAction",
730 Gtk.ActionEntry about = { "AboutAction",
738 N_("About this application"),
746 private void create_ui_manager ()
748 Gtk.ActionGroup action_group = new Gtk.ActionGroup ("GeneralActionGroup");
749 action_group.add_actions (create_actions (), this);
750 ui_manager.insert_action_group (action_group, 0);
753 ui_manager.add_ui_from_string (layout, -1);
757 stderr.printf ("%s\n", e.message);
759 ui_manager.ensure_update ();
762 private void build_ui()
764 create_ui_manager ();
766 this.search_entry = new Entry();
768 set_atk_name_description (search_entry, _("Search entry"), _("Search for a specific ID Card"));
769 this.search_entry.set_icon_from_pixbuf (EntryIconPosition.PRIMARY,
770 find_icon_sized ("edit-find", Gtk.IconSize.MENU));
771 // find_icon_sized ("edit-find-symbolic", Gtk.IconSize.MENU));
772 this.search_entry.set_icon_tooltip_text (EntryIconPosition.PRIMARY,
773 _("Search identity or service"));
774 this.search_entry.set_icon_sensitive (EntryIconPosition.PRIMARY, false);
776 this.search_entry.set_icon_from_pixbuf (EntryIconPosition.SECONDARY,
777 find_icon_sized ("process-stop", Gtk.IconSize.MENU));
778 // find_icon_sized ("edit-clear-symbolic", Gtk.IconSize.MENU));
779 this.search_entry.set_icon_tooltip_text (EntryIconPosition.SECONDARY,
780 _("Clear the current search"));
781 this.search_entry.set_icon_sensitive (EntryIconPosition.SECONDARY, false);
784 this.search_entry.icon_press.connect (search_entry_icon_press_cb);
785 this.search_entry.notify["text"].connect (search_entry_text_changed_cb);
786 this.search_entry.key_press_event.connect(search_entry_key_press_event_cb);
788 this.custom_vbox = new CustomVBox (this, false, 6);
790 var viewport = new Viewport (null, null);
791 viewport.set_border_width (6);
792 viewport.set_shadow_type (ShadowType.NONE);
793 viewport.add (custom_vbox);
794 var scroll = new ScrolledWindow (null, null);
795 scroll.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC);
796 scroll.set_shadow_type (ShadowType.IN);
797 scroll.add_with_viewport (viewport);
798 this.prompting_service = new Label (_(""));
800 prompting_service.set_alignment(0, (float )0.5);
802 var vbox_left = new VBox (false, 0);
803 vbox_left.pack_start (search_entry, false, false, 6);
804 vbox_left.pack_start (scroll, true, true, 0);
805 vbox_left.pack_start (prompting_service, false, false, 6);
806 vbox_left.set_size_request (WINDOW_WIDTH, 0);
808 this.no_identity_title = new Label (_("No Identity: Send this identity to services which should not use Moonshot"));
809 no_identity_title.set_alignment(0, (float ) 0.5);
810 no_identity_title.set_line_wrap(true);
811 no_identity_title.show();
813 var login_vbox_title = new Label (_("Login: "));
814 label_make_bold (login_vbox_title);
815 login_vbox_title.set_alignment (0, (float) 0.5);
816 var issuer_label = new Label (_("Issuer:"));
817 issuer_label.set_alignment (1, (float) 0.5);
818 this.issuer_entry = new Entry ();
819 issuer_entry.set_can_focus (false);
820 var username_label = new Label (_("Username:"));
821 username_label.set_alignment (1, (float) 0.5);
822 this.username_entry = new Entry ();
823 username_entry.set_can_focus (false);
824 var password_label = new Label (_("Password:"));
825 password_label.set_alignment (1, (float) 0.5);
826 this.password_entry = new Entry ();
827 password_entry.set_invisible_char ('*');
828 password_entry.set_visibility (false);
829 password_entry.set_sensitive (false);
830 this.remember_checkbutton = new CheckButton.with_label (_("Remember password"));
831 remember_checkbutton.set_sensitive(false);
832 this.update_password_button = new Button.with_label (_("Update Password"));
833 this.update_password_button.clicked.connect(update_password_cb);
835 set_atk_relation (issuer_label, issuer_entry, Atk.RelationType.LABEL_FOR);
836 set_atk_relation (username_label, username_entry, Atk.RelationType.LABEL_FOR);
837 set_atk_relation (password_entry, password_entry, Atk.RelationType.LABEL_FOR);
839 var login_table = new Table (5, 2, false);
840 login_table.set_col_spacings (10);
841 login_table.set_row_spacings (10);
842 login_table.attach_defaults (issuer_label, 0, 1, 0, 1);
843 login_table.attach_defaults (issuer_entry, 1, 2, 0, 1);
844 login_table.attach_defaults (username_label, 0, 1, 1, 2);
845 login_table.attach_defaults (username_entry, 1, 2, 1, 2);
846 login_table.attach_defaults (password_label, 0, 1, 2, 3);
847 login_table.attach_defaults (password_entry, 1, 2, 2, 3);
848 login_table.attach_defaults (remember_checkbutton, 1, 2, 3, 4);
849 login_table.attach_defaults (update_password_button, 0, 1, 4, 5);
850 var login_vbox_alignment = new Alignment (0, 0, 0, 0);
851 login_vbox_alignment.set_padding (0, 0, 12, 0);
852 login_vbox_alignment.add (login_table);
853 this.login_vbox = new VBox (false, 6);
854 login_vbox.pack_start (login_vbox_title, false, true, 0);
855 login_vbox.pack_start (login_vbox_alignment, false, true, 0);
857 var services_vbox_title = new Label (_("Services:"));
858 label_make_bold (services_vbox_title);
859 services_vbox_title.set_alignment (0, (float) 0.5);
860 var services_vbox_alignment = new Alignment (0, 0, 0, 0);
861 services_vbox_alignment.set_padding (0, 0, 12, 0);
862 this.services_internal_vbox = new VBox (true, 6);
863 services_vbox_alignment.add (services_internal_vbox);
864 this.services_vbox = new VBox (false, 6);
865 services_vbox.pack_start (services_vbox_title, false, true, 0);
866 services_vbox.pack_start (services_vbox_alignment, false, true, 0);
868 this.vbox_right = new VBox (false, 18);
869 vbox_right.pack_start (login_vbox, false, true, 0);
870 vbox_right.pack_start (services_vbox, false, true, 0);
872 var hbox = new HBox (false, 12);
873 hbox.pack_start (vbox_left, false, false, 0);
874 hbox.pack_start (vbox_right, true, true, 0);
876 var main_vbox = new VBox (false, 0);
877 main_vbox.set_border_width (12);
880 // hide the File | Quit menu item which is now on the Mac Menu
881 Gtk.Widget quit_item = this.ui_manager.get_widget("/MenuBar/FileMenu/Quit");
884 Gtk.MenuShell menushell = this.ui_manager.get_widget("/MenuBar") as Gtk.MenuShell;
885 osxApp.set_menu_bar(menushell);
886 osxApp.set_use_quartz_accelerators(true);
887 osxApp.sync_menu_bar();
890 var menubar = this.ui_manager.get_widget ("/MenuBar");
891 main_vbox.pack_start (menubar, false, false, 0);
893 main_vbox.pack_start (hbox, true, true, 0);
895 main_vbox.show_all();
896 this.vbox_right.hide ();
899 private void set_atk_name_description (Widget widget, string name, string description)
901 var atk_widget = widget.get_accessible ();
903 atk_widget.set_name (name);
904 atk_widget.set_description (description);
907 private void connect_signals()
909 this.destroy.connect (Gtk.main_quit);
910 this.identities_manager.card_list_changed.connect(this.on_card_list_changed);
913 private static void set_atk_relation (Widget widget, Widget target_widget, Atk.RelationType relationship)
915 var atk_widget = widget.get_accessible ();
916 var atk_target_widget = target_widget.get_accessible ();
918 atk_widget.add_relationship (relationship, atk_target_widget);