Track browser tab visibility, only activate webcam/gcode viewer when visible

This might help with #1065 if indeed is related to background tab suspending behaviours in
browsers, but is a completely blind guess at this point since I still have not been able to
reproduce that issue myself.
This commit is contained in:
Gina Häußge 2015-11-18 17:13:41 +01:00
parent 50c3f99a42
commit 720cdadfbb
5 changed files with 135 additions and 28 deletions

View file

@ -379,7 +379,7 @@ GCODE.renderer = (function(){
};
var drawLayer = function(layerNum, fromProgress, toProgress, isNotCurrentLayer){
console.log("Drawing layer " + layerNum + " from " + fromProgress + " to " + toProgress + " (current: " + !isNotCurrentLayer + ")");
log.trace("Drawing layer " + layerNum + " from " + fromProgress + " to " + toProgress + " (current: " + !isNotCurrentLayer + ")");
var i;

View file

@ -26,6 +26,71 @@ $(function() {
});
});
//~~ some CoreUI specific stuff we put into OctoPrint.coreui
OctoPrint.coreui = (function() {
var exports = {
browserTabVisibility: undefined,
selectedTab: undefined
};
var browserVisibilityCallbacks = [];
var getHiddenProp = function() {
var prefixes = ["webkit", "moz", "ms", "o"];
// if "hidden" is natively supported just return it
if ("hidden" in document) {
return "hidden"
}
// otherwise loop over all the known prefixes until we find one
var vendorPrefix = _.find(prefixes, function(prefix) {
return (prefix + "Hidden" in document);
});
if (vendorPrefix !== undefined) {
return vendorPrefix + "Hidden";
}
// nothing found
return undefined;
};
var isHidden = function() {
var prop = getHiddenProp();
if (!prop) return false;
return document[prop];
};
var updateBrowserVisibility = function() {
var visible = !isHidden();
exports.browserTabVisible = visible;
_.each(browserVisibilityCallbacks, function(callback) {
callback(visible);
})
};
// register for browser visibility tracking
var prop = getHiddenProp();
if (!prop) return undefined;
var eventName = prop.replace(/[H|h]idden/, "") + "visibilitychange";
document.addEventListener(eventName, updateBrowserVisibility);
updateBrowserVisibility();
// exports
exports.isVisible = function() { return !isHidden() };
exports.onBrowserVisibilityChange = function(callback) {
browserVisibilityCallbacks.push(callback);
};
return exports;
})();
//~~ AJAX setup
// work around a stupid iOS6 bug where ajax requests get cached and only work once, as described at
@ -410,11 +475,17 @@ $(function() {
$('.nav-pills, .nav-tabs').tabdrop();
// Allow components to react to tab change
var onTabChange = function(current, previous) {
log.debug("Selected OctoPrint tab changed: previous = " + previous + ", current = " + current);
OctoPrint.coreui.selectedTab = current;
callViewModels(allViewModels, "onTabChange", [current, previous]);
};
var tabs = $('#tabs a[data-toggle="tab"]');
tabs.on('show', function (e) {
var current = e.target.hash;
var previous = e.relatedTarget.hash;
callViewModels(allViewModels, "onTabChange", [current, previous]);
onTabChange(current, previous);
});
tabs.on('shown', function (e) {
@ -423,6 +494,8 @@ $(function() {
callViewModels(allViewModels, "onAfterTabChange", [current, previous]);
});
onTabChange(OCTOPRINT_INITIAL_TAB);
// Fix input element click problems on dropdowns
$(".dropdown input, .dropdown label").click(function(e) {
e.stopPropagation();
@ -516,7 +589,14 @@ $(function() {
callViewModels(allViewModels, "onAllBound", [allViewModels]);
log.info("... binding done");
// startup complete
callViewModels(allViewModels, "onStartupComplete");
// make sure we can track the browser tab visibility
OctoPrint.coreui.onBrowserVisibilityChange(function(status) {
log.debug("Browser tab is now " + (status ? "visible" : "hidden"));
callViewModels(allViewModels, "onBrowserTabVisibilityChange", [status]);
});
};
if (!_.has(viewModelMap, "settingsViewModel")) {

View file

@ -357,31 +357,51 @@ $(function() {
self.onSettingsBeforeSave = self.updateRotatorWidth;
self._disableWebcam = function() {
// only disable webcam stream if tab is out of focus for more than 5s, otherwise we might cause
// more load by the constant connection creation than by the actual webcam stream
self.webcamDisableTimeout = setTimeout(function () {
$("#webcam_image").attr("src", "");
}, 5000);
};
self._enableWebcam = function() {
if (OctoPrint.coreui.selectedTab != "#control" || !OctoPrint.coreui.browserTabVisible) {
return;
}
if (self.webcamDisableTimeout != undefined) {
clearTimeout(self.webcamDisableTimeout);
}
var webcamImage = $("#webcam_image");
var currentSrc = webcamImage.attr("src");
if (currentSrc === undefined || currentSrc.trim() == "") {
var newSrc = CONFIG_WEBCAM_STREAM;
if (CONFIG_WEBCAM_STREAM.lastIndexOf("?") > -1) {
newSrc += "&";
} else {
newSrc += "?";
}
newSrc += new Date().getTime();
self.updateRotatorWidth();
webcamImage.attr("src", newSrc);
}
};
self.onTabChange = function (current, previous) {
if (current == "#control") {
if (self.webcamDisableTimeout != undefined) {
clearTimeout(self.webcamDisableTimeout);
}
var webcamImage = $("#webcam_image");
var currentSrc = webcamImage.attr("src");
if (currentSrc === undefined || currentSrc.trim() == "") {
var newSrc = CONFIG_WEBCAM_STREAM;
if (CONFIG_WEBCAM_STREAM.lastIndexOf("?") > -1) {
newSrc += "&";
} else {
newSrc += "?";
}
newSrc += new Date().getTime();
self.updateRotatorWidth();
webcamImage.attr("src", newSrc);
}
self._enableWebcam();
} else if (previous == "#control") {
// only disable webcam stream if tab is out of focus for more than 5s, otherwise we might cause
// more load by the constant connection creation than by the actual webcam stream
self.webcamDisableTimeout = setTimeout(function () {
$("#webcam_image").attr("src", "");
}, 5000);
self._disableWebcam();
}
};
self.onBrowserTabVisibilityChange = function(status) {
if (status) {
self._enableWebcam();
} else {
self._disableWebcam();
}
};

View file

@ -356,7 +356,7 @@ $(function() {
if(self.loadedFilename
&& self.loadedFilename == data.job.file.name
&& self.loadedFileDate == data.job.file.date) {
if (self.tabActive && self.currentlyPrinting && self.renderer_syncProgress() && !self.waitForApproval()) {
if (OctoPrint.coreui.browserTabVisible && self.tabActive && self.currentlyPrinting && self.renderer_syncProgress() && !self.waitForApproval()) {
var cmdIndex = GCODE.gCodeReader.getCmdIndexForPercentage(data.progress.completion);
if(cmdIndex){
GCODE.renderer.render(cmdIndex.layer, 0, cmdIndex.cmd);
@ -502,12 +502,11 @@ $(function() {
self.onBeforeBinding = function() {
self.initialize();
}
};
self.onTabChange = function(current, previous) {
self.tabActive = current == "#gcode";
}
};
}
OCTOPRINT_VIEWMODELS.push([

View file

@ -34,4 +34,12 @@
var OCTOPRINT_VIEWMODELS = [];
var ADDITIONAL_VIEWMODELS = [];
var OCTOPRINT_ADDITIONAL_BINDINGS = [];
{% if templates.tab.order %}
{% set first_tab = templates.tab.order[0] %}
{% set entry, data = templates.tab.entries[first_tab] %}
var OCTOPRINT_INITIAL_TAB = "#{{ data._div }}";
{% else %}
var OCTOPRINT_INITIAL_TAB = undefined;
{% endif %}
</script>