/// <summary> /// Initalize Gtk and DBus stuff /// </summary> private void GtkDBusInit() { /* setup StatusIcon */ statusIcon = new Gtk.StatusIcon(); statusIcon.IconName = "keepass2-locked"; #if DEBUG statusIcon.File = Path.GetFullPath("Resources/icons/hicolor/16x16/apps/keepass2-locked.png"); #endif statusIcon.Tooltip = PwDefs.ProductName; statusIconMenu = new Gtk.Menu(); var trayContextMenu = pluginHost.MainWindow.TrayContextMenu; // make copy of item list to prevent list changed exception when iterating var menuItems = new System.Windows.Forms.ToolStripItem[trayContextMenu.Items.Count]; trayContextMenu.Items.CopyTo(menuItems, 0); trayContextMenu.ItemAdded += (sender, e) => DBusBackgroundWorker.InvokeGtkThread (() => ConvertAndAddMenuItem(e.Item, statusIconMenu)); foreach (System.Windows.Forms.ToolStripItem item in menuItems) { ConvertAndAddMenuItem(item, statusIconMenu); } statusIcon.PopupMenu += OnPopupMenu; statusIcon.Activate += (sender, e) => { DBusBackgroundWorker.InvokeWinformsThread (() => pluginHost.MainWindow.EnsureVisibleForegroundWindow(true, true)); }; }
void OnPopupMenu(object sender, Gtk.PopupMenuArgs e) { try { var mainWindowType = pluginHost.MainWindow.GetType(); var cxtTrayField = mainWindowType.GetField("m_ctxTray", BindingFlags.Instance | BindingFlags.NonPublic); var ctxTray = cxtTrayField.GetValue(pluginHost.MainWindow); // Synthesize menu open events. These are expected by KeePass and // other plugins var onOpening = ctxTray.GetType().GetMethod("OnOpening", BindingFlags.Instance | BindingFlags.NonPublic); DBusBackgroundWorker.InvokeWinformsThread(() => onOpening.Invoke(ctxTray, new[] { new CancelEventArgs() })); statusIconMenu.Popup(null, null, null, (uint)e.Args[0], (uint)e.Args[1]); var onOpened = ctxTray.GetType().GetMethod("OnOpened", BindingFlags.Instance | BindingFlags.NonPublic); DBusBackgroundWorker.InvokeWinformsThread(() => onOpened.Invoke(ctxTray, new[] { new CancelEventArgs() })); } catch (Exception ex) { Debug.Fail(ex.ToString()); } }
private void OnAppIndicatorMenuShown(object sender, EventArgs e) { try { var mainWindowType = pluginHost.MainWindow.GetType(); var onCtxTrayOpeningMethodInfo = mainWindowType.GetMethod("OnCtxTrayOpening", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic, null, new[] { typeof(object), typeof(CancelEventArgs) }, null); if (onCtxTrayOpeningMethodInfo != null) { DBusBackgroundWorker.InvokeWinformsThread (() => onCtxTrayOpeningMethodInfo.Invoke(pluginHost.MainWindow, new[] { sender, new CancelEventArgs() } ) ); } } catch (Exception ex) { Debug.Fail(ex.ToString()); } }
void On_updateUITimer_Tick(object sender, System.EventArgs e) { try { var mainWindowType = pluginHost.MainWindow.GetType(); var cxtTrayField = mainWindowType.GetField("m_ctxTray", BindingFlags.Instance | BindingFlags.NonPublic); var ctxTray = cxtTrayField.GetValue(pluginHost.MainWindow); // Synthesize menu open events. These are expected by KeePass and // other plugins var onOpening = ctxTray.GetType().GetMethod("OnOpening", BindingFlags.Instance | BindingFlags.NonPublic); DBusBackgroundWorker.InvokeWinformsThread(() => onOpening.Invoke(ctxTray, new[] { new CancelEventArgs() })); var onOpened = ctxTray.GetType().GetMethod("OnOpened", BindingFlags.Instance | BindingFlags.NonPublic); DBusBackgroundWorker.InvokeWinformsThread(() => onOpened.Invoke(ctxTray, new[] { new CancelEventArgs() })); } catch (Exception ex) { Debug.Fail(ex.ToString()); } finally { updateUITimer.Stop(); } }
private void OnActivateWorkaroundTimerTick(object sender, EventArgs e) { // There seems to be a bug? in Mono where if you change Visible from // false to true and WindowState from Minimized to !Minimized and then call // Activate() all in the same method call, then the icon in the launcher // is resored, but the window is not shown. To work around this, we use a // timer to invoke Activate() a second time to get the window to show. activateWorkaroundTimer.Stop(); DBusBackgroundWorker.InvokeWinformsThread ((Action)pluginHost.MainWindow.Activate); }
public void Activate(int x, int y) { DBusBackgroundWorker.InvokeWinformsThread(() => { if (pluginHost.MainWindow.Visible) { pluginHost.MainWindow.Hide(); } else { pluginHost.MainWindow.EnsureVisibleForegroundWindow(true, true); } }); }
public override void Terminate() { try { pluginHost.MainWindow.Activated -= MainWindow_Activated; GlobalWindowManager.WindowAdded -= GlobalWindowManager_WindowAdded; GlobalWindowManager.WindowRemoved -= GlobalWindowManager_WindowRemoved; DBusBackgroundWorker.InvokeWinformsThread(() => { pluginHost.MainWindow.MainMenu.Visible = true; }); DBusBackgroundWorker.Release(); } catch (Exception ex) { Debug.Fail(ex.ToString()); } }
/// <summary> /// Initalize Gtk and DBus stuff /// </summary> private void GtkDBusInit() { /* setup StatusNotifierItem */ const string sniWatcherServiceName = "org.kde.StatusNotifierWatcher"; const string sniWatcherPath = "/StatusNotifierWatcher"; const string applicationPathTemplate = "/org/keepass/KeePass{0}"; var watcher = Bus.Session.GetObject <IStatusNotifierWatcher>( sniWatcherServiceName, new ObjectPath(sniWatcherPath)); #if DEBUG watcher.StatusNotifierItemRegistered += (obj) => Console.WriteLine(obj); #endif var mainWindowType = pluginHost.MainWindow.GetType(); var cxtTrayField = mainWindowType.GetField("m_ctxTray", BindingFlags.Instance | BindingFlags.NonPublic); var ctxTray = cxtTrayField.GetValue(pluginHost.MainWindow); var onOpening = ctxTray.GetType().GetMethod("OnOpening", BindingFlags.Instance | BindingFlags.NonPublic); var onOpened = ctxTray.GetType().GetMethod("OnOpened", BindingFlags.Instance | BindingFlags.NonPublic); var applicationPath = new ObjectPath(string.Format(applicationPathTemplate, pluginHost.MainWindow.Handle)); statusNotifier = new KeePassStatusNotifierItem(pluginHost, applicationPath); // Synthesize menu open events. These are expected by KeePass and // other plugins statusNotifier.Showing += (sender, e) => { DBusBackgroundWorker.InvokeWinformsThread(() => onOpening.Invoke(ctxTray, new[] { new CancelEventArgs() })); }; statusNotifier.Shown += (sender, e) => { DBusBackgroundWorker.InvokeWinformsThread(() => onOpened.Invoke(ctxTray, new[] { new CancelEventArgs() })); }; Bus.Session.Register(applicationPath, statusNotifier); watcher.RegisterStatusNotifierItem(applicationPath.ToString()); }
private void ConvertAndAddMenuItem(System.Windows.Forms.ToolStripItem item, Dbusmenu.Menuitem parent) { if (item is System.Windows.Forms.ToolStripMenuItem) { var winformMenuItem = item as System.Windows.Forms.ToolStripMenuItem; var dbusMenuItem = new Dbusmenu.Menuitem(); dbusMenuItem.PropertySet("label", winformMenuItem.Text.Replace("&", "")); // VisibleChanged does not seem to be firing, so make everything visible for now //dbusMenuItem.PropertySetBool("visible", winformMenuItem.Visible); dbusMenuItem.PropertySetBool("enabled", winformMenuItem.Enabled); dbusMenuItem.ItemActivated += (sender, e) => DBusBackgroundWorker.InvokeWinformsThread((Action)winformMenuItem.PerformClick); winformMenuItem.TextChanged += (sender, e) => DBusBackgroundWorker.InvokeGtkThread(() => dbusMenuItem.PropertySet("label", winformMenuItem.Text.Replace("&", ""))); winformMenuItem.EnabledChanged += (sender, e) => DBusBackgroundWorker.InvokeGtkThread(() => dbusMenuItem.PropertySetBool("enabled", winformMenuItem.Enabled)); winformMenuItem.VisibleChanged += (sender, e) => DBusBackgroundWorker.InvokeGtkThread(() => dbusMenuItem.PropertySetBool("visible", winformMenuItem.Visible)); parent.ChildAppend(dbusMenuItem); } else if (item is System.Windows.Forms.ToolStripSeparator) { // Ignore separator for now because there are too many of them // var dbusMenuItem = new DbusmenuMenuitem(); // dbusMenuItem.PropertySet("type", "separator"); // parent.ChildAppend(dbusMenuItem); } else { Debug.Fail("Unexpected menu item"); } }
void GtkDBusInit() { /* setup ApplicationMenu */ dbusMenu = new MenuStripDBusMenu(pluginHost.MainWindow.MainMenu); emptyDBusMenu = new MenuStripDBusMenu(new MenuStrip()); var sessionBus = Bus.Session; #if DEBUG const string dbusBusPath = "/org/freedesktop/DBus"; const string dbusBusName = "org.freedesktop.DBus"; var dbusObjectPath = new ObjectPath(dbusBusPath); var dbusService = sessionBus.GetObject <org.freedesktop.DBus.IBus>(dbusBusName, dbusObjectPath); dbusService.NameAcquired += (name) => Console.WriteLine("NameAcquired: " + name); #endif const string registrarBusPath = "/com/canonical/AppMenu/Registrar"; const string registratBusName = "com.canonical.AppMenu.Registrar"; var registrarObjectPath = new ObjectPath(registrarBusPath); unityPanelServiceBus = sessionBus.GetObject <com.canonical.AppMenu.Registrar.IRegistrar>(registratBusName, registrarObjectPath); mainFormXid = GetWindowXid(pluginHost.MainWindow); mainFormObjectPath = new ObjectPath(string.Format(menuPath, mainFormXid)); sessionBus.Register(mainFormObjectPath, dbusMenu); try { unityPanelServiceBus.RegisterWindow((uint)mainFormXid.ToInt32(), mainFormObjectPath); } catch (Exception) { if (!pluginHost.CustomConfig.GetBool(keebuntuAppMenuWarningSeenId, false)) { Task.Run((Action)ShowErrorMessage); } DBusBackgroundWorker.InvokeWinformsThread(() => Terminate()); } }
private void ConvertAndAddMenuItem(System.Windows.Forms.ToolStripItem item, Gtk.MenuShell gtkMenuShell) { if (item is System.Windows.Forms.ToolStripMenuItem) { var winformMenuItem = item as System.Windows.Forms.ToolStripMenuItem; // windows forms use '&' for mneumonic, gtk uses '_' var gtkMenuItem = new Gtk.ImageMenuItem(winformMenuItem.Text.Replace("&", "_")); if (winformMenuItem.Image != null) { MemoryStream memStream; var image = winformMenuItem.Image; if (image.Width != 16 || image.Height != 16) { var newImage = ResizeImage(image, 16, 16); memStream = new MemoryStream(newImage); } else { memStream = new MemoryStream(); image.Save(memStream, ImageFormat.Png); memStream.Position = 0; } gtkMenuItem.Image = new Gtk.Image(memStream); } gtkMenuItem.TooltipText = winformMenuItem.ToolTipText; gtkMenuItem.Visible = winformMenuItem.Visible; gtkMenuItem.Sensitive = winformMenuItem.Enabled; gtkMenuItem.Activated += (sender, e) => DBusBackgroundWorker.InvokeWinformsThread((Action)winformMenuItem.PerformClick); winformMenuItem.TextChanged += (sender, e) => DBusBackgroundWorker.InvokeGtkThread(() => { var label = gtkMenuItem.Child as Gtk.Label; if (label != null) { label.Text = winformMenuItem.Text; } } ); winformMenuItem.EnabledChanged += (sender, e) => DBusBackgroundWorker.InvokeGtkThread (() => gtkMenuItem.Sensitive = winformMenuItem.Enabled); winformMenuItem.VisibleChanged += (sender, e) => DBusBackgroundWorker.InvokeGtkThread (() => gtkMenuItem.Visible = winformMenuItem.Visible); gtkMenuItem.Show(); gtkMenuShell.Insert(gtkMenuItem, winformMenuItem.Owner.Items.IndexOf(winformMenuItem)); if (winformMenuItem.HasDropDownItems) { var subMenu = new Gtk.Menu(); foreach (System.Windows.Forms.ToolStripItem dropDownItem in winformMenuItem.DropDownItems) { ConvertAndAddMenuItem(dropDownItem, subMenu); } gtkMenuItem.Submenu = subMenu; winformMenuItem.DropDown.ItemAdded += (sender, e) => DBusBackgroundWorker.InvokeGtkThread (() => ConvertAndAddMenuItem(e.Item, subMenu)); } } else if (item is System.Windows.Forms.ToolStripSeparator) { var gtkSeparator = new Gtk.SeparatorMenuItem(); gtkSeparator.Show(); gtkMenuShell.Insert(gtkSeparator, item.Owner.Items.IndexOf(item)); } else { Debug.Fail("Unexpected menu item"); } }
/// <summary> /// Initalize Gtk and DBus stuff /// </summary> private void GtkDBusInit() { /* setup ApplicationIndicator */ indicator = new ApplicationIndicator("keepass2-plugin-appindicator" + instanceCount++, "keepass2-locked", AppIndicator.Category.ApplicationStatus); #if DEBUG indicator.IconThemePath = Path.GetFullPath("Resources/icons"); #endif indicator.Title = PwDefs.ProductName; indicator.Status = AppIndicator.Status.Active; appIndicatorMenu = new Gtk.Menu(); var trayContextMenu = pluginHost.MainWindow.TrayContextMenu; // make copy of item list to prevent list changed exception when iterating var menuItems = new System.Windows.Forms.ToolStripItem[trayContextMenu.Items.Count]; trayContextMenu.Items.CopyTo(menuItems, 0); trayContextMenu.ItemAdded += (sender, e) => DBusBackgroundWorker.InvokeGtkThread (() => ConvertAndAddMenuItem(e.Item, appIndicatorMenu)); foreach (System.Windows.Forms.ToolStripItem item in menuItems) { ConvertAndAddMenuItem(item, appIndicatorMenu); } indicator.Menu = appIndicatorMenu; try { // This is a hack to get the about-to-show event from the dbusmenu // that is created by the appindicator. var getPropertyMethod = typeof(GLib.Object).GetMethod("GetProperty", BindingFlags.NonPublic | BindingFlags.Instance); var dbusMenuServer = (GLib.Value)getPropertyMethod.Invoke(indicator, new object[] { "dbus-menu-server" }); var rootNode = (GLib.Value)getPropertyMethod.Invoke(dbusMenuServer.Val, new object[] { "root-node" }); aboutToShowSignal = GLib.Signal.Lookup((GLib.Object)rootNode.Val, "about-to-show"); aboutToShowSignal.AddDelegate((EventHandler)OnAppIndicatorMenuShown); } catch (Exception ex) { Debug.Fail(ex.Message); // On desktops that don't support application indicators, libappinidicator // creates a fallback GtkStatusIcon. This event only fires in that case. appIndicatorMenu.Shown += OnAppIndicatorMenuShown; } // when mouse cursor is over application indicator, scroll up will untray // and scroll down will tray KeePass indicator.ScrollEvent += (o, args) => { /* Workaround for bug in mono/appindicator-sharp. * * args.Direction throws InvalidCastException * Can't cast args.Arg[1] to Gdk.ScrollDirection for some reason, so we * have to cast to uint first (that is the underlying data type) and * then cast to Gdk.ScrollDirection */ var scrollDirectionUint = (uint)args.Args[1]; var scrollDirection = (Gdk.ScrollDirection)scrollDirectionUint; var trayMenuItem = trayContextMenu.Items["m_ctxTrayTray"]; if (trayMenuItem.Enabled && (scrollDirection == Gdk.ScrollDirection.Up ^ pluginHost.MainWindow.Visible)) { DBusBackgroundWorker.InvokeWinformsThread (() => trayMenuItem.PerformClick()); } }; }