├── .gitignore ├── AUTHORS ├── CHANGELOG ├── COPYING ├── README.md ├── docs ├── CNAME ├── api │ └── index.html ├── index.html └── src │ ├── LICENSE │ ├── api │ ├── LICENSE │ ├── index.adoc │ └── readme.txt │ ├── generate.sh │ ├── icons.svg │ ├── index.adoc │ ├── jackpatch.1 │ ├── jackpatch.h2m │ ├── manpage-common.h2m │ ├── non-session-manager.1 │ ├── nsm-legacy-gui.1 │ ├── nsm-proxy-gui.1 │ ├── nsm-proxy.1 │ ├── nsmd.1 │ ├── readme-00.md │ ├── readme-01.md │ └── readme-02.md ├── extras ├── README.md ├── nsm.h │ ├── COPYING │ └── nsm.h └── pynsm │ ├── LICENSE │ ├── README.md │ ├── exampleBoilerplate.py │ ├── exampleQt.py │ ├── minimalClients │ ├── base.py │ ├── broadcast.py │ ├── label.py │ ├── nsmclient.py │ └── source_me_with_port.bash │ ├── nsmclient.py │ └── test-importResource.py ├── meson.build ├── meson_options.txt └── src ├── Endpoint.cpp ├── Endpoint.hpp ├── FL ├── Fl_Packscroller.H ├── Fl_Scalepack.C └── Fl_Scalepack.H ├── NSM_Proxy_UI.fl ├── Thread.cpp ├── Thread.hpp ├── debug.cpp ├── debug.h ├── file.cpp ├── file.h ├── jackpatch.c ├── jackpatch.svg ├── nsm-legacy-gui.cpp ├── nsm-legacy-gui.svg ├── nsm-proxy-gui.cpp ├── nsm-proxy.cpp ├── nsm-proxy.svg ├── nsmd.cpp ├── org.jackaudio.jackpatch.desktop ├── org.jackaudio.nsm-legacy-gui.desktop └── org.jackaudio.nsm-proxy.desktop /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.bak 3 | *.swp 4 | *.[ao] 5 | TAGS 6 | .nfs* 7 | build 8 | builddir 9 | subprojects 10 | # Ignore (compiled) python files, 11 | *__pycache__/* 12 | *.pyc 13 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # A complete list of authors. For individual contributions please read CHANGELOG 2 | 3 | Liles, Jonathan Moore / original-male (original author) 4 | for authors before the fork in May 2020 please see https://github.com/original-male/non 5 | 6 | Coelho, Filipe / falktx (new-session-manager fork) 7 | Hilbricht, Nils (new-session-manager fork) 8 | 9 | # Individual Contributions in alphabetical surname order 10 | 11 | Meyer, Hermann / brummer 12 | Picot, Mathieu / houston 13 | Berkelder, Rik 14 | Runge, David / dvzrv 15 | / TheGreatWhiteShark 16 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | #Changelog 2 | Format: Double ## for a version number followed by a space, ISO-Date, Semantic Versioning: 3 | ## YYYY-MM-DD major.minor.patch 4 | Two empty lines before the next entry. 5 | External contributors notice at the end of the line: (LastName, FirstName / nick) 6 | 7 | 8 | ## 2022-10-15 1.6.1 9 | Absolutely make sure that all clients of the session are closed when closing the session. 10 | This solves the invisible, hidden clients still running even after nsmd quit itself. 11 | Decrease wait time for such clients at session quit from extreme 60s to very long 30s. 12 | For lockfiles fall back to hardcoded /run/user/ when $XDG_RUNTIME_DIR is not available on the system. 13 | 14 | 15 | ## 2022-04-15 1.6.0 16 | nsmd: 17 | Now follows the XDG Base Directory Specifications. 18 | Default session directory moved from ~/NSM Sessions/ to $XDG_DATA_HOME/nsm/ (see issue #gh-15) 19 | The old path ~/NSM Sessions/ is still supported and has priority, for now. This may be switched off in the future. 20 | 21 | Lockfiles fixed (see issue #gh-31) 22 | Lockfiles are now in $XDG_RUNTIME_DIR/nsm/ 23 | Lockfiles now each contain the session path, the osc NSM_URL and the nsmd PID 24 | One daemon file for each currently running nsmd is created in $XDG_RUNTIME_DIR/nsm/d/ containing the osc url. This enables discovery of running daemons. 25 | 26 | New section in the API documentation for the above. 27 | Handle write-protected session files and related errors on save. They will not crash the daemon anymore. 28 | Fixes and guards against trying to load non-existing sessions and creating new sessions under existing names 29 | Handle various crashes-on-exit and replace them with controlled exits. 30 | 31 | Jackpatch Version 1.0.0 (previously 0.2.0): 32 | Jackpatch will finally not "forget" connections anymore. See #gh-74 33 | Reduce verbosity level of log ouput. 34 | Document 'hidden' standalone (no NSM) command line mode in --help 35 | Handle SIGNALs even when in standalone mode 36 | Add a jackpatch desktop file with X-NSM-Capable=true and X-NSM-Exec=jackpatch and NoDisplay=true 37 | 38 | NSM-Proxy: 39 | Add a nsm-proxy desktop file with X-NSM-Capable=true and X-NSM-Exec=nsm-proxy and NoDisplay=true 40 | 41 | 42 | ## 2022-01-15 1.5.3 43 | Add [jackpatch] to terminal log output of jackpatch. 44 | Remove hardcoded ANSI colors from terminal log output 45 | 46 | 47 | ## 2021-07-15 1.5.2 48 | pynsm2 library: Fixed a rare crash, where the hostname must be case sensitive but Pythons urlparse forced lower-case. 49 | 50 | 51 | ## 2021-03-19 1.5.1 52 | Web-URLs changed to https://new-session-manager.jackaudio.org and https://github.com/jackaudio/new-session-manager 53 | No codechanges. 54 | 55 | 56 | ## 2021-01-15 1.5.0 57 | WARNING: Next scheduled release (2021-04-15) will switch the default session root 58 | to $XDG_DATA_HOME ( default on most distributions: ~/.local/share/nsm/ ) 59 | With the next release prepare to do one of the following: 60 | * Move old sessions to the new root directory (preferred) 61 | * Symlink "~/NSM Sessions" to the new root directory 62 | * use the nsmd --session-root commandline argument. 63 | 64 | nsmd: 65 | Fix session discovery to not report nested sessions anymore. Also more robust file system error handling. 66 | Command line option --quiet: Suppress messages except warnings and errors 67 | Protect against orphaned clients or daemons when the server, or even a GUI, crashes. 68 | Replace cowboy-slang in info-level OSC with descriptive, technical messages. 69 | 70 | Legacy-GUI: 71 | Fix manpage description and usage with the correct executable name 72 | Fix resizing to very small and back. ( / TheGreatWhiteShark ) 73 | 74 | NSM-Proxy: 75 | Multiple layout and style fixes. Better texts for beginners. 76 | 77 | API: 78 | NSM_API_VERSION_PATCH from 0 to 1 (1.1.0 -> 1.1.1) 79 | Please see API document chapter "Changes in API Version 1.1.1" 80 | 81 | Extras: 82 | This repository now contains extras (libraries, programs, documentation etc.) 83 | Extras are technically not connected to the main programs of this repository. 84 | There is no dependency to any "extra" nor any license implications. 85 | Please read extras/README.md. 86 | 87 | nsm.h was moved to extras/nsm.h 88 | "extras/pynsm" is now a part of NEW-SM. It was a standalone git repo until now. 89 | 90 | 91 | ## 2020-07-15 1.4.0 92 | Add documentation and manpages. 93 | 94 | Legacy-GUI: 95 | Overhaul look and feel. 96 | Rewrite labels and buttons with unambiguous descriptions. 97 | Protect text-input dialog windows from empty strings, like "Add New Client" or "New Session" 98 | Scale icons, support more icon formats. 99 | Show all icons and buttons when attaching to a running nsmd session 100 | Various small fixes. 101 | Always show correct session name, no matter how the session was loaded or how the GUI was started 102 | 103 | nsmd: 104 | NSM_API_VERSION_MINOR from 0 to 1 (1.0 -> 1.1) 105 | Repair nsmd to correctly send client data when running headless and a GUI announces later. 106 | ClientId generation now prevent collision with existing IDs. 107 | nsmd command line option --load-session to directly load one (Berkelder, Rik) 108 | Better detection of clients that failed to launch leads to faster session startup (by 5 seconds) 109 | Users get informed by client-label if an executable is not present on the system or permission denied 110 | Fixed reply for listing sessions from a plain "Done." to proper reply path with empty string as terminal symbol "/reply", "/nsm/server/list", "" 111 | Fix operation reply to last treated client instead to reply to sender (Picot, Mathieu / houston) 112 | /nsm/gui/session/name send consistent session name/relative-path pair to the annouced GUI, no matter how the session was loaded. 113 | 114 | nsm.h 115 | :optional-gui: support to nsm.h, for other applications to include and use. (Meyer, Hermann / brummer) 116 | 117 | 118 | ## 2020-06-20 1.3.2 119 | Rename new-session-manager executable to nsm-legacy-gui to prevent future confusion. 120 | 121 | 122 | ## 2020-06-20 1.3.1 123 | Add header copyright even to unchanged files to adhere to stricter packaging requirements. 124 | Meson can now switch off individual executables and will stop/error when trying to build without dependencies. 125 | 126 | 127 | ## 2020-06-17 1.3.0 128 | Rebranding to "new session manager" 129 | Upstream GUI tools "non-session-manager" and "nsm-proxy" converted to standard FLTK instead of a custom toolkit 130 | Changed build system to meson 131 | License upgraded to GPLv3 132 | Simplified file structure 133 | Fix compiler warnings. 134 | 135 | 136 | ## 2020-04-19 1.2.1 137 | Current state of upstream Non Session Manager v1.2 including unreleased /nsm/gui/session/root 138 | 139 | 140 | ## 2017-07-08 1.2.0 141 | Last release of Non-Session-Manager. 142 | Commit 1904aba516341287ac297cefbbcd185f643e5538 143 | 144 | 145 | ## 2012-03-03 1.1.0 146 | Initial release of Non-Session-Manager. 147 | https://non.tuxfamily.org/wiki/2012-03-03%20Release%20Announcement%20v1.1.0 148 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # New Session Manager 2 | 3 | ## Introduction 4 | 5 | New Session Manager (NSM) is a tool to assist music production by grouping standalone programs into 6 | sessions. Your workflow becomes easy to manage, robust and fast by leveraging the full potential of 7 | cooperative applications. 8 | 9 | NSM continues to be free in every sense of the word: free of cost, free to share and use, free of 10 | spyware or ads, free-and-open-source. 11 | 12 | You can create a session, or project, add programs to it and then use commands to save, start/stop, 13 | hide/show all programs at once, or individually. At a later date you can then re-open the session 14 | and continue where you left off. 15 | 16 | All files belonging to the session will be saved in the same directory. 17 | 18 | If you are a user (and not a programmer or packager) everything you need is to install NSM 19 | through your distributions package manager and, highly recommended, Agordejo as a GUI (see below). 20 | 21 | To learn NSM you don't need to know the background information from our documentation, which 22 | is aimed at developers that want to implement NSM support in their programs. Learn the GUI, 23 | not the server and protocol. 24 | 25 | 26 | ## Bullet Points 27 | * Drop-In replacement for the non-session-manager daemon nsmd and tools (e.g. jackpatch) 28 | * Simple and hassle-free build system to make packaging easy 29 | * Possibility to react to sensible bug fixes that would not have been integrated original nsmd 30 | * Stay upwards and downwards compatible with original nsmd 31 | * Conservative and hesitant in regards to new features and behaviour-changes, but possible in principle 32 | * Keep the session-manager separate from the other NON* tools Mixer, Sequencer and Timeline. 33 | * Protect nsmd from vanishing from the internet one day. 34 | * The goal is to become the de-facto standard music session manager for Linux distributions 35 | 36 | ## User Interface 37 | It is highly recommended to use Agordejo ( https://www.laborejo.org/agordejo/ ) as graphical 38 | user interface. In fact, if you install Agordejo in your distribution it will install NSM as 39 | dependency and you don't need to do anything yourself with this software package. 40 | 41 | This repository also contains the legacy FLTK interface simply called `nsm-legacy-gui`, 42 | symlinked to `non-session-manager` for backwards compatibility. (e.g. autostart scripts etc.) 43 | 44 | ## Supported Clients 45 | 46 | While NSM can start and stop any program it only becomes convenient if clients specifically 47 | implement support. This enables saving and hiding the GUI, amongst other features. 48 | Documentation and tutorials for software-developers will be added at a later date. 49 | 50 | ## Documentation and Manual 51 | 52 | Our documentation contains the API specification for the NSM protocol, which is the central document 53 | if you want to add NSM support to your own application. 54 | 55 | You can find html documentation installed to your systems SHARE dir or docs/out/index.html in this 56 | repository. 57 | There is also an online version https://jackaudio.github.io/new-session-manager/ 58 | 59 | We also provide a set of manpages for each executable (see Build). 60 | 61 | 62 | ## Fork and License 63 | This is a fork of non-session-manager, by Jonathan Moore Liles http://non.tuxfamily.org/ 64 | which was released under the GNU GENERAL PUBLIC LICENSE Version 2, June 1991. 65 | 66 | All files, except nsm.h kept in this fork were GPL "version 2 of the License, or (at your 67 | option) any later version." 68 | 69 | `nsm.h` is licensed under the ISC License. 70 | 71 | New-Session-Manager changed the license to GNU GENERAL PUBLIC LICENSE, Version 3, 29 June 2007. 72 | See file COPYING 73 | 74 | Documentation in docs/ is licensed Creative Commons CC-By-Sa. 75 | It consist of mostly generated files and snippet files which do not have a license header for 76 | technical reasons. 77 | All original documentation source files are CC-By-Sa Version v4.0 (see file docs/src/LICENSE), 78 | the source file docs/src/api/index.adoc is a derived work from NON-Session-Managers API file which 79 | is licensed CC-By-Sa v2.5. Therefore our derived API document is also CC-By-Sa v2.5 80 | (see files docs/src/api/readme.txt and docs/src/api/LICENSE) 81 | 82 | 83 | ## Build 84 | The build system is meson. 85 | 86 | This is a software package that will compile and install multiple executables: 87 | * `nsmd`, the daemon or server itself. It is mandatory. 88 | * It has no GUI. 89 | * Dependency is `liblo`, the OSC library. 90 | * `jackpatch`, NSM client to save and remember JACK connections. 91 | * It has no GUI. 92 | * Dependencies are `JACK Audio Connection Kit` and `liblo`, the OSC library. 93 | * Can be deactivated (see below) `-Djackpatch=false` 94 | * `nsm-legacy-gui`, Legacy GUI for the user 95 | * Formerly known as "non-session-manager" 96 | * Dependencies are `FLTK`>=v1.3.0 and `liblo`, the OSC library. 97 | * Can be deactivated (see below) `-Dlegacy-gui=false` 98 | * `nsm-proxy`, NSM GUI Client to run any program without direct NSM support 99 | * Dependencies are `FLTK`>=v1.3.0, `fluid` (FLTK Editor/compiler, maybe in the same package as FLTK, maybe not) and `liblo`, the OSC library. 100 | * Can be deactivated (see below) `-Dnsm-proxy=false` 101 | 102 | 103 | ``` 104 | meson build --prefix=/usr 105 | #or disable individual build targets: 106 | #meson build --prefix=/usr -Dlegacy-gui=false -Dnsm-proxy=false -Djackpatch=false 107 | cd build && ninja 108 | sudo ninja install 109 | ``` 110 | 111 | Optionally you can skip `sudo ninja install` and run all executables from the build-dir. 112 | In this case you need to add the build-dir to your PATH environment variable so that the tools 113 | can find each other. 114 | 115 | ## Names of Executable Files and Symlinks 116 | 117 | Some distributions (and possibly local laws) prevent a forked software project from creating 118 | executable files under the same name, if the name itself is an original work subject to copyright, 119 | which it arguably is for the "NON-"-suite. Therefore New Session Manager renamed 120 | `non-session-manager` to `nsm-legacy-gui`. Installing will also create a symlink to 121 | `non-session-manager` for backwards compatibility. (e.g. autostart scripts etc.). 122 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | new-session-manager.jackaudio.org -------------------------------------------------------------------------------- /docs/src/api/LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons 2 | 3 | Creative Commons Legal Code 4 | Attribution-ShareAlike 2.5 5 | 6 | https://creativecommons.org/licenses/by-sa/2.5/legalcode 7 | 8 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. 9 | License 10 | 11 | THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. 12 | 13 | BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 14 | 15 | 1. Definitions 16 | 17 | "Collective Work" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License. 18 | "Derivative Work" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License. 19 | "Licensor" means the individual or entity that offers the Work under the terms of this License. 20 | "Original Author" means the individual or entity who created the Work. 21 | "Work" means the copyrightable work of authorship offered under the terms of this License. 22 | "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. 23 | "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike. 24 | 2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws. 25 | 26 | 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: 27 | 28 | to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works; 29 | to create and reproduce Derivative Works; 30 | to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works; 31 | to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works. 32 | For the avoidance of doubt, where the work is a musical composition: 33 | 34 | Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work. 35 | Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to collect, whether individually or via a music rights society or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions). 36 | Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions). 37 | The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved. 38 | 39 | 4. Restrictions.The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: 40 | 41 | You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by clause 4(c), as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any credit as required by clause 4(c), as requested. 42 | You may distribute, publicly display, publicly perform, or publicly digitally perform a Derivative Work only under the terms of this License, a later version of this License with the same License Elements as this License, or a Creative Commons iCommons license that contains the same License Elements as this License (e.g. Attribution-ShareAlike 2.5 Japan). You must include a copy of, or the Uniform Resource Identifier for, this License or other license specified in the previous sentence with every copy or phonorecord of each Derivative Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Derivative Works that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder, and You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Derivative Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Derivative Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Derivative Work itself to be made subject to the terms of this License. 43 | If you distribute, publicly display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or Licensor designate another party or parties (e.g. a sponsor institute, publishing entity, journal) for attribution in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit. 44 | 5. Representations, Warranties and Disclaimer 45 | 46 | UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE MATERIALS, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. 47 | 48 | 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 49 | 50 | 7. Termination 51 | 52 | This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. 53 | Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. 54 | 8. Miscellaneous 55 | 56 | Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. 57 | Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. 58 | If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. 59 | No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. 60 | This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. 61 | Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. 62 | 63 | Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, neither party will use the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. 64 | 65 | Creative Commons may be contacted at https://creativecommons.org/. 66 | -------------------------------------------------------------------------------- /docs/src/api/readme.txt: -------------------------------------------------------------------------------- 1 | The statements made here only concern the API document. All other documentation and help texts of 2 | the "New Session Manager" are original works. 3 | 4 | This subdirectory "API" contains an adapted copy of http://non.tuxfamily.org/nsm/API.html, which 5 | was released by Jonathan Moore Liles under the title "Non Session Management 6 | API Version 1." 7 | 8 | It was published on the the NON-Website on 2013-04-06 with git commit 9 | d7cf8955b8557ccc56d108425a2c61b0e1ac73f4 under the Creative Commons By-Sa License 2.5, as was the 10 | whole website (see website footer). For a full copy of the license please see the attached file 11 | LICENSE. 12 | 13 | This adaption and all changes are licensed under CC-By-Sa 2.5 as well. The original work was copied 14 | from the NON-website by hand in 2020-07 by Nils Hilbricht. 15 | 16 | Initial git commit on 2020-07-06 is the unaltered content by Jonathan Moore Liles, not counting 17 | layout changes because the document format changed. All subsequent changes and authors can be 18 | reviewed by git log. 19 | -------------------------------------------------------------------------------- /docs/src/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #The documentation is built statically and does not belong to the normal build process. 4 | #Updating is part of the development process, not compiling or packaging. 5 | #Run this before a release, or any time you want to update the docs or the README. 6 | 7 | #This script takes common snippets of information and updates or generates source info files from 8 | #them. 9 | # parse src/nsmd.cpp for API version, insert into /docs/src/api/index.adoc 10 | # parse src/nsmd.cpp for package version, insert into /meson.build and /docs/src/index.adoc 11 | # generate /README.md (shares text with manual index) 12 | # generate manpages 13 | # convert all .adoc files to html in /docs/ (This enables github to directly present this dir as website) 14 | # 15 | # WARNING: You still need to manually edit the date and version in /CHANGELOG 16 | # 17 | #We do _not_ change the copyright date in files license-headers. 18 | #They only exist to mark to year of the fork. In the future dates might be removed completely. 19 | 20 | set -e #Stop script on errors 21 | set -u #Trace unset variables as an error. 22 | 23 | #Change pwd to root dir 24 | parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P ) 25 | cd "$parent_path"/../.. 26 | [ -f "CHANGELOG" ] || ( echo "not in the root dir"; exit 1 ) #assert correct dir 27 | [ -f "build/nsmd" ] || ( echo "no build/ dir with binaries"; exit 1 ) #assert build was made, for manpages 28 | 29 | #Gather data 30 | ROOT=$(pwd) #save for later 31 | VERSION=$(grep "define VERSION_STRING" "src/nsmd.cpp" | cut -d ' ' -f 3) #Get version as "1.4" string 32 | VERSION="${VERSION%\"}" #Remove " 33 | VERSION="${VERSION#\"}" #Remove " 34 | 35 | _MAJORAPI=$(grep "define NSM_API_VERSION_MAJOR" "src/nsmd.cpp" | cut -d ' ' -f 3) 36 | _MINORAPI=$(grep "define NSM_API_VERSION_MINOR" "src/nsmd.cpp" | cut -d ' ' -f 3) 37 | _PATCHAPI=$(grep "define NSM_API_VERSION_PATCH" "src/nsmd.cpp" | cut -d ' ' -f 3) 38 | APIVERSION=$_MAJORAPI"."$_MINORAPI"."$_PATCHAPI 39 | 40 | #Present data to confirm write-action 41 | echo "Root: $ROOT" 42 | echo "Version: $VERSION" 43 | echo "API Version: $APIVERSION" 44 | echo "Please make sure that your meson build dir is up to date for manpage generation" 45 | read -p "Is parsed data correct? Continue by writing files? [y|n] " -n 1 -r 46 | if [[ ! $REPLY =~ ^[Yy]$ ]] 47 | then 48 | echo 49 | echo "Abort" 50 | exit 1 51 | fi 52 | echo 53 | echo 54 | 55 | echo "Update meson.build version number" 56 | cd "$ROOT" 57 | sed -i "/^version :.*/c\version : '$VERSION'," meson.build #Find the version line and replace with entire new line 58 | 59 | echo "Update docs to programs version number" 60 | cd "$ROOT/docs/src" 61 | sed -i '/^\:revnumber.*/c\:revnumber: '$VERSION index.adoc #Find the revnumber line and replace with entire new line 62 | 63 | echo "Update API document to API version number" 64 | cd "$ROOT/docs/src/api" 65 | sed -i '/^\:revnumber.*/c\:revnumber: API '$APIVERSION index.adoc #Find the revnumber line and replace with entire new line 66 | 67 | 68 | echo "Generate README from snippets" 69 | cd "$ROOT/docs/src" 70 | cat "readme-00.md" "readme-01.md" "readme-02.md" > "$ROOT/README.md" 71 | 72 | 73 | echo "Generate website and documentation with Asciidoctor using README snippets" 74 | echo " We generate directly into docs/ and not into e.g. docs/out because github can read docs/ directly." 75 | cd "$ROOT/docs/" 76 | mkdir -p "api" 77 | asciidoctor src/index.adoc -o index.html 78 | asciidoctor src/api/index.adoc -o api/index.html 79 | 80 | 81 | echo "Generate all manpages" 82 | cd "$ROOT/docs/src" #We tested earlier that a build-dir exists 83 | 84 | help2man ../../build/nsmd --version-string="nsmd Version $VERSION" --no-info --include manpage-common.h2m > nsmd.1 85 | help2man ../../build/nsm-legacy-gui --version-string="nsm-legacy-gui Version $VERSION" --no-info --include manpage-common.h2m > nsm-legacy-gui.1 86 | help2man ../../build/nsm-legacy-gui --version-string="nsm-legacy-gui Version $VERSION" --no-info --include manpage-common.h2m > non-session-manager.1 87 | help2man ../../build/nsm-proxy --version-string="nsm-proxy Version $VERSION" --no-info --include manpage-common.h2m > nsm-proxy.1 88 | help2man ../../build/nsm-proxy-gui --version-string="nsm-proxy-gui Version $VERSION" --no-info --include manpage-common.h2m > nsm-proxy-gui.1 89 | help2man ../../build/jackpatch --version-string="jackpatch Version $VERSION" --no-info --include manpage-common.h2m > jackpatch.1 90 | 91 | echo 92 | echo "Don't forget to adjust the version and date in CHANGELOG manually." 93 | echo "Finished. You need to commit your changes to git manually." 94 | -------------------------------------------------------------------------------- /docs/src/icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 39 | 41 | 42 | 44 | image/svg+xml 45 | 47 | 48 | 49 | 50 | 51 | 55 | 59 | nsm 61 | 68 | NSM 79 | 80 | 84 | jackpatch 86 | 93 | JP 104 | 105 | 108 | proxy 110 | 117 | PRX 128 | 129 | 133 | 137 | 141 | 145 | 149 | 150 | 154 | 158 | 162 | 166 | 170 | 174 | 178 | 182 | 183 | Texts andObjects 199 | Convertedto paths 215 | Inkscape export single icon:Select Icon, Ctrl+Shift+Rto resize to selection.File -> Save a Copy Inkscape SVG works as icon 246 | 247 | 248 | -------------------------------------------------------------------------------- /docs/src/index.adoc: -------------------------------------------------------------------------------- 1 | //// 2 | This is "asciidoctor", not plain "asciidoc". 3 | https://asciidoctor.org/docs/user-manual/ 4 | //// 5 | 6 | 7 | //// 8 | This documentation is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. 9 | To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/ or send a 10 | letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. 11 | A copy of the license has been provided in the file documentation/LICENSE. 12 | //// 13 | 14 | :Author: Nils Hilbricht 15 | :iconfont-remote!: 16 | :!webfonts: 17 | :revnumber: 1.6.1 18 | 19 | = New Session Manager Documentation 20 | 21 | * link:https://github.com/jackaudio/new-session-manager[Sourcecode] 22 | * link:https://github.com/jackaudio/new-session-manager/issues[Bug and Issue Tracker] 23 | * link:api/index.html[API] document that describes all OSC Messages 24 | * link:http://non.tuxfamily.org/session-manager/doc/MANUAL.html[Legacy-GUI Manual]. The original Non-Session-Manager GUI manual is still valid. 25 | 26 | 27 | include::readme-01.md[] 28 | -------------------------------------------------------------------------------- /docs/src/jackpatch.1: -------------------------------------------------------------------------------- 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2. 2 | .TH JACKPATCH "1" "October 2022" "jackpatch Version 1.6.1" "User Commands" 3 | .SH NAME 4 | jackpatch \- manual page for jackpatch Version 1.6.1 5 | .SH DESCRIPTION 6 | jackpatch \- Remember and restore the JACK Audio Connection Kit Graph in NSM 7 | .PP 8 | It is intended as module for the 'New Session Manager' and only communicates 9 | over OSC in an NSM\-Session. 10 | .PP 11 | It has limited standalone functionality for testing and debugging, such as: 12 | .SS "Usage:" 13 | .TP 14 | jackpatch [filename] 15 | Restore a snapshot from \fB\-\-save\fR and monitor. 16 | .IP 17 | jackpatch \fB\-\-help\fR 18 | .SH OPTIONS 19 | .TP 20 | \fB\-\-help\fR 21 | Show this screen and exit 22 | .TP 23 | \fB\-\-version\fR 24 | Show version and exit 25 | .TP 26 | \fB\-\-save\fR 27 | Save current connection snapshot to file and exit 28 | .SH "REPORTING BUGS" 29 | https://github.com/jackaudio/new-session-manager/issues 30 | .SH COPYRIGHT 31 | up to 2020: 32 | Jonathan Moore Liles https://non.tuxfamily.org/ 33 | 34 | from 2020: 35 | Nils Hilbricht et al. https://new-session-manager.jackaudio.org 36 | .SH "SEE ALSO" 37 | The full documentation for NSM is maintained as html site in your systems doc-dir. 38 | For example: 39 | xdg-open file:///usr/share/doc/new-session-manager/index.html 40 | 41 | The documentation can also be found online https://new-session-manager.jackaudio.org 42 | -------------------------------------------------------------------------------- /docs/src/jackpatch.h2m: -------------------------------------------------------------------------------- 1 | 2 | [name] 3 | jackpatch - JACK Audio Connection Kit environment saver for the "New Session Manager" 4 | 5 | [usage] 6 | jackapatch is a module for "New Session Manager". 7 | It only communicates over OSC in an NSM-Session and has no standalone functionality. 8 | 9 | [Reporting bugs] 10 | https://github.com/jackaudio/new-session-manager/issues 11 | 12 | [copyright] 13 | up to 2020: 14 | Jonathan Moore Liles https://non.tuxfamily.org/ 15 | 16 | from 2020: 17 | Nils Hilbricht et al. https://new-session-manager.jackaudio.org 18 | 19 | [see also] 20 | The full documentation for NSM is maintained as html site in your systems doc-dir. 21 | For example: 22 | xdg-open file:///usr/share/doc/new-session-manager/index.html 23 | 24 | The documentation can also be found online https://new-session-manager.jackaudio.org 25 | -------------------------------------------------------------------------------- /docs/src/manpage-common.h2m: -------------------------------------------------------------------------------- 1 | 2 | [Reporting bugs] 3 | https://github.com/jackaudio/new-session-manager/issues 4 | 5 | [copyright] 6 | up to 2020: 7 | Jonathan Moore Liles https://non.tuxfamily.org/ 8 | 9 | from 2020: 10 | Nils Hilbricht et al. https://new-session-manager.jackaudio.org 11 | 12 | [see also] 13 | The full documentation for NSM is maintained as html site in your systems doc-dir. 14 | For example: 15 | xdg-open file:///usr/share/doc/new-session-manager/index.html 16 | 17 | The documentation can also be found online https://new-session-manager.jackaudio.org 18 | -------------------------------------------------------------------------------- /docs/src/non-session-manager.1: -------------------------------------------------------------------------------- 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2. 2 | .TH NSM-LEGACY-GUI "1" "October 2022" "nsm-legacy-gui Version 1.6.1" "User Commands" 3 | .SH NAME 4 | nsm-legacy-gui \- manual page for nsm-legacy-gui Version 1.6.1 5 | .SH DESCRIPTION 6 | nsm\-legacy\-gui \- FLTK GUI for the 'New Session Manager' 7 | .SS "Usage:" 8 | .IP 9 | nsm\-legacy\-gui 10 | nsm\-legacy\-gui \fB\-\-help\fR 11 | .SH OPTIONS 12 | .TP 13 | \fB\-\-help\fR 14 | Show this screen 15 | .TP 16 | \fB\-\-nsm\-url\fR url 17 | Connect to a running nsmd [Example: osc.udp://mycomputer.localdomain:38356/]. 18 | .TP 19 | \fB\-\-\fR 20 | Everything after \fB\-\-\fR will be given to nsmd as server options. See nsmd \fB\-\-help\fR . 21 | .PP 22 | For backwards compatibility this executable also exist as symlink 'non\-session\-manager' 23 | .SH "REPORTING BUGS" 24 | https://github.com/jackaudio/new-session-manager/issues 25 | .SH COPYRIGHT 26 | up to 2020: 27 | Jonathan Moore Liles https://non.tuxfamily.org/ 28 | 29 | from 2020: 30 | Nils Hilbricht et al. https://new-session-manager.jackaudio.org 31 | .SH "SEE ALSO" 32 | The full documentation for NSM is maintained as html site in your systems doc-dir. 33 | For example: 34 | xdg-open file:///usr/share/doc/new-session-manager/index.html 35 | 36 | The documentation can also be found online https://new-session-manager.jackaudio.org 37 | -------------------------------------------------------------------------------- /docs/src/nsm-legacy-gui.1: -------------------------------------------------------------------------------- 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2. 2 | .TH NSM-LEGACY-GUI "1" "October 2022" "nsm-legacy-gui Version 1.6.1" "User Commands" 3 | .SH NAME 4 | nsm-legacy-gui \- manual page for nsm-legacy-gui Version 1.6.1 5 | .SH DESCRIPTION 6 | nsm\-legacy\-gui \- FLTK GUI for the 'New Session Manager' 7 | .SS "Usage:" 8 | .IP 9 | nsm\-legacy\-gui 10 | nsm\-legacy\-gui \fB\-\-help\fR 11 | .SH OPTIONS 12 | .TP 13 | \fB\-\-help\fR 14 | Show this screen 15 | .TP 16 | \fB\-\-nsm\-url\fR url 17 | Connect to a running nsmd [Example: osc.udp://mycomputer.localdomain:38356/]. 18 | .TP 19 | \fB\-\-\fR 20 | Everything after \fB\-\-\fR will be given to nsmd as server options. See nsmd \fB\-\-help\fR . 21 | .PP 22 | For backwards compatibility this executable also exist as symlink 'non\-session\-manager' 23 | .SH "REPORTING BUGS" 24 | https://github.com/jackaudio/new-session-manager/issues 25 | .SH COPYRIGHT 26 | up to 2020: 27 | Jonathan Moore Liles https://non.tuxfamily.org/ 28 | 29 | from 2020: 30 | Nils Hilbricht et al. https://new-session-manager.jackaudio.org 31 | .SH "SEE ALSO" 32 | The full documentation for NSM is maintained as html site in your systems doc-dir. 33 | For example: 34 | xdg-open file:///usr/share/doc/new-session-manager/index.html 35 | 36 | The documentation can also be found online https://new-session-manager.jackaudio.org 37 | -------------------------------------------------------------------------------- /docs/src/nsm-proxy-gui.1: -------------------------------------------------------------------------------- 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2. 2 | .TH NSM-PROXY-GUI "1" "October 2022" "nsm-proxy-gui Version 1.6.1" "User Commands" 3 | .SH NAME 4 | nsm-proxy-gui \- manual page for nsm-proxy-gui Version 1.6.1 5 | .SH DESCRIPTION 6 | nsm\-proxy\-gui \- GUI for nsm\-proxy, a wrapper for executables without direct NSM\-Support. 7 | .SS "Usage:" 8 | .IP 9 | nsm\-proxy\-gui \fB\-\-help\fR 10 | nsm\-proxy\-gui \fB\-\-connect\-to\fR 11 | .SH OPTIONS 12 | .TP 13 | \fB\-\-help\fR 14 | Show this screen 15 | .TP 16 | \fB\-\-connect\-to\fR 17 | Connect to running nsm\-proxy 18 | .PP 19 | nsmd\-proxy\-gui is usually not called by the user directly, 20 | but autostarted when nsm\-proxy is added to a session (through a GUI). 21 | .SH "REPORTING BUGS" 22 | https://github.com/jackaudio/new-session-manager/issues 23 | .SH COPYRIGHT 24 | up to 2020: 25 | Jonathan Moore Liles https://non.tuxfamily.org/ 26 | 27 | from 2020: 28 | Nils Hilbricht et al. https://new-session-manager.jackaudio.org 29 | .SH "SEE ALSO" 30 | The full documentation for NSM is maintained as html site in your systems doc-dir. 31 | For example: 32 | xdg-open file:///usr/share/doc/new-session-manager/index.html 33 | 34 | The documentation can also be found online https://new-session-manager.jackaudio.org 35 | -------------------------------------------------------------------------------- /docs/src/nsm-proxy.1: -------------------------------------------------------------------------------- 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2. 2 | .TH NSM-PROXY "1" "October 2022" "nsm-proxy Version 1.6.1" "User Commands" 3 | .SH NAME 4 | nsm-proxy \- manual page for nsm-proxy Version 1.6.1 5 | .SH DESCRIPTION 6 | nsm\-proxy \- Wrapper for executables without direct NSM\-Support. 7 | .PP 8 | It is a module for the 'New Session Manager' and only communicates 9 | over OSC in an NSM\-Session and has no standalone functionality. 10 | .SS "Usage:" 11 | .IP 12 | nsm\-proxy \fB\-\-help\fR 13 | .SH OPTIONS 14 | .TP 15 | \fB\-\-help\fR 16 | Show this screen 17 | .SH "REPORTING BUGS" 18 | https://github.com/jackaudio/new-session-manager/issues 19 | .SH COPYRIGHT 20 | up to 2020: 21 | Jonathan Moore Liles https://non.tuxfamily.org/ 22 | 23 | from 2020: 24 | Nils Hilbricht et al. https://new-session-manager.jackaudio.org 25 | .SH "SEE ALSO" 26 | The full documentation for NSM is maintained as html site in your systems doc-dir. 27 | For example: 28 | xdg-open file:///usr/share/doc/new-session-manager/index.html 29 | 30 | The documentation can also be found online https://new-session-manager.jackaudio.org 31 | -------------------------------------------------------------------------------- /docs/src/nsmd.1: -------------------------------------------------------------------------------- 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2. 2 | .TH NSMD "1" "October 2022" "nsmd Version 1.6.1" "User Commands" 3 | .SH NAME 4 | nsmd \- manual page for nsmd Version 1.6.1 5 | .SH DESCRIPTION 6 | nsmd \- Daemon and server for the 'New Session Manager' 7 | .SS "Usage:" 8 | .IP 9 | nsmd 10 | nsmd \fB\-\-help\fR 11 | nsmd \fB\-\-version\fR 12 | .SH OPTIONS 13 | .TP 14 | \fB\-\-help\fR 15 | Show this screen 16 | .TP 17 | \fB\-\-version\fR 18 | Show version 19 | .TP 20 | \fB\-\-osc\-port\fR portnum 21 | OSC port number [Default: provided by system]. 22 | .TP 23 | \fB\-\-session\-root\fR path 24 | Base path for sessions [Default: $XDG_DATA_HOME/nsm/]. 25 | .TP 26 | \fB\-\-load\-session\fR name 27 | Load existing session [Example: "My Song"]. 28 | .TP 29 | \fB\-\-gui\-url\fR url 30 | Connect to running legacy\-gui [Example: osc.udp://mycomputer.localdomain:38356/]. 31 | .TP 32 | \fB\-\-detach\fR 33 | Detach from console. 34 | .TP 35 | \fB\-\-quiet\fR 36 | Suppress messages except warnings and errors. 37 | .PP 38 | nsmd can be run headless with existing sessions. To create new ones it is recommended to use a GUI 39 | such as nsm\-legacy\-gui (included) or Agordejo (separate package) 40 | .SH "REPORTING BUGS" 41 | https://github.com/jackaudio/new-session-manager/issues 42 | .SH COPYRIGHT 43 | up to 2020: 44 | Jonathan Moore Liles https://non.tuxfamily.org/ 45 | 46 | from 2020: 47 | Nils Hilbricht et al. https://new-session-manager.jackaudio.org 48 | .SH "SEE ALSO" 49 | The full documentation for NSM is maintained as html site in your systems doc-dir. 50 | For example: 51 | xdg-open file:///usr/share/doc/new-session-manager/index.html 52 | 53 | The documentation can also be found online https://new-session-manager.jackaudio.org 54 | -------------------------------------------------------------------------------- /docs/src/readme-00.md: -------------------------------------------------------------------------------- 1 | # New Session Manager 2 | -------------------------------------------------------------------------------- /docs/src/readme-01.md: -------------------------------------------------------------------------------- 1 | 2 | ## Introduction 3 | 4 | New Session Manager (NSM) is a tool to assist music production by grouping standalone programs into 5 | sessions. Your workflow becomes easy to manage, robust and fast by leveraging the full potential of 6 | cooperative applications. 7 | 8 | NSM continues to be free in every sense of the word: free of cost, free to share and use, free of 9 | spyware or ads, free-and-open-source. 10 | 11 | You can create a session, or project, add programs to it and then use commands to save, start/stop, 12 | hide/show all programs at once, or individually. At a later date you can then re-open the session 13 | and continue where you left off. 14 | 15 | All files belonging to the session will be saved in the same directory. 16 | 17 | If you are a user (and not a programmer or packager) everything you need is to install NSM 18 | through your distributions package manager and, highly recommended, Agordejo as a GUI (see below). 19 | 20 | To learn NSM you don't need to know the background information from our documentation, which 21 | is aimed at developers that want to implement NSM support in their programs. Learn the GUI, 22 | not the server and protocol. 23 | 24 | 25 | ## Bullet Points 26 | * Drop-In replacement for the non-session-manager daemon nsmd and tools (e.g. jackpatch) 27 | * Simple and hassle-free build system to make packaging easy 28 | * Possibility to react to sensible bug fixes that would not have been integrated original nsmd 29 | * Stay upwards and downwards compatible with original nsmd 30 | * Conservative and hesitant in regards to new features and behaviour-changes, but possible in principle 31 | * Keep the session-manager separate from the other NON* tools Mixer, Sequencer and Timeline. 32 | * Protect nsmd from vanishing from the internet one day. 33 | * The goal is to become the de-facto standard music session manager for Linux distributions 34 | 35 | ## User Interface 36 | It is highly recommended to use Agordejo ( https://www.laborejo.org/agordejo/ ) as graphical 37 | user interface. In fact, if you install Agordejo in your distribution it will install NSM as 38 | dependency and you don't need to do anything yourself with this software package. 39 | 40 | This repository also contains the legacy FLTK interface simply called `nsm-legacy-gui`, 41 | symlinked to `non-session-manager` for backwards compatibility. (e.g. autostart scripts etc.) 42 | 43 | ## Supported Clients 44 | 45 | While NSM can start and stop any program it only becomes convenient if clients specifically 46 | implement support. This enables saving and hiding the GUI, amongst other features. 47 | Documentation and tutorials for software-developers will be added at a later date. 48 | -------------------------------------------------------------------------------- /docs/src/readme-02.md: -------------------------------------------------------------------------------- 1 | 2 | ## Documentation and Manual 3 | 4 | Our documentation contains the API specification for the NSM protocol, which is the central document 5 | if you want to add NSM support to your own application. 6 | 7 | You can find html documentation installed to your systems SHARE dir or docs/out/index.html in this 8 | repository. 9 | There is also an online version https://jackaudio.github.io/new-session-manager/ 10 | 11 | We also provide a set of manpages for each executable (see Build). 12 | 13 | 14 | ## Fork and License 15 | This is a fork of non-session-manager, by Jonathan Moore Liles http://non.tuxfamily.org/ 16 | which was released under the GNU GENERAL PUBLIC LICENSE Version 2, June 1991. 17 | 18 | All files, except nsm.h kept in this fork were GPL "version 2 of the License, or (at your 19 | option) any later version." 20 | 21 | `nsm.h` is licensed under the ISC License. 22 | 23 | New-Session-Manager changed the license to GNU GENERAL PUBLIC LICENSE, Version 3, 29 June 2007. 24 | See file COPYING 25 | 26 | Documentation in docs/ is licensed Creative Commons CC-By-Sa. 27 | It consist of mostly generated files and snippet files which do not have a license header for 28 | technical reasons. 29 | All original documentation source files are CC-By-Sa Version v4.0 (see file docs/src/LICENSE), 30 | the source file docs/src/api/index.adoc is a derived work from NON-Session-Managers API file which 31 | is licensed CC-By-Sa v2.5. Therefore our derived API document is also CC-By-Sa v2.5 32 | (see files docs/src/api/readme.txt and docs/src/api/LICENSE) 33 | 34 | 35 | ## Build 36 | The build system is meson. 37 | 38 | This is a software package that will compile and install multiple executables: 39 | * `nsmd`, the daemon or server itself. It is mandatory. 40 | * It has no GUI. 41 | * Dependency is `liblo`, the OSC library. 42 | * `jackpatch`, NSM client to save and remember JACK connections. 43 | * It has no GUI. 44 | * Dependencies are `JACK Audio Connection Kit` and `liblo`, the OSC library. 45 | * Can be deactivated (see below) `-Djackpatch=false` 46 | * `nsm-legacy-gui`, Legacy GUI for the user 47 | * Formerly known as "non-session-manager" 48 | * Dependencies are `FLTK`>=v1.3.0 and `liblo`, the OSC library. 49 | * Can be deactivated (see below) `-Dlegacy-gui=false` 50 | * `nsm-proxy`, NSM GUI Client to run any program without direct NSM support 51 | * Dependencies are `FLTK`>=v1.3.0, `fluid` (FLTK Editor/compiler, maybe in the same package as FLTK, maybe not) and `liblo`, the OSC library. 52 | * Can be deactivated (see below) `-Dnsm-proxy=false` 53 | 54 | 55 | ``` 56 | meson build --prefix=/usr 57 | #or disable individual build targets: 58 | #meson build --prefix=/usr -Dlegacy-gui=false -Dnsm-proxy=false -Djackpatch=false 59 | cd build && ninja 60 | sudo ninja install 61 | ``` 62 | 63 | Optionally you can skip `sudo ninja install` and run all executables from the build-dir. 64 | In this case you need to add the build-dir to your PATH environment variable so that the tools 65 | can find each other. 66 | 67 | ## Names of Executable Files and Symlinks 68 | 69 | Some distributions (and possibly local laws) prevent a forked software project from creating 70 | executable files under the same name, if the name itself is an original work subject to copyright, 71 | which it arguably is for the "NON-"-suite. Therefore New Session Manager renamed 72 | `non-session-manager` to `nsm-legacy-gui`. Installing will also create a symlink to 73 | `non-session-manager` for backwards compatibility. (e.g. autostart scripts etc.). 74 | -------------------------------------------------------------------------------- /extras/README.md: -------------------------------------------------------------------------------- 1 | # New Session Manager - Extras 2 | 3 | Each subdirectory in /extras holds additional libraries, software, documentation etc. 4 | 5 | They are included for convenience, e.g. the library pynsm is useful for client-programmers, 6 | and also developed by the same author as New-Session-Manager. 7 | 8 | Each "extra" is standalone regarding license and build process. They are not build or installed 9 | through nsm(d) meson build. The main programs in this repository do not depend on files in /extra in 10 | any way. From a technical point of view `/extras` could be safely deleted. 11 | -------------------------------------------------------------------------------- /extras/nsm.h/COPYING: -------------------------------------------------------------------------------- 1 | https://www.isc.org/licenses/ 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without 4 | fee is hereby granted, provided that the above copyright notice and this permission notice appear 5 | in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS” AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 8 | INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE 9 | FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 10 | FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 11 | ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 12 | -------------------------------------------------------------------------------- /extras/pynsm/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) since 2014: Laborejo Software Suite , All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 6 | associated documentation files (the "Software"), to deal in the Software without restriction, 7 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 8 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or 12 | substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 15 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 16 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 18 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /extras/pynsm/README.md: -------------------------------------------------------------------------------- 1 | # pynsm 2 | NSM/New Session Manager client library in Python - No dependencies except Python3. 3 | 4 | PyNSMClient - A New Session Manager Client-Library in one file. 5 | 6 | Copyright (c) since 2014: Laborejo Software Suite , All rights reserved. 7 | 8 | This library is licensed under the MIT license. Please check the file LICENSE for more information. 9 | 10 | This library has no version numbers, or releases. It is a "rolling" git. Copy it into your source and update only if you need new features. 11 | 12 | ## Short Instructions 13 | Before you start a word about control flow: NSM and any client, like this one, can be 14 | considered automation and remote-control of GUI operations, normally done by the user. That means 15 | this module needs to be included in your GUI code. The author personally creates the pynsm-object 16 | as early as possible in his PyQt Mainwindow class. 17 | 18 | Copy nsmclient.py to your own program and import and initialize it as early as possible (see below) 19 | Then add nsmClient.reactToMessage to your existing event loop. 20 | 21 | from nsmclient import NSMClient 22 | nsmClient = NSMClient(prettyName = niceTitle, #will raise an error and exit if this example is not run from NSM. 23 | saveCallback = saveCallbackFunction, 24 | openOrNewCallback = openOrNewCallbackFunction, 25 | supportsSaveStatus = False, # Change this to True if your program announces it's save status to NSM 26 | exitProgramCallback = exitCallbackFunction, 27 | hideGUICallback = None, #replace with your hiding function. You need to answer in your function with nsmClient.announceGuiVisibility(False) 28 | showGUICallback = None, #replace with your showing function. You need to answer in your function with nsmClient.announceGuiVisibility(True) 29 | broadcastCallback = None, #give a function that reacts to any broadcast by any other client. 30 | sessionIsLoadedCallback = None, #give a function that reacts to the one-time state when a session has fully loaded. 31 | loggingLevel = "info", #"info" for development or debugging, "error" for production. default is error. 32 | ) 33 | 34 | 35 | Don't forget to add nsmClient.reactToMessage to your event loop. 36 | 37 | * Each of the callbacks "save", "open/new" and "exit" receive three parameters: ourPath, sessionName, ourClientNameUnderNSM. 38 | * openOrNew gets called first. Init your jack client there with ourClientNameUnderNSM as name. 39 | * exitProgramCallback is the place to gracefully exit your program, including jack-client closing. 40 | * saveCallback gets called all the time. Use ourPath either as filename or as directory. 41 | * If you choose filename add an extension. 42 | * If you choose directory make sure that the filenames inside are static, no matter what project/session. The user must have no influence over file naming 43 | * broadcastCallback receives five parameters. The three standard: ourPath, sessionName, ourClientNameUnderNSM. And additionally messagePath and listOfArguments. MessagePath is entirely program specific, the number and type of arguments depend on the sender. 44 | * sessionIsLoadedCallback receives no parameters. It is ONLY send once, after the session is fully loaded. This is NOT the place to delay your announce. If you add your client to a running session (which must happen at some point) sessionLoaded will NOT get called. 45 | * Additional callbacks are: hideGUICallback and showGUICallback. These receive no parameters and need to answer with the function: nsmClient.announceGuiVisibility(bool). That means you can decline show or hide, dependending on the state of your program. 46 | 47 | The nsmClient object has methods and variables such as: 48 | 49 | * nsmClient.ourClientNameUnderNSM 50 | * Always use this name for your program 51 | * nsmClient.announceSaveStatus(False) 52 | * Announce your save status (dirty = False / clean = True), If your program sends those messages set supportsSaveStatus = True when intializing NSMClient with both hideGUICallback and showGUICallback 53 | * nsmClient.sessionName 54 | * nsmClient.ourOscUrl = osc.udp://{ip}:{port}/ Use this to broadcast your presence, to handshake communication between different programs 55 | * nsmClient.announceGuiVisibility(bool) 56 | * Announce if your GUI is visible (True) or not (False). Only works if you initialized NSMClient with both hideGUICallback and showGUICallback. Don't forget to send it once for your state after starting your program. 57 | * nsmcClient.changeLabel(prettyName) 58 | * Tell the GUI to append (prettyName) to our name. This is not saved by NSM but you need to send it yourself each startup. 59 | * nsmClient.serverSendSaveToSelf() 60 | * A clean solution to use the nsm save callbacks from within your program (Ctrl+S or File->Save). No need for redundant save mechanism. 61 | * nsmClient.serverSendExitToSelf() 62 | * A clean quit, without "client died unexpectedly". Use sys.exit() to exit your program in your nms-quit callback. 63 | * nsmClient.importResource(filepath) 64 | * Use this to load external resources, for example a sample file. It links the sample file into the session dir, according to the NSM rules, and returns the path of the linked file. 65 | * nsmClient.debugResetDataAndExit() 66 | * Deletes self.ourpath, which is the session save file or directory, recursively and exits the client. This is only meant for debugging and testing. 67 | 68 | ## Long Instructions 69 | * Read and start example.py, then read and understand nsmclient.py. It requires PyQt5 to execute and a brain to read. 70 | * There are several very minimal and basic clients in the directory `minimalClients/` 71 | * For your own program read and learn the NSM API: http://non.tuxfamily.org/nsm/API.html 72 | * The hard part about session management is not to use this lib or write your own but to make your program comply to the strict rules of session management. 73 | 74 | ## Additional Examples 75 | More examples can be found in `/minimalClients`. This mimics a minimal, but functional program. 76 | To actually run the programs and attach them to a running session execute the inluced file `source_me_with_port.bash ` 77 | where is the NSM port the server printed out after starting. 78 | 79 | You can see that nsmclient.py is included in this dir again, to avoid redundancy only as symlink. 80 | In your real program this would be the real file. 81 | 82 | ## Sources and Influences 83 | * The New-Session-Manager by Jonathan Moore Liles : http://non.tuxfamily.org/nsm/ 84 | * New Session Manager by Nils Hilbricht et al https://new-session-manager.jackaudio.org 85 | * With help from code fragments from https://github.com/attwad/python-osc ( DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE v2 ) 86 | -------------------------------------------------------------------------------- /extras/pynsm/exampleBoilerplate.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | PyNSMClient - A New Session Manager Client-Library in one file. 5 | 6 | The Non-Session-Manager by Jonathan Moore Liles : http://non.tuxfamily.org/nsm/ 7 | New Session Manager by Nils Hilbricht et al https://new-session-manager.jackaudio.org 8 | With help from code fragments from https://github.com/attwad/python-osc ( DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE v2 ) 9 | 10 | MIT License 11 | 12 | Copyright (c) since 2014: Laborejo Software Suite , All rights reserved. 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 15 | associated documentation files (the "Software"), to deal in the Software without restriction, 16 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 17 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all copies or 21 | substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 24 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 26 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 27 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | """ 29 | 30 | 31 | from time import sleep # main event loop at the bottom of this file 32 | # nsm only 33 | from nsmclient import NSMClient # will raise an error and exit if this example is not run from NSM. 34 | 35 | ######################################################################## 36 | # General 37 | ######################################################################## 38 | niceTitle = "myNSMprogram" # This is the name of your program. This will display in NSM and can be used in your save file 39 | 40 | ######################################################################## 41 | # Prepare the NSM Client 42 | # This has to be done as the first thing because NSM needs to get the paths 43 | # and may quit if NSM environment var was not found. 44 | # 45 | # This is also where to set up your functions that react to messages from NSM, 46 | ######################################################################## 47 | # Here are some variables you can use: 48 | # ourPath = Full path to your NSM save file/directory with serialized NSM extension 49 | # ourClientNameUnderNSM = Your NSM save file/directory with serialized NSM extension and no path information 50 | # sessionName = The name of your session with no path information 51 | ######################################################################## 52 | 53 | def saveCallback(ourPath, sessionName, ourClientNameUnderNSM): 54 | # Put your code to save your config file in here 55 | print("saveCallback"); 56 | 57 | 58 | def openCallback(ourPath, sessionName, ourClientNameUnderNSM): 59 | # Put your code to open your config file in here 60 | print("openCallback"); 61 | 62 | 63 | def exitProgram(ourPath, sessionName, ourClientNameUnderNSM): 64 | """This function is a callback for NSM. 65 | We have a chance to close our clients and open connections here. 66 | If not nsmclient will just kill us no matter what 67 | """ 68 | print("exitProgram"); 69 | # Exit is done by NSM kill. 70 | 71 | 72 | def showGUICallback(): 73 | # Put your code that shows your GUI in here 74 | print("showGUICallback"); 75 | nsmClient.announceGuiVisibility(isVisible=True) # Inform NSM that the GUI is now visible. Put this at the end. 76 | 77 | 78 | def hideGUICallback(): 79 | # Put your code that hides your GUI in here 80 | print("hideGUICallback"); 81 | nsmClient.announceGuiVisibility(isVisible=False) # Inform NSM that the GUI is now hidden. Put this at the end. 82 | 83 | 84 | nsmClient = NSMClient(prettyName = niceTitle, 85 | saveCallback = saveCallback, 86 | openOrNewCallback = openCallback, 87 | showGUICallback = showGUICallback, # Comment this line out if your program does not have an optional GUI 88 | hideGUICallback = hideGUICallback, # Comment this line out if your program does not have an optional GUI 89 | supportsSaveStatus = False, # Change this to True if your program announces it's save status to NSM 90 | exitProgramCallback = exitProgram, 91 | loggingLevel = "info", # "info" for development or debugging, "error" for production. default is error. 92 | ) 93 | 94 | # If NSM did not start up properly the program quits here. 95 | 96 | ######################################################################## 97 | # If your project uses JACK, activate your client here 98 | # You can use jackClientName or create your own 99 | ######################################################################## 100 | jackClientName = nsmClient.ourClientNameUnderNSM 101 | 102 | ######################################################################## 103 | # Start main program loop. 104 | ######################################################################## 105 | 106 | # showGUICallback() # If you want your GUI to be shown by default, uncomment this line 107 | print("Entering main loop") 108 | 109 | while True: 110 | nsmClient.reactToMessage() # Make sure this exists somewhere in your main loop 111 | # nsmClient.announceSaveStatus(False) # Announce your save status (dirty = False / clean = True) 112 | sleep(0.05) 113 | -------------------------------------------------------------------------------- /extras/pynsm/exampleQt.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | PyNSMClient - A New Session Manager Client-Library in one file. 5 | 6 | The Non-Session-Manager by Jonathan Moore Liles : http://non.tuxfamily.org/nsm/ 7 | New Session Manager by Nils Hilbricht et al https://new-session-manager.jackaudio.org 8 | With help from code fragments from https://github.com/attwad/python-osc ( DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE v2 ) 9 | 10 | MIT License 11 | 12 | Copyright (c) since 2014: Laborejo Software Suite , All rights reserved. 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 15 | associated documentation files (the "Software"), to deal in the Software without restriction, 16 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 17 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all copies or 21 | substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 24 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 26 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 27 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | """ 29 | 30 | import sys #for qt app args. 31 | from os import getpid #we use this as jack meta data 32 | from PyQt5 import QtWidgets, QtCore 33 | 34 | #jack only 35 | import ctypes 36 | from random import uniform #to generate samples between -1.0 and 1.0 for Jack. 37 | 38 | #nsm only 39 | from nsmclient import NSMClient 40 | 41 | 42 | ######################################################################## 43 | #Prepare the Qt Window 44 | ######################################################################## 45 | class Main(QtWidgets.QWidget): 46 | def __init__(self, qtApp): 47 | super().__init__() 48 | 49 | self.qtApp = qtApp 50 | self.layout = QtWidgets.QVBoxLayout() 51 | self.layout.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft) 52 | self.setLayout(self.layout) 53 | 54 | niceTitle = "PyNSM v2 Example - JACK Noise" 55 | self.title = QtWidgets.QLabel("") 56 | self.saved = QtWidgets.QLabel("") 57 | self._value = QtWidgets.QSlider(orientation = 1) #horizontal 58 | self._value.setMinimum(0) 59 | self._value.setMaximum(100) 60 | self._value.setValue(50) #only visible for the first start. 61 | 62 | self.valueLabel = QtWidgets.QLabel("Noise Volume: " + str(self._value.value())) 63 | self._value.valueChanged.connect(lambda new: self.valueLabel.setText("Noise Volume: " + str(new))) 64 | 65 | self.layout.addWidget(self.title) 66 | self.layout.addWidget(self.saved) 67 | self.layout.addWidget(self._value) 68 | self.layout.addWidget(self.valueLabel) 69 | 70 | #Prepare the NSM Client 71 | #This has to be done as soon as possible because NSM provides paths and names for us. 72 | #and may quit if NSM environment var was not found. 73 | self.nsmClient = NSMClient(prettyName = niceTitle, #will raise an error and exit if this example is not run from NSM. 74 | supportsSaveStatus = True, 75 | saveCallback = self.saveCallback, 76 | openOrNewCallback = self.openOrNewCallback, 77 | exitProgramCallback = self.exitCallback, 78 | loggingLevel = "info", #"info" for development or debugging, "error" for production. default is error. 79 | ) 80 | #If NSM did not start up properly the program quits here with an error message from NSM. 81 | #No JACK client gets created, no Qt window can be seen. 82 | 83 | 84 | self.title.setText("" + self.nsmClient.ourClientNameUnderNSM + "") 85 | 86 | self.eventLoop = QtCore.QTimer() 87 | self.eventLoop.start(100) #10ms-20ms is smooth for "real time" feeling. 100ms is still ok. 88 | self.eventLoop.timeout.connect(self.nsmClient.reactToMessage) 89 | 90 | #self.show is called as the new/open callback. 91 | 92 | @property 93 | def value(self): 94 | return str(self._value.value()) 95 | 96 | @value.setter 97 | def value(self, new): 98 | new = int(new) 99 | self._value.setValue(new) 100 | 101 | def saveCallback(self, ourPath, sessionName, ourClientNameUnderNSM): #parameters are filled in by NSM. 102 | if self.value: 103 | with open(ourPath, "w") as f: #ourpath is taken as a filename here. We have this path name at our disposal and we know we only want one file. So we don't make a directory. This way we don't have to create a dir first. 104 | f.write(self.value) 105 | 106 | def openOrNewCallback(self, ourPath, sessionName, ourClientNameUnderNSM): #parameters are filled in by NSM. 107 | try: 108 | with open(ourPath, "r") as f: 109 | savedValue = f.read() #a string 110 | self.saved.setText("{}: {}".format(ourPath, savedValue)) 111 | self.value = savedValue #internal casting to int. Sets the slider. 112 | except FileNotFoundError: 113 | self.saved.setText("{}: No save file found. Normal for first start.".format(ourPath)) 114 | finally: 115 | self.show() 116 | 117 | def exitCallback(self, ourPath, sessionName, ourClientNameUnderNSM): 118 | """This function is a callback for NSM. 119 | We have a chance to close our clients and open connections here. 120 | If not nsmclient will just kill us no matter what 121 | """ 122 | cjack.jack_remove_properties(ctypesJackClient, ctypesJackUuid) #clean our metadata 123 | cjack.jack_client_close(ctypesJackClient) #omitting this introduces problems. in Jack1 this would mute all jack clients for several seconds. 124 | exit() #or get SIGKILLed through NSM 125 | 126 | def closeEvent(self, event): 127 | """Qt likes to quits on its own. For example when the window manager closes the 128 | main window. Ignore that request and instead send a roundtrip through NSM""" 129 | self.nsmClient.serverSendExitToSelf() 130 | event.ignore() 131 | 132 | #Prepare the window instance. Gets executed at the end of this file. 133 | qtApp = QtWidgets.QApplication(sys.argv) 134 | ourClient = Main(qtApp) 135 | 136 | ######################################################################## 137 | #Prepare the JACK Client 138 | #We need the client name from NSM first. 139 | ######################################################################## 140 | cjack = ctypes.cdll.LoadLibrary("libjack.so.0") 141 | clientName = ourClient.nsmClient.prettyName #the nsm client is in the qt instance here. But in your program it can be anywhere. 142 | options = 0 143 | status = None 144 | 145 | class jack_client_t(ctypes.Structure): 146 | _fields_ = [] 147 | cjack.jack_client_open.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.POINTER(ctypes.c_int)] #the two ints are enum and pointer to enum. #http://jackaudio.org/files/docs/html/group__ClientFunctions.html#gab8b16ee616207532d0585d04a0bd1d60 148 | cjack.jack_client_open.restype = ctypes.POINTER(jack_client_t) 149 | ctypesJackClient = cjack.jack_client_open(clientName.encode("ascii"), options, status) 150 | 151 | #Create one output port 152 | class jack_port_t(ctypes.Structure): 153 | _fields_ = [] 154 | 155 | JACK_DEFAULT_AUDIO_TYPE = "32 bit float mono audio".encode("ascii") #http://jackaudio.org/files/docs/html/types_8h.html 156 | JACK_PORT_IS_OUTPUT = 0x2 #http://jackaudio.org/files/docs/html/types_8h.html 157 | portname = "output".encode("ascii") 158 | 159 | cjack.jack_port_register.argtypes = [ctypes.POINTER(jack_client_t), ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_ulong] #http://jackaudio.org/files/docs/html/group__PortFunctions.html#ga3e21d145c3c82d273a889272f0e405e7 160 | cjack.jack_port_register.restype = ctypes.POINTER(jack_port_t) 161 | outputPort = cjack.jack_port_register(ctypesJackClient, portname, JACK_DEFAULT_AUDIO_TYPE, JACK_PORT_IS_OUTPUT, 0) 162 | 163 | cjack.jack_client_close.argtypes = [ctypes.POINTER(jack_client_t),] 164 | 165 | #Create the callback 166 | #http://jackaudio.org/files/docs/html/group__ClientCallbacks.html#gafb5ec9fb4b736606d676c135fb97888b 167 | 168 | jack_nframes_t = ctypes.c_uint32 169 | cjack.jack_port_get_buffer.argtypes = [ctypes.POINTER(jack_port_t), jack_nframes_t] 170 | cjack.jack_port_get_buffer.restype = ctypes.POINTER(ctypes.c_float) #this is only valid for audio, not for midi. C Jack has a pointer to void here. 171 | 172 | def pythonJackCallback(nframes, void): #types: jack_nframes_t (ctypes.c_uint32), pointer to void 173 | """http://jackaudio.org/files/docs/html/simple__client_8c.html#a01271cc6cf692278ae35d0062935d7ae""" 174 | out = cjack.jack_port_get_buffer(outputPort, nframes) #out should be a pointer to jack_default_audio_sample_t (float, ctypes.POINTER(ctypes.c_float)) 175 | 176 | #For each required sample 177 | for i in range(nframes): 178 | factor = ourClient._value.value() / 100 179 | val = ctypes.c_float(round(uniform(-0.5, 0.5) * factor, 10)) 180 | out[i]= val 181 | 182 | return 0 # 0 on success, otherwise a non-zero error code, causing JACK to remove that client from the process() graph. 183 | 184 | JACK_CALLBACK_TYPE = ctypes.CFUNCTYPE(ctypes.c_int, jack_nframes_t, ctypes.c_void_p) #the first parameter is the return type, the following are input parameters 185 | callbackFunction = JACK_CALLBACK_TYPE(pythonJackCallback) 186 | 187 | cjack.jack_set_process_callback.argtypes = [ctypes.POINTER(jack_client_t), JACK_CALLBACK_TYPE, ctypes.c_void_p] 188 | cjack.jack_set_process_callback.restype = ctypes.c_uint32 #I think this is redundant since ctypes has int as default result type 189 | cjack.jack_set_process_callback(ctypesJackClient, callbackFunction, 0) 190 | 191 | #Ready. Activate the client. 192 | cjack.jack_activate(ctypesJackClient) 193 | #The Jack Processing functions gets called by jack in another thread. We just have to keep this program itself running. Qt does the job. 194 | 195 | 196 | #Jack Metadata - Inform the jack server about our program. Optional but has benefits when used with other programs that rely on metadata. 197 | #http://jackaudio.org/files/docs/html/group__Metadata.html 198 | jack_uuid_t = ctypes.c_uint64 199 | cjack.jack_set_property.argtypes = [ctypes.POINTER(jack_client_t), jack_uuid_t, ctypes.c_char_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_char_p)] #client(we), subject/uuid,key,value/data,type 200 | cjack.jack_remove_properties.argtypes = [ctypes.POINTER(jack_client_t), jack_uuid_t] #for cleaning up when the program stops. the jack server can do it in newer jack versions, but this is safer. 201 | 202 | cjack.jack_get_uuid_for_client_name.argtypes = [ctypes.POINTER(jack_client_t), ctypes.c_char_p] 203 | cjack.jack_get_uuid_for_client_name.restype = ctypes.c_char_p 204 | 205 | ourJackUuid = cjack.jack_get_uuid_for_client_name(ctypesJackClient, clientName.encode("ascii")) 206 | ourJackUuid = int(ourJackUuid.decode("UTF-8")) 207 | ctypesJackUuid = jack_uuid_t(ourJackUuid) 208 | 209 | cjack.jack_set_property(ctypesJackClient, ctypesJackUuid, ctypes.c_char_p(b"pid"), ctypes.c_char_p(str(getpid()).encode()), None) 210 | 211 | ################## 212 | #Start everything 213 | qtApp.exec_() 214 | -------------------------------------------------------------------------------- /extras/pynsm/minimalClients/base.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | PyNSMClient - A New Session Manager Client-Library in one file. 5 | 6 | The Non-Session-Manager by Jonathan Moore Liles : http://non.tuxfamily.org/nsm/ 7 | New Session Manager by Nils Hilbricht et al https://new-session-manager.jackaudio.org 8 | With help from code fragments from https://github.com/attwad/python-osc ( DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE v2 ) 9 | 10 | MIT License 11 | 12 | Copyright (c) since 2014: Laborejo Software Suite , All rights reserved. 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 15 | associated documentation files (the "Software"), to deal in the Software without restriction, 16 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 17 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all copies or 21 | substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 24 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 26 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 27 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | """ 29 | 30 | #/nsm/server/announce #A hack to get this into Agordejo launcher discovery 31 | 32 | 33 | from nsmclient import NSMClient 34 | import sys 35 | from time import sleep 36 | import os 37 | from threading import Timer 38 | 39 | sys.path.append(os.getcwd()) 40 | 41 | class BaseClient(object): 42 | 43 | def saveCallbackFunction(self, ourPath, sessionName, ourClientNameUnderNSM): 44 | print (__file__, "save") 45 | 46 | def openOrNewCallbackFunction(self, ourPath, sessionName, ourClientNameUnderNSM): 47 | print (__file__,"open/new") 48 | 49 | def exitCallbackFunction(self, ourPath, sessionName, ourClientNameUnderNSM): 50 | print (__file__, "quit") 51 | sys.exit() 52 | 53 | def broadcastCallbackFunction(self, ourPath, sessionName, ourClientNameUnderNSM, messagePath, listOfArguments): 54 | print (__file__, "broadcast") 55 | 56 | def event(self, nsmClient): 57 | pass 58 | 59 | def __init__(self, name, delayedFunctions=[], eventFunction=None): 60 | """delayedFunctions are a (timer delay in seconds, function call) list of tuples. They will 61 | be executed once. 62 | If the function is a string instead it will be evaluated in the BaseClient context, 63 | providing self. Do not give a lambda! 64 | 65 | 66 | Give eventFunction for repeated execution.""" 67 | 68 | self.nsmClient = NSMClient(prettyName = name, #will raise an error and exit if this example is not run from NSM. 69 | saveCallback = self.saveCallbackFunction, 70 | openOrNewCallback = self.openOrNewCallbackFunction, 71 | supportsSaveStatus = False, # Change this to True if your program announces it's save status to NSM 72 | exitProgramCallback = self.exitCallbackFunction, 73 | broadcastCallback = self.broadcastCallbackFunction, 74 | hideGUICallback = None, #replace with your hiding function. You need to answer in your function with nsmClient.announceGuiVisibility(False) 75 | showGUICallback = None, #replace with your showing function. You need to answer in your function with nsmClient.announceGuiVisibility(True) 76 | loggingLevel = "info", #"info" for development or debugging, "error" for production. default is error. 77 | ) 78 | 79 | if eventFunction: 80 | self.event = eventFunction 81 | 82 | for delay, func in delayedFunctions: 83 | if type(func) is str: 84 | func = eval('lambda self=self: ' + func ) 85 | t = Timer(interval=delay, function=func, args=()) 86 | t.start() 87 | 88 | while True: 89 | self.nsmClient.reactToMessage() 90 | self.event(self.nsmClient) 91 | sleep(0.05) 92 | 93 | if __name__ == '__main__': 94 | """This is the most minimal nsm client in existence""" 95 | BaseClient(name="testclient_base") #this never returns an object. 96 | 97 | -------------------------------------------------------------------------------- /extras/pynsm/minimalClients/broadcast.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | PyNSMClient - A New Session Manager Client-Library in one file. 5 | 6 | The Non-Session-Manager by Jonathan Moore Liles : http://non.tuxfamily.org/nsm/ 7 | New Session Manager by Nils Hilbricht et al https://new-session-manager.jackaudio.org 8 | With help from code fragments from https://github.com/attwad/python-osc ( DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE v2 ) 9 | 10 | MIT License 11 | 12 | Copyright (c) since 2014: Laborejo Software Suite , All rights reserved. 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 15 | associated documentation files (the "Software"), to deal in the Software without restriction, 16 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 17 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all copies or 21 | substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 24 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 26 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 27 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | """ 29 | 30 | #/nsm/server/announce #A hack to get this into Agordejo launcher discovery 31 | 32 | 33 | import base 34 | from time import sleep 35 | 36 | def hello(nsmClient): 37 | nsmClient.broadcast("/index/counter", [hello.i]) 38 | hello.i += 1 39 | sleep(1) 40 | hello.i = 0 41 | 42 | 43 | class BroadcastClient(base.BaseClient): 44 | 45 | def broadcastCallbackFunction(self, ourPath, sessionName, ourClientNameUnderNSM, messagePath, listOfArguments): 46 | print (f"We are only an example client, but surely it would be valuable to react to {messagePath} for {listOfArguments}") 47 | 48 | if __name__ == '__main__': 49 | BroadcastClient(name="testclient_broadcast", eventFunction=hello) #this never returns an object. 50 | -------------------------------------------------------------------------------- /extras/pynsm/minimalClients/label.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | PyNSMClient - A New Session Manager Client-Library in one file. 5 | 6 | The Non-Session-Manager by Jonathan Moore Liles : http://non.tuxfamily.org/nsm/ 7 | New Session Manager by Nils Hilbricht et al https://new-session-manager.jackaudio.org 8 | With help from code fragments from https://github.com/attwad/python-osc ( DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE v2 ) 9 | 10 | MIT License 11 | 12 | Copyright (c) since 2014: Laborejo Software Suite , All rights reserved. 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 15 | associated documentation files (the "Software"), to deal in the Software without restriction, 16 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 17 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all copies or 21 | substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 24 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 26 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 27 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | """ 29 | 30 | 31 | #/nsm/server/announce #A hack to get this into Agordejo launcher discovery 32 | 33 | import base 34 | 35 | if __name__ == '__main__': 36 | funcs = [ 37 | (1, 'self.nsmClient.changeLabel("Pretty Name")'), 38 | #(4, lambda: print ("four")), 39 | ] 40 | base.BaseClient(name="testclient_label", delayedFunctions=funcs) #this never returns an object. 41 | -------------------------------------------------------------------------------- /extras/pynsm/minimalClients/nsmclient.py: -------------------------------------------------------------------------------- 1 | ../nsmclient.py -------------------------------------------------------------------------------- /extras/pynsm/minimalClients/source_me_with_port.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ -z "$1" ]]; then 4 | echo "Give NSM OSC Port as only parameter. Afterwards you can run the executable pythons in this dir, directly, without ./" 5 | exit 1 6 | fi 7 | 8 | export NSM_URL=osc.udp://0.0.0.0:$1/ 9 | export PATH=$(pwd):$PATH 10 | -------------------------------------------------------------------------------- /extras/pynsm/test-importResource.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | PyNSMClient - A New Session Manager Client-Library in one file. 5 | 6 | The Non-Session-Manager by Jonathan Moore Liles : http://non.tuxfamily.org/nsm/ 7 | New Session Manager by Nils Hilbricht et al https://new-session-manager.jackaudio.org 8 | With help from code fragments from https://github.com/attwad/python-osc ( DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE v2 ) 9 | 10 | MIT License 11 | 12 | Copyright (c) since 2014: Laborejo Software Suite , All rights reserved. 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 15 | associated documentation files (the "Software"), to deal in the Software without restriction, 16 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 17 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all copies or 21 | substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 24 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 26 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 27 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | """ 29 | 30 | #Test file for the resource import function in nsmclient.py 31 | 32 | 33 | if __name__ == "__main__": 34 | 35 | from nsmclient import NSMClient 36 | #We do not start nsmclient, just the the function with temporary files 37 | importResource = NSMClient.importResource 38 | import os, os.path 39 | 40 | import logging 41 | logging.basicConfig(level=logging.INFO) 42 | 43 | from inspect import currentframe 44 | def get_linenumber(): 45 | cf = currentframe() 46 | return cf.f_back.f_lineno 47 | 48 | from tempfile import mkdtemp 49 | class self(object): 50 | ourPath = mkdtemp() 51 | ourClientNameUnderNSM = "Loader Test" 52 | assert os.path.isdir(self.ourPath) 53 | 54 | 55 | #First a meta test to see if our system is working: 56 | assert os.path.exists("/etc/hostname") 57 | try: 58 | result = importResource(self, "/etc/hostname") #should not fail! 59 | except FileNotFoundError: 60 | pass 61 | else: 62 | print (f"Meta Test System works as of line {get_linenumber()}") 63 | print ("""You should not see any "Test Error" messages""") 64 | print ("Working in", self.ourPath) 65 | print (f"Removing {result} for a clean test environment") 66 | os.remove(result) 67 | print() 68 | 69 | #Real tests 70 | 71 | try: 72 | importResource(self, "/floot/nonexistent") #should fail 73 | except FileNotFoundError: 74 | pass 75 | else: 76 | print (f"Test Error in line {get_linenumber()}") 77 | 78 | try: 79 | importResource(self, "////floot//nonexistent/") #should fail 80 | except FileNotFoundError: 81 | pass 82 | else: 83 | print (f"Test Error in line {get_linenumber()}") 84 | 85 | try: 86 | importResource(self, "/etc/shadow") #reading not possible 87 | except PermissionError: 88 | pass 89 | else: 90 | print (f"Test Error in line {get_linenumber()}") 91 | 92 | 93 | assert os.path.exists("/etc/hostname") 94 | try: 95 | org = self.ourPath 96 | self.ourPath = "/" #writing not possible 97 | importResource(self, "/etc/hostname") 98 | except PermissionError: 99 | self.ourPath = org 100 | else: 101 | print (f"Test Error in line {get_linenumber()}") 102 | 103 | 104 | from tempfile import NamedTemporaryFile 105 | tmpf = NamedTemporaryFile() 106 | assert os.path.exists("/etc/hostname") 107 | try: 108 | org = self.ourPath 109 | self.ourPath = tmpf.name #writable, but not a dir 110 | importResource(self, "/etc/hostname") 111 | except NotADirectoryError: 112 | self.ourPath = org 113 | else: 114 | print (f"Test Error in line {get_linenumber()}") 115 | 116 | #Test the real purpose 117 | result = importResource(self, "/etc/hostname") 118 | print ("imported to", result) 119 | 120 | 121 | #Test what happens if we try to import already imported resource again 122 | result = importResource(self, result) 123 | print ("imported to", result) 124 | 125 | #Test what happens if we try to import a resource that would result in a name collision 126 | result = importResource(self, "/etc/hostname") 127 | print ("imported to", result) 128 | 129 | #Count the number of resulting files. 130 | assert len(os.listdir(self.ourPath)) == 2 131 | 132 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # Copyright (C) 2020- Nils Hilbricht 3 | # 4 | # This file is part of New-Session-Manager 5 | # 6 | # New-Session-Manager is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # New-Session-Manager is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with New-Session-Manager. If not, see . 18 | ############################################################################## 19 | 20 | 21 | #Please keep the version number in a separate line so we can automatically update it. 22 | #Also keep it at the beginning of the line and leave spaces around the colon. 23 | #It's source is in src/nsmd.cpp #DEFINE VERSION_STRING 24 | project( 25 | 'new-session-manager', 26 | 'c', 'cpp', 27 | version : '1.6.1', 28 | license : 'GPLv3', 29 | ) 30 | 31 | ############## 32 | #Dependencies 33 | ############## 34 | 35 | liblodep = dependency('liblo') #and not 'lo' 36 | threaddep = dependency('threads') 37 | jackdep = dependency('jack', required: get_option('jackpatch')) #and not 'libjack' 38 | 39 | cc = meson.get_compiler('c') 40 | fltkdep = cc.find_library('fltk', required: get_option('nsm-legacy-gui') or get_option('nsm-proxy')) 41 | fltkimagesdep = cc.find_library('fltk_images', required: get_option('nsm-legacy-gui')) 42 | fluid = find_program('fluid', required: get_option('nsm-proxy')) 43 | 44 | 45 | ############## 46 | #Build Targets 47 | ############## 48 | 49 | executable('nsmd', 50 | sources: ['src/nsmd.cpp', 'src/debug.cpp', 'src/Endpoint.cpp', 'src/file.cpp', 'src/Thread.cpp'], 51 | dependencies: [liblodep, threaddep], 52 | install: true, 53 | ) 54 | 55 | install_man(['docs/src/nsmd.1']) 56 | install_data('docs/index.html', install_dir : get_option('datadir') / 'doc/new-session-manager') 57 | install_data('docs/api/index.html', install_dir : get_option('datadir') / 'doc/new-session-manager/api') 58 | install_data('CHANGELOG', install_dir : get_option('datadir') / 'doc/new-session-manager') 59 | install_data('README.md', install_dir : get_option('datadir') / 'doc/new-session-manager') 60 | 61 | #For options see meson_options.txt 62 | #All get_options are default=true 63 | 64 | if get_option('jackpatch') 65 | 66 | executable('jackpatch', 67 | 'src/jackpatch.c', 68 | dependencies: [liblodep, jackdep], 69 | install: true, 70 | ) 71 | 72 | install_data('src/jackpatch.svg', install_dir : get_option('datadir') / 'icons/hicolor/scalable/apps') 73 | install_data('src/org.jackaudio.jackpatch.desktop', install_dir : get_option('datadir') / 'applications') 74 | install_man(['docs/src/jackpatch.1', ]) 75 | endif 76 | 77 | 78 | if get_option('nsm-proxy') 79 | 80 | NSM_Proxy_UI_cpp = custom_target( 81 | 'NSM_Proxy_UI.cpp', 82 | output : 'NSM_Proxy_UI.C', 83 | input : 'src/NSM_Proxy_UI.fl', 84 | command : [fluid, '-c', '-o', '@OUTPUT@', '@INPUT@'], 85 | ) 86 | 87 | NSM_Proxy_UI_h = custom_target( 88 | 'NSM_Proxy_UI.h', 89 | output : 'NSM_Proxy_UI.H', 90 | input : 'src/NSM_Proxy_UI.fl', 91 | command : [fluid, '-c', '-h', '@OUTPUT@', '@INPUT@'], 92 | ) 93 | 94 | 95 | executable('nsm-proxy', 96 | sources: ['src/nsm-proxy.cpp', 'src/debug.cpp'], 97 | dependencies: [liblodep, threaddep], 98 | install: true, 99 | ) 100 | 101 | executable('nsm-proxy-gui', 102 | sources: ['src/nsm-proxy-gui.cpp', [NSM_Proxy_UI_cpp, NSM_Proxy_UI_h]], 103 | dependencies: [fltkdep, liblodep, threaddep], 104 | install: true, 105 | ) 106 | 107 | install_data('src/nsm-proxy.svg', install_dir : get_option('datadir') / 'icons/hicolor/scalable/apps') 108 | install_data('src/org.jackaudio.nsm-proxy.desktop', install_dir : get_option('datadir') / 'applications') 109 | install_man(['docs/src/nsm-proxy.1', 'docs/src/nsm-proxy-gui.1']) 110 | 111 | endif 112 | 113 | if get_option('nsm-legacy-gui') 114 | 115 | executable('nsm-legacy-gui', 116 | sources: ['src/nsm-legacy-gui.cpp', 'src/debug.cpp', 'src/Endpoint.cpp', 'src/Thread.cpp', 'src/FL/Fl_Scalepack.C'], 117 | dependencies: [fltkimagesdep, fltkdep, liblodep, threaddep], 118 | install: true, 119 | ) 120 | 121 | install_data('src/org.jackaudio.nsm-legacy-gui.desktop', install_dir : get_option('datadir') / 'applications') 122 | install_data('src/nsm-legacy-gui.svg', install_dir : get_option('datadir') / 'icons/hicolor/scalable/apps') 123 | install_man(['docs/src/nsm-legacy-gui.1', 'docs/src/non-session-manager.1']) 124 | 125 | #Symlinking is a one-way operation and can't be uninstalled, we rely on distribution packages for that 126 | meson.add_install_script('sh', '-c', 127 | 'ln -sf nsm-legacy-gui ${DESTDIR}@0@/@1@/non-session-manager'.format( 128 | get_option('prefix'), get_option('bindir'))) 129 | 130 | endif 131 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('nsm-legacy-gui', type : 'boolean', value : true, description : 'Build nsm-legacy-gui, symlinked as non-session-manager') 2 | option('jackpatch', type : 'boolean', value : true, description : 'Build jackpatch client') 3 | option('nsm-proxy', type : 'boolean', value : true, description : 'Build nsm-proxy client with GUI.') 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Endpoint.hpp: -------------------------------------------------------------------------------- 1 | 2 | /*******************************************************************************/ 3 | /* Copyright (C) 2008-2020 Jonathan Moore Liles (as "Non-Session-Manager") */ 4 | /* Copyright (C) 2020- Nils Hilbricht */ 5 | /* */ 6 | /* This file is part of New-Session-Manager */ 7 | /* */ 8 | /* New-Session-Manager is free software: you can redistribute it and/or modify */ 9 | /* it under the terms of the GNU General Public License as published by */ 10 | /* the Free Software Foundation, either version 3 of the License, or */ 11 | /* (at your option) any later version. */ 12 | /* */ 13 | /* New-Session-Manager is distributed in the hope that it will be useful, */ 14 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 15 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 16 | /* GNU General Public License for more details. */ 17 | /* */ 18 | /* You should have received a copy of the GNU General Public License */ 19 | /* along with New-Session-Manager. If not, see .*/ 20 | /*******************************************************************************/ 21 | 22 | #pragma once 23 | 24 | #include 25 | #include "Thread.hpp" 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace OSC 33 | { 34 | class OSC_Value 35 | { 36 | 37 | protected: 38 | 39 | char _type; 40 | 41 | float f; 42 | double d; 43 | int i; 44 | const char *s; 45 | 46 | public: 47 | 48 | OSC_Value ( const OSC_Value &rhs ) 49 | { 50 | _type = rhs._type; 51 | 52 | f =rhs.f; 53 | d = rhs.d; 54 | i = rhs.i; 55 | s = rhs.s; 56 | } 57 | 58 | OSC_Value ( ) 59 | { 60 | _type = 0; 61 | 62 | f = 0; 63 | d = 0; 64 | i = 0; 65 | s = 0; 66 | } 67 | 68 | virtual ~OSC_Value ( ) { } 69 | virtual char type ( void ) const { return _type; } 70 | }; 71 | 72 | class OSC_Float : public OSC_Value 73 | { 74 | 75 | public: 76 | 77 | float value ( void ) const { return f; } 78 | 79 | OSC_Float ( float v ) 80 | { 81 | _type = 'f'; 82 | f = v; 83 | } 84 | }; 85 | 86 | class OSC_Int : public OSC_Value 87 | { 88 | 89 | public: 90 | 91 | int value ( void ) const { return i; } 92 | 93 | OSC_Int ( int v ) 94 | { 95 | _type = 'i'; 96 | i = v; 97 | } 98 | }; 99 | 100 | class OSC_String : public OSC_Value 101 | { 102 | public: 103 | 104 | const char * value ( void ) const { return s; } 105 | 106 | OSC_String ( const char *v ) 107 | { 108 | _type = 's'; 109 | s = v; 110 | } 111 | }; 112 | 113 | struct Parameter_Limits 114 | { 115 | float min; 116 | float max; 117 | float default_value; 118 | }; 119 | 120 | class Endpoint; 121 | class Signal; 122 | struct Peer 123 | { 124 | bool _scanning; 125 | 126 | char *name; 127 | lo_address addr; 128 | 129 | std::list _signals; 130 | }; 131 | 132 | typedef int (*signal_handler) ( float value, void *user_data ); 133 | 134 | class Signal 135 | { 136 | // static int next_id; 137 | 138 | public: 139 | 140 | enum State { 141 | Created = 0, 142 | Removed = 1 143 | }; 144 | 145 | enum Direction { 146 | Input, 147 | Output, 148 | Bidirectional 149 | }; 150 | 151 | private: 152 | 153 | Endpoint *_endpoint; 154 | 155 | Peer *_peer; 156 | 157 | char *_path; 158 | char *_documentation; 159 | 160 | float _value; 161 | 162 | Direction _direction; 163 | 164 | signal_handler _handler; 165 | void *_user_data; 166 | Parameter_Limits _parameter_limits; 167 | 168 | void (*_connection_state_callback)(OSC::Signal *, void*); 169 | void *_connection_state_userdata; 170 | 171 | public: 172 | 173 | const char * peer_name ( void ) const { 174 | return _peer->name; 175 | } 176 | 177 | Signal ( const char *path, Direction dir ); 178 | ~Signal ( ); 179 | 180 | Direction direction ( void ) const { return _direction; } 181 | 182 | void parameter_limits ( float min, float max, float default_value ) 183 | { 184 | _parameter_limits.min = min; 185 | _parameter_limits.max = max; 186 | _parameter_limits.default_value = default_value; 187 | _value = default_value; 188 | } 189 | 190 | 191 | void connection_state_callback ( void(*_cb)(OSC::Signal *, void*), void *userdata) 192 | { 193 | _connection_state_callback = _cb; 194 | _connection_state_userdata = userdata; 195 | } 196 | 197 | const Parameter_Limits& parameter_limits ( void ) const { return _parameter_limits; } 198 | 199 | const char *path ( void ) const { return _path; } 200 | 201 | void rename ( const char *name ); 202 | 203 | /* publishes value to targets */ 204 | void value ( float v ); 205 | /* get current value */ 206 | float value ( void ) const { return _value; } 207 | 208 | bool is_connected_to ( const Signal *s ) const; 209 | 210 | friend class Endpoint; 211 | }; 212 | 213 | class Method 214 | { 215 | char *_path; 216 | char *_typespec; 217 | char *_documentation; 218 | 219 | public: 220 | 221 | const char *path ( void ) { return _path; } 222 | const char *typespec ( void ) { return _typespec; } 223 | 224 | Method ( ); 225 | ~Method ( ); 226 | 227 | friend class Endpoint; 228 | }; 229 | 230 | 231 | class Endpoint 232 | { 233 | Thread _thread; 234 | 235 | friend class Signal; 236 | 237 | // lo_server_thread _st; 238 | lo_server _server; 239 | lo_address _addr; 240 | 241 | std::list _peers; 242 | std::list _signals; 243 | std::list _methods; 244 | 245 | char *_learning_path; 246 | 247 | class TranslationDestination { 248 | 249 | public: 250 | std::string path; 251 | float current_value; 252 | bool suppress_feedback; 253 | 254 | TranslationDestination ( ) 255 | { 256 | suppress_feedback = false; 257 | current_value = -1.0f; 258 | } 259 | }; 260 | 261 | std::map _translations; 262 | 263 | void (*_peer_scan_complete_callback)(void*); 264 | void *_peer_scan_complete_userdata; 265 | 266 | char *_name; 267 | 268 | static void error_handler(int num, const char *msg, const char *path); 269 | 270 | static int osc_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); 271 | 272 | static int osc_signal_lister ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); 273 | static int osc_generic ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); 274 | static int osc_sig_handler ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); 275 | static int osc_sig_renamed ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); 276 | static int osc_sig_removed ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); 277 | static int osc_sig_created ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); 278 | static int osc_sig_disconnect ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); 279 | static int osc_sig_connect ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); 280 | static int osc_sig_hello ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); 281 | 282 | 283 | Peer * add_peer ( const char *name, const char *url ); 284 | void scan_peer ( const char *name, const char *url ); 285 | 286 | private: 287 | 288 | static void *osc_thread ( void *arg ); 289 | void osc_thread ( void ); 290 | 291 | OSC::Signal *find_peer_signal_by_path ( Peer *p, const char *path ); 292 | OSC::Signal *find_signal_by_path ( const char *path ); 293 | 294 | Peer *find_peer_by_name ( const char *name ); 295 | Peer *find_peer_by_address ( lo_address addr ); 296 | static bool address_matches ( lo_address addr1, lo_address addr2 ); 297 | 298 | static Signal *find_target_by_peer_address ( std::list *l, lo_address addr ); 299 | 300 | void del_signal ( Signal *signal ); 301 | void send_signal_rename_notifications( Signal *s ); 302 | 303 | 304 | void (*_peer_signal_notification_callback)( OSC::Signal *, OSC::Signal::State, void*); 305 | void *_peer_signal_notification_userdata; 306 | 307 | public: 308 | 309 | void send_feedback ( const char *path, float v ); 310 | void learn ( const char *path ); 311 | 312 | lo_address address ( void ) 313 | { 314 | return _addr; 315 | } 316 | 317 | const char * * get_connections ( const char *path ); 318 | void clear_translations ( void ); 319 | void del_translation ( const char *a ); 320 | void add_translation ( const char *a, const char *b ); 321 | void rename_translation_destination ( const char *a, const char *b ); 322 | void rename_translation_source ( const char *a, const char *b ); 323 | int ntranslations ( void ); 324 | bool get_translation ( int n, const char **from, const char **to ); 325 | 326 | void peer_signal_notification_callback ( void (*cb)(OSC::Signal *, OSC::Signal::State, void*), void *userdata ) 327 | { 328 | _peer_signal_notification_callback = cb; 329 | _peer_signal_notification_userdata = userdata; 330 | } 331 | 332 | // can be used to point back to owning object. 333 | void *owner; 334 | 335 | void list_peer_signals ( void *v ); 336 | 337 | int init ( int proto, const char *port = 0 ); 338 | 339 | Endpoint ( ); 340 | 341 | ~Endpoint ( ); 342 | 343 | bool disconnect_signal ( OSC::Signal *s, OSC::Signal *d ); 344 | bool disconnect_signal ( OSC::Signal *s, const char *signal_path ); 345 | bool connect_signal ( OSC::Signal *s, OSC::Signal *d ); 346 | bool connect_signal ( OSC::Signal *s, const char *peer_name, const char *signal_path ); 347 | // bool connect_signal ( OSC::Signal *s, const char *peer_name, int signal_id ); 348 | bool connect_signal ( OSC::Signal *s, const char *peer_and_path ); 349 | 350 | Signal * add_signal ( const char *path, Signal::Direction dir, float min, float max, float default_value, signal_handler handler, void *user_data ); 351 | Method *add_method ( const char *path, const char *typespec, lo_method_handler handler, void *user_data, const char *argument_description ); 352 | void del_method ( const char *path, const char *typespec ); 353 | void del_method ( Method* method ); 354 | void start ( void ); 355 | void stop ( void ); 356 | int port ( void ) const; 357 | char * url ( void ) const; 358 | 359 | void check ( void ) const; 360 | void wait ( int timeout ) const; 361 | void run ( void ) const; 362 | 363 | void name ( const char *name ) { _name = strdup( name ); } 364 | const char *name ( void ) { return _name; } 365 | 366 | void hello ( const char *url ); 367 | void handle_hello ( const char *peer_name, const char *peer_url ); 368 | 369 | int send ( lo_address to, const char *path, std::list< OSC_Value > values ); 370 | 371 | /* overloads for common message formats */ 372 | int send ( lo_address to, const char *path ); 373 | int send ( lo_address to, const char *path, float v ); 374 | int send ( lo_address to, const char *path, double v ); 375 | int send ( lo_address to, const char *path, int v ); 376 | int send ( lo_address to, const char *path, long v ); 377 | int send ( lo_address to, const char *path, int v1, int v2 ); 378 | int send ( lo_address to, const char *path, int v1, float v2 ); 379 | int send ( lo_address to, const char *path, int v1, int v2, float v3 ); 380 | int send ( lo_address to, const char *path, const char *v ); 381 | int send ( lo_address to, const char *path, const char *v1, float v2 ); 382 | int send ( lo_address to, const char *path, const char *v1, int v2, int v3 ); 383 | int send ( lo_address to, const char *path, const char *v1, const char *v2 ); 384 | int send ( lo_address to, const char *path, const char *v1, const char *v2, const char *v3 ); 385 | int send ( lo_address to, const char *path, const char *v1, int v2, int v3, int v4 ); 386 | int send ( lo_address to, const char *path, const char *v1, const char *v2, int v3, int v4, int v5 ); 387 | 388 | int send ( lo_address to, const char *path, const char *v1, int v2 ); 389 | int send ( lo_address to, const char *path, int v1, const char *v2 ); 390 | int send ( lo_address to, const char *path, const char *v1, int v2, int v3, float v4 ); 391 | 392 | int send ( lo_address to, const char *path, const char *v1, const char *v2, const char *v3, int v4, int v5, int v6 ); 393 | int send ( lo_address to, const char *path, const char *v1, int v2, const char *v3 ); 394 | int send ( lo_address to, const char *path, int v1, const char *v2, const char *v3, const char *v4 ); 395 | int send ( lo_address to, const char *path, const char *v1, int v2, const char *v3, const char *v4, const char *v5 ); 396 | int send ( lo_address to, const char *path, const char *v1, const char *v2, const char *v3, const char *v4, const char *v5 ); 397 | int send ( lo_address to, const char *path, const char *v1, const char *v2, const char *v3, const char *v4 ); 398 | 399 | int send ( lo_address to, const char *path, lo_message msg ); 400 | 401 | int send ( lo_address to, const char *path, const char *v1, const char *v2, const char *v3, float v4, float v5, float v6 ); 402 | 403 | int send ( lo_address to, const char *path, const char *v1, const char *v2, int v3, float v4, float v5, float v6 ); 404 | 405 | int send ( lo_address to, const char *path, const char *v1, const char *v2, const char *v3, int v4, float v5, float v6, float v7 ); 406 | 407 | void peer_scan_complete_callback ( void(*_cb)(void*), void *userdata) 408 | { 409 | _peer_scan_complete_callback = _cb; 410 | _peer_scan_complete_userdata = userdata; 411 | } 412 | 413 | 414 | friend Signal::~Signal(); 415 | friend void Signal::rename ( const char *name ); 416 | }; 417 | 418 | } 419 | 420 | /* helper macros for defining OSC handlers */ 421 | /* #define OSC_NAME( name ) osc_ ## name */ 422 | #define OSC_DMSG() MESSAGE( "Got OSC message: %s", path ); 423 | // #define OSC_HANDLER( name ) static int OSC_NAME( name ) ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) 424 | 425 | 426 | /* #define OSC_REPLY_OK() ((OSC::Endpoint*)user_data)->send( lo_message_get_source( msg ), path, "ok" ) */ 427 | /* #define OSC_REPLY( value ) ((OSC::Endpoint*)user_data)->send( lo_message_get_source( msg ), path, value ) */ 428 | /* #define OSC_REPLY_ERR() ((OSC::Endpoint*)user_data)->send( lo_message_get_source( msg ), path, "err" ) */ 429 | /* #define OSC_ENDPOINT() ((OSC::Endpoint*)user_data) */ 430 | -------------------------------------------------------------------------------- /src/FL/Fl_Packscroller.H: -------------------------------------------------------------------------------- 1 | 2 | /*******************************************************************************/ 3 | /* Copyright (C) 2008-2020 Jonathan Moore Liles (as "Non-Session-Manager") */ 4 | /* Copyright (C) 2020- Nils Hilbricht */ 5 | /* */ 6 | /* This file is part of New-Session-Manager */ 7 | /* */ 8 | /* New-Session-Manager is free software: you can redistribute it and/or modify */ 9 | /* it under the terms of the GNU General Public License as published by */ 10 | /* the Free Software Foundation, either version 3 of the License, or */ 11 | /* (at your option) any later version. */ 12 | /* */ 13 | /* New-Session-Manager is distributed in the hope that it will be useful, */ 14 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 15 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 16 | /* GNU General Public License for more details. */ 17 | /* */ 18 | /* You should have received a copy of the GNU General Public License */ 19 | /* along with New-Session-Manager. If not, see .*/ 20 | /*******************************************************************************/ 21 | 22 | /* Scrolling group suitable for containing a single child (a 23 | * pack). When the Fl_Packscroller is resized, the child will be resized 24 | * too. No scrollbars are displayed, but the widget responds to 25 | * FL_MOUSEWHEEL events. */ 26 | 27 | #pragma once 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | /* FIXME: Optimize scroll */ 34 | 35 | class Fl_Packscroller : public Fl_Group 36 | { 37 | int _increment; 38 | int _yposition; 39 | static const int sbh = 15; /* scroll button height */ 40 | 41 | public: 42 | 43 | Fl_Packscroller ( int X, int Y, int W, int H, const char *L = 0 ) : Fl_Group( X, Y, W, H, L ) 44 | { 45 | _increment = 30; 46 | _yposition = 0; 47 | // color( FL_WHITE ); 48 | } 49 | 50 | int increment ( void ) const { return _increment; } 51 | void increment ( int v ) { _increment = v; } 52 | 53 | void yposition ( int v ) 54 | { 55 | if ( ! children() ) 56 | return; 57 | 58 | int Y = v; 59 | 60 | if ( Y > 0 ) 61 | Y = 0; 62 | 63 | const int H = h(); 64 | // - (sbh * 2); 65 | 66 | Fl_Widget *o = child( 0 ); 67 | 68 | if ( o->h() > H && 69 | Y + o->h() < H ) 70 | Y = H - o->h(); 71 | else if ( o->h() < H ) 72 | Y = 0; 73 | 74 | if ( _yposition != Y ) 75 | { 76 | _yposition = Y; 77 | 78 | damage( FL_DAMAGE_SCROLL ); 79 | } 80 | } 81 | 82 | int yposition ( void ) const 83 | { 84 | if ( children() ) 85 | return child( 0 )->y() - (y() + sbh); 86 | 87 | return 0; 88 | } 89 | 90 | void bbox ( int &X, int &Y, int &W, int &H ) 91 | { 92 | X = x(); 93 | Y = y() + ( sbh * top_sb_visible() ); 94 | W = w(); 95 | H = h() - ( sbh * ( top_sb_visible() + bottom_sb_visible() ) ); 96 | } 97 | 98 | int top_sb_visible ( void ) 99 | { 100 | return children() && child(0)->y() != y() ? 1 : 0; 101 | } 102 | 103 | int bottom_sb_visible ( void ) 104 | { 105 | if ( children() ) 106 | { 107 | Fl_Widget *o = child( 0 ); 108 | 109 | if ( o->h() > h() && o->y() + o->h() != y() + h() ) 110 | return 1; 111 | } 112 | 113 | return 0; 114 | } 115 | 116 | virtual void 117 | draw ( void ) 118 | { 119 | if ( damage() & FL_DAMAGE_ALL ) 120 | { 121 | fl_rectf( x(), y(), w(), h(), color() ); 122 | } 123 | 124 | if ( ! children() ) 125 | return; 126 | 127 | Fl_Widget *o = child( 0 ); 128 | 129 | o->position( x(), y() + _yposition ); 130 | 131 | const int top_sb = top_sb_visible(); 132 | const int bottom_sb = bottom_sb_visible(); 133 | 134 | fl_push_clip( x(), y() + ( sbh * top_sb ), w(), h() - (sbh * (top_sb + bottom_sb) )); 135 | 136 | draw_children(); 137 | 138 | fl_pop_clip(); 139 | 140 | fl_font( FL_HELVETICA, 12 ); 141 | 142 | if ( top_sb ) 143 | { 144 | fl_draw_box( box(), x(), y(), w(), sbh, color() ); 145 | fl_color( fl_contrast( FL_FOREGROUND_COLOR, color() ) ); 146 | fl_draw( "@2<", x(), y(), w(), sbh, FL_ALIGN_CENTER ); 147 | } 148 | 149 | if ( bottom_sb ) 150 | { 151 | fl_draw_box( box(), x(), y() + h() - sbh, w(), sbh, color() ); 152 | fl_color( fl_contrast( FL_FOREGROUND_COLOR, color() ) ); 153 | fl_draw( "@2>", x(), y() + h() - sbh, w(), sbh, FL_ALIGN_CENTER ); 154 | } 155 | } 156 | 157 | virtual int 158 | handle ( int m ) 159 | { 160 | switch ( m ) 161 | { 162 | case FL_PUSH: 163 | if ( top_sb_visible() && 164 | Fl::event_inside( x(), y(), w(), sbh ) ) 165 | { 166 | return 1; 167 | } 168 | else if ( bottom_sb_visible() && 169 | Fl::event_inside( x(), y() + h() - sbh, w(), sbh ) ) 170 | { 171 | return 1; 172 | } 173 | break; 174 | case FL_RELEASE: 175 | { 176 | if ( top_sb_visible() && 177 | Fl::event_inside( x(), y(), w(), sbh ) ) 178 | { 179 | yposition( yposition() + ( h() / 4 ) ); 180 | return 1; 181 | } 182 | else if ( bottom_sb_visible() && 183 | Fl::event_inside( x(), y() + h() - sbh, w(), sbh ) ) 184 | { 185 | yposition( yposition() - (h() / 4 ) ); 186 | return 1; 187 | } 188 | break; 189 | } 190 | case FL_KEYBOARD: 191 | { 192 | if ( Fl::event_key() == FL_Up ) 193 | { 194 | yposition( yposition() + ( h() / 4 ) ); 195 | return 1; 196 | } 197 | else if ( Fl::event_key() == FL_Down ) 198 | { 199 | yposition( yposition() - (h() / 4 ) ); 200 | return 1; 201 | } 202 | break; 203 | } 204 | case FL_MOUSEWHEEL: 205 | { 206 | yposition( yposition() - ( Fl::event_dy() * _increment ) ); 207 | 208 | return 1; 209 | } 210 | } 211 | 212 | return Fl_Group::handle( m ); 213 | } 214 | }; 215 | -------------------------------------------------------------------------------- /src/FL/Fl_Scalepack.C: -------------------------------------------------------------------------------- 1 | 2 | /*******************************************************************************/ 3 | /* Copyright (C) 2008-2020 Jonathan Moore Liles (as "Non-Session-Manager") */ 4 | /* Copyright (C) 2020- Nils Hilbricht */ 5 | /* */ 6 | /* This file is part of New-Session-Manager */ 7 | /* */ 8 | /* New-Session-Manager is free software: you can redistribute it and/or modify */ 9 | /* it under the terms of the GNU General Public License as published by */ 10 | /* the Free Software Foundation, either version 3 of the License, or */ 11 | /* (at your option) any later version. */ 12 | /* */ 13 | /* New-Session-Manager is distributed in the hope that it will be useful, */ 14 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 15 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 16 | /* GNU General Public License for more details. */ 17 | /* */ 18 | /* You should have received a copy of the GNU General Public License */ 19 | /* along with New-Session-Manager. If not, see .*/ 20 | /*******************************************************************************/ 21 | 22 | 23 | /* Fl_Scalepack 24 | 25 | This is similar to an Fl_Pack, but instead of the pack resizing 26 | itself to enclose its children, this pack resizes its children to 27 | fit itself. Of course, this only works well with highly flexible 28 | widgets, but the task comes up often enough to warrent this class. 29 | 30 | If and child happens to be the resizable() widget, then it will be 31 | resized so the all the other children can fit around it, with their 32 | current sizes (and the size of the Fl_Scalepack) maintained. 33 | 34 | NOTES: An Fl_Pack as a direct child will not work, because Fl_Pack 35 | changes its size in draw(), which throws off our resize 36 | calculation. The whole idea of widgets being able to resize 37 | themselves within draw() is horribly broken... 38 | */ 39 | 40 | #include "Fl_Scalepack.H" 41 | 42 | #include 43 | #include 44 | #include 45 | 46 | Fl_Scalepack::Fl_Scalepack ( int X, int Y, int W, int H, const char *L ) : 47 | Fl_Group( X, Y, W, H, L ) 48 | { 49 | resizable( 0 ); 50 | _spacing = 0; 51 | } 52 | 53 | void 54 | Fl_Scalepack::resize ( int X, int Y, int W, int H ) 55 | { 56 | /* Fl_Group's resize will change our child widget sizes, which 57 | interferes with our own resizing method. */ 58 | long dx = X - x(); 59 | long dy = Y - y(); 60 | 61 | bool r = W != w() || H != h(); 62 | 63 | Fl_Widget::resize( X, Y, W, H ); 64 | 65 | Fl_Widget*const* a = array(); 66 | 67 | for (int i=children(); i--;) 68 | { 69 | Fl_Widget* o = *a++; 70 | 71 | o->position( o->x() + dx, o->y() + dy ); 72 | } 73 | 74 | if ( r ) 75 | redraw(); 76 | } 77 | 78 | void 79 | Fl_Scalepack::draw ( void ) 80 | { 81 | 82 | if ( resizable() == this ) 83 | /* this resizable( this ) is the default for Fl_Group and is 84 | * reset by Fl_Group::clear(), but it is not our default... */ 85 | resizable( 0 ); 86 | 87 | int tx = x() + Fl::box_dx( box() ); 88 | int ty = y() + Fl::box_dy( box() ); 89 | int tw = w() - Fl::box_dw( box() ); 90 | int th = h() - Fl::box_dh( box() ); 91 | 92 | if ( damage() & FL_DAMAGE_ALL ) 93 | { 94 | draw_box(); 95 | 96 | draw_label(); 97 | } 98 | 99 | int v = 0; 100 | 101 | int cth = 0; 102 | int ctw = 0; 103 | 104 | Fl_Widget * const * a = array(); 105 | 106 | for ( int i = children(); i--; ) 107 | { 108 | Fl_Widget *o = *a++; 109 | 110 | if ( o->visible() ) 111 | { 112 | ++v; 113 | 114 | if ( o != this->resizable() ) 115 | { 116 | cth += o->h(); 117 | ctw += o->w(); 118 | } 119 | 120 | cth += _spacing; 121 | ctw += _spacing; 122 | } 123 | } 124 | 125 | ctw -= _spacing; 126 | cth -= _spacing; 127 | 128 | if ( 0 == v ) 129 | return; 130 | 131 | if ( this->resizable() ) 132 | { 133 | int pos = 0; 134 | 135 | Fl_Widget * const * a = array(); 136 | 137 | for ( int i = children(); i--; ) 138 | { 139 | Fl_Widget *o = *a++; 140 | 141 | if ( o->visible() ) 142 | { 143 | int X, Y, W, H; 144 | 145 | if ( type() == HORIZONTAL ) 146 | { 147 | X = tx + pos; 148 | Y = ty; 149 | W = o->w(); 150 | H = th; 151 | } 152 | else 153 | { 154 | X = tx; 155 | Y = ty + pos; 156 | W = tw; 157 | H = o->h(); 158 | } 159 | 160 | if ( this->resizable() == o ) 161 | { 162 | if ( type() == HORIZONTAL ) 163 | W = tw - ctw - 3; 164 | else 165 | H = th - cth; 166 | } 167 | 168 | if (X != o->x() || Y != o->y() || W != o->w() || H != o->h() ) 169 | { 170 | o->resize(X,Y,W,H); 171 | o->clear_damage(FL_DAMAGE_ALL); 172 | } 173 | 174 | if ( damage() & FL_DAMAGE_ALL ) 175 | { 176 | draw_child( *o ); 177 | draw_outside_label( *o ); 178 | } 179 | else 180 | update_child( *o ); 181 | 182 | /* if ( this->resizable() == o ) */ 183 | /* fl_rect( o->x(), o->y(), o->w(), o->h(), type() == VERTICAL ? FL_GREEN : FL_BLUE ); */ 184 | 185 | if ( type() == HORIZONTAL ) 186 | pos += o->w() + spacing(); 187 | else 188 | pos += o->h() + spacing(); 189 | 190 | } 191 | } 192 | } 193 | else 194 | { 195 | int sz = 0; 196 | int pos = 0; 197 | 198 | if ( type() == HORIZONTAL ) 199 | sz = (tw - (_spacing * (v - 1))) / v; 200 | else 201 | sz = (th - (_spacing * (v - 1))) / v; 202 | 203 | Fl_Widget * const * a = array(); 204 | 205 | for ( int i = children(); i--; ) 206 | { 207 | Fl_Widget *o = *a++; 208 | 209 | if ( o->visible() ) 210 | { 211 | int X, Y, W, H; 212 | 213 | if ( type() == HORIZONTAL ) 214 | { 215 | X = tx + pos; 216 | Y = ty; 217 | W = sz; 218 | H = th; 219 | } 220 | else 221 | { 222 | X = tx; 223 | Y = ty + pos; 224 | W = tw; 225 | H = sz; 226 | } 227 | 228 | if (X != o->x() || Y != o->y() || W != o->w() || H != o->h() ) 229 | { 230 | o->resize(X,Y,W,H); 231 | o->clear_damage(FL_DAMAGE_ALL); 232 | } 233 | 234 | if ( damage() & FL_DAMAGE_ALL ) 235 | { 236 | draw_child( *o ); 237 | draw_outside_label( *o ); 238 | } 239 | else 240 | update_child( *o ); 241 | 242 | // fl_rect( o->x(), o->y(), o->w(), o->h(), type() == VERTICAL ? FL_RED : FL_YELLOW ); 243 | 244 | if ( type() == HORIZONTAL ) 245 | pos += o->w() + spacing(); 246 | else 247 | pos += o->h() + spacing(); 248 | 249 | } 250 | } 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /src/FL/Fl_Scalepack.H: -------------------------------------------------------------------------------- 1 | 2 | /*******************************************************************************/ 3 | /* Copyright (C) 2008-2020 Jonathan Moore Liles (as "Non-Session-Manager") */ 4 | /* Copyright (C) 2020- Nils Hilbricht */ 5 | /* */ 6 | /* This file is part of New-Session-Manager */ 7 | /* */ 8 | /* New-Session-Manager is free software: you can redistribute it and/or modify */ 9 | /* it under the terms of the GNU General Public License as published by */ 10 | /* the Free Software Foundation, either version 3 of the License, or */ 11 | /* (at your option) any later version. */ 12 | /* */ 13 | /* New-Session-Manager is distributed in the hope that it will be useful, */ 14 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 15 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 16 | /* GNU General Public License for more details. */ 17 | /* */ 18 | /* You should have received a copy of the GNU General Public License */ 19 | /* along with New-Session-Manager. If not, see .*/ 20 | /*******************************************************************************/ 21 | 22 | #pragma once 23 | 24 | #include 25 | 26 | class Fl_Scalepack : public Fl_Group 27 | { 28 | 29 | int _spacing; 30 | 31 | public: 32 | 33 | enum { VERTICAL, HORIZONTAL }; 34 | 35 | Fl_Scalepack ( int X, int Y, int W, int H, const char *L = 0 ); 36 | virtual ~Fl_Scalepack ( ) { } 37 | 38 | int spacing ( void ) const { return _spacing; } 39 | void spacing ( int v ) { _spacing = v; redraw(); } 40 | 41 | virtual void resize ( int, int, int, int ); 42 | 43 | virtual void draw ( void ); 44 | 45 | }; 46 | -------------------------------------------------------------------------------- /src/NSM_Proxy_UI.fl: -------------------------------------------------------------------------------- 1 | # data file for the Fltk User Interface Designer (fluid) 2 | version 1.0305 3 | header_name {.H} 4 | code_name {.C} 5 | class NSM_Proxy_UI {open 6 | } { 7 | Function {make_window()} {open 8 | } { 9 | Fl_Window {} { 10 | label {NSM Proxy} open 11 | xywh {720 472 675 505} type Double color 47 labelcolor 55 xclass {NSM-Proxy} visible 12 | } { 13 | Fl_Return_Button start_button { 14 | label Start 15 | xywh {285 460 88 25} 16 | } 17 | Fl_Button kill_button { 18 | label Kill 19 | xywh {150 460 80 25} color 72 hide 20 | } 21 | Fl_Tabs {} {open 22 | xywh {0 0 678 445} 23 | } { 24 | Fl_Group {} { 25 | label Run open 26 | xywh {25 46 635 359} 27 | } { 28 | Fl_Box {} { 29 | label {NSM-Proxy handles clients without direct NSM support. 30 | It should not be used to start real NSM clients. 31 | 32 | Command-line options MUST go in the "Arguments" field. 33 | 34 | The program will be started with its current working directory being a uniquely named directory under the current session directory. It is recommended that you only refer to files as arguments in this directory to guarantee a transportable and archivable session. 35 | } selected 36 | xywh {28 87 612 150} box BORDER_BOX color 41 labelfont 8 labelsize 12 labelcolor 55 align 128 37 | } 38 | Fl_Input arguments_input { 39 | label {Arguments:} 40 | tooltip {Command line parameter like --verbose} xywh {170 285 345 25} 41 | } 42 | Fl_Input label_input { 43 | label {NSM GUI Label:} 44 | tooltip {Will show in your NSM GUI, useful if you have multiple NSM-Proxy clients in one session} xywh {170 324 345 26} 45 | } 46 | Fl_Input executable_input { 47 | label {Executable Name:} 48 | tooltip {The pure name of the executable. Just xterm not /usr/bin/xterm} xywh {170 249 345 26} 49 | } 50 | } 51 | Fl_Group {} { 52 | label Advanced open 53 | xywh {12 31 663 414} hide 54 | } { 55 | Fl_Choice save_signal_choice { 56 | label {Save Signal:} open 57 | xywh {246 400 170 25} down_box BORDER_BOX 58 | } { 59 | MenuItem {} { 60 | label None 61 | xywh {10 10 40 24} 62 | } 63 | MenuItem {} { 64 | label SIGUSR1 65 | xywh {20 20 40 24} 66 | } 67 | MenuItem {} { 68 | label SIGUSR2 69 | xywh {30 30 40 24} 70 | } 71 | MenuItem {} { 72 | label SIGINT 73 | xywh {40 40 40 24} 74 | } 75 | } 76 | Fl_Box {} { 77 | label {The environment variables $NSM_CLIENT_ID and $NSM_SESSION_NAME will contain the unique client ID (suitable for use as e.g. a JACK client name) and the display name for the session, respectively. The variable $CONFIG_FILE will contain the name of the nsm-proxy config file.} 78 | xywh {26 46 610 84} box BORDER_BOX color 41 labelfont 8 labelsize 12 labelcolor 55 align 128 79 | } 80 | Fl_Box {} { 81 | label {Very few programs may respond to a specific Unix signal by somehow saving their state. If 'Save Signal' is set to something other than 'None', then NSM Proxy will deliver the specified signal to the proxied process upon an NSM 'Save' event. Most programs will treat these signals just like SIGTERM and die. NSM-Proxy cannot force a program to save in our session directory. } 82 | xywh {26 306 610 79} box BORDER_BOX color 41 labelfont 8 labelsize 12 labelcolor 55 align 128 83 | } 84 | Fl_Choice stop_signal_choice { 85 | label {Stop Signal:} open 86 | xywh {246 255 170 25} down_box BORDER_BOX 87 | } { 88 | MenuItem {} { 89 | label SIGTERM 90 | xywh {20 20 40 24} 91 | } 92 | MenuItem {} { 93 | label SIGINT 94 | xywh {50 50 40 24} 95 | } 96 | MenuItem {} { 97 | label SIGHUP 98 | xywh {60 60 40 24} 99 | } 100 | } 101 | Fl_Box {} { 102 | label {Most programs will shutdown gracefully when sent a SIGTERM or SIGINT signal. It's impossible to know which signal a specific program will respond to. A unhandled signal will simply kill the process, and may cause problems with the audio subsystem (e.g. JACK). Check the program's documentation or source code to determine which signal to use to stop it gracefully.} 103 | xywh {26 166 610 79} box BORDER_BOX color 41 labelfont 8 labelsize 12 labelcolor 55 align 128 104 | } 105 | Fl_File_Input config_file_input { 106 | label {(Hidden!) Config File:} 107 | xywh {158 409 406 31} hide 108 | } 109 | Fl_Button config_file_browse_button { 110 | label Browse 111 | xywh {573 410 85 25} hide 112 | } 113 | } 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/Thread.cpp: -------------------------------------------------------------------------------- 1 | 2 | /*******************************************************************************/ 3 | /* Copyright (C) 2008-2020 Jonathan Moore Liles (as "Non-Session-Manager") */ 4 | /* Copyright (C) 2020- Nils Hilbricht */ 5 | /* */ 6 | /* This file is part of New-Session-Manager */ 7 | /* */ 8 | /* New-Session-Manager is free software: you can redistribute it and/or modify */ 9 | /* it under the terms of the GNU General Public License as published by */ 10 | /* the Free Software Foundation, either version 3 of the License, or */ 11 | /* (at your option) any later version. */ 12 | /* */ 13 | /* New-Session-Manager is distributed in the hope that it will be useful, */ 14 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 15 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 16 | /* GNU General Public License for more details. */ 17 | /* */ 18 | /* You should have received a copy of the GNU General Public License */ 19 | /* along with New-Session-Manager. If not, see .*/ 20 | /*******************************************************************************/ 21 | 22 | #include "Thread.hpp" 23 | #include 24 | #include 25 | 26 | 27 | 28 | pthread_key_t Thread::_current = 0; 29 | 30 | 31 | 32 | Thread::Thread ( ) 33 | { 34 | _thread = 0; 35 | _running = false; 36 | _name = 0; 37 | } 38 | 39 | Thread::Thread ( const char *name ) 40 | { 41 | _thread = 0; 42 | _running = false; 43 | _name = name; 44 | } 45 | 46 | void 47 | Thread::init ( void ) 48 | { 49 | pthread_key_create( &_current, NULL ); 50 | } 51 | 52 | bool 53 | Thread::is ( const char *name ) 54 | { 55 | return ! strcmp( Thread::current()->name(), name ); 56 | } 57 | 58 | /** to be used by existing threads (that won't call clone()) */ 59 | void 60 | Thread::set ( const char *name ) 61 | { 62 | _thread = pthread_self(); 63 | _name = name; 64 | _running = true; 65 | 66 | pthread_setspecific( _current, (void*)this ); 67 | } 68 | 69 | Thread * 70 | Thread::current ( void ) 71 | { 72 | return (Thread*)pthread_getspecific( _current ); 73 | } 74 | 75 | 76 | struct thread_data 77 | { 78 | void *(*entry_point)(void *); 79 | void *arg; 80 | void *t; 81 | }; 82 | 83 | void * 84 | Thread::run_thread ( void *arg ) 85 | { 86 | thread_data td = *(thread_data *)arg; 87 | delete (thread_data*)arg; 88 | 89 | pthread_setspecific( _current, td.t ); 90 | 91 | ((Thread*)td.t)->_running = true; 92 | 93 | void * r = td.entry_point( td.arg ); 94 | 95 | ((Thread*)td.t)->_running = false; 96 | 97 | return r; 98 | } 99 | 100 | 101 | bool 102 | Thread::clone ( void *(*entry_point)(void *), void *arg ) 103 | { 104 | assert( ! _thread ); 105 | 106 | thread_data *td = new thread_data; 107 | td->entry_point = entry_point; 108 | td->arg = arg; 109 | td->t = this; 110 | 111 | if ( pthread_create( &_thread, NULL, run_thread, td ) != 0 ) 112 | return false; 113 | 114 | return true; 115 | } 116 | 117 | void 118 | Thread::detach ( void ) 119 | { 120 | pthread_detach( _thread ); 121 | _thread = 0; 122 | } 123 | 124 | void 125 | Thread::cancel ( void ) 126 | { 127 | pthread_cancel( _thread ); 128 | _thread = 0; 129 | } 130 | 131 | void 132 | Thread::join ( void ) 133 | { 134 | if ( _thread != 0 ) 135 | { 136 | /* not joined yet, go ahead. */ 137 | pthread_join( _thread, NULL ); 138 | } 139 | _thread = 0; 140 | } 141 | 142 | /* never call this unless some other thread will be calling 'join' on 143 | * this one, otherwise, running() will return true even though the 144 | * thread is dead */ 145 | void 146 | Thread::exit ( void *retval ) 147 | { 148 | _running = false; 149 | pthread_exit( retval ); 150 | } 151 | -------------------------------------------------------------------------------- /src/Thread.hpp: -------------------------------------------------------------------------------- 1 | 2 | /*******************************************************************************/ 3 | /* Copyright (C) 2008-2020 Jonathan Moore Liles (as "Non-Session-Manager") */ 4 | /* Copyright (C) 2020- Nils Hilbricht */ 5 | /* */ 6 | /* This file is part of New-Session-Manager */ 7 | /* */ 8 | /* New-Session-Manager is free software: you can redistribute it and/or modify */ 9 | /* it under the terms of the GNU General Public License as published by */ 10 | /* the Free Software Foundation, either version 3 of the License, or */ 11 | /* (at your option) any later version. */ 12 | /* */ 13 | /* New-Session-Manager is distributed in the hope that it will be useful, */ 14 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 15 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 16 | /* GNU General Public License for more details. */ 17 | /* */ 18 | /* You should have received a copy of the GNU General Public License */ 19 | /* along with New-Session-Manager. If not, see .*/ 20 | /*******************************************************************************/ 21 | 22 | #pragma once 23 | 24 | /* simple wrapper for pthreads with thread role checking */ 25 | #include 26 | 27 | #define THREAD_ASSERT( n ) ASSERT( Thread::is( #n ), "Function called from wrong thread! (is %s, should be %s)", Thread::current()->name(), #n ) 28 | 29 | class Thread 30 | { 31 | static pthread_key_t _current; 32 | 33 | pthread_t _thread; 34 | const char * _name; 35 | 36 | volatile bool _running; 37 | 38 | static void * run_thread ( void *arg ); 39 | 40 | public: 41 | 42 | static bool is ( const char *name ); 43 | 44 | static void init ( void ); 45 | static Thread *current ( void ); 46 | 47 | Thread ( ); 48 | Thread ( const char *name ); 49 | 50 | const char *name ( void ) const { return _name; } 51 | void name ( const char *name ) { _name = name; } 52 | 53 | bool running ( void ) const { return _running; } 54 | void set ( const char *name ); 55 | void set ( void ) { set( _name ); } 56 | bool clone ( void *(*entry_point)(void *), void *arg ); 57 | void detach ( void ); 58 | void join ( void ); 59 | void cancel ( void ); 60 | void exit ( void *retval = 0 ); 61 | 62 | }; 63 | -------------------------------------------------------------------------------- /src/debug.cpp: -------------------------------------------------------------------------------- 1 | 2 | /*******************************************************************************/ 3 | /* Copyright (C) 2008-2020 Jonathan Moore Liles (as "Non-Session-Manager") */ 4 | /* Copyright (C) 2020- Nils Hilbricht */ 5 | /* */ 6 | /* This file is part of New-Session-Manager */ 7 | /* */ 8 | /* New-Session-Manager is free software: you can redistribute it and/or modify */ 9 | /* it under the terms of the GNU General Public License as published by */ 10 | /* the Free Software Foundation, either version 3 of the License, or */ 11 | /* (at your option) any later version. */ 12 | /* */ 13 | /* New-Session-Manager is distributed in the hope that it will be useful, */ 14 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 15 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 16 | /* GNU General Public License for more details. */ 17 | /* */ 18 | /* You should have received a copy of the GNU General Public License */ 19 | /* along with New-Session-Manager. If not, see .*/ 20 | /*******************************************************************************/ 21 | 22 | 23 | #include "debug.h" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | extern char * program_invocation_short_name; 30 | 31 | bool quietMessages = false; 32 | 33 | void 34 | warnf ( warning_t level, 35 | const char *module, 36 | const char *file, 37 | const char *function, int line, const char *fmt, ... ) 38 | { 39 | va_list args; 40 | static const char *level_tab[] = { 41 | "message", "", 42 | "warning", "", 43 | "assertion", "" 44 | }; 45 | 46 | module = program_invocation_short_name; 47 | 48 | if ( module ) 49 | fprintf( stderr, "[%s] ", module ); 50 | #ifndef NDEBUG 51 | if ( file ) 52 | fprintf( stderr, "%s", file ); 53 | if ( line ) 54 | fprintf( stderr, ":%i", line ); 55 | if ( function ) 56 | fprintf( stderr, " %s()", function ); 57 | 58 | fprintf( stderr, ": " ); 59 | #endif 60 | 61 | if ( unsigned( ( level << 1 ) + 1 ) < 62 | ( sizeof( level_tab ) / sizeof( level_tab[0] ) ) ) 63 | fprintf( stderr, "%s", level_tab[( level << 1 ) + 1] ); 64 | 65 | if ( fmt ) 66 | { 67 | va_start( args, fmt ); 68 | vfprintf( stderr, fmt, args ); 69 | va_end( args ); 70 | } 71 | 72 | fprintf( stderr, "\n" ); 73 | } 74 | -------------------------------------------------------------------------------- /src/debug.h: -------------------------------------------------------------------------------- 1 | 2 | /*******************************************************************************/ 3 | /* Copyright (C) 2008-2020 Jonathan Moore Liles (as "Non-Session-Manager") */ 4 | /* Copyright (C) 2020- Nils Hilbricht */ 5 | /* */ 6 | /* This file is part of New-Session-Manager */ 7 | /* */ 8 | /* New-Session-Manager is free software: you can redistribute it and/or modify */ 9 | /* it under the terms of the GNU General Public License as published by */ 10 | /* the Free Software Foundation, either version 3 of the License, or */ 11 | /* (at your option) any later version. */ 12 | /* */ 13 | /* New-Session-Manager is distributed in the hope that it will be useful, */ 14 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 15 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 16 | /* GNU General Public License for more details. */ 17 | /* */ 18 | /* You should have received a copy of the GNU General Public License */ 19 | /* along with New-Session-Manager. If not, see .*/ 20 | /*******************************************************************************/ 21 | 22 | /* debug.h 23 | * 24 | * 11/21/2003 - Jonathan Moore Liles 25 | * 26 | * Debuging support. 27 | * 28 | * Disable by defining the preprocessor variable NDEBUG prior to inclusion. 29 | * 30 | * The following macros sould be defined as string literals 31 | * 32 | * name value 33 | * 34 | * __MODULE__ Name of module. eg. "libfoo" 35 | * 36 | * __FILE__ Name of file. eg. "foo.c" 37 | * 38 | * __FUNCTION__ Name of enclosing function. eg. "bar" 39 | * 40 | * (inteter literal) 41 | * __LINE__ Number of enclosing line. 42 | * 43 | * 44 | * __FILE__, and __LINE__ are automatically defined by standard CPP 45 | * implementations. __FUNCTION__ is more or less unique to GNU, and isn't 46 | * strictly a preprocessor macro, but rather a reserved word in the compiler. 47 | * There is a sed script available with this toolset that is able to fake 48 | * __FUNCTION__ (among other things) with an extra preprocesessing step. 49 | * 50 | * __MODULE__ is nonstandard and should be defined the enclosing program(s). 51 | * Autoconf defines PACKAGE as the module name, and these routines will use its 52 | * value instead if __MODULE__ is undefined. 53 | * 54 | * The following routines are provided (as macros) and take the same arguments 55 | * as printf(): 56 | * 57 | * MESSAGE( const char *format, ... ) 58 | * WARNING( const char *format, ... ) 59 | * FATAL( const char *format, ... ) 60 | * 61 | * Calling MESSAGE or WARNING prints the message to stderr along with module, 62 | * file and line information, as well as appropriate emphasis. Calling 63 | * FATAL will do the same, and then call abort() to end the program. It is 64 | * unwise to supply any of these marcros with arguments that produce side 65 | * effects. As, doing so will most likely result in Heisenbugs; program 66 | * behavior that changes when debugging is disabled. 67 | * 68 | */ 69 | 70 | 71 | 72 | 73 | #ifndef _DEBUG_H 74 | #define _DEBUG_H 75 | 76 | #ifndef __MODULE__ 77 | #ifdef PACKAGE 78 | #define __MODULE__ PACKAGE 79 | #else 80 | #define __MODULE__ NULL 81 | #endif 82 | #endif 83 | 84 | #ifndef __GNUC__ 85 | #define __FUNCTION__ NULL 86 | #endif 87 | 88 | extern bool quietMessages; 89 | 90 | typedef enum { 91 | W_MESSAGE = 0, 92 | W_WARNING, 93 | W_FATAL 94 | } warning_t; 95 | 96 | void 97 | warnf ( warning_t level, 98 | const char *module, 99 | const char *file, 100 | const char *function, int line, const char *fmt, ... ); 101 | 102 | //We do not use NDEBUG anymore. Messages are a command line switch. 103 | //Warnings, asserts and errors are always important. 104 | 105 | // #define MESSAGE( fmt, args... ) warnf( W_MESSAGE, __MODULE__, __FILE__, __FUNCTION__, __LINE__, fmt, ## args ) 106 | #define MESSAGE( fmt, args... ) do { if ( ! (quietMessages) ) { warnf( W_MESSAGE, __MODULE__, __FILE__, __FUNCTION__, __LINE__, fmt, ## args ); } } while ( 0 ) 107 | #define WARNING( fmt, args... ) warnf( W_WARNING, __MODULE__, __FILE__, __FUNCTION__, __LINE__, fmt, ## args ) 108 | #define FATAL( fmt, args... ) ( warnf( W_FATAL, __MODULE__, __FILE__, __FUNCTION__, __LINE__, fmt, ## args ), abort() ) 109 | #define ASSERT( pred, fmt, args... ) do { if ( ! (pred) ) { warnf( W_FATAL, __MODULE__, __FILE__, __FUNCTION__, __LINE__, fmt, ## args ); abort(); } } while ( 0 ) 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /src/file.cpp: -------------------------------------------------------------------------------- 1 | 2 | /*******************************************************************************/ 3 | /* Copyright (C) 2008-2020 Jonathan Moore Liles (as "Non-Session-Manager") */ 4 | /* Copyright (C) 2020- Nils Hilbricht */ 5 | /* */ 6 | /* This file is part of New-Session-Manager */ 7 | /* */ 8 | /* New-Session-Manager is free software: you can redistribute it and/or modify */ 9 | /* it under the terms of the GNU General Public License as published by */ 10 | /* the Free Software Foundation, either version 3 of the License, or */ 11 | /* (at your option) any later version. */ 12 | /* */ 13 | /* New-Session-Manager is distributed in the hope that it will be useful, */ 14 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 15 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 16 | /* GNU General Public License for more details. */ 17 | /* */ 18 | /* You should have received a copy of the GNU General Public License */ 19 | /* along with New-Session-Manager. If not, see .*/ 20 | /*******************************************************************************/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | unsigned long 32 | modification_time ( const char *file ) 33 | { 34 | struct stat st; 35 | 36 | if ( stat( file, &st ) ) 37 | return 0; 38 | 39 | return st.st_mtime; 40 | } 41 | 42 | /** returns /true/ if /file1/ is newer than /file2/ (or file2 doesn't exist) */ 43 | bool 44 | newer ( const char *file1, const char *file2 ) 45 | { 46 | return modification_time( file1 ) > modification_time( file2 ); 47 | } 48 | 49 | unsigned long 50 | size ( const char *file ) 51 | { 52 | struct stat st; 53 | 54 | if ( stat( file, &st ) ) 55 | return 0; 56 | 57 | return st.st_size; 58 | } 59 | 60 | int 61 | exists ( const char *name ) 62 | { 63 | struct stat st; 64 | 65 | return 0 == stat( name, &st ); 66 | } 67 | 68 | 69 | char * 70 | simple_hash( const char *s ) 71 | { //djb2 72 | unsigned long hashAddress = 5381; 73 | for ( int counter = 0; s[counter]!='\0'; counter++ ) { 74 | hashAddress = ( (hashAddress << 5) + hashAddress ) + s[counter]; 75 | } 76 | 77 | char *result = NULL; 78 | asprintf( &result, "%lu", hashAddress % 65521 ); 79 | return result; 80 | } 81 | 82 | int 83 | backwards_fgetc ( FILE *fp ) 84 | { 85 | int c; 86 | 87 | if ( fseek( fp, -1, SEEK_CUR ) != 0 ) 88 | return -1; 89 | 90 | c = fgetc( fp ); 91 | 92 | fseek( fp, -1, SEEK_CUR ); 93 | 94 | return c; 95 | } 96 | 97 | char * 98 | backwards_afgets ( FILE *fp ) 99 | { 100 | size_t size = 0; 101 | 102 | char *s = NULL; 103 | size_t i = 0; 104 | int c; 105 | while ( ( c = backwards_fgetc( fp ) ) >= 0 ) 106 | { 107 | if ( i > 0 && '\n' == c ) 108 | break; 109 | 110 | if ( i >= size ) 111 | { 112 | size += 256; 113 | s = (char*)realloc( s, size ); 114 | } 115 | 116 | s[i++] = c; 117 | 118 | } 119 | 120 | if ( s ) 121 | { 122 | s[i] = 0; 123 | 124 | int len = strlen(s) ; 125 | int c, i, j; 126 | 127 | for (i = 0, j = len - 1; i < j; i++, j--) 128 | { 129 | c = s[i]; 130 | s[i] = s[j]; 131 | s[j] = c; 132 | } 133 | } 134 | 135 | fseek( fp, 1, SEEK_CUR ); 136 | 137 | return s; 138 | } 139 | 140 | 141 | /** update the modification time of file referred to by /fd/ */ 142 | void 143 | touch ( int fd ) 144 | { 145 | struct stat st; 146 | 147 | fstat( fd, &st ); 148 | 149 | fchmod( fd, st.st_mode ); 150 | } 151 | 152 | /** write a single string to a file */ 153 | void 154 | write_line ( const char *dir, const char *name, const char *value ) 155 | { 156 | char path[512]; 157 | 158 | snprintf( path, sizeof( path ), "%s/%s", dir, name ); 159 | 160 | FILE *fp = fopen( path, "w" ); 161 | 162 | if ( ! fp ) 163 | return; 164 | 165 | fputs( value, fp ); 166 | 167 | fclose( fp ); 168 | } 169 | 170 | /** read a single string from a file */ 171 | char * 172 | read_line ( const char *dir, const char *name ) 173 | { 174 | char path[512]; 175 | 176 | snprintf( path, sizeof( path ), "%s/%s", dir, name ); 177 | 178 | FILE *fp = fopen( path, "r" ); 179 | 180 | if ( ! fp ) 181 | return 0; 182 | 183 | char *value = (char*)malloc( 512 ); 184 | 185 | if ( ! fgets( value, 512, fp ) ) 186 | value[0] = 0; 187 | 188 | fclose( fp ); 189 | 190 | return value; 191 | } 192 | 193 | #include 194 | 195 | /** return the number of blocks free on filesystem containing file named /file/ */ 196 | fsblkcnt_t 197 | free_space ( const char *file ) 198 | { 199 | struct statfs st; 200 | memset( &st, 0, sizeof( st ) ); 201 | 202 | statfs( file, &st ); 203 | 204 | return st.f_bavail; 205 | } 206 | 207 | /** return the total number of blocks on filesystem containing file named /file/ */ 208 | fsblkcnt_t 209 | total_space ( const char *file ) 210 | { 211 | struct statfs st; 212 | memset( &st, 0, sizeof( st ) ); 213 | 214 | statfs( file, &st ); 215 | 216 | return st.f_blocks; 217 | } 218 | 219 | /** return the percentage of usage on filesystem containing file named /file/ */ 220 | int 221 | percent_used ( const char *file ) 222 | { 223 | const double ts = total_space( file ); 224 | const double fs = free_space( file ); 225 | 226 | double percent_free = ( ( fs / ts ) * 100.0f ); 227 | 228 | return (int) (100.0f - percent_free); 229 | } 230 | -------------------------------------------------------------------------------- /src/file.h: -------------------------------------------------------------------------------- 1 | 2 | /*******************************************************************************/ 3 | /* Copyright (C) 2008-2020 Jonathan Moore Liles (as "Non-Session-Manager") */ 4 | /* Copyright (C) 2020- Nils Hilbricht */ 5 | /* */ 6 | /* This file is part of New-Session-Manager */ 7 | /* */ 8 | /* New-Session-Manager is free software: you can redistribute it and/or modify */ 9 | /* it under the terms of the GNU General Public License as published by */ 10 | /* the Free Software Foundation, either version 3 of the License, or */ 11 | /* (at your option) any later version. */ 12 | /* */ 13 | /* New-Session-Manager is distributed in the hope that it will be useful, */ 14 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 15 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 16 | /* GNU General Public License for more details. */ 17 | /* */ 18 | /* You should have received a copy of the GNU General Public License */ 19 | /* along with New-Session-Manager. If not, see .*/ 20 | /*******************************************************************************/ 21 | 22 | #include 23 | 24 | unsigned long modification_time ( const char *file ); 25 | 26 | bool newer ( const char *file1, const char *file2 ); 27 | unsigned long size ( const char *file ); 28 | int exists ( const char *name ); 29 | char * simple_hash( const char *s); 30 | int backwards_fgetc ( FILE *fp ); 31 | char * backwards_afgets ( FILE *fp ); 32 | void touch ( int fd ); 33 | void write_line ( const char *dir, const char *name, const char *value ); 34 | char * read_line ( const char *dir, const char *name ); 35 | size_t free_space ( const char *file ); 36 | size_t total_space ( const char *file ); 37 | int percent_used ( const char *file ); 38 | -------------------------------------------------------------------------------- /src/jackpatch.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 43 | 45 | 46 | 48 | image/svg+xml 49 | 51 | 52 | 53 | 54 | 55 | 60 | 64 | nsm 66 | 73 | NSM 84 | 85 | 89 | jackpatch 91 | 98 | JP 109 | 110 | 113 | proxy 115 | 122 | PRX 133 | 134 | 138 | 142 | 146 | 150 | 154 | 155 | 159 | 163 | 167 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /src/nsm-legacy-gui.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 39 | 41 | 42 | 44 | image/svg+xml 45 | 47 | 48 | 49 | 50 | 51 | 56 | 60 | nsm 62 | 69 | NSM 80 | 81 | 85 | jackpatch 87 | 94 | JP 105 | 106 | 109 | proxy 111 | 118 | PRX 129 | 130 | 134 | 138 | 142 | 146 | 150 | 151 | 155 | 159 | 163 | 167 | 171 | 175 | 179 | 183 | 184 | Texts andObjects 200 | Convertedto paths 216 | Select Icon, Ctrl+Shift+Rto resize to selection.File -> Save Copy Inkscape SVG works as icon 242 | 243 | 244 | -------------------------------------------------------------------------------- /src/nsm-proxy-gui.cpp: -------------------------------------------------------------------------------- 1 | 2 | /*******************************************************************************/ 3 | /* Copyright (C) 2008-2020 Jonathan Moore Liles (as "Non-Session-Manager") */ 4 | /* Copyright (C) 2020- Nils Hilbricht */ 5 | /* */ 6 | /* This file is part of New-Session-Manager */ 7 | /* */ 8 | /* New-Session-Manager is free software: you can redistribute it and/or modify */ 9 | /* it under the terms of the GNU General Public License as published by */ 10 | /* the Free Software Foundation, either version 3 of the License, or */ 11 | /* (at your option) any later version. */ 12 | /* */ 13 | /* New-Session-Manager is distributed in the hope that it will be useful, */ 14 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 15 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ 16 | /* GNU General Public License for more details. */ 17 | /* */ 18 | /* You should have received a copy of the GNU General Public License */ 19 | /* along with New-Session-Manager. If not, see .*/ 20 | /*******************************************************************************/ 21 | 22 | #pragma GCC diagnostic ignored "-Wunused-parameter" 23 | 24 | 25 | #define _MODULE_ "nsm-proxy-gui" 26 | 27 | #define APP_NAME "NSM Proxy" 28 | #define APP_TITLE "NSM Proxy" 29 | 30 | #include 31 | #include 32 | #include "NSM_Proxy_UI.H" 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | 41 | lo_server losrv; 42 | lo_address nsmp_addr; 43 | 44 | static NSM_Proxy_UI *ui; 45 | 46 | static char *client_error; 47 | 48 | int 49 | osc_update ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) 50 | { 51 | //Updates are arriving one OSC message at a time. 52 | 53 | printf( "Got update for %s\n", path ); 54 | 55 | Fl::lock(); 56 | 57 | if (!strcmp( path, "/nsm/proxy/label" )) 58 | ui->label_input->value( &argv[0]->s ); 59 | else if (!strcmp( path, "/nsm/proxy/arguments" )) 60 | ui->arguments_input->value( &argv[0]->s ); 61 | else if (!strcmp( path, "/nsm/proxy/executable" )) { 62 | ui->executable_input->value( &argv[0]->s ); 63 | if ( strcmp( &argv[0]->s , "") ) { 64 | //We want to avoid that the button is always labeled 'Start', creating the 65 | //false impression that a new sub-client instance is started each time you press it. 66 | //If the string is empty there is no program running at the moment. 67 | //This does not cover all cases but gets us there 90%, which is good enough for something cosmetic. 68 | ui->start_button->label("Ok"); 69 | } 70 | } 71 | else if (!strcmp( path, "/nsm/proxy/config_file" )) 72 | ui->config_file_input->value( &argv[0]->s ); 73 | else if (!strcmp( path, "/nsm/proxy/save_signal" )) 74 | { 75 | if ( argv[0]->i == SIGUSR1 ) 76 | ui->save_signal_choice->value( 1 ); 77 | else if ( argv[0]->i == SIGUSR2 ) 78 | ui->save_signal_choice->value( 2 ); 79 | else if ( argv[0]->i == SIGINT ) 80 | ui->save_signal_choice->value( 3 ); 81 | else 82 | ui->save_signal_choice->value( 0 ); 83 | } 84 | else if (!strcmp( path, "/nsm/proxy/stop_signal" )) 85 | { 86 | if ( argv[0]->i == SIGTERM ) 87 | ui->stop_signal_choice->value( 0 ); 88 | else if ( argv[0]->i == SIGINT ) 89 | ui->stop_signal_choice->value( 1 ); 90 | else if ( argv[0]->i == SIGHUP ) 91 | ui->stop_signal_choice->value( 2 ); 92 | } 93 | if (!strcmp( path, "/nsm/proxy/client_error" )) 94 | { 95 | if ( client_error != NULL ) 96 | free(client_error); 97 | 98 | client_error = NULL; 99 | 100 | if ( strlen(&argv[0]->s) > 0 ) 101 | client_error = strdup(&argv[0]->s); 102 | } 103 | 104 | Fl::unlock(); 105 | 106 | return 0; 107 | } 108 | 109 | 110 | void 111 | init_osc ( const char *osc_port ) 112 | { 113 | 114 | lo_server_thread loth = lo_server_thread_new( osc_port, NULL ); 115 | losrv = lo_server_thread_get_server( loth ); 116 | 117 | //error_handler ); 118 | 119 | char *url = lo_server_get_url(losrv); 120 | printf("OSC: %s\n",url); 121 | free(url); 122 | 123 | /* GUI */ 124 | 125 | lo_server_thread_add_method( loth, "/nsm/proxy/executable", "s", osc_update, NULL ); 126 | lo_server_thread_add_method( loth, "/nsm/proxy/arguments", "s", osc_update, NULL ); 127 | lo_server_thread_add_method( loth, "/nsm/proxy/config_file", "s", osc_update, NULL ); 128 | lo_server_thread_add_method( loth, "/nsm/proxy/label", "s", osc_update, NULL ); 129 | lo_server_thread_add_method( loth, "/nsm/proxy/save_signal", "i", osc_update, NULL ); 130 | lo_server_thread_add_method( loth, "/nsm/proxy/stop_signal", "i", osc_update, NULL ); 131 | lo_server_thread_add_method( loth, "/nsm/proxy/client_error", "s", osc_update, NULL ); 132 | 133 | lo_server_thread_start( loth ); 134 | } 135 | 136 | /*****************/ 137 | /* GUI Callbacks */ 138 | /*****************/ 139 | 140 | void 141 | handle_kill ( Fl_Widget *o, void *v ) 142 | { 143 | lo_send_from( nsmp_addr, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/kill", "" ); 144 | } 145 | 146 | void 147 | handle_start ( Fl_Widget *o, void *v ) 148 | { 149 | //Executed when Start Button is clicked. 150 | //"/nsm/proxy/start" for the sub-client is always sent, no matter if the software already runs. 151 | //nsm-proxy.cpp handles the redundancy. 152 | lo_send_from( nsmp_addr, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/start", "sss", 153 | ui->executable_input->value(), 154 | ui->arguments_input->value(), 155 | ui->config_file_input->value() ); 156 | } 157 | 158 | void 159 | handle_label ( Fl_Widget *o, void *v ) 160 | { 161 | lo_send_from( nsmp_addr, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/label", "s", 162 | ui->label_input->value() ); 163 | } 164 | 165 | void 166 | handle_executable ( Fl_Widget *o, void *v ) 167 | { 168 | //Autofill the label field when the executable name is edited 169 | ui->label_input->value( ui->executable_input->value() ); 170 | //This does not trigger handle_label so we call it manually 171 | lo_send_from( nsmp_addr, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/label", "s", 172 | ui->label_input->value() ); 173 | } 174 | 175 | 176 | void 177 | handle_config_file ( Fl_Widget *o, void *v ) 178 | { 179 | } 180 | 181 | void 182 | handle_config_file_browse ( Fl_Widget *o, void *v ) 183 | { 184 | const char * file = fl_file_chooser( "Pick file", "*", NULL, 1 ); 185 | 186 | ui->config_file_input->value( file ); 187 | } 188 | 189 | void 190 | handle_save_signal ( Fl_Widget *o, void *v ) 191 | { 192 | int sig = 0; 193 | 194 | const char* picked = ui->save_signal_choice->mvalue()->label(); 195 | 196 | if ( !strcmp( picked, "SIGUSR1" ) ) 197 | sig = SIGUSR1; 198 | else if ( !strcmp( picked, "SIGUSR2" ) ) 199 | sig = SIGUSR2; 200 | else if ( !strcmp( picked, "SIGINT" ) ) 201 | sig = SIGINT; 202 | 203 | lo_send_from( nsmp_addr, losrv, LO_TT_IMMEDIATE,"/nsm/proxy/save_signal", "i", 204 | sig ); 205 | } 206 | 207 | void 208 | handle_stop_signal ( Fl_Widget *o, void *v ) 209 | { 210 | int sig = SIGTERM; 211 | 212 | const char* picked = ui->stop_signal_choice->mvalue()->label(); 213 | 214 | if ( !strcmp( picked, "SIGTERM" ) ) 215 | sig = SIGTERM; 216 | else if ( !strcmp( picked, "SIGINT" ) ) 217 | sig = SIGINT; 218 | else if ( !strcmp( picked, "SIGHUP" ) ) 219 | sig = SIGHUP; 220 | 221 | lo_send_from( nsmp_addr, losrv, LO_TT_IMMEDIATE,"/nsm/proxy/stop_signal", "i", 222 | sig ); 223 | } 224 | 225 | void 226 | connect_ui ( void ) 227 | { 228 | ui->executable_input->callback( handle_executable, NULL ); 229 | ui->config_file_input->callback( handle_config_file, NULL ); 230 | ui->kill_button->callback( handle_kill, NULL ); 231 | ui->start_button->callback( handle_start, NULL ); 232 | ui->save_signal_choice->callback( handle_save_signal, NULL ); 233 | ui->stop_signal_choice->callback( handle_stop_signal, NULL ); 234 | ui->label_input->callback( handle_label, NULL ); 235 | ui->config_file_browse_button->callback( handle_config_file_browse, NULL ); 236 | } 237 | 238 | 239 | 240 | void cb_dismiss_button ( Fl_Widget *w, void *v ) 241 | { 242 | w->window()->hide(); 243 | } 244 | 245 | void 246 | check_error ( void *v ) 247 | { 248 | if ( client_error ) 249 | { 250 | { 251 | Fl_Double_Window *o = new Fl_Double_Window(600,300+15,"Abnormal Termination"); 252 | //Create a new floating Window that shows an error message. 253 | { 254 | Fl_Box *o = new Fl_Box(0+15,0+15,600-30,50); 255 | o->box(FL_BORDER_BOX); 256 | o->color(FL_RED); 257 | o->labelcolor(FL_WHITE); 258 | o->align(FL_ALIGN_CENTER|FL_ALIGN_WRAP); 259 | o->copy_label( client_error ); 260 | } 261 | { 262 | Fl_Text_Display *o = new Fl_Text_Display(0+15,50+15,600-30,300-75-30); 263 | o->buffer(new Fl_Text_Buffer()); 264 | o->buffer()->loadfile( "error.log" ); 265 | } 266 | { 267 | Fl_Button *o = new Fl_Button(600-75-15,300-25,75,25,"Dismiss"); 268 | o->callback(cb_dismiss_button,0); 269 | } 270 | 271 | o->show(); 272 | } 273 | 274 | free(client_error); 275 | client_error = NULL; 276 | } 277 | 278 | Fl::repeat_timeout( 0.5f, check_error, v ); 279 | } 280 | 281 | int 282 | main ( int argc, char **argv ) 283 | { 284 | //The NSM-Proxy GUI is a client that communicates with another binary, nsm-proxy via OSC. 285 | //This GUI executable is actually closed and restarted each time you show/hide the GUI. 286 | //In other words: it is not a persistent GUI state. 287 | 288 | 289 | //Command line parameters 290 | const char * gui_url = NULL; 291 | static struct option long_options[] = 292 | { 293 | { "connect-to", required_argument, 0, 'u' }, 294 | { "help", no_argument, 0, 'h' }, 295 | { 0, 0, 0, 0 } 296 | }; 297 | int option_index = 0; 298 | int c = 0; 299 | while ( ( c = getopt_long_only( argc, argv, "", long_options, &option_index ) ) != -1 ) 300 | { 301 | switch ( c ) 302 | { 303 | case 'u': 304 | { 305 | gui_url = optarg; 306 | break; 307 | } 308 | 309 | case 'h': 310 | { 311 | const char *usage = 312 | "nsm-proxy-gui - GUI for nsm-proxy, a wrapper for executables without direct NSM-Support.\n\n" 313 | "Usage:\n" 314 | " nsm-proxy-gui --help\n" 315 | " nsm-proxy-gui --connect-to\n" 316 | "\n" 317 | "Options:\n" 318 | " --help Show this screen\n" 319 | " --connect-to Connect to running nsm-proxy\n" 320 | "\n\n" 321 | "nsmd-proxy-gui is usually not called by the user directly,\n" 322 | "but autostarted when nsm-proxy is added to a session (through a GUI).\n" 323 | ""; 324 | puts ( usage ); 325 | exit(0); 326 | break; 327 | } 328 | } 329 | } 330 | 331 | if ( gui_url == NULL ) 332 | exit(1); 333 | 334 | init_osc( NULL ); 335 | 336 | nsmp_addr = lo_address_new_from_url( gui_url ); 337 | 338 | if ( ! nsmp_addr ) 339 | exit(1); 340 | 341 | printf( "Connecting to nsm-proxy at: %s\n", gui_url ); 342 | 343 | ui = new NSM_Proxy_UI; 344 | 345 | Fl::scheme( "gtk+" ); 346 | Fl::visual(FL_DOUBLE|FL_INDEX); // FLKT Double_Window: "higly recommended […] put before the first show() of any window in your program" 347 | 348 | Fl_Double_Window *w = ui->make_window(); 349 | 350 | connect_ui(); 351 | 352 | lo_send_from( nsmp_addr, losrv, LO_TT_IMMEDIATE, "/nsm/proxy/update", "" ); 353 | 354 | //The config file option allows the user to choose a different config file for the proxy settings. 355 | //This does more harm than good, so we hide the gui field. 356 | ui->config_file_input->hide(); 357 | 358 | w->show(); 359 | 360 | Fl::lock(); 361 | 362 | //Setting colors only after main window creation. 363 | //We keep them all in once place instead of setting them in the widgets 364 | //Colors are the same as nsm-legacy-gui.cpp . If one changes you need to change the other by hand. 365 | 366 | 367 | Fl::set_color( 55, 223, 237, 255 ); //Override FLUID palette with RGB Value. 55 is label text. Same as FL_FOREGROUND_COLOR 368 | Fl::set_color( 41, 55, 61, 69 ); //Override FLUID palette with RGB Value. 41 is label background 369 | 370 | Fl::set_color( FL_DARK1, 37, 40, 45 ); //Main window background 371 | Fl::set_color( FL_BACKGROUND_COLOR, 37, 40, 45 ); //These are the colors used as backgrounds by almost all widgets and used to draw the edges of all the boxtypes. 372 | Fl::set_color( FL_BACKGROUND2_COLOR, 55, 61, 69 ); //This color is used as a background by Fl_Input and other text widgets. 373 | Fl::set_color( FL_FOREGROUND_COLOR, 223, 237, 255 ); 374 | Fl::set_color( FL_INACTIVE_COLOR, 255, 0, 0 ); // Not used 375 | Fl::set_color( FL_SELECTION_COLOR, 80, 84, 92 ); // e.g. the currently selected session 376 | Fl::reload_scheme(); 377 | 378 | 379 | Fl::add_timeout( 0.5f, check_error, NULL ); 380 | 381 | Fl::run(); 382 | 383 | return 0; 384 | } 385 | -------------------------------------------------------------------------------- /src/nsm-proxy.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 39 | 41 | 42 | 44 | image/svg+xml 45 | 47 | 48 | 49 | 50 | 51 | 56 | 60 | nsm 62 | 69 | NSM 80 | 81 | 85 | jackpatch 87 | 94 | JP 105 | 106 | 109 | proxy 111 | 118 | PRX 129 | 130 | 134 | 138 | 142 | 146 | 150 | 151 | 155 | 159 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /src/org.jackaudio.jackpatch.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=JACKpatch 4 | Comment=Remember the JACK Audio Connection Kit Graph in NSM 5 | Exec=jackpatch 6 | Icon=jackpatch 7 | Terminal=false 8 | StartupNotify=false 9 | Version=1.0 10 | Categories=AudioVideo;Audio; 11 | X-NSM-Capable=true 12 | X-NSM-Exec=jackpatch 13 | NoDisplay=true 14 | -------------------------------------------------------------------------------- /src/org.jackaudio.nsm-legacy-gui.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=New Session Manager (Legacy GUI) 4 | Name[fr]=New Session Manager (ancienne interface) 5 | Comment=Audio session manager (Legacy GUI) 6 | Comment[de]=Verwaltet Audiositzungen (Alte Oberfläche) 7 | Comment[fr]=Gestionnaire de session audio (ancienne interface) 8 | Comment[it]=Gestore di sessioni audio (Vecchia GUI) 9 | Comment[pt]=Gestor de sessões audio (Antiga GUI) 10 | Exec=nsm-legacy-gui 11 | Icon=nsm-legacy-gui 12 | Terminal=false 13 | StartupNotify=false 14 | Version=1.0 15 | Categories=AudioVideo;Audio; 16 | -------------------------------------------------------------------------------- /src/org.jackaudio.nsm-proxy.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=NSM-Proxy 4 | Comment=Wrapper for executables without direct NSM-Support. 5 | Exec=nsm-proxy 6 | Icon=nsm-proxy 7 | Terminal=false 8 | StartupNotify=false 9 | Version=1.0 10 | Categories=AudioVideo;Audio; 11 | X-NSM-Capable=true 12 | X-NSM-Exec=nsm-proxy 13 | NoDisplay=true 14 | --------------------------------------------------------------------------------