Add 'start_hidden' capability for winnt.

This commit is contained in:
foudfou 2014-04-12 15:16:09 +02:00
parent 74ac8d54d7
commit f1c5c02c8f
9 changed files with 129 additions and 41 deletions

View File

@ -68,8 +68,8 @@ var firetrayUIOptions = {
hideUnsupportedOptions: function() { // full_feat
// windows prefs
['ui_hides_last_only', 'ui_start_hidden', 'ui_show_activates',
'ui_remember_desktop'].forEach(function(id){
['ui_hides_last_only', 'ui_show_activates', 'ui_remember_desktop']
.forEach(function(id){
document.getElementById(id).hidden = true;
});

View File

@ -143,7 +143,6 @@ var firetrayChrome = { // each new window gets a new firetrayChrome !
}
}
};
// should be sufficient for a delayed Startup (no need for window.setTimeout())

View File

@ -319,7 +319,7 @@ firetray.Handler = {
} else {
for (let winId in firetray.Handler.windows) {
firetray.Chat.detachSelectListeners(firetray.Handler.windows[winId].chromeWin);
firetray.ChatStatusIcon.detachOnFocusInCallback(winId);
firetray.ChatStatusIcon.detachOnFocusInCallback(winId); // FIXME: to be removed
}
firetray.Chat.shutdown();
}
@ -709,7 +709,7 @@ firetray.VersionChangeHandler = {
"hide_show_mm_key", "accounts_to_exclude" ];
let v0_4_0b2_Opts = [ 'mail_notification' ];
let v0_5_0b1_Opts = [ 'mail_urgency_hint', 'app_icon_filename', 'custom_mail_icon' ];
let oldOpt = v0_3_Opts.concat(v0_4_0b2_Opts).concat(v0_5_0b1_Opts);
let oldOpts = v0_3_Opts.concat(v0_4_0b2_Opts).concat(v0_5_0b1_Opts);
for (let i = 0, length = oldOpts.length; i<length; ++i) {
try {

View File

@ -362,6 +362,19 @@ function user32_defines(lib) {
lib.lazy_bind("GetCursorPos", win32.BOOL, win32.LPPOINT);
lib.lazy_bind("GetMessagePos", win32.DWORD);
this.WINDOWPLACEMENT = ctypes.StructType("WINDOWPLACEMENT", [
{ "length": win32.UINT },
{ "flags": win32.UINT },
{ "showCmd": win32.UINT },
{ "ptMinPosition": win32.POINT },
{ "ptMaxPosition": win32.POINT },
{ "rcNormalPosition": win32.RECT }
]);
this.PWINDOWPLACEMENT = this.LPWINDOWPLACEMENT = this.WINDOWPLACEMENT.ptr;
lib.lazy_bind("GetWindowPlacement", win32.BOOL, win32.HWND, this.WINDOWPLACEMENT.ptr);
lib.lazy_bind("SetWindowPlacement", win32.BOOL, win32.HWND, this.WINDOWPLACEMENT.ptr);
}
new ctypes_library(USER32_LIBNAME, USER32_ABIS, user32_defines, this);

View File

@ -121,6 +121,15 @@ var win32 = new function() {
this.WM_SHOWWINDOW = 0x0018;
this.WM_WININICHANGE = 0x001A;
this.WM_SETTINGCHANGE = this.WM_WININICHANGE;
this.WM_DEVMODECHANGE = 0x001B;
this.WM_ACTIVATEAPP = 0x001C;
this.WM_FONTCHANGE = 0x001D;
this.WM_TIMECHANGE = 0x001E;
this.WM_CANCELMODE = 0x001F;
this.WM_SETCURSOR = 0x0020;
this.WM_MOUSEACTIVATE = 0x0021;
this.WM_CHILDACTIVATE = 0x0022;
this.WM_QUEUESYNC = 0x0023;
this.WM_COMMAND = 0x0111;
this.WM_SYSCOMMAND = 0x0112;
this.WM_HSCROLL = 0x0114;
@ -153,6 +162,12 @@ var win32 = new function() {
this.SC_MINIMIZE = 0xF020;
this.SC_CLOSE = 0xF060;
this.SIZE_RESTORED = 0;
this.SIZE_MINIMIZED = 1;
this.SIZE_MAXIMIZED = 2;
this.SIZE_MAXSHOW = 3;
this.SIZE_MAXHIDE = 4;
this.BITMAP = ctypes.StructType("BITMAP", [
{ "bmType": this.LONG },
{ "bmWidth": this.LONG },

View File

@ -563,6 +563,9 @@ firetray.Window.startupFilter = function(xev, gdkEv, data) {
let xany = ctypes.cast(xev, x11.XAnyEvent.ptr);
let xid = xany.contents.window;
// MapRequest already taken by window manager. Not sure we could be notified
// *before* the window is actually mapped, in order to minimize it before
// it's shown.
if (xany.contents.type === x11.MapNotify) {
gdk.gdk_window_remove_filter(firetray.Handler.gdkWindows.get(xid),
firetray.Handler.windows[xid].startupFilterCb, null);

View File

@ -228,12 +228,11 @@ firetray.StatusIcon = {
proxyWndProc: function(hWnd, uMsg, wParam, lParam) {
// log.debug("ProxyWindowProc CALLED: hWnd="+hWnd+", uMsg="+uMsg+", wParam="+wParam+", lParam="+lParam);
// FIXME: WM_TASKBARCREATED is needed in case of explorer crash
// http://twigstechtips.blogspot.fr/2011/02/c-detect-when-windows-explorer-has.html
if (uMsg === firetray.Win32.WM_TASKBARCREATED) {
log.info("____________TASKBARCREATED");
} else if (uMsg === firetray.Win32.WM_TRAYMESSAGEFWD) {
log.debug("ProxyWindowProc WM_TRAYMESSAGEFWD reached!");
} else if (uMsg === firetray.Win32.WM_TRAYMESSAGE) {
switch (win32.LOWORD(lParam)) {

View File

@ -16,11 +16,11 @@ firetray.Handler.subscribeLibsForClosing([kernel32, user32]);
let log = firetray.Logging.getLogger("firetray.Win32");
const kMessageTray = "_FIRETRAY_Tray";
const kMessageTrayFwd = "_FIRETRAY_TrayFwd";
if ("undefined" == typeof(firetray.Handler))
log.error("This module MUST be imported from/after FiretrayHandler !");
function Win32Env() {
this.hInstance = kernel32.GetModuleHandleW("xul"); // ordinary windows are created from xul.dll
@ -29,7 +29,6 @@ function Win32Env() {
// we use our own messages because we create a different window class than Moz
this.WM_TASKBARCREATED = user32.RegisterWindowMessageW("TaskbarCreated");
this.WM_TRAYMESSAGE = user32.RegisterWindowMessageW(kMessageTray);
this.WM_TRAYMESSAGEFWD = user32.RegisterWindowMessageW(kMessageTrayFwd);
log.debug("WM_*="+this.WM_TASKBARCREATED+" "+this.WM_TRAYMESSAGE+" "+this.WM_TRAYCALLBACK);
/* if Administrator, accept messages from applications running in a lower

View File

@ -8,12 +8,13 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://firetray/ctypes/ctypesMap.jsm");
Cu.import("resource://firetray/ctypes/winnt/win32.jsm");
Cu.import("resource://firetray/ctypes/winnt/kernel32.jsm");
Cu.import("resource://firetray/ctypes/winnt/user32.jsm");
Cu.import("resource://firetray/ctypes/winnt/win32.jsm");
Cu.import("resource://firetray/winnt/FiretrayWin32.jsm");
Cu.import("resource://firetray/FiretrayWindow.jsm");
Cu.import("resource://firetray/commons.js");
firetray.Handler.subscribeLibsForClosing([user32]);
firetray.Handler.subscribeLibsForClosing([user32, kernel32]);
let log = firetray.Logging.getLogger("firetray.Window");
@ -25,8 +26,10 @@ const FIRETRAY_XWINDOW_MAXIMIZED = 1 << 1;
// We need to keep long-living references to wndProcs callbacks. As they also
// happen to be ctypes pointers, we store them into real ctypes arrays.
firetray.Handler.wndProcs = new ctypesMap(user32.WNDPROC);
firetray.Handler.wndProcsOrig = new ctypesMap(user32.WNDPROC);
firetray.Handler.wndProcs = new ctypesMap(user32.WNDPROC);
firetray.Handler.wndProcsOrig = new ctypesMap(user32.WNDPROC);
firetray.Handler.procHooks = new ctypesMap(win32.HHOOK);
firetray.Handler.procHooksRegistred = new ctypesMap(win32.HHOOK);
firetray.Window = new FiretrayWindow();
@ -54,23 +57,10 @@ firetray.Window.setVisibility = function(wid, visible) {
};
firetray.Window.wndProc = function(hWnd, uMsg, wParam, lParam) { // filterWindow
// log.debug("wndProc CALLED: hWnd="+hWnd+", uMsg="+uMsg+", wParam="+wParam+", lParam="+lParam);
// log.debug("wndProc CALLED: hWnd="+hWnd+", uMsg=0x"+uMsg.toString(16)+", wParam="+wParam+", lParam="+lParam);
let wid = firetray.Win32.hwndToHexStr(hWnd);
if (uMsg === firetray.Win32.WM_TRAYMESSAGE) {
log.debug("wndProc CALLED with WM_TRAYMESSAGE");
} else if (uMsg === firetray.Win32.WM_TRAYMESSAGEFWD) {
log.debug("wndProc CALLED with WM_TRAYMESSAGEFWD");
} else if (uMsg === win32.WM_USER) {
log.debug("wndProc CALLED with WM_USER");
} else if (uMsg === win32.WM_CLOSE) {
log.debug("wndProc CALLED with WM_CLOSE");
} else if (uMsg === win32.WM_SYSCOMMAND) {
// FIXME: not work with window.minimize() (menubar hidden)
if (uMsg === win32.WM_SYSCOMMAND) {
log.debug("wndProc CALLED with WM_SYSCOMMAND wParam="+wParam);
if (wParam === win32.SC_MINIMIZE) {
log.debug("GOT ICONIFIED");
@ -78,21 +68,67 @@ firetray.Window.wndProc = function(hWnd, uMsg, wParam, lParam) { // filterWindow
return 0; // processed => preventDefault
}
}
} else if (uMsg === win32.WM_DESTROY) {
log.debug("wndProc CALLED with WM_DESTROY "+wid);
} else if (uMsg === win32.WM_MOVE) {
log.debug("wndProc CALLED with WM_MOVE "+wid);
} else if (uMsg === win32.WM_ACTIVATE) {
log.debug("wndProc CALLED with WM_ACTIVATE "+wid);
}
let procPrev = firetray.Handler.wndProcsOrig.get(wid);
return user32.CallWindowProcW(procPrev, hWnd, uMsg, wParam, lParam); // or DefWindowProcW
};
// We could chain wndProcs, but adding a hook looks simpler.
firetray.Window.showCount = 0;
firetray.Window.startupHook = function(nCode, wParam, lParam) { // WH_CALLWNDPROC, WH_GETMESSAGE
// log.debug("startupHook CALLED: nCode="+nCode+", wParam="+wParam+", lParam="+lParam);
if (nCode < 0) return user32.CallNextHookEx(null, nCode, wParam, lParam); // user32.HC_ACTION
let cwpstruct = ctypes.cast(win32.LPARAM(lParam), user32.CWPSTRUCT.ptr).contents;
let uMsg = cwpstruct.message;
let hwnd = cwpstruct.hwnd;
let wid = firetray.Win32.hwndToHexStr(hwnd);
let wparam = cwpstruct.wParam;
let lparam = cwpstruct.lParam;
if (uMsg === win32.WM_SHOWWINDOW && wparam == 1 && lparam == 0) { // shown and ShowWindow called
log.debug("startupHook CALLED with WM_SHOWWINDOW wparam="+wparam+" lparam="+lparam);
firetray.Window.showCount += 1;
if (firetray.Utils.prefService.getBoolPref('start_hidden')) {
log.debug("start_hidden");
/* Compared to ShowWindow, SetWindowPlacement seems to bypass window
animations. http://stackoverflow.com/a/6087214 */
let placement = new user32.WINDOWPLACEMENT;
let ret = user32.GetWindowPlacement(hwnd, placement.address());
log.debug(" GetWindowPlacement="+ret+" winLastError="+ctypes.winLastError);
log.debug(" PLACEMENT="+placement);
if (firetray.Window.showCount < 2) {
// we can't prevent ShowWindow, so we mitigate the effect by minimizing
// it before. This is why we'll have to restore it when unhidden.
placement.showCmd = user32.SW_SHOWMINNOACTIVE;
ret = user32.SetWindowPlacement(hwnd, placement.address());
log.debug(" SetWindowPlacement="+ret+" winLastError="+ctypes.winLastError);
firetray.Utils.timer(
FIRETRAY_DELAY_NOWAIT_MILLISECONDS,
Ci.nsITimer.TYPE_ONE_SHOT, function(){firetray.Handler.hideWindow(wid);}
); // looks like CData (hwnd) cannot be closured
} else { // restore
firetray.Window.detachHook(wid);
placement.showCmd = user32.SW_RESTORE;
user32.SetWindowPlacement(hwnd, placement.address());
}
} else {
firetray.Window.detachHook(wid);
}
}
return user32.CallNextHookEx(null, nCode, wParam, lParam);
};
firetray.Window.attachWndProc = function(wid, hwnd) {
try {
let wndProc = user32.WNDPROC(firetray.Window.wndProc);
@ -103,8 +139,8 @@ firetray.Window.attachWndProc = function(wid, hwnd) {
ctypes.cast(wndProc, win32.LONG_PTR))
);
log.debug("procPrev="+procPrev+" winLastError="+ctypes.winLastError);
// we can't store WNDPROC callbacks (JS ctypes objects) with SetPropW(), as
// we need long-living refs.
/* we can't store WNDPROC callbacks (JS ctypes objects) with SetPropW(), as
we need long-living refs. */
firetray.Handler.wndProcsOrig.insert(wid, procPrev);
} catch (x) {
@ -135,6 +171,28 @@ firetray.Window.detachWndProc = function(wid) {
firetray.Handler.wndProcsOrig.remove(wid);
};
firetray.Window.attachHook = function(wid) { // detaches itself alone
let startupHook = user32.HOOKPROC(firetray.Window.startupHook);
log.debug("callhk="+startupHook);
firetray.Handler.procHooks.insert(wid, startupHook);
// Global hooks must reside in a dll (hence hInst). This is important for
// the scope of variables.
let hhook = user32.SetWindowsHookExW(
user32.WH_CALLWNDPROC, startupHook, null, kernel32.GetCurrentThreadId());
log.debug(" hhook="+hhook+" winLastError="+ctypes.winLastError);
firetray.Handler.procHooksRegistred.insert(wid, hhook);
};
firetray.Window.detachHook = function(wid) { // detaches itself alone
let hook = firetray.Handler.procHooksRegistred.get(wid);
if (!user32.UnhookWindowsHookEx(hook)) {
log.error("UnhookWindowsHookEx for window "+wid+" failed: winLastError="+ctypes.winLastError);
return;
}
firetray.Handler.procHooks.remove(wid);
firetray.Handler.procHooksRegistred.remove(wid);
};
///////////////////////// firetray.Handler overriding /////////////////////////
@ -170,10 +228,12 @@ firetray.Handler.registerWindow = function(win) {
Object.defineProperties(this.windows[wid], {
"visible": { get: function(){return firetray.Window.getVisibility(wid);} }
});
log.debug("window "+wid+" registered");
firetray.Window.attachWndProc(wid, hwnd);
if (!firetray.Handler.appStarted) {
firetray.Window.attachHook(wid);
}
firetray.Win32.acceptAllMessages(hwnd);