1
0
mirror of https://github.com/moparisthebest/FireTray synced 2025-01-08 12:08:05 -05:00

* refactoring

* attempt to set our WndProc on Moz windows
* store window Id as a string

Calling CallWindowProc or ctypes.FuncType from a WNDPROC added to a Firefox
window crashes. See
https://bugzilla.mozilla.org/show_bug.cgi?id=598679
https://bugzilla.mozilla.org/show_bug.cgi?id=671266

The problem does not seem to occur on non-Firefox windows (for ex. a a hidden
window that we created).

We'll try to test Hooks instead of WndProcs.
This commit is contained in:
foudfou 2013-12-01 18:26:36 +01:00
parent d52245cc87
commit 2e234064bb
8 changed files with 215 additions and 145 deletions

View File

@ -327,7 +327,6 @@ firetray.Handler = {
setIconVisibility: function(visible) {}, setIconVisibility: function(visible) {},
registerWindow: function(win) {}, registerWindow: function(win) {},
unregisterWindow: function(win) {}, unregisterWindow: function(win) {},
getWindowIdFromChromeWindow: function(win) {},
hideWindow: function(winId) {}, hideWindow: function(winId) {},
showWindow: function(winId) {}, showWindow: function(winId) {},
showHideAllWindows: function() {}, showHideAllWindows: function() {},

View File

@ -29,4 +29,11 @@ FiretrayWindow.prototype = {
win.visible = visibility; // nsIBaseWin.visibility always true :-( win.visible = visibility; // nsIBaseWin.visibility always true :-(
}, },
getRegisteredWinIdFromChromeWindow: function(win) {
for (let wid in firetray.Handler.windows)
if (firetray.Handler.windows[wid].chromeWin === win) return wid;
log.error("unknown window while lookup");
return null;
},
}; };

View File

@ -57,6 +57,11 @@ function user32_defines(lib) {
this.LR_SHARED = 0x00008000; this.LR_SHARED = 0x00008000;
this.LR_VGACOLOR = 0x00000080; this.LR_VGACOLOR = 0x00000080;
lib.lazy_bind("GetPropW", win32.HANDLE, win32.HWND, win32.LPCTSTR);
lib.lazy_bind("SetPropW", win32.BOOL, win32.HWND, win32.LPCTSTR, win32.HANDLE);
lib.lazy_bind("GetWindowLongW", win32.LONG_PTR, win32.HWND, ctypes.int);
lib.lazy_bind("SetWindowLongW", win32.LONG_PTR , win32.HWND, ctypes.int, win32.LONG_PTR);
// SetWindowLongPtrW aliases SetWindowLongW with the correct signature thank // SetWindowLongPtrW aliases SetWindowLongW with the correct signature thank
// win32.LONG_PTR // win32.LONG_PTR
lib.lazy_bind("SetWindowLongW", win32.LONG_PTR , win32.HWND, ctypes.int, win32.LONG_PTR); lib.lazy_bind("SetWindowLongW", win32.LONG_PTR , win32.HWND, ctypes.int, win32.LONG_PTR);
@ -71,7 +76,8 @@ function user32_defines(lib) {
WinCbABI, win32.LRESULT, WinCbABI, win32.LRESULT,
[win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM]).ptr; [win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM]).ptr;
lib.lazy_bind("CallWindowProcW", win32.LRESULT, this.WNDPROC, win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM); // lib.lazy_bind("CallWindowProcW", win32.LRESULT, this.WNDPROC, win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM);
lib.lazy_bind("CallWindowProcW", win32.LRESULT, ctypes.voidptr_t, win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM);
lib.lazy_bind("DefWindowProcW", win32.LRESULT, win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM); lib.lazy_bind("DefWindowProcW", win32.LRESULT, win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM);
this.WNDCLASSEXW = ctypes.StructType("WNDCLASSEXW", [ this.WNDCLASSEXW = ctypes.StructType("WNDCLASSEXW", [

View File

@ -5,97 +5,95 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/ctypes.jsm"); Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://firetray/ctypes/ctypes-utils.jsm"); Cu.import("resource://firetray/ctypes/ctypes-utils.jsm");
const INT_PTR_T = is64bit ? ctypes.int64_t : ctypes.int;
const UINT_PTR_T = is64bit ? ctypes.uint64_t : ctypes.unsigned_int;
const LONG_PTR_T = is64bit ? ctypes.int64_t : ctypes.long;
const ULONG_PTR_T = is64bit ? ctypes.uint64_t : ctypes.unsigned_long;
const HANDLE_T = ctypes.voidptr_t; // oder ctypes.intptr_t, ctypes.size_t, ctypes.int32_t ?
const WORD_T = ctypes.unsigned_short;
var win32 = { var win32 = new function() {
WIN_VERSIONS: { // maj*10 + min this.WIN_VERSIONS = { // maj*10 + min
'8': 62, // 2012 '8': 62, // 2012
'7': 61, // 2009 '7': 61, // 2009
'Vista': 60, // 2007 'Vista': 60, // 2007
'XP': 51, // 2001 'XP': 51, // 2001
'2K': 50, // 2000 '2K': 50, // 2000
}, };
WINVER: null, // initialized in kernel32.jsm this.WINVER = null; // initialized in kernel32.jsm
BOOL: ctypes.bool, this.BOOL = ctypes.bool;
BYTE: ctypes.unsigned_char, this.BYTE = ctypes.unsigned_char;
UINT: ctypes.unsigned_int, this.INT_PTR = is64bit ? ctypes.int64_t : ctypes.int;
WORD: WORD_T, this.UINT = ctypes.unsigned_int;
DWORD: ctypes.unsigned_long, this.UINT_PTR = is64bit ? ctypes.uint64_t : ctypes.unsigned_int;
PVOID: ctypes.voidptr_t, this.WORD = ctypes.unsigned_short;
LPVOID: ctypes.voidptr_t, this.DWORD = ctypes.unsigned_long;
LONG: ctypes.long, this.PVOID = ctypes.voidptr_t;
LONG_PTR: LONG_PTR_T, this.LPVOID = ctypes.voidptr_t;
ULONG_PTR: ULONG_PTR_T, this.LONG = ctypes.long;
SIZE_T: ULONG_PTR_T, this.LONG_PTR = is64bit ? ctypes.int64_t : ctypes.long;
ATOM: WORD_T, this.ULONG_PTR = is64bit ? ctypes.uint64_t : ctypes.unsigned_long;
HWND: HANDLE_T, this.SIZE_T = this.ULONG_PTR;
HICON: HANDLE_T, this.ATOM = this.WORD;
HINSTANCE: HANDLE_T, this.HANDLE = ctypes.voidptr_t;
HMODULE: HANDLE_T, this.HWND = this.HANDLE;
HMENU: HANDLE_T, this.HICON = this.HANDLE;
HBRUSH: HANDLE_T, // HICON this.HINSTANCE = this.HANDLE;
HCURSOR: HANDLE_T, this.HMODULE = this.HANDLE;
TCHAR: ctypes.jschar, // Mozilla compiled with UNICODE/_UNICODE macros and wchar_t: jschar this.HMENU = this.HANDLE;
LPSTR: ctypes.char.ptr, this.HBRUSH = this.HICON;
LPCSTR: ctypes.char.ptr, this.HCURSOR = this.HANDLE;
LPTSTR: ctypes.jschar.ptr, // UNICODE this.TCHAR = ctypes.jschar, // Mozilla compiled with UNICODE/_UNICODE macros and wchar_t = jschar
LPCTSTR: ctypes.jschar.ptr, this.LPSTR = ctypes.char.ptr;
LPCWSTR: ctypes.jschar.ptr, this.LPCSTR = ctypes.char.ptr;
LPWSTR: ctypes.jschar.ptr, // WCHAR this.LPTSTR = ctypes.jschar.ptr; // UNICODE
LRESULT: LONG_PTR_T, this.LPCTSTR = ctypes.jschar.ptr;
WPARAM: UINT_PTR_T, this.LPCWSTR = ctypes.jschar.ptr;
LPARAM: LONG_PTR_T, this.LPWSTR = ctypes.jschar.ptr; // WCHAR
FARPROC: ctypes.voidptr_t, // typedef INT_PTR (FAR WINAPI *FARPROC)(); this.LRESULT = this.LONG_PTR;
this.WPARAM = this.UINT_PTR;
this.LPARAM = this.LONG_PTR;
this.FARPROC = ctypes.voidptr_t; // typedef INT_PTR (FAR WINAPI *FARPROC)();
GUID: ctypes.StructType("GUID", [ this.GUID = ctypes.StructType("GUID", [
{ "Data1": ctypes.unsigned_long }, { "Data1": ctypes.unsigned_long },
{ "Data2": ctypes.unsigned_short }, { "Data2": ctypes.unsigned_short },
{ "Data3": ctypes.unsigned_short }, { "Data3": ctypes.unsigned_short },
{ "Data4": ctypes.char.array(8) } { "Data4": ctypes.char.array(8) }
]), ]);
/* /*
* #define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i)))) * #define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i))))
* #define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i)))) * #define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i))))
*/ */
MAKEINTRESOURCE: function(i) {return this.LPWSTR(i); }, this.MAKEINTRESOURCE = function(i) {return this.LPWSTR(i);};
_T: function(str) { this._T = function(str) {
return ctypes.jschar.array()(str); return ctypes.jschar.array()(str);
}, };
ERROR_INVALID_WINDOW_HANDLE: 1400, this.ERROR_INVALID_WINDOW_HANDLE = 1400;
ERROR_RESOURCE_TYPE_NOT_FOUND: 1813, this.ERROR_RESOURCE_TYPE_NOT_FOUND = 1813;
// WinUser.h // WinUser.h
WM_USER: 0x0400, this.WM_USER = 0x0400;
this.WM_APP = 0x8000;
WM_CONTEXTMENU: 0x007B, this.WM_CONTEXTMENU = 0x007B;
WM_MOUSEFIRST: 0x0200, this.WM_MOUSEFIRST = 0x0200;
WM_MOUSEMOVE: 0x0200, this.WM_MOUSEMOVE = 0x0200;
WM_LBUTTONDOWN: 0x0201, this.WM_LBUTTONDOWN = 0x0201;
WM_LBUTTONUP: 0x0202, this.WM_LBUTTONUP = 0x0202;
WM_LBUTTONDBLCLK: 0x0203, this.WM_LBUTTONDBLCLK = 0x0203;
WM_RBUTTONDOWN: 0x0204, this.WM_RBUTTONDOWN = 0x0204;
WM_RBUTTONUP: 0x0205, this.WM_RBUTTONUP = 0x0205;
WM_RBUTTONDBLCLK: 0x0206, this.WM_RBUTTONDBLCLK = 0x0206;
WM_MBUTTONDOWN: 0x0207, this.WM_MBUTTONDOWN = 0x0207;
WM_MBUTTONUP: 0x0208, this.WM_MBUTTONUP = 0x0208;
WM_MBUTTONDBLCLK: 0x0209, this.WM_MBUTTONDBLCLK = 0x0209;
WM_MOUSEWHEEL: 0x020A, this.WM_MOUSEWHEEL = 0x020A;
WM_XBUTTONDOWN: 0x020B, this.WM_XBUTTONDOWN = 0x020B;
WM_XBUTTONUP: 0x020C, this.WM_XBUTTONUP = 0x020C;
WM_XBUTTONDBLCLK: 0x020D, this.WM_XBUTTONDBLCLK = 0x020D;
WM_MOUSELAST: 0x020D, this.WM_MOUSELAST = 0x020D;
WM_MOUSELAST: 0x020A, this.WM_MOUSELAST = 0x020A;
}; };

View File

@ -53,13 +53,12 @@ var _find_data_t = ctypes.StructType("_find_data_t", [
// NOTE: storing ctypes pointers into a JS object doesn't work: pointers are // NOTE: storing ctypes pointers into a JS object doesn't work: pointers are
// "evolving" after a while (maybe due to back and forth conversion). So we // "evolving" after a while (maybe due to back and forth conversion). So we
// need to store them into a real ctypes array ! // need to store them into a real ctypes array !
firetray.Handler.gtkWindows = new ctypesMap(gtk.GtkWindow.ptr), firetray.Handler.gtkWindows = new ctypesMap(gtk.GtkWindow.ptr);
firetray.Handler.gdkWindows = new ctypesMap(gdk.GdkWindow.ptr), firetray.Handler.gdkWindows = new ctypesMap(gdk.GdkWindow.ptr);
firetray.Handler.gtkPopupMenuWindowItems = new ctypesMap(gtk.GtkImageMenuItem.ptr), firetray.Handler.gtkPopupMenuWindowItems = new ctypesMap(gtk.GtkImageMenuItem.ptr);
firetray.Window = new FiretrayWindow(); firetray.Window = new FiretrayWindow();
firetray.Window.signals = {'focus-in': {callback: {}, handler: {}}}; firetray.Window.signals = {'focus-in': {callback: {}, handler: {}}};
firetray.Window.init = function() { firetray.Window.init = function() {
@ -187,7 +186,7 @@ firetray.Window.getGtkWindowFromGdkWindow = function(gdkWin) {
return gtkw; return gtkw;
}; };
/* consider using getXIDFromChromeWindow() if you only need the XID */ /* consider using getRegisteredWinIdFromChromeWindow() if you only need the XID */
firetray.Window.getWindowsFromChromeWindow = function(win) { firetray.Window.getWindowsFromChromeWindow = function(win) {
let baseWin = firetray.Handler.getWindowInterface(win, "nsIBaseWindow"); let baseWin = firetray.Handler.getWindowInterface(win, "nsIBaseWindow");
let nativeHandle = baseWin.nativeHandle; // Moz' private pointer to the GdkWindow let nativeHandle = baseWin.nativeHandle; // Moz' private pointer to the GdkWindow
@ -205,13 +204,6 @@ firetray.Window.getWindowsFromChromeWindow = function(win) {
return [baseWin, gtkWin, gdkWin, xid]; return [baseWin, gtkWin, gdkWin, xid];
}; };
firetray.Window.getXIDFromChromeWindow = function(win) {
for (let xid in firetray.Handler.windows)
if (firetray.Handler.windows[xid].chromeWin === win) return xid;
log.error("unknown window while lookup");
return null;
};
firetray.Window.unregisterWindowByXID = function(xid) { firetray.Window.unregisterWindowByXID = function(xid) {
if (!firetray.Handler.windows.hasOwnProperty(xid)) { if (!firetray.Handler.windows.hasOwnProperty(xid)) {
log.error("can't unregister unknown window "+xid); log.error("can't unregister unknown window "+xid);
@ -656,8 +648,6 @@ firetray.Handler.dumpWindows = function() {
for (let winId in firetray.Handler.windows) log.info(winId+"="+firetray.Handler.gtkWindows.get(winId)); for (let winId in firetray.Handler.windows) log.info(winId+"="+firetray.Handler.gtkWindows.get(winId));
}; };
firetray.Handler.getWindowIdFromChromeWindow = firetray.Window.getXIDFromChromeWindow;
firetray.Handler.registerWindow = function(win) { firetray.Handler.registerWindow = function(win) {
log.debug("register window"); log.debug("register window");
@ -713,7 +703,7 @@ firetray.Handler.registerWindow = function(win) {
firetray.Handler.unregisterWindow = function(win) { firetray.Handler.unregisterWindow = function(win) {
log.debug("unregister window"); log.debug("unregister window");
let xid = firetray.Window.getXIDFromChromeWindow(win); let xid = firetray.Window.getRegisteredWinIdFromChromeWindow(win);
return firetray.Window.unregisterWindowByXID(xid); return firetray.Window.unregisterWindowByXID(xid);
}; };

View File

@ -20,9 +20,6 @@ Cu.import("resource://firetray/winnt/FiretrayWin32.jsm");
Cu.import("resource://firetray/commons.js"); Cu.import("resource://firetray/commons.js");
firetray.Handler.subscribeLibsForClosing([kernel32, shell32, user32]); firetray.Handler.subscribeLibsForClosing([kernel32, shell32, user32]);
const kMessageTray = "_FIRETRAY_TrayMessage";
const kMessageCallback = "_FIRETRAY_TrayCallback";
let log = firetray.Logging.getLogger("firetray.StatusIcon"); let log = firetray.Logging.getLogger("firetray.StatusIcon");
if ("undefined" == typeof(firetray.Handler)) if ("undefined" == typeof(firetray.Handler))
@ -33,7 +30,6 @@ firetray.StatusIcon = {
initialized: false, initialized: false,
callbacks: {}, // pointers to JS functions. MUST LIVE DURING ALL THE EXECUTION callbacks: {}, // pointers to JS functions. MUST LIVE DURING ALL THE EXECUTION
notifyIconData: null, notifyIconData: null,
msg: {WM_TASKBARCREATED:null, WM_TRAYMESSAGE:null, WM_TRAYCALLBACK:null},
hwndProxy: null, hwndProxy: null,
WNDCLASS_NAME: "FireTrayHiddenWindowClass", WNDCLASS_NAME: "FireTrayHiddenWindowClass",
WNDCLASS_ATOM: null, WNDCLASS_ATOM: null,
@ -42,7 +38,6 @@ firetray.StatusIcon = {
this.FILENAME_BLANK = firetray.Utils.chromeToPath( this.FILENAME_BLANK = firetray.Utils.chromeToPath(
"chrome://firetray/skin/blank-icon.png"); "chrome://firetray/skin/blank-icon.png");
this.registerMessages();
this.create(); this.create();
this.initialized = true; this.initialized = true;
@ -57,17 +52,6 @@ firetray.StatusIcon = {
this.initialized = false; this.initialized = false;
}, },
registerMessages: function() {
this.msg.WM_TASKBARCREATED = user32.RegisterWindowMessageW("TaskbarCreated");
this.msg.WM_TRAYMESSAGE = user32.RegisterWindowMessageW(kMessageTray);
this.msg.WM_TRAYCALLBACK = user32.RegisterWindowMessageW(kMessageCallback);
log.debug("WM_*="+this.msg.WM_TASKBARCREATED+" "+this.msg.WM_TRAYMESSAGE+" "+this.msg.WM_TRAYCALLBACK);
},
unregisterMessages: function() {
// FIXME: TODO:
},
create: function() { create: function() {
let hwnd_hidden = this.createProxyWindow(); let hwnd_hidden = this.createProxyWindow();
@ -81,7 +65,7 @@ firetray.StatusIcon = {
nid.szTip = firetray.Handler.appName; nid.szTip = firetray.Handler.appName;
nid.hIcon = this.getIconFromWindow(hwnd_hidden_moz); nid.hIcon = this.getIconFromWindow(hwnd_hidden_moz);
nid.hWnd = hwnd_hidden; nid.hWnd = hwnd_hidden;
nid.uCallbackMessage = this.msg.WM_TRAYMESSAGE; nid.uCallbackMessage = firetray.Win32.WM_TRAYMESSAGE;
nid.uFlags = shell32.NIF_ICON | shell32.NIF_MESSAGE | shell32.NIF_TIP; nid.uFlags = shell32.NIF_ICON | shell32.NIF_MESSAGE | shell32.NIF_TIP;
nid.uVersion = shell32.NOTIFYICON_VERSION_4; nid.uVersion = shell32.NOTIFYICON_VERSION_4;
@ -98,8 +82,6 @@ firetray.StatusIcon = {
createProxyWindow: function() { createProxyWindow: function() {
this.registerWindowClass(); this.registerWindowClass();
this.callbacks.hiddenWinProc = user32.WNDPROC(firetray.StatusIcon.proxyWindowProc);
let hwnd_hidden = user32.CreateWindowExW( let hwnd_hidden = user32.CreateWindowExW(
0, win32.LPCTSTR(this.WNDCLASS_ATOM), // lpClassName can also be _T(WNDCLASS_NAME) 0, win32.LPCTSTR(this.WNDCLASS_ATOM), // lpClassName can also be _T(WNDCLASS_NAME)
"Firetray Message Window", 0, "Firetray Message Window", 0,
@ -107,8 +89,18 @@ firetray.StatusIcon = {
null, null, firetray.Win32.hInstance, null); null, null, firetray.Win32.hInstance, null);
log.debug("CreateWindow="+!hwnd_hidden.isNull()+" winLastError="+ctypes.winLastError); log.debug("CreateWindow="+!hwnd_hidden.isNull()+" winLastError="+ctypes.winLastError);
this.callbacks.proxyWndProc = user32.WNDPROC(firetray.StatusIcon.proxyWndProc);
/*
// TESTING
let proc = user32.GetWindowLongW(hwnd_hidden, user32.GWLP_WNDPROC);
log.debug(" proc="+proc.toString(16)+" winLastError="+ctypes.winLastError);
this.callbacks.procPrev = user32.WNDPROC(
user32.SetWindowLongW(hwnd_hidden, user32.GWLP_WNDPROC,
ctypes.cast(this.callbacks.proxyWndProc, win32.LONG_PTR))
);
*/
let procPrev = user32.SetWindowLongW(hwnd_hidden, user32.GWLP_WNDPROC, let procPrev = user32.SetWindowLongW(hwnd_hidden, user32.GWLP_WNDPROC,
ctypes.cast(this.callbacks.hiddenWinProc, win32.LONG_PTR)); ctypes.cast(this.callbacks.proxyWndProc, win32.LONG_PTR));
log.debug("procPrev="+procPrev+" winLastError="+ctypes.winLastError); log.debug("procPrev="+procPrev+" winLastError="+ctypes.winLastError);
firetray.Win32.acceptAllMessages(hwnd_hidden); firetray.Win32.acceptAllMessages(hwnd_hidden);
@ -126,13 +118,13 @@ firetray.StatusIcon = {
log.debug("WNDCLASS_ATOM="+this.WNDCLASS_ATOM); log.debug("WNDCLASS_ATOM="+this.WNDCLASS_ATOM);
}, },
proxyWindowProc: function(hWnd, uMsg, wParam, lParam) { proxyWndProc: function(hWnd, uMsg, wParam, lParam) {
// log.debug("ProxyWindowProc CALLED: hWnd="+hWnd+", uMsg="+uMsg+", wParam="+wParam+", lParam="+lParam); // log.debug("ProxyWindowProc CALLED: hWnd="+hWnd+", uMsg="+uMsg+", wParam="+wParam+", lParam="+lParam);
if (uMsg === firetray.StatusIcon.msg.WM_TASKBARCREATED) { if (uMsg === firetray.Win32.WM_TASKBARCREATED) {
log.info("____________TASKBARCREATED"); log.info("____________TASKBARCREATED");
} else if (uMsg === firetray.StatusIcon.msg.WM_TRAYMESSAGE) { } else if (uMsg === firetray.Win32.WM_TRAYMESSAGE) {
switch (+lParam) { switch (+lParam) {
case win32.WM_LBUTTONUP: case win32.WM_LBUTTONUP:
@ -152,6 +144,15 @@ firetray.StatusIcon = {
} }
/*
// CallWindowProcW() on a non-moz window works fine
let procPrev = firetray.StatusIcon.callbacks.procPrev;
log.debug(" procPrev="+procPrev);
let rv = user32.CallWindowProcW(procPrev, hWnd, uMsg, wParam, lParam);
log.debug(" CallWindowProc="+rv);
return rv;
*/
return user32.DefWindowProcW(hWnd, uMsg, wParam, lParam); return user32.DefWindowProcW(hWnd, uMsg, wParam, lParam);
}, },

View File

@ -15,6 +15,9 @@ firetray.Handler.subscribeLibsForClosing([kernel32, user32]);
let log = firetray.Logging.getLogger("firetray.Win32"); let log = firetray.Logging.getLogger("firetray.Win32");
const kMessageTray = "_FIRETRAY_TrayMessage";
const kMessageCallback = "_FIRETRAY_TrayCallback";
if ("undefined" == typeof(firetray.Handler)) if ("undefined" == typeof(firetray.Handler))
log.error("This module MUST be imported from/after FiretrayHandler !"); log.error("This module MUST be imported from/after FiretrayHandler !");
@ -23,11 +26,16 @@ function Win32Env() {
this.hInstance = kernel32.GetModuleHandleW("xul"); // ordinary windows are created from xul.dll this.hInstance = kernel32.GetModuleHandleW("xul"); // ordinary windows are created from xul.dll
log.debug("hInstance="+this.hInstance); log.debug("hInstance="+this.hInstance);
this.WM_TASKBARCREATED = user32.RegisterWindowMessageW("TaskbarCreated");
this.WM_TRAYMESSAGE = user32.RegisterWindowMessageW(kMessageTray);
this.WM_TRAYCALLBACK = user32.RegisterWindowMessageW(kMessageCallback);
log.debug("WM_*="+this.WM_TASKBARCREATED+" "+this.WM_TRAYMESSAGE+" "+this.WM_TRAYCALLBACK);
/* if Administrator, accept messages from applications running in a lower /* if Administrator, accept messages from applications running in a lower
privilege level */ privilege level */
this.acceptAllMessages = function(hwnd) { this.acceptAllMessages = function(hwnd) {
let rv = null; let rv = null;
log.info(win32.WINVER+" >= "+win32.WIN_VERSIONS["7"]); log.debug(win32.WINVER+" >= "+win32.WIN_VERSIONS["7"]);
if (win32.WINVER >= win32.WIN_VERSIONS["7"]) { if (win32.WINVER >= win32.WIN_VERSIONS["7"]) {
rv = user32.ChangeWindowMessageFilterEx(hwnd, firetray.Win32.WM_TASKBARCREATED, user32.MSGFLT_ALLOW, null); rv = user32.ChangeWindowMessageFilterEx(hwnd, firetray.Win32.WM_TASKBARCREATED, user32.MSGFLT_ALLOW, null);
log.debug("ChangeWindowMessageFilterEx res="+rv+" winLastError="+ctypes.winLastError); log.debug("ChangeWindowMessageFilterEx res="+rv+" winLastError="+ctypes.winLastError);

View File

@ -6,8 +6,6 @@ const Cc = Components.classes;
const Ci = Components.interfaces; const Ci = Components.interfaces;
const Cu = Components.utils; const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/ctypes.jsm"); Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://firetray/ctypes/ctypesMap.jsm"); Cu.import("resource://firetray/ctypes/ctypesMap.jsm");
Cu.import("resource://firetray/ctypes/winnt/win32.jsm"); Cu.import("resource://firetray/ctypes/winnt/win32.jsm");
@ -22,17 +20,17 @@ let log = firetray.Logging.getLogger("firetray.Window");
if ("undefined" == typeof(firetray.Handler)) if ("undefined" == typeof(firetray.Handler))
log.error("This module MUST be imported from/after FiretrayHandler !"); log.error("This module MUST be imported from/after FiretrayHandler !");
const Services2 = {};
XPCOMUtils.defineLazyServiceGetter(
Services2,
"uuid",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator"
);
const FIRETRAY_XWINDOW_HIDDEN = 1 << 0; // when minimized also const FIRETRAY_XWINDOW_HIDDEN = 1 << 0; // when minimized also
const FIRETRAY_XWINDOW_MAXIMIZED = 1 << 1; const FIRETRAY_XWINDOW_MAXIMIZED = 1 << 1;
const kPropProcPrev = "_FIRETRAY_OLD_PROC";
// NOTE: storing ctypes pointers into a JS object doesn't work: pointers are
// "evolving" after a while (maybe due to back and forth conversion). So we
// need to store them into a real ctypes array !
firetray.Handler.wndProcs = new ctypesMap(user32.WNDPROC);
firetray.Handler.wndProcsOrig = new ctypesMap(user32.WNDPROC);
firetray.Window = new FiretrayWindow(); firetray.Window = new FiretrayWindow();
@ -59,6 +57,50 @@ firetray.Window.startupHide = function(xid) {
firetray.Window.setVisibility = function(xid, visibility) { firetray.Window.setVisibility = function(xid, visibility) {
}; };
// wid will be used as a string most of the time (through f.Handler.windows mainly)
firetray.Window.hwndToHexStr = function(hWnd) {
return "0x" + ctypes.cast(hWnd, ctypes.uintptr_t).value.toString(16);
};
firetray.Window.wndProc = function(hWnd, uMsg, wParam, lParam) { // filterWindow
log.debug("wndProc CALLED: hWnd="+hWnd+", uMsg="+uMsg+", wParam="+wParam+", lParam="+lParam);
let proc = user32.GetWindowLongW(hWnd, user32.GWLP_WNDPROC);
log.debug(" proc="+proc.toString(16)+" winLastError="+ctypes.winLastError);
try {
let wid = firetray.Window.hwndToHexStr(hWnd);
// let procPrev = firetray.Handler.wndProcsOrig.get(wid);
// let procPrev = ctypes.cast(user32.GetPropW(hWnd, win32._T(kPropProcPrev)), user32.WNDPROC);
// let procPrev = user32.GetPropW(hWnd, win32._T(kPropProcPrev));
log.debug(" wid="+wid+" prev="+procPrev);
/*
* https://bugzilla.mozilla.org/show_bug.cgi?id=598679
* https://bugzilla.mozilla.org/show_bug.cgi?id=671266
*/
// let rv = user32.CallWindowProcW(procPrev, hWnd, uMsg, wParam, lParam);
let rv = procPrev(hWnd, uMsg, wParam, lParam);
log.debug(" CallWindowProc="+rv);
return rv;
} catch(error) {
log.error(error);
}
// user32.SetWindowLongW(hWnd, user32.GWLP_WNDPROC, ctypes.cast(procPrev, win32.LONG_PTR));
// if (uMsg === win32.WM_USER) {
// log.debug("wndProc CALLED: hWnd="+hWnd+", uMsg="+uMsg+", wParam="+wParam+", lParam="+lParam);
// // return user32.DefWindowProcW(hWnd, uMsg, wParam, lParam);
// }
// return user32.DefWindowProcW(hWnd, uMsg, wParam, lParam);
};
///////////////////////// firetray.Handler overriding ///////////////////////// ///////////////////////// firetray.Handler overriding /////////////////////////
@ -66,13 +108,11 @@ firetray.Window.setVisibility = function(xid, visibility) {
firetray.Handler.dumpWindows = function() { firetray.Handler.dumpWindows = function() {
let dumpStr = ""+firetray.Handler.windowsCount; let dumpStr = ""+firetray.Handler.windowsCount;
for (let wid in firetray.Handler.windows) { for (let wid in firetray.Handler.windows) {
dumpStr += " 0x"+wid; dumpStr += " "+wid;
} }
log.info(dumpStr); log.info(dumpStr);
}; };
firetray.Handler.getWindowIdFromChromeWindow = firetray.Window.getXIDFromChromeWindow;
firetray.Handler.registerWindow = function(win) { firetray.Handler.registerWindow = function(win) {
log.debug("register window"); log.debug("register window");
@ -81,8 +121,7 @@ firetray.Handler.registerWindow = function(win) {
let hwnd = nativeHandle ? let hwnd = nativeHandle ?
new ctypes.voidptr_t(ctypes.UInt64(nativeHandle)) : new ctypes.voidptr_t(ctypes.UInt64(nativeHandle)) :
user32.FindWindowW("MozillaWindowClass", win.document.title); user32.FindWindowW("MozillaWindowClass", win.document.title);
// wid will be used as a string most of the time (through f.Handler.windows mainly) let wid = firetray.Window.hwndToHexStr(hwnd);
let wid = ctypes.cast(hwnd, ctypes.uintptr_t).value.toString(16);
log.debug("=== hwnd="+hwnd+" wid="+wid+" win.document.title: "+win.document.title); log.debug("=== hwnd="+hwnd+" wid="+wid+" win.document.title: "+win.document.title);
if (this.windows.hasOwnProperty(wid)) { if (this.windows.hasOwnProperty(wid)) {
@ -104,33 +143,40 @@ firetray.Handler.registerWindow = function(win) {
// NOTE: no need to check for window state to set visibility because all // NOTE: no need to check for window state to set visibility because all
// windows *are* shown at startup // windows *are* shown at startup
firetray.Window.updateVisibility(wid, true); firetray.Window.updateVisibility(wid, true);
log.debug("window 0x"+wid+" registered"); log.debug("window "+wid+" registered");
// NOTE: shouldn't be necessary to gtk_widget_add_events(gtkWin, gdk.GDK_ALL_EVENTS_MASK); // NOTE: shouldn't be necessary to gtk_widget_add_events(gtkWin, gdk.GDK_ALL_EVENTS_MASK);
/* /*
try { // try {
// NOTE: we could try to catch the "delete-event" here and block try {
// delete_event_cb (in gtk2/nsWindow.cpp), but we prefer to use the let wndProc = user32.WNDPROC(firetray.Window.wndProc);
// provided 'close' JS event log.debug("proc="+wndProc);
this.wndProcs.insert(wid, wndProc);
let procPrev = user32.WNDPROC(
user32.SetWindowLongW(hwnd, user32.GWLP_WNDPROC, ctypes.cast(wndProc, win32.LONG_PTR))
);
log.debug("procPrev="+procPrev+" winLastError="+ctypes.winLastError);
this.wndProcsOrig.insert(wid, procPrev); // could be set as a window prop (SetPropW)
this.windows[xid].filterWindowCb = gdk.GdkFilterFunc_t(firetray.Window.filterWindow); procPrev = ctypes.cast(procPrev, win32.HANDLE);
gdk.gdk_window_add_filter(gdkWin, this.windows[xid].filterWindowCb, null); user32.SetPropW(hwnd, win32._T(kPropProcPrev), procPrev);
if (!firetray.Handler.appStarted) { log.debug("SetPropW: "+procPrev+" winLastError="+ctypes.winLastError);
this.windows[xid].startupFilterCb = gdk.GdkFilterFunc_t(firetray.Window.startupFilter); } catch(error) {
gdk.gdk_window_add_filter(gdkWin, this.windows[xid].startupFilterCb, null); log.error(error);
}
firetray.Window.attachOnFocusInCallback(xid);
if (firetray.Handler.isChatEnabled() && firetray.Chat.initialized) {
firetray.Chat.attachSelectListeners(win);
}
} catch (x) {
firetray.Window.unregisterWindowByXID(xid);
log.error(x);
return null;
} }
*/ */
// firetray.Win32.acceptAllMessages(hwnd);
// } catch (x) {
// if (x.name === "RangeError") // instanceof not working :-(
// win.alert(x+"\n\nYou seem to have more than "+FIRETRAY_WINDOW_COUNT_MAX
// +" windows open. This breaks FireTray and most probably "
// +firetray.Handler.appName+".");
// else win.alert(x);
// }
// TODO: check wndproc chaining http://stackoverflow.com/a/8835843/421846 if
// needed for startupFilter
log.debug("AFTER"); firetray.Handler.dumpWindows(); log.debug("AFTER"); firetray.Handler.dumpWindows();
return wid; return wid;
@ -138,8 +184,23 @@ firetray.Handler.registerWindow = function(win) {
firetray.Handler.unregisterWindow = function(win) { firetray.Handler.unregisterWindow = function(win) {
log.debug("unregister window"); log.debug("unregister window");
let xid = firetray.Window.getXIDFromChromeWindow(win);
return firetray.Window.unregisterWindowByXID(xid); let wid = firetray.Window.getWIDFromChromeWindow(win);
if (!firetray.Handler.windows.hasOwnProperty(wid)) {
log.error("can't unregister unknown window "+wid);
return false;
}
if (!delete firetray.Handler.windows[wid])
throw new DeleteError();
// firetray.Handler.wndProcs.remove(wid);
// firetray.Handler.wndProcsOrig.remove(wid);
firetray.Handler.windowsCount -= 1;
firetray.Handler.visibleWindowsCount -= 1;
log.debug("window "+wid+" unregistered");
return true;
}; };
firetray.Handler.showWindow = firetray.Window.show; firetray.Handler.showWindow = firetray.Window.show;