!7 concept Profile { S name, options; S computerID; // to send clipboard (optional) } cmodule VNCViewerTrayIcon > DynCRUD { transient TrayIcon trayIcon; switchable bool inProcess; // don't think true works yet start { db(); onConceptsChangeAndNow(r makeTrayIcon); } void makeTrayIcon enter { disposeTrayIcon(trayIcon); L menuItems = ll(r launchVNCViewer); for (Profile p : sortConceptsByID(list(Profile))) addAll(menuItems, p.name, r { launch(p) }); add(menuItems, "---"); L withComputerID = whereFieldNempty computerID(list(Profile)); if (nempty(withComputerID)) { for (Profile p : withComputerID) addAll(menuItems, "Send clipboard to " + p.name, r { dm_sendClipboardTo_verbose(p.computerID) }); add(menuItems, "---"); } addAll(menuItems, "VNC Viewer Connection Dialog", r { if (inProcess) launchVNCViewer_inProcess(); else launchVNCViewer() }); addAll(menuItems, "Edit Profiles...", r dm_activateOSAndModule); trayIcon = installTrayIcon(#1101468, "Start VNC Viewer", menuItems); } afterVisualize { // TODO: disable when at beginning/end of list addSelectionDependentButton("Move Up", r { Profile a = selected(), b = itemBefore(list(), a); if (a != null && b != null) swapConceptIDs(a, b); }); addSelectionDependentButton("Move Down", r { Profile a = selected(), b = itemAfter(list(), a); if (a != null && b != null) swapConceptIDs(a, b); }); addSelectionDependentButton("Connect", rThread { launch(selected()); }); } void cleanMeUp { disposeTrayIcon(trayIcon); } void launch(Profile p) { if (p == null) ret; if (inProcess) launchVNCViewer_inProcess(p.options); else launchVNCViewer(p.options); } }