Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
The Tor Project
Applications
torbutton
Commits
ddd8a6a7
Commit
ddd8a6a7
authored
Feb 08, 2015
by
Arthur Edelstein
Browse files
Bug #14429: Quantize content window inner width, height
parent
d2c3f9e7
Changes
6
Hide whitespace changes
Inline
Side-by-side
src/chrome/content/content-sizer.js
0 → 100644
View file @
ddd8a6a7
// The purpose of this file is to ensure that window.innerWidth and window.innerHeight
// always return rounded values.
// This file is formatted for docco.js. Later functions call earlier ones.
/* jshint esnext: true */
// __quantizeBrowserSizeOnLoad(window, xStep, yStep)__.
// Once a window is fully loaded, ensures that gBrowser width and height are multiples of
// xStep and yStep.
let
quantizeBrowserSizeOnLoad
=
function
(
window
,
xStep
,
yStep
)
{
// Use Task.jsm to avoid callback hell.
Cu
.
import
(
"
resource://gre/modules/Task.jsm
"
);
// Make the TorButton logger available.
let
logger
=
Cc
[
"
@torproject.org/torbutton-logger;1
"
]
.
getService
(
Components
.
interfaces
.
nsISupports
).
wrappedJSObject
;
// Utility function
let
{
bindPrefAndInit
}
=
Cu
.
import
(
"
resource://torbutton/modules/utils.js
"
);
// __largestMultipleLessThan(factor, max)__.
// Returns the largest number that is a multiple of factor
// and is less or equal to max.
let
largestMultipleLessThan
=
function
(
factor
,
max
)
{
return
Math
.
max
(
1
,
Math
.
floor
((
1
+
max
)
/
factor
,
1
))
*
factor
;
};
// __listen(target, eventType, useCapture, timeoutMs)__.
// Listens for a single event of eventType on target.
// Returns a Promise that resolves to an Event object, if the event fires.
// If a timeout occurs, then Promise is rejected with a "Timed out" error.
let
listen
=
function
(
target
,
eventType
,
useCapture
,
timeoutMs
)
{
return
new
Promise
(
function
(
resolve
,
reject
)
{
let
listenFunction
=
function
(
event
)
{
target
.
removeEventListener
(
eventType
,
listenFunction
,
useCapture
);
resolve
(
event
);
};
target
.
addEventListener
(
eventType
,
listenFunction
,
useCapture
);
if
(
timeoutMs
!==
undefined
&&
timeoutMs
!==
null
)
{
window
.
setTimeout
(
function
()
{
target
.
removeEventListener
(
eventType
,
listenFunction
,
useCapture
);
resolve
(
new
Event
(
"
timeout
"
));
},
timeoutMs
);
}
});
};
// __sleep(time_ms)__.
// Returns a Promise that sleeps for the specified time interval,
// and returns an Event object of type "wake".
let
sleep
=
function
(
timeoutMs
)
{
return
new
Promise
(
function
(
resolve
,
reject
)
{
window
.
setTimeout
(
function
()
{
resolve
(
new
Event
(
"
wake
"
));
},
timeoutMs
);
});
};
// __isNumber(value)__.
// Returns true iff the value is a number.
let
isNumber
=
x
=>
typeof
x
===
"
number
"
;
// __reshape(window, {left, top, width, height}, timeoutMs)__.
// Reshapes the window to rectangle {left, top, width, height} and yields
// until the window reaches its target size, or the timeout occurs.
let
reshape
=
function
*
(
window
,
{
left
,
top
,
width
,
height
},
timeoutMs
)
{
let
finishTime
=
Date
.
now
()
+
timeoutMs
,
x
=
isNumber
(
left
)
?
left
:
window
.
screenX
,
y
=
isNumber
(
top
)
?
top
:
window
.
screenY
,
w
=
isNumber
(
width
)
?
width
:
window
.
outerWidth
,
h
=
isNumber
(
height
)
?
height
:
window
.
outerHeight
;
// Make sure we are in a new event.
yield
sleep
(
0
);
if
(
w
!==
window
.
outerWidth
||
h
!==
window
.
outerWidth
)
{
window
.
resizeTo
(
w
,
h
);
}
if
(
x
!==
window
.
screenX
||
y
!==
window
.
screenY
)
{
window
.
moveTo
(
x
,
y
);
}
// Yield until we have the correct screen position and size, or
// we timeout. Multiple resize events often fire in a resize.
while
(
x
!==
window
.
screenX
||
y
!==
window
.
screenY
||
w
!==
window
.
outerWidth
||
h
!==
window
.
outerHeight
)
{
let
timeLeft
=
finishTime
-
Date
.
now
();
if
(
timeLeft
<=
0
)
break
;
yield
listen
(
window
,
"
resize
"
,
true
,
timeLeft
);
}
};
// __rebuild(window)__.
// Jog the size of the window slightly, to remind the window manager
// to redraw the window.
let
rebuild
=
function
*
(
window
)
{
let
h
=
window
.
outerHeight
;
yield
reshape
(
window
,
{
height
:
(
h
+
1
)},
300
);
yield
reshape
(
window
,
{
height
:
h
},
300
);
};
// __gaps(window)__.
// Deltas between gBrowser and its container. Returns null if there is no gap.
let
gaps
=
function
(
window
)
{
let
gBrowser
=
window
.
gBrowser
,
container
=
gBrowser
.
parentElement
,
deltaWidth
=
Math
.
max
(
0
,
container
.
clientWidth
-
gBrowser
.
clientWidth
-
1
),
deltaHeight
=
Math
.
max
(
0
,
container
.
clientHeight
-
gBrowser
.
clientHeight
-
1
);
//logger.eclog(3, "gaps " + deltaWidth + "," + deltaHeight);
return
(
deltaWidth
===
0
&&
deltaHeight
===
0
)
?
null
:
{
deltaWidth
:
deltaWidth
,
deltaHeight
:
deltaHeight
};
};
// __shrinkwrap(window)__.
// Shrinks the window so that it encloses the gBrowser with no gaps.
let
shrinkwrap
=
function
*
(
window
)
{
// Maximized windows in Linux and Windows need to be demaximized first.
if
(
gaps
(
window
)
&&
window
.
windowState
===
1
&&
/* maximized */
Services
.
appinfo
.
OS
!==
"
Darwin
"
)
{
if
(
Services
.
appinfo
.
OS
!==
"
WINNT
"
)
{
// Linux windows need an extra jolt out of maximized mode.
window
.
moveBy
(
1
,
1
);
}
// If window has been maximized, demaximize by shrinking it to
// fit within the available screen area.
yield
reshape
(
window
,
{
left
:
window
.
screen
.
availLeft
+
1
,
top
:
window
.
screen
.
availTop
+
1
,
width
:
window
.
screen
.
availWidth
-
2
,
height
:
window
.
screen
.
availHeight
-
2
},
500
);
}
// Figure out what size change we need.
let
currentGaps
=
gaps
(
window
);
if
(
currentGaps
)
{
// Now resize to close the gaps.
yield
reshape
(
window
,
{
width
:
(
window
.
outerWidth
-
currentGaps
.
deltaWidth
),
height
:
(
window
.
outerHeight
-
currentGaps
.
deltaHeight
)},
500
);
}
};
// __updateContainerAppearance(container, on)__.
// Get the color and position of margins right.
let
updateContainerAppearance
=
function
(
container
,
on
)
{
// Align the browser at top left, so any gray margin will be visible
// at right and bottom. Except in fullscreen, where we have black
// margins and gBrowser in top center.
container
.
align
=
on
?
(
window
.
fullScreen
?
"
center
"
:
"
start
"
)
:
""
;
container
.
pack
=
on
?
"
start
"
:
""
;
container
.
style
.
backgroundColor
=
on
?
(
window
.
fullScreen
?
"
Black
"
:
"
DimGray
"
)
:
""
;
};
// __fixWindow(window)__.
// An async function for Task.jsm. Makes sure the window looks okay
// given the quantized browser element.
let
fixWindow
=
function
*
(
window
)
{
updateContainerAppearance
(
window
.
gBrowser
.
parentElement
,
true
);
if
(
!
window
.
fullScreen
)
{
yield
shrinkwrap
(
window
);
if
(
Services
.
appinfo
.
OS
!==
"
Darwin
"
&&
Services
.
appinfo
.
OS
!==
"
WINNT
"
)
{
// Linux tends to require us to rebuild the window, or we might be
// left with a large useless white area on the screen.
yield
rebuild
(
window
);
}
}
};
// __autoresize(window, stepMs)__.
// Do what it takes to eliminate the gray margin around the gBrowser inside
// window. Periodically (stepMs) attempt to shrink the window. Runs
// as a Task.jsm coroutine.
let
autoresize
=
function
(
window
,
stepMs
)
{
let
stop
=
false
;
Task
.
spawn
(
function
*
()
{
while
(
!
stop
)
{
// Do nothing until the user starts to resize window.
let
event
=
yield
listen
(
window
,
"
resize
"
,
true
);
// Here we wrestle with the window size. If the user has released the
// mouse cursor on the window's drag/resize handle, then fixWindow
// will resize the window on its first call. Unfortunately, on some
// OSs, the window resize fails if the user is still holding on
// to the drag-resize handle. Even more unfortunately, the
// only way to know that the user no longer has the mouse down
// on the window's drag/resize handle is if we detect the mouse
// cursor inside the window. So until the window fires a mousemove
// event, we repeatedly call fixWindow every stepMs.
while
(
event
.
type
!==
"
mousemove
"
)
{
event
=
yield
Promise
.
race
(
[
listen
(
window
,
"
resize
"
,
true
,
stepMs
),
listen
(
window
,
"
mousemove
"
,
true
,
stepMs
)]);
// If the user has stopped resizing the window after `stepMs`, then we can resize
// the window so no gray margin is visible.
if
(
event
.
type
===
"
timeout
"
||
event
.
type
===
"
mousemove
"
)
{
yield
fixWindow
(
window
);
}
}
}
});
return
()
=>
{
stop
=
true
;
};
};
// __updateDimensions(gBrowser, xStep, yStep)__.
// Changes the width and height of the gBrowser XUL element to be a multiple of x/yStep.
let
updateDimensions
=
function
(
gBrowser
,
xStep
,
yStep
)
{
// TODO: Get zooming to work such that it doesn't cause the window
// to continuously shrink.
// We'll use something like:
// let winUtils = gBrowser.contentWindow
// .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
// .getInterface(Components.interfaces.nsIDOMWindowUtils),
// zoom = winUtils.screenPixelsPerCSSPixel,
let
zoom
=
1
,
parentWidth
=
gBrowser
.
parentElement
.
clientWidth
,
parentHeight
=
gBrowser
.
parentElement
.
clientHeight
,
targetContentWidth
=
largestMultipleLessThan
(
xStep
,
parentWidth
/
zoom
),
targetContentHeight
=
largestMultipleLessThan
(
yStep
,
parentHeight
/
zoom
),
targetBrowserWidth
=
targetContentWidth
*
zoom
,
targetBrowserHeight
=
targetContentHeight
*
zoom
;
// Because gBrowser is inside a vbox, width and height behave differently. It turns
// out we need to set `gBrowser.width` and `gBrowser.maxHeight`.
gBrowser
.
width
=
targetBrowserWidth
;
gBrowser
.
maxHeight
=
targetBrowserHeight
;
// If the content window's innerWidth/innerHeight failed to updated correctly,
// then jog the gBrowser width/height. (With zoom there may also be a rounding
// error, but we can't do much about that.)
if
(
gBrowser
.
contentWindow
.
innerWidth
!==
targetContentWidth
||
gBrowser
.
contentWindow
.
innerHeight
!==
targetContentHeight
)
{
gBrowser
.
width
=
targetBrowserWidth
+
1
;
gBrowser
.
maxHeight
=
gBrowser
.
targetBrowserHeight
+
1
;
gBrowser
.
width
=
targetBrowserWidth
;
gBrowser
.
maxHeight
=
targetBrowserHeight
;
}
logger
.
eclog
(
3
,
"
zoom
"
+
zoom
+
"
X
"
+
"
chromeWin
"
+
window
.
outerWidth
+
"
x
"
+
window
.
outerHeight
+
"
container
"
+
parentWidth
+
"
x
"
+
parentHeight
+
"
gBrowser
"
+
gBrowser
.
clientWidth
+
"
x
"
+
gBrowser
.
clientHeight
+
"
content
"
+
gBrowser
.
contentWindow
.
innerWidth
+
"
x
"
+
gBrowser
.
contentWindow
.
innerHeight
);
};
// __quantizeBrowserSizeNow(window, xStep, yStep)__.
// Ensures that gBrowser width and height are multiples of xStep and yStep, and always as
// large as possible inside the chrome window.
let
quantizeBrowserSizeNow
=
function
(
window
,
xStep
,
yStep
)
{
let
gBrowser
=
window
.
gBrowser
,
container
=
window
.
gBrowser
.
parentElement
,
updater
=
event
=>
updateDimensions
(
gBrowser
,
xStep
,
yStep
),
originalMinWidth
=
gBrowser
.
minWidth
,
originalMinHeight
=
gBrowser
.
minHeight
,
stopAutoresizing
,
activate
=
function
(
on
)
{
// Don't let the browser shrink below a single xStep x yStep size.
gBrowser
.
minWidth
=
on
?
xStep
:
originalMinWidth
;
gBrowser
.
minHeight
=
on
?
yStep
:
originalMinHeight
;
updateContainerAppearance
(
container
,
on
);
if
(
on
)
{
// Quantize browser size on activation.
updateDimensions
(
gBrowser
,
xStep
,
yStep
);
shrinkwrap
(
window
);
// Quantize browser size at subsequent resize events.
window
.
addEventListener
(
"
resize
"
,
updater
,
false
);
stopAutoresizing
=
autoresize
(
window
,
250
);
}
else
{
if
(
stopAutoresizing
)
stopAutoresizing
();
// Ignore future resize events.
window
.
removeEventListener
(
"
resize
"
,
updater
,
false
);
// Let gBrowser expand with its parent vbox.
gBrowser
.
width
=
""
;
gBrowser
.
maxHeight
=
""
;
}
};
bindPrefAndInit
(
"
extensions.torbutton.resize_windows
"
,
activate
);
};
let
onLoad
=
()
=>
quantizeBrowserSizeNow
(
window
,
xStep
,
yStep
);
window
.
gBrowser
.
addEventListener
(
"
load
"
,
onLoad
,
true
);
return
()
=>
window
.
gBrowser
.
removeEventListener
(
"
load
"
,
onLoad
,
true
);
// quantizeBrowserSizeOnLoad
};
src/chrome/content/tor-circuit-display.js
View file @
ddd8a6a7
...
...
@@ -32,6 +32,9 @@ Cu.import("resource://gre/modules/Task.jsm");
// Import the controller code.
let
{
controller
}
=
Cu
.
import
(
"
resource://torbutton/modules/tor-control-port.js
"
);
// Utility functions
let
{
bindPrefAndInit
}
=
Cu
.
import
(
"
resource://torbutton/modules/utils.js
"
);
// Make the TorButton logger available.
let
logger
=
Cc
[
"
@torproject.org/torbutton-logger;1
"
]
.
getService
(
Components
.
interfaces
.
nsISupports
).
wrappedJSObject
;
...
...
@@ -303,38 +306,6 @@ let syncDisplayWithSelectedTab = (function() {
};
})();
// ## Pref utils
// __prefs__. A shortcut to Mozilla Services.prefs.
let
prefs
=
Services
.
prefs
;
// __getPrefValue(prefName)__
// Returns the current value of a preference, regardless of its type.
let
getPrefValue
=
function
(
prefName
)
{
switch
(
prefs
.
getPrefType
(
prefName
))
{
case
prefs
.
PREF_BOOL
:
return
prefs
.
getBoolPref
(
prefName
);
case
prefs
.
PREF_INT
:
return
prefs
.
getIntPref
(
prefName
);
case
prefs
.
PREF_STRING
:
return
prefs
.
getCharPref
(
prefName
);
default
:
return
null
;
}
};
// __bindPrefAndInit(prefName, prefHandler)__
// Applies prefHandler to the current value of pref specified by prefName.
// Re-applies prefHandler whenever the value of the pref changes.
// Returns a zero-arg function that unbinds the pref.
let
bindPrefAndInit
=
function
(
prefName
,
prefHandler
)
{
let
update
=
()
=>
{
prefHandler
(
getPrefValue
(
prefName
));
},
observer
=
{
observe
:
function
(
subject
,
topic
,
data
)
{
if
(
data
===
prefName
)
{
update
();
}
}
};
prefs
.
addObserver
(
prefName
,
observer
,
false
);
update
();
return
()
=>
{
prefs
.
removeObserver
(
prefName
,
observer
);
};
};
// ## Main function
// setupDisplay(host, port, password, enablePrefName)__.
...
...
src/chrome/content/torbutton.js
View file @
ddd8a6a7
...
...
@@ -636,6 +636,8 @@ function torbutton_init() {
createTorCircuitDisplay
(
m_tb_control_host
,
m_tb_control_port
,
m_tb_control_pass
,
"
extensions.torbutton.display_circuit
"
);
quantizeBrowserSizeOnLoad
(
window
,
200
,
100
);
torbutton_log
(
3
,
'
init completed
'
);
}
...
...
src/chrome/content/torbutton.xul
View file @
ddd8a6a7
...
...
@@ -9,6 +9,7 @@
<script
type=
"application/x-javascript"
src=
"chrome://torbutton/content/torbutton_util.js"
/>
<script
type=
"application/x-javascript"
src=
"chrome://torbutton/content/tor-circuit-display.js"
/>
<script
type=
"application/x-javascript"
src=
"chrome://torbutton/content/content-sizer.js"
/>
<script
type=
"application/x-javascript"
src=
"chrome://torbutton/content/torbutton.js"
/>
<script
language=
"JavaScript"
>
//onLoad Hander
...
...
src/defaults/preferences/preferences.js
View file @
ddd8a6a7
...
...
@@ -159,6 +159,7 @@ pref("extensions.torbutton.close_newnym",true);
pref
(
"
extensions.torbutton.block_js_history
"
,
true
);
pref
(
"
extensions.torbutton.resize_on_toggle
"
,
true
);
pref
(
"
extensions.torbutton.resize_new_windows
"
,
true
);
pref
(
"
extensions.torbutton.resize_windows
"
,
true
);
pref
(
"
extensions.torbutton.banned_ports
"
,
"
9050,9051,9150,9151
"
);
pref
(
"
extensions.torbutton.block_tor_file_net
"
,
true
);
pref
(
"
extensions.torbutton.block_nontor_file_net
"
,
false
);
...
...
src/modules/utils.js
0 → 100644
View file @
ddd8a6a7
// # Utils.js
// Various helpful utility functions.
// ### Shortcut
const
Cu
=
Components
.
utils
;
// ### Import Mozilla Services
Cu
.
import
(
"
resource://gre/modules/Services.jsm
"
);
// ## Pref utils
// __prefs__. A shortcut to Mozilla Services.prefs.
let
prefs
=
Services
.
prefs
;
// __getPrefValue(prefName)__
// Returns the current value of a preference, regardless of its type.
let
getPrefValue
=
function
(
prefName
)
{
switch
(
prefs
.
getPrefType
(
prefName
))
{
case
prefs
.
PREF_BOOL
:
return
prefs
.
getBoolPref
(
prefName
);
case
prefs
.
PREF_INT
:
return
prefs
.
getIntPref
(
prefName
);
case
prefs
.
PREF_STRING
:
return
prefs
.
getCharPref
(
prefName
);
default
:
return
null
;
}
};
// __bindPrefAndInit(prefName, prefHandler)__
// Applies prefHandler to the current value of pref specified by prefName.
// Re-applies prefHandler whenever the value of the pref changes.
// Returns a zero-arg function that unbinds the pref.
let
bindPrefAndInit
=
function
(
prefName
,
prefHandler
)
{
let
update
=
()
=>
{
prefHandler
(
getPrefValue
(
prefName
));
},
observer
=
{
observe
:
function
(
subject
,
topic
,
data
)
{
if
(
data
===
prefName
)
{
update
();
}
}
};
prefs
.
addObserver
(
prefName
,
observer
,
false
);
update
();
return
()
=>
{
prefs
.
removeObserver
(
prefName
,
observer
);
};
};
// Export utility functions for external use.
let
EXPORTED_SYMBOLS
=
[
"
bindPrefAndInit
"
,
"
getPrefValue
"
];
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment