diff --git a/csdr/csdr.py b/csdr/csdr.py index d6cfc11..b2f2129 100644 --- a/csdr/csdr.py +++ b/csdr/csdr.py @@ -329,7 +329,7 @@ class dsp(object): logger.debug("secondary command (fft) = %s", secondary_command_fft) self.secondary_process_fft = subprocess.Popen( - secondary_command_fft, stdout=subprocess.PIPE, shell=True, preexec_fn=os.setpgrp, env=my_env + secondary_command_fft, stdout=subprocess.PIPE, shell=True, start_new_session=True, env=my_env ) self.output.send_output( "secondary_fft", @@ -341,7 +341,7 @@ class dsp(object): # it would block if not read. by piping it to devnull, we avoid a potential pitfall here. secondary_output = subprocess.DEVNULL if self.isPacket() else subprocess.PIPE self.secondary_process_demod = subprocess.Popen( - secondary_command_demod, stdout=secondary_output, shell=True, preexec_fn=os.setpgrp, env=my_env + secondary_command_demod, stdout=secondary_output, shell=True, start_new_session=True, env=my_env ) self.secondary_processes_running = True @@ -669,7 +669,7 @@ class dsp(object): my_env["CSDR_PRINT_BUFSIZES"] = "1" out = subprocess.PIPE if self.output.supports_type("audio") else subprocess.DEVNULL - self.process = subprocess.Popen(command, stdout=out, shell=True, preexec_fn=os.setpgrp, env=my_env) + self.process = subprocess.Popen(command, stdout=out, shell=True, start_new_session=True, env=my_env) def watch_thread(): rc = self.process.wait() diff --git a/htdocs/css/openwebrx.css b/htdocs/css/openwebrx.css index 9f0ac6f..556558f 100644 --- a/htdocs/css/openwebrx.css +++ b/htdocs/css/openwebrx.css @@ -304,34 +304,9 @@ input[type=range]:focus::-ms-fill-upper color: #ff6262; } -/*#webrx-freq-show -{ - visibility: hidden; - position: absolute; - top: 0px; - left: 0px; - padding: 5px; - font-weight: bold; - border-radius: 10px; - -moz-border-radius: 10px; - background-color: #999999; - color: White; - z-index:9999; /*should be higher? - -}*/ - -/* removed non-free fonts like that: */ -/*@font-face { - font-family: 'unibody_8_pro_regregular'; - src: url('../gfx/unibody8pro-regular-webfont.eot'); - src: url('../gfx/unibody8pro-regular-webfont.ttf'); - font-weight: normal; - font-style: normal; -}*/ - @font-face { - font-family: 'expletus-sans-medium'; - src: url('../gfx/font-expletus-sans/ExpletusSans-Medium.ttf'); + font-family: 'roboto-mono'; + src: url('../fonts/RobotoMono-Regular.ttf'); font-weight: normal; font-style: normal; } @@ -341,7 +316,7 @@ input[type=range]:focus::-ms-fill-upper width: 100%; text-align: left; font-size: 16pt; - font-family: 'expletus-sans-medium'; + font-family: 'roboto-mono'; padding: 0; margin: 0; line-height:22px; @@ -354,7 +329,7 @@ input[type=range]:focus::-ms-fill-upper text-align: left; font-size: 10pt; color: #AAA; - font-family: 'expletus-sans-medium'; + font-family: 'roboto-mono'; margin-bottom: 5px; } @@ -646,7 +621,7 @@ img.openwebrx-mirror-img float: right; margin-right: 5px; margin-top: 24px; - font-family: 'expletus-sans-medium'; + font-family: 'roboto-mono'; } .openwebrx-overlay { diff --git a/htdocs/fonts/RobotoMono-Regular.ttf b/htdocs/fonts/RobotoMono-Regular.ttf new file mode 100644 index 0000000..5919b5d Binary files /dev/null and b/htdocs/fonts/RobotoMono-Regular.ttf differ diff --git a/htdocs/gfx/font-expletus-sans/ExpletusSans-Medium.ttf b/htdocs/gfx/font-expletus-sans/ExpletusSans-Medium.ttf deleted file mode 100644 index dfc87f8..0000000 Binary files a/htdocs/gfx/font-expletus-sans/ExpletusSans-Medium.ttf and /dev/null differ diff --git a/htdocs/gfx/font-expletus-sans/OFL.txt b/htdocs/gfx/font-expletus-sans/OFL.txt deleted file mode 100644 index 5979654..0000000 --- a/htdocs/gfx/font-expletus-sans/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright (c) 2011, Jasper de Waard (jasper@designtown.nl), -with Reserved Font Name "Expletus Sans". -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/htdocs/index.html b/htdocs/index.html index f18f659..d9296c9 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -31,6 +31,7 @@ + diff --git a/htdocs/lib/BookmarkBar.js b/htdocs/lib/BookmarkBar.js index 4edac8e..d039494 100644 --- a/htdocs/lib/BookmarkBar.js +++ b/htdocs/lib/BookmarkBar.js @@ -9,7 +9,7 @@ function BookmarkBar() { me.$container.find('.bookmark').removeClass('selected'); var b = $bookmark.data(); if (!b || !b.frequency || (!b.modulation && !b.digital_modulation)) return; - demodulator_set_offset_frequency(0, b.frequency - center_freq); + demodulators[0].set_offset_frequency(b.frequency - center_freq); if (b.modulation) { demodulator_analog_replace(b.modulation); } else if (b.digital_modulation) { diff --git a/htdocs/lib/FrequencyDisplay.js b/htdocs/lib/FrequencyDisplay.js new file mode 100644 index 0000000..0353fd8 --- /dev/null +++ b/htdocs/lib/FrequencyDisplay.js @@ -0,0 +1,61 @@ +function FrequencyDisplay(element) { + this.element = $(element); + this.digits = []; + this.digitContainer = $(''); + this.element.html([this.digitContainer, $(' MHz')]); + this.decimalSeparator = (0.1).toLocaleString().substring(1, 2); + this.setFrequency(0); +} + +FrequencyDisplay.prototype.setFrequency = function(freq) { + this.frequency = freq; + var formatted = (freq / 1e6).toLocaleString(undefined, {maximumFractionDigits: 4, minimumFractionDigits: 4}); + var children = this.digitContainer.children(); + for (var i = 0; i < formatted.length; i++) { + if (!this.digits[i]) { + this.digits[i] = $(''); + var before = children[i]; + if (before) { + $(before).after(this.digits[i]); + } else { + this.digitContainer.append(this.digits[i]); + } + } + this.digits[i][(isNaN(formatted[i]) ? 'remove' : 'add') + 'Class']('digit'); + this.digits[i].html(formatted[i]); + } + while (this.digits.length > formatted.length) { + this.digits.pop().remove(); + } +}; + +function TuneableFrequencyDisplay(element) { + FrequencyDisplay.call(this, element); + this.setupEvents(); +} + +TuneableFrequencyDisplay.prototype = new FrequencyDisplay(); + +TuneableFrequencyDisplay.prototype.setupEvents = function() { + var me = this; + this.element.on('wheel', function(e){ + e.preventDefault(); + e.stopPropagation(); + + var index = me.digitContainer.find('.digit').index(e.target); + if (index < 0) return; + + var delta = 10 ** (Math.floor(Math.log10(me.frequency)) - index); + if (e.originalEvent.deltaY > 0) delta *= -1; + var newFrequency = me.frequency + delta; + + me.listeners.forEach(function(l) { + l(newFrequency); + }); + }); + this.listeners = []; +}; + +TuneableFrequencyDisplay.prototype.onFrequencyChange = function(listener){ + this.listeners.push(listener); +}; \ No newline at end of file diff --git a/htdocs/openwebrx.js b/htdocs/openwebrx.js index e81c4c1..50cfdec 100644 --- a/htdocs/openwebrx.js +++ b/htdocs/openwebrx.js @@ -334,7 +334,6 @@ function demod_envelope_where_clicked(x, drag_ranges, key_modifiers) { // Check //******* class Demodulator ******* // this can be used as a base class for ANY demodulator Demodulator = function (offset_frequency) { - //console.log("this too"); this.offset_frequency = offset_frequency; this.envelope = {}; this.color = demodulators_get_next_color(); @@ -357,11 +356,7 @@ Demodulator.draggable_ranges = { demodulator_response_time = 50; -//in ms; if we don't limit the number of SETs sent to the server, audio will underrun (possibly output buffer is cleared on SETs in GNU Radio - function Demodulator_default_analog(offset_frequency, subtype) { - //console.log("hopefully this happens"); - //http://stackoverflow.com/questions/4152931/javascript-inheritance-call-super-constructor-or-use-prototype-chain Demodulator.call(this, offset_frequency); this.subtype = subtype; this.filter = { @@ -512,7 +507,7 @@ function Demodulator_default_analog(offset_frequency, subtype) { mkenvelopes(this.visible_range); this.parent.set(); //will have to change this when changing to multi-demodulator mode: - e("webrx-actual-freq").innerHTML = format_frequency("{x} MHz", center_freq + this.parent.offset_frequency, 1e6, 4); + tunedFrequencyDisplay.setFrequency(center_freq + this.parent.offset_frequency); return true; }; @@ -565,12 +560,12 @@ function demodulator_analog_replace(subtype, for_digital) { //this function shou update_digitalvoice_panels("openwebrx-panel-metadata-" + subtype); } -function demodulator_set_offset_frequency(which, to_what) { +Demodulator.prototype.set_offset_frequency = function(to_what) { if (to_what > bandwidth / 2 || to_what < -bandwidth / 2) return; - demodulators[0].offset_frequency = Math.round(to_what); - demodulators[0].set(); + this.offset_frequency = Math.round(to_what); + this.set(); mkenvelopes(get_visible_freq_range()); - $("#webrx-actual-freq").html(format_frequency("{x} MHz", center_freq + to_what, 1e6, 4)); + tunedFrequencyDisplay.setFrequency(center_freq + to_what); } function waterfallWidth() { @@ -584,9 +579,11 @@ function waterfallWidth() { var scale_ctx; var scale_canvas; +var tunedFrequencyDisplay; +var mouseFrequencyDisplay; function scale_setup() { - e("webrx-actual-freq").innerHTML = format_frequency("{x} MHz", canvas_get_frequency(window.innerWidth / 2), 1e6, 4); + tunedFrequencyDisplay.setFrequency(canvas_get_frequency(window.innerWidth / 2)); scale_canvas = e("openwebrx-scale-canvas"); scale_ctx = scale_canvas.getContext("2d"); scale_canvas.addEventListener("mousedown", scale_canvas_mousedown, false); @@ -633,14 +630,14 @@ function scale_canvas_mousemove(evt) { else if (scale_canvas_drag_params.drag) { //call the drag_move for all demodulators (and they will decide if they're dragged) for (i = 0; i < demodulators.length; i++) event_handled |= demodulators[i].envelope.drag_move(evt.pageX); - if (!event_handled) demodulator_set_offset_frequency(0, scale_offset_freq_from_px(evt.pageX)); + if (!event_handled) demodulators[0].set_offset_frequency(scale_offset_freq_from_px(evt.pageX)); } } function frequency_container_mousemove(evt) { var frequency = center_freq + scale_offset_freq_from_px(evt.pageX); - e("webrx-mouse-freq").innerHTML = format_frequency("{x} MHz", frequency, 1e6, 4); + mouseFrequencyDisplay.setFrequency(frequency); } function scale_canvas_end_drag(x) { @@ -649,7 +646,7 @@ function scale_canvas_end_drag(x) { scale_canvas_drag_params.mouse_down = false; var event_handled = false; for (var i = 0; i < demodulators.length; i++) event_handled |= demodulators[i].envelope.drag_end(); - if (!event_handled) demodulator_set_offset_frequency(0, scale_offset_freq_from_px(x)); + if (!event_handled) demodulators[0].set_offset_frequency(scale_offset_freq_from_px(x)); } function scale_canvas_mouseup(evt) { @@ -916,8 +913,9 @@ function canvas_mousemove(evt) { mkscale(); bookmarks.position(); } + } else { + mouseFrequencyDisplay.setFrequency(canvas_get_frequency(relativeX)); } - else e("webrx-mouse-freq").innerHTML = format_frequency("{x} MHz", canvas_get_frequency(relativeX), 1e6, 4); } function canvas_container_mouseleave() { @@ -929,7 +927,7 @@ function canvas_mouseup(evt) { var relativeX = get_relative_x(evt); if (!canvas_drag) { - demodulator_set_offset_frequency(0, canvas_get_freq_offset(relativeX)); + demodulators[0].set_offset_frequency(canvas_get_freq_offset(relativeX)); } else { canvas_end_drag(); @@ -1534,7 +1532,7 @@ function initialize_demodulator() { demodulator_analog_replace(starting_mod); if (starting_offset_frequency) { demodulators[0].offset_frequency = starting_offset_frequency; - e("webrx-actual-freq").innerHTML = format_frequency("{x} MHz", center_freq + starting_offset_frequency, 1e6, 4); + tunedFrequencyDisplay.setFrequency(center_freq + starting_offset_frequency); demodulators[0].set(); mkscale(); } @@ -1787,6 +1785,11 @@ function openwebrx_init() { secondary_demod_init(); digimodes_init(); initPanels(); + tunedFrequencyDisplay = new TuneableFrequencyDisplay($('#webrx-actual-freq')); + tunedFrequencyDisplay.onFrequencyChange(function(f) { + demodulators[0].set_offset_frequency(f - center_freq); + }); + mouseFrequencyDisplay = new FrequencyDisplay($('#webrx-mouse-freq')); window.addEventListener("resize", openwebrx_resize); check_top_bar_congestion(); init_header(); diff --git a/owrx/source/__init__.py b/owrx/source/__init__.py index 77e56e0..cb050f2 100644 --- a/owrx/source/__init__.py +++ b/owrx/source/__init__.py @@ -145,13 +145,13 @@ class SdrSource(ABC): if len(cmd) > 1: # multiple commands with pipes cmd = "|".join(cmd) - self.process = subprocess.Popen(cmd, shell=True, preexec_fn=os.setpgrp) + self.process = subprocess.Popen(cmd, shell=True, start_new_session=True) else: # single command cmd = cmd[0] - # preexec_fn can go as soon as there's no piped commands left + # start_new_session can go as soon as there's no piped commands left # the os.killpg call must be replaced with something more reasonable at the same time - self.process = subprocess.Popen(shlex.split(cmd), preexec_fn=os.setpgrp) + self.process = subprocess.Popen(shlex.split(cmd), start_new_session=True) logger.info("Started sdr source: " + cmd) available = False