mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 944443 - Uplift rotation feature from simulator to b2g desktop. r=vingtetun
This commit is contained in:
parent
774578ba82
commit
68ca432d8e
@ -34,3 +34,26 @@
|
||||
background-color: #888;
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
#rotate-button {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
bottom: 3px;
|
||||
right: 3px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: #eee url("images/desktop/rotate.png") center no-repeat;
|
||||
border: 1px solid #888;
|
||||
border-radius: 12px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#rotate-button:hover {
|
||||
background-color: #ccc;
|
||||
border-color: #555;
|
||||
}
|
||||
|
||||
#rotate-button.active {
|
||||
background-color: #888;
|
||||
border-color: black;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ function enableTouch() {
|
||||
touchEventHandler.start();
|
||||
}
|
||||
|
||||
function setupHomeButton() {
|
||||
function setupButtons() {
|
||||
let homeButton = document.getElementById('home-button');
|
||||
if (!homeButton) {
|
||||
// The toolbar only exists in b2g desktop build with
|
||||
@ -34,9 +34,19 @@ function setupHomeButton() {
|
||||
shell.sendChromeEvent({type: 'home-button-release'});
|
||||
homeButton.classList.remove('active');
|
||||
});
|
||||
|
||||
Cu.import("resource://gre/modules/GlobalSimulatorScreen.jsm");
|
||||
let rotateButton = document.getElementById('rotate-button');
|
||||
rotateButton.addEventListener('touchstart', function () {
|
||||
rotateButton.classList.add('active');
|
||||
});
|
||||
rotateButton.addEventListener('touchend', function() {
|
||||
GlobalSimulatorScreen.flipScreen();
|
||||
rotateButton.classList.remove('active');
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('ContentStart', function() {
|
||||
enableTouch();
|
||||
setupHomeButton();
|
||||
setupButtons();
|
||||
});
|
||||
|
BIN
b2g/chrome/content/images/desktop/rotate.png
Normal file
BIN
b2g/chrome/content/images/desktop/rotate.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 657 B |
@ -18,7 +18,7 @@ window.addEventListener('ContentStart', function() {
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
let hostDPI = windowUtils.displayDPI;
|
||||
|
||||
let DEFAULT_SCREEN = "320x480";
|
||||
let DEFAULT_SCREEN = '320x480';
|
||||
|
||||
// This is a somewhat random selection of named screens.
|
||||
// Add more to this list when we support more hardware.
|
||||
@ -120,43 +120,93 @@ window.addEventListener('ContentStart', function() {
|
||||
if (!width || !height || !dpi)
|
||||
usage();
|
||||
}
|
||||
|
||||
// In order to do rescaling, we set the <browser> tag to the specified
|
||||
// width and height, and then use a CSS transform to scale it so that
|
||||
// it appears at the correct size on the host display. We also set
|
||||
// the size of the <window> element to that scaled target size.
|
||||
let scale = rescale ? hostDPI / dpi : 1;
|
||||
|
||||
// Set the window width and height to desired size plus chrome
|
||||
// Set the window width and height to desired size plus chrome
|
||||
// Include the size of the toolbox displayed under the system app
|
||||
let controls = document.getElementById('controls');
|
||||
let controlsHeight = 0;
|
||||
if (controls) {
|
||||
controlsHeight = controls.getBoundingClientRect().height;
|
||||
}
|
||||
let chromewidth = window.outerWidth - window.innerWidth;
|
||||
let chromeheight = window.outerHeight - window.innerHeight + controlsHeight;
|
||||
window.resizeTo(Math.round(width * scale) + chromewidth,
|
||||
Math.round(height * scale) + chromeheight);
|
||||
Cu.import("resource://gre/modules/GlobalSimulatorScreen.jsm");
|
||||
function resize(width, height, dpi, shouldFlip) {
|
||||
GlobalSimulatorScreen.width = width;
|
||||
GlobalSimulatorScreen.height = height;
|
||||
|
||||
// Set the browser element to the full unscaled size of the screen
|
||||
browser.style.width = browser.style.minWidth = browser.style.maxWidth =
|
||||
width + 'px';
|
||||
browser.style.height = browser.style.minHeight = browser.style.maxHeight =
|
||||
height + 'px';
|
||||
browser.setAttribute('flex', '0'); // Don't let it stretch
|
||||
// In order to do rescaling, we set the <browser> tag to the specified
|
||||
// width and height, and then use a CSS transform to scale it so that
|
||||
// it appears at the correct size on the host display. We also set
|
||||
// the size of the <window> element to that scaled target size.
|
||||
let scale = rescale ? hostDPI / dpi : 1;
|
||||
|
||||
// Now scale the browser element as needed
|
||||
if (scale !== 1) {
|
||||
browser.style.transformOrigin = 'top left';
|
||||
browser.style.transform = 'scale(' + scale + ',' + scale + ')';
|
||||
// Set the window width and height to desired size plus chrome
|
||||
// Include the size of the toolbox displayed under the system app
|
||||
let controls = document.getElementById('controls');
|
||||
let controlsHeight = 0;
|
||||
if (controls) {
|
||||
controlsHeight = controls.getBoundingClientRect().height;
|
||||
}
|
||||
let chromewidth = window.outerWidth - window.innerWidth;
|
||||
let chromeheight = window.outerHeight - window.innerHeight + controlsHeight;
|
||||
window.resizeTo(Math.round(width * scale) + chromewidth,
|
||||
Math.round(height * scale) + chromeheight);
|
||||
|
||||
let frameWidth = width, frameHeight = height;
|
||||
if (shouldFlip) {
|
||||
frameWidth = height;
|
||||
frameHeight = width;
|
||||
}
|
||||
|
||||
// Set the browser element to the full unscaled size of the screen
|
||||
let style = browser.style;
|
||||
style.width = style.minWidth = style.maxWidth =
|
||||
frameWidth + 'px';
|
||||
style.height = style.minHeight = style.maxHeight =
|
||||
frameHeight + 'px';
|
||||
browser.setAttribute('flex', '0'); // Don't let it stretch
|
||||
|
||||
style.transformOrigin = '';
|
||||
style.transform = '';
|
||||
|
||||
// Now scale the browser element as needed
|
||||
if (scale !== 1) {
|
||||
style.transformOrigin = 'top left';
|
||||
style.transform += ' scale(' + scale + ',' + scale + ')';
|
||||
}
|
||||
|
||||
if (shouldFlip) {
|
||||
// Display the system app with a 90° clockwise rotation
|
||||
let shift = Math.floor(Math.abs(frameWidth-frameHeight) / 2);
|
||||
style.transform +=
|
||||
' rotate(0.25turn) translate(-' + shift + 'px, -' + shift + 'px)';
|
||||
}
|
||||
|
||||
// Set the pixel density that we want to simulate.
|
||||
// This doesn't change the on-screen size, but makes
|
||||
// CSS media queries and mozmm units work right.
|
||||
Services.prefs.setIntPref('layout.css.dpi', dpi);
|
||||
}
|
||||
|
||||
// Set the pixel density that we want to simulate.
|
||||
// This doesn't change the on-screen size, but makes
|
||||
// CSS media queries and mozmm units work right.
|
||||
Services.prefs.setIntPref('layout.css.dpi', dpi);
|
||||
// Resize on startup
|
||||
resize(width, height, dpi, false);
|
||||
|
||||
let defaultOrientation = width < height ? 'portrait' : 'landscape';
|
||||
|
||||
// Then resize on each rotation button click,
|
||||
// or when the system app lock/unlock the orientation
|
||||
Services.obs.addObserver(function orientationChangeListener(subject) {
|
||||
let screen = subject.wrappedJSObject;
|
||||
let { mozOrientation, screenOrientation } = screen;
|
||||
|
||||
let newWidth = width;
|
||||
let newHeight = height;
|
||||
// If we have an orientation different than the startup one,
|
||||
// we switch the sizes
|
||||
if (screenOrientation != defaultOrientation) {
|
||||
newWidth = height;
|
||||
newHeight = width;
|
||||
}
|
||||
|
||||
// If the current app doesn't supports the current screen orientation
|
||||
// still resize the window, but rotate its frame so that
|
||||
// it is displayed rotated on the side
|
||||
let shouldFlip = mozOrientation != screenOrientation;
|
||||
|
||||
resize(newWidth, newHeight, dpi, shouldFlip);
|
||||
}, 'simulator-adjust-window-size', false);
|
||||
|
||||
// A utility function like console.log() for printing to the terminal window
|
||||
// Uses dump(), but enables it first, if necessary
|
||||
@ -164,7 +214,7 @@ window.addEventListener('ContentStart', function() {
|
||||
let dump_enabled =
|
||||
Services.prefs.getBoolPref('browser.dom.window.dump.enabled');
|
||||
|
||||
if (!dump_enabled)
|
||||
if (!dump_enabled)
|
||||
Services.prefs.setBoolPref('browser.dom.window.dump.enabled', true);
|
||||
|
||||
dump(Array.prototype.join.call(arguments, ' ') + '\n');
|
||||
|
@ -41,6 +41,7 @@
|
||||
-->
|
||||
<footer id="controls">
|
||||
<button id="home-button"></button>
|
||||
<button id="rotate-button"></button>
|
||||
</footer>
|
||||
#elifdef MOZ_WIDGET_COCOA
|
||||
<!--
|
||||
|
@ -18,6 +18,7 @@ chrome.jar:
|
||||
content/desktop.css (content/desktop.css)
|
||||
content/images/desktop/home-black.png (content/images/desktop/home-black.png)
|
||||
content/images/desktop/home-white.png (content/images/desktop/home-white.png)
|
||||
content/images/desktop/rotate.png (content/images/desktop/rotate.png)
|
||||
#endif
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
content/desktop.js (content/desktop.js)
|
||||
|
@ -81,3 +81,9 @@ contract @mozilla.org/fxaccounts/fxaccounts-ui-glue;1 {51875c14-91d7-4b8c-b65d-3
|
||||
# HelperAppDialog.js
|
||||
component {710322af-e6ae-4b0c-b2c9-1474a87b077e} HelperAppDialog.js
|
||||
contract @mozilla.org/helperapplauncherdialog;1 {710322af-e6ae-4b0c-b2c9-1474a87b077e}
|
||||
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
component {c83c02c0-5d43-4e3e-987f-9173b313e880} SimulatorScreen.js
|
||||
contract @mozilla.org/simulator-screen;1 {c83c02c0-5d43-4e3e-987f-9173b313e880}
|
||||
category profile-after-change SimulatorScreen @mozilla.org/simulator-screen;1
|
||||
#endif
|
||||
|
90
b2g/components/GlobalSimulatorScreen.jsm
Normal file
90
b2g/components/GlobalSimulatorScreen.jsm
Normal file
@ -0,0 +1,90 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ 'GlobalSimulatorScreen' ];
|
||||
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
this.GlobalSimulatorScreen = {
|
||||
mozOrientationLocked: false,
|
||||
|
||||
// Actual orientation of apps
|
||||
mozOrientation: 'portrait',
|
||||
|
||||
// The restricted list of actual orientation that can be used
|
||||
// if mozOrientationLocked is true
|
||||
lockedOrientation: [],
|
||||
|
||||
// The faked screen orientation
|
||||
// if screenOrientation doesn't match mozOrientation due
|
||||
// to lockedOrientation restriction, the app will be displayed
|
||||
// on the side on desktop
|
||||
screenOrientation: 'portrait',
|
||||
|
||||
// Updated by screen.js
|
||||
width: 0, height: 0,
|
||||
|
||||
lock: function(orientation) {
|
||||
this.mozOrientationLocked = true;
|
||||
|
||||
// Normalize to portrait or landscape,
|
||||
// i.e. the possible values of screenOrientation
|
||||
function normalize(str) {
|
||||
if (str.match(/^portrait/)) {
|
||||
return 'portrait';
|
||||
} else if (str.match(/^landscape/)) {
|
||||
return 'landscape';
|
||||
} else {
|
||||
return 'portrait';
|
||||
}
|
||||
}
|
||||
this.lockedOrientation = orientation.map(normalize);
|
||||
|
||||
this.updateOrientation();
|
||||
},
|
||||
|
||||
unlock: function() {
|
||||
this.mozOrientationLocked = false;
|
||||
this.updateOrientation();
|
||||
},
|
||||
|
||||
updateOrientation: function () {
|
||||
let orientation = this.screenOrientation;
|
||||
|
||||
// If the orientation is locked, we have to ensure ending up with a value
|
||||
// of lockedOrientation. If none of lockedOrientation values matches
|
||||
// the screen orientation we just choose the first locked orientation.
|
||||
// This will be the precise scenario where the app is displayed on the
|
||||
// side on desktop!
|
||||
if (this.mozOrientationLocked &&
|
||||
this.lockedOrientation.indexOf(this.screenOrientation) == -1) {
|
||||
orientation = this.lockedOrientation[0];
|
||||
}
|
||||
|
||||
// If the actual orientation changed,
|
||||
// we have to fire mozorientation DOM events
|
||||
if (this.mozOrientation != orientation) {
|
||||
this.mozOrientation = orientation;
|
||||
|
||||
// Notify each app screen object to fire the event
|
||||
Services.obs.notifyObservers(null, 'simulator-orientation-change', null);
|
||||
}
|
||||
|
||||
// Finally, in any case, we update the window size and orientation
|
||||
// (Use wrappedJSObject trick to be able to pass a raw JS object)
|
||||
Services.obs.notifyObservers({wrappedJSObject:this}, 'simulator-adjust-window-size', null);
|
||||
},
|
||||
|
||||
flipScreen: function() {
|
||||
if (this.screenOrientation == 'portrait') {
|
||||
this.screenOrientation = 'landscape';
|
||||
} else if (this.screenOrientation == 'landscape') {
|
||||
this.screenOrientation = 'portrait';
|
||||
}
|
||||
this.updateOrientation();
|
||||
}
|
||||
}
|
112
b2g/components/SimulatorScreen.js
Normal file
112
b2g/components/SimulatorScreen.js
Normal file
@ -0,0 +1,112 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
let Ci = Components.interfaces;
|
||||
let Cu = Components.utils;
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import('resource://gre/modules/DOMRequestHelper.jsm');
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'GlobalSimulatorScreen',
|
||||
'resource://gre/modules/GlobalSimulatorScreen.jsm');
|
||||
|
||||
let DEBUG_PREFIX = 'SimulatorScreen.js - ';
|
||||
function debug() {
|
||||
//dump(DEBUG_PREFIX + Array.slice(arguments) + '\n');
|
||||
}
|
||||
|
||||
function fireOrientationEvent(window) {
|
||||
let e = new window.Event('mozorientationchange');
|
||||
window.screen.dispatchEvent(e);
|
||||
}
|
||||
|
||||
function hookScreen(window) {
|
||||
let nodePrincipal = window.document.nodePrincipal;
|
||||
let origin = nodePrincipal.origin;
|
||||
if (nodePrincipal.appStatus == nodePrincipal.APP_STATUS_NOT_INSTALLED) {
|
||||
Cu.reportError('deny mozLockOrientation:' + origin + 'is not installed');
|
||||
return;
|
||||
}
|
||||
|
||||
let screen = window.wrappedJSObject.screen;
|
||||
|
||||
screen.mozLockOrientation = function (orientation) {
|
||||
debug('mozLockOrientation:', orientation, 'from', origin);
|
||||
|
||||
// Normalize and do some checks against orientation input
|
||||
if (typeof(orientation) == 'string') {
|
||||
orientation = [orientation];
|
||||
}
|
||||
|
||||
function isInvalidOrientationString(str) {
|
||||
return typeof(str) != 'string' ||
|
||||
!str.match(/^default$|^(portrait|landscape)(-(primary|secondary))?$/);
|
||||
}
|
||||
if (!Array.isArray(orientation) ||
|
||||
orientation.some(isInvalidOrientationString)) {
|
||||
Cu.reportError('Invalid orientation "' + orientation + '"');
|
||||
return false;
|
||||
}
|
||||
|
||||
GlobalSimulatorScreen.lock(orientation);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
screen.mozUnlockOrientation = function() {
|
||||
debug('mozOrientationUnlock from', origin);
|
||||
GlobalSimulatorScreen.unlock();
|
||||
return true;
|
||||
};
|
||||
|
||||
Object.defineProperty(screen, 'width', {
|
||||
get: function () GlobalSimulatorScreen.width
|
||||
});
|
||||
Object.defineProperty(screen, 'height', {
|
||||
get: function () GlobalSimulatorScreen.height
|
||||
});
|
||||
Object.defineProperty(screen, 'mozOrientation', {
|
||||
get: function () GlobalSimulatorScreen.mozOrientation
|
||||
});
|
||||
}
|
||||
|
||||
function SimulatorScreen() {}
|
||||
SimulatorScreen.prototype = {
|
||||
classID: Components.ID('{c83c02c0-5d43-4e3e-987f-9173b313e880}'),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
_windows: new Set(),
|
||||
|
||||
observe: function (subject, topic, data) {
|
||||
switch (topic) {
|
||||
case 'profile-after-change':
|
||||
Services.obs.addObserver(this, 'document-element-inserted', false);
|
||||
Services.obs.addObserver(this, 'simulator-orientation-change', false);
|
||||
break;
|
||||
|
||||
case 'document-element-inserted':
|
||||
let window = subject.defaultView;
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
hookScreen(window);
|
||||
|
||||
let windows = this._windows;
|
||||
window.addEventListener('unload', function unload() {
|
||||
window.removeEventListener('unload', unload);
|
||||
windows.delete(window);
|
||||
});
|
||||
windows.add(window);
|
||||
break;
|
||||
|
||||
case 'simulator-orientation-change':
|
||||
this._windows.forEach(fireOrientationEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SimulatorScreen]);
|
@ -23,6 +23,11 @@ EXTRA_COMPONENTS += [
|
||||
'YoutubeProtocolHandler.js',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
|
||||
EXTRA_COMPONENTS += [
|
||||
'SimulatorScreen.js'
|
||||
]
|
||||
|
||||
EXTRA_PP_COMPONENTS += [
|
||||
'B2GComponents.manifest',
|
||||
'DirectoryProvider.js',
|
||||
@ -41,6 +46,11 @@ EXTRA_JS_MODULES += [
|
||||
'WebappsUpdater.jsm',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
|
||||
EXTRA_JS_MODULES += [
|
||||
'GlobalSimulatorScreen.jsm'
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_SERVICES_FXACCOUNTS']:
|
||||
EXTRA_COMPONENTS += [
|
||||
'FxAccountsUIGlue.js'
|
||||
|
Loading…
Reference in New Issue
Block a user