diff --git a/src/chrome/content/options.js b/src/chrome/content/options.js index ffe619e..eca0060 100644 --- a/src/chrome/content/options.js +++ b/src/chrome/content/options.js @@ -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; }); diff --git a/src/chrome/content/overlay.js b/src/chrome/content/overlay.js index f65306e..7f92236 100644 --- a/src/chrome/content/overlay.js +++ b/src/chrome/content/overlay.js @@ -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()) diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index 88c4541..06fdf31 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -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 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);