diff --git a/src/install.rdf b/src/install.rdf index 0dd8901..f948aac 100644 --- a/src/install.rdf +++ b/src/install.rdf @@ -14,7 +14,8 @@ chrome://firetray/content/options.xul chrome://firetray/skin/firetray48.png chrome://firetray/skin/firetray64.png - Linux + Linux + WINNT diff --git a/src/modules/FiretrayHandler.jsm b/src/modules/FiretrayHandler.jsm index eacbcc4..1b74574 100644 --- a/src/modules/FiretrayHandler.jsm +++ b/src/modules/FiretrayHandler.jsm @@ -69,8 +69,15 @@ firetray.Handler = { Cu.import("resource://firetray/linux/FiretrayWindow.jsm"); log.debug('FiretrayWindow imported'); break; + case "WINNT": + Cu.import("resource://firetray/winnt/FiretrayStatusIcon.jsm"); + log.debug('FiretrayStatusIcon imported'); + Cu.import("resource://firetray/winnt/FiretrayWindow.jsm"); + log.debug('FiretrayWindow imported'); + break; default: - log.error("FIRETRAY: only Linux platform supported at this time. Firetray not loaded"); + log.error("FIRETRAY: only Linux and WINNT platforms supported at this" + + "time. Firetray not loaded"); return false; } diff --git a/src/modules/ctypes/ctypes-utils.jsm b/src/modules/ctypes/ctypes-utils.jsm index 3ddfa34..c6b951e 100644 --- a/src/modules/ctypes/ctypes-utils.jsm +++ b/src/modules/ctypes/ctypes-utils.jsm @@ -36,13 +36,18 @@ * * ***** END LICENSE BLOCK ***** */ +var EXPORTED_SYMBOLS = [ "ctypes_library", "is64bit" ]; + const Cu = Components.utils; Cu.import("resource://gre/modules/ctypes.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://firetray/logging.jsm"); -var EXPORTED_SYMBOLS = [ "ctypes_library" ]; +const is64bit = ctypes.size_t.size == 8; // firetray.Handler.runtimeABI.indexOf('_64') > -1; + +const WinABI = is64bit ? ctypes.default_abi : ctypes.winapi_abi; +const WinCbABI = is64bit ? ctypes.default_abi : ctypes.stdcall_abi; let log = firetray.Logging.getLogger("firetray.ctypes-utils"); @@ -111,7 +116,10 @@ function ctypes_library(aName, aABIs, aDefines, aGlobal) { var library; for each (let abi in aABIs) { - let soname = "lib" + aName + ".so." + abi.toString(); + // FIXME: ABI is in fact SO_VER. Now we're mixing .so versions and the + // .dll extension :( + let soname = abi === 'dll' ? aName : + "lib" + aName + ".so." + abi.toString(); log.debug("Trying " + soname); try { library = ctypes.open(soname); @@ -155,7 +163,12 @@ function ctypes_library(aName, aABIs, aDefines, aGlobal) { try { args = []; args.push(arguments[0]); - args.push(ctypes.default_abi); + // FIXME: ugly hack. We'll see when we need WinCbABI + if (this.ABI === 'dll') { + args.push(WinABI); + } else { + args.push(ctypes.default_abi); + } for each (let arg in Array.prototype.slice.call(arguments, 1)) { args.push(arg); } diff --git a/src/modules/ctypes/winnt/kernel32.jsm b/src/modules/ctypes/winnt/kernel32.jsm new file mode 100644 index 0000000..4495e19 --- /dev/null +++ b/src/modules/ctypes/winnt/kernel32.jsm @@ -0,0 +1,36 @@ +var EXPORTED_SYMBOLS = [ "kernel32" ]; + +const KERNEL32_LIBNAME = "kernel32"; +const KERNEL32_ABIS = [ "dll" ]; + +const Cu = Components.utils; + +Cu.import("resource://gre/modules/ctypes.jsm"); +Cu.import("resource://firetray/ctypes/ctypes-utils.jsm"); +Cu.import("resource://firetray/ctypes/winnt/types.jsm"); + +function kernel32_defines(lib) { + + this.OSVERSIONINFOEXW = ctypes.StructType("OSVERSIONINFOEXW", [ + { "dwOSVersionInfoSize": win_t.DWORD }, + { "dwMajorVersion": win_t.DWORD }, + { "dwMinorVersion": win_t.DWORD }, + { "dwBuildNumber": win_t.DWORD }, + { "dwPlatformId": win_t.DWORD }, + { "szCSDVersion": ctypes.ArrayType(win_t.TCHAR, 128) }, + { "wServicePackMajor": win_t.WORD }, + { "wServicePackMinor": win_t.WORD }, + { "wSuiteMask": win_t.WORD }, + { "wProductType": win_t.BYTE }, + { "wReserved": win_t.BYTE } + ]); + + // lib.lazy_bind("GetLastError", win_t.DWORD); // use ctypes.winLastError instead + lib.lazy_bind("GetVersionExW", win_t.BOOL, this.OSVERSIONINFOEXW.ptr); + lib.lazy_bind("GetConsoleWindow", win_t.HWND); + lib.lazy_bind("GetConsoleTitleW", win_t.DWORD, win_t.LPTSTR, win_t.DWORD); + lib.lazy_bind("GetModuleHandleW", win_t.HMODULE, win_t.LPCTSTR); + +} + +new ctypes_library(KERNEL32_LIBNAME, KERNEL32_ABIS, kernel32_defines, this); diff --git a/src/modules/ctypes/winnt/shell32.jsm b/src/modules/ctypes/winnt/shell32.jsm new file mode 100644 index 0000000..a07f0a2 --- /dev/null +++ b/src/modules/ctypes/winnt/shell32.jsm @@ -0,0 +1,53 @@ +var EXPORTED_SYMBOLS = [ "shell32" ]; + +const SHELL32_LIBNAME = "shell32"; +const SHELL32_ABIS = [ "dll" ]; + +const Cu = Components.utils; + +Cu.import("resource://gre/modules/ctypes.jsm"); +Cu.import("resource://firetray/ctypes/ctypes-utils.jsm"); +Cu.import("resource://firetray/ctypes/winnt/types.jsm"); + +function shell32_defines(lib) { + + // notify icon message + this.NIM_ADD = 0x00000000; + this.NIM_MODIFY = 0x00000001; + this.NIM_DELETE = 0x00000002; + this.NIM_SETFOCUS = 0x00000003; + this.NIM_SETVERSION = 0x00000004; + + // for NOTIFYICONDATAW.uFlags + this.NIF_MESSAGE = 0x00000001; + this.NIF_ICON = 0x00000002; + this.NIF_TIP = 0x00000004; + this.NIF_STATE = 0x00000008; + this.NIF_INFO = 0x00000010; + this.NIF_GUID = 0x00000020; + this.NIF_REALTIME = 0x00000040; + this.NIF_SHOWTIP = 0x00000080; + + this.NOTIFYICONDATAW = ctypes.StructType("NOTIFYICONDATAW", [ + { "cbSize": win_t.DWORD }, + { "hWnd": win_t.HWND }, + { "uID": win_t.UINT }, + { "uFlags": win_t.UINT }, + { "uCallbackMessage": win_t.UINT }, + { "hIcon": win_t.HICON }, + { "szTip": ctypes.ArrayType(win_t.TCHAR, 64) }, // 128 on win2k+ + { "dwState": win_t.DWORD }, + { "dwStateMask": win_t.DWORD }, + { "szInfo": ctypes.ArrayType(win_t.TCHAR, 256) }, + { "uTimeoutOrVersion": win_t.UINT }, // union + { "szInfoTitle[64]": win_t.TCHAR }, + { "dwInfoFlags": win_t.DWORD }, + { "guidItem": win_t.GUID }, + { "hBalloonIcon": win_t.HICON } + ]); + + lib.lazy_bind("Shell_NotifyIconW", win_t.BOOL, win_t.DWORD, this.NOTIFYICONDATAW.ptr); + +} + +new ctypes_library(SHELL32_LIBNAME, SHELL32_ABIS, shell32_defines, this); diff --git a/src/modules/ctypes/winnt/types.jsm b/src/modules/ctypes/winnt/types.jsm new file mode 100644 index 0000000..8f89e2b --- /dev/null +++ b/src/modules/ctypes/winnt/types.jsm @@ -0,0 +1,51 @@ +var EXPORTED_SYMBOLS = [ "win_t" ]; + +const Cu = Components.utils; + +Cu.import("resource://gre/modules/ctypes.jsm"); +Cu.import("resource://firetray/ctypes/ctypes-utils.jsm"); + +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, + +var win_t = { + + BOOL: ctypes.bool, + BYTE: ctypes.unsigned_char, + UINT: ctypes.unsigned_int, + WORD: ctypes.unsigned_short, + DWORD: ctypes.unsigned_long, + PVOID: ctypes.voidptr_t, + ULONG_PTR: ULONG_PTR_T, + SIZE_T: ULONG_PTR_T, + HWND: HANDLE_T, + HICON: HANDLE_T, + HINSTANCE: HANDLE_T, + HMODULE: HANDLE_T, + TCHAR: ctypes.jschar, // Mozilla compiled with UNICODE/_UNICODE macros and wchar_t: jschar + LPSTR: ctypes.char.ptr, + LPCSTR: ctypes.char.ptr, + LPTSTR: ctypes.jschar.ptr, // UNICODE + LPCTSTR: ctypes.jschar.ptr, + LPCWSTR: ctypes.jschar.ptr, + LPWSTR: ctypes.jschar.ptr, // WCHAR + LRESULT: LONG_PTR_T, + WPARAM: UINT_PTR_T, + LPARAM: LONG_PTR_T, + + GUID: ctypes.StructType("GUID", [ + { "Data1": ctypes.unsigned_long }, + { "Data2": ctypes.unsigned_short }, + { "Data3": ctypes.unsigned_short }, + { "Data4": ctypes.char.array(8) } + ]), + + /* + * #define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i)))) + * #define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i)))) + */ + MAKEINTRESOURCE: function(i) {return this.LPWSTR(i); } + +}; diff --git a/src/modules/ctypes/winnt/user32.jsm b/src/modules/ctypes/winnt/user32.jsm new file mode 100644 index 0000000..9d04b56 --- /dev/null +++ b/src/modules/ctypes/winnt/user32.jsm @@ -0,0 +1,45 @@ +var EXPORTED_SYMBOLS = [ "user32" ]; + +const USER32_LIBNAME = "user32"; +const USER32_ABIS = [ "dll" ]; + +const Cu = Components.utils; + +Cu.import("resource://gre/modules/ctypes.jsm"); +Cu.import("resource://firetray/ctypes/ctypes-utils.jsm"); +Cu.import("resource://firetray/ctypes/winnt/types.jsm"); + +function user32_defines(lib) { + + lib.lazy_bind("GetWindowTextW", ctypes.int, win_t.HWND, win_t.LPTSTR, ctypes.int); + lib.lazy_bind("FindWindowW", win_t.HWND, win_t.LPCTSTR, win_t.LPCTSTR); + + lib.lazy_bind("SendMessageW", win_t.LRESULT, win_t.HWND, win_t.UINT, win_t.WPARAM, win_t.WPARAM); + this.WM_GETICON = 0x007F; + this.ICON_SMALL = 0; + this.ICON_BIG = 1; + this.ICON_SMALL2 = 2; + + lib.lazy_bind("GetClassLongPtrW", win_t.ULONG_PTR, win_t.HWND, ctypes.int); + lib.lazy_bind("GetClassLongW", win_t.DWORD, win_t.HWND, ctypes.int); // 32-bits + this.GetClassLong = is64bit ? this.GetClassLongPtrW : this.GetClassLongW; + this.GCLP_HICONSM = -34; + + lib.lazy_bind("LoadIconW", win_t.HICON, win_t.HINSTANCE, win_t.LPCTSTR); // superseeded by LoadImage + this.IDI_APPLICATION = 32512; + + lib.lazy_bind("LoadImageW", win_t.HANDLE, win_t.HINSTANCE, win_t.LPCTSTR, + win_t.UINT, ctypes.int, ctypes.int, win_t.UINT); + this.LR_CREATEDIBSECTION = 0x00002000; + this.LR_DEFAULTCOLOR = 0x00000000; + this.LR_DEFAULTSIZE = 0x00000040; + this.LR_LOADFROMFILE = 0x00000010; + this.LR_LOADMAP3DCOLORS = 0x00001000; + this.LR_LOADTRANSPARENT = 0x00000020; + this.LR_MONOCHROME = 0x00000001; + this.LR_SHARED = 0x00008000; + this.LR_VGACOLOR = 0x00000080; + +} + +new ctypes_library(USER32_LIBNAME, USER32_ABIS, user32_defines, this); diff --git a/src/modules/logging.jsm b/src/modules/logging.jsm index 1b03300..0801c31 100644 --- a/src/modules/logging.jsm +++ b/src/modules/logging.jsm @@ -6,7 +6,9 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; -const FIRETRAY_LOG_LEVEL = "Warn"; // "All" for debugging +Cu.import("resource://gre/modules/Services.jsm"); + +const FIRETRAY_LOG_LEVEL = "All"; // "All" for debugging const COLOR_NORMAL = ""; const COLOR_RESET = "\033[m"; @@ -77,25 +79,10 @@ firetray.Logging = { setupLogging: function(loggerName) { // lifted from log4moz.js - function SimpleFormatter(dateFormat) { - if (dateFormat) - this.dateFormat = dateFormat; - } + function SimpleFormatter() {} SimpleFormatter.prototype = { __proto__: Log4Moz.Formatter.prototype, - _dateFormat: null, - - get dateFormat() { - if (!this._dateFormat) - this._dateFormat = "%Y-%m-%d %H:%M:%S"; - return this._dateFormat; - }, - - set dateFormat(format) { - this._dateFormat = format; - }, - format: function(message) { let messageString = ""; if (message.hasOwnProperty("message")) @@ -108,7 +95,9 @@ firetray.Logging = { ([,mo] in Iterator(message.messageObjects))].join(" "); let date = new Date(message.time); - let stringLog = date.toLocaleFormat(this.dateFormat) + " " + + let dateStr = date.getHours() + ":" + date.getMinutes() + ":" + + date.getSeconds() + "." + date.getMilliseconds(); + let stringLog = dateStr + " " + message.levelDesc + " " + message.loggerName + " " + messageString + "\n"; @@ -119,10 +108,7 @@ firetray.Logging = { } }; - function ColorTermFormatter(dateFormat) { - if (dateFormat) - this.dateFormat = dateFormat; - } + function ColorTermFormatter() {} ColorTermFormatter.prototype = { __proto__: SimpleFormatter.prototype, @@ -141,15 +127,19 @@ firetray.Logging = { this._logger.level = Log4Moz.Level[FIRETRAY_LOG_LEVEL]; // A console appender outputs to the JS Error Console - let dateFormat = "%T"; - let simpleFormatter = new SimpleFormatter(dateFormat); + let simpleFormatter = new SimpleFormatter(); let capp = new Log4Moz.ConsoleAppender(simpleFormatter); capp.level = Log4Moz.Level["Debug"]; this._logger.addAppender(capp); // A dump appender outputs to standard out - let colorFormatter = new ColorTermFormatter(dateFormat); - let dapp = new Log4Moz.DumpAppender(colorFormatter); + let dumpFormatter; + if (Services.appinfo.OS.match(/(^Linux|^Darwin|BSD$)/)) { + dumpFormatter = new ColorTermFormatter(); + } else { + dumpFormatter = new SimpleFormatter(); + } + let dapp = new Log4Moz.DumpAppender(dumpFormatter); dapp.level = Log4Moz.Level["Debug"]; this._logger.addAppender(dapp); }, diff --git a/src/modules/winnt/FiretrayStatusIcon.jsm b/src/modules/winnt/FiretrayStatusIcon.jsm new file mode 100644 index 0000000..f47fa58 --- /dev/null +++ b/src/modules/winnt/FiretrayStatusIcon.jsm @@ -0,0 +1,68 @@ +/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +var EXPORTED_SYMBOLS = [ "firetray" ]; + +const Cc = Components.classes; +const Ci = Components.interfaces; +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://firetray/ctypes/linux/pangocairo.jsm"); +Cu.import("resource://firetray/commons.js"); +// firetray.Handler.subscribeLibsForClosing([pangocairo]); + +let log = firetray.Logging.getLogger("firetray.StatusIcon"); + +if ("undefined" == typeof(firetray.Handler)) + log.error("This module MUST be imported from/after FiretrayHandler !"); + + +firetray.StatusIcon = { + initialized: false, + callbacks: {}, // pointers to JS functions. MUST LIVE DURING ALL THE EXECUTION + trayIcon: null, + themedIconApp: null, + themedIconNewMail: null, + prefAppIconNames: null, + prefNewMailIconNames: null, + defaultAppIconName: null, + defaultNewMailIconName: null, + + init: function() { + this.FILENAME_BLANK = firetray.Utils.chromeToPath( + "chrome://firetray/skin/blank-icon.png"); + + log.warn("YEAH! From Windobe!"); + + this.initialized = true; + return true; + }, + + shutdown: function() { + log.debug("Disabling StatusIcon"); + this.initialized = false; + }, +}; // firetray.StatusIcon + +firetray.Handler.setIconImageDefault = function() { + log.debug("setIconImageDefault"); +}; + +firetray.Handler.setIconImageNewMail = function() { +}; + +// firetray.Handler.setIconImageFromFile = firetray.StatusIcon.setIconImageFromFile; + +firetray.Handler.setIconTooltip = function(toolTipStr) { +}; + +firetray.Handler.setIconTooltipDefault = function() { +}; + +firetray.Handler.setIconText = function(text, color) { // FIXME: function too long +}; + +firetray.Handler.setIconVisibility = function(visible) { +}; diff --git a/src/modules/winnt/FiretrayWindow.jsm b/src/modules/winnt/FiretrayWindow.jsm new file mode 100644 index 0000000..eb6b7fe --- /dev/null +++ b/src/modules/winnt/FiretrayWindow.jsm @@ -0,0 +1,310 @@ +/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* GdkWindow and GtkWindow are totally different things. A GtkWindow is a + "standalone" window. A GdkWindow is just a region on the screen that can + capture events and has certain attributes (such as a cursor, and a coordinate + system). Basically a GdkWindow is an X window, in the Xlib sense, and + GtkWindow is a widget used for a particular UI effect. + (http://mail.gnome.org/archives/gtk-app-devel-list/1999-January/msg00138.html) */ + +var EXPORTED_SYMBOLS = [ "firetray" ]; + +const Cc = Components.classes; +const Ci = Components.interfaces; +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://firetray/ctypes/ctypesMap.jsm"); +Cu.import("resource://firetray/ctypes/winnt/types.jsm"); +Cu.import("resource://firetray/ctypes/winnt/kernel32.jsm"); +Cu.import("resource://firetray/ctypes/winnt/shell32.jsm"); +Cu.import("resource://firetray/ctypes/winnt/user32.jsm"); +Cu.import("resource://firetray/commons.js"); +firetray.Handler.subscribeLibsForClosing([kernel32, shell32, user32]); + +let log = firetray.Logging.getLogger("firetray.Window"); + +if ("undefined" == typeof(firetray.Handler)) + 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_MAXIMIZED = 1 << 1; + +// // 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.gtkWindows = new ctypesMap(gtk.GtkWindow.ptr), + + +firetray.Window = { + signals: {'focus-in': {callback: {}, handler: {}}}, + + init: function() { + this.initialized = true; + }, + + shutdown: function() { + this.initialized = false; + }, + + show: function(xid) { + log.debug("show xid="+xid); + }, + + hide: function(xid) { + log.debug("hide"); + }, + + startupHide: function(xid) { + log.debug('startupHide: '+xid); + }, + + setVisibility: function(xid, visibility) { + }, + +}; // firetray.Window + + +///////////////////////// firetray.Handler overriding ///////////////////////// + +/** debug facility */ +firetray.Handler.dumpWindows = function() { + log.debug(firetray.Handler.windowsCount); + 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) { + log.debug("register window"); + + // TESTING + let baseWin = firetray.Handler.getWindowInterface(win, "nsIBaseWindow"); + let nativeHandle = baseWin.nativeHandle; // Moz' private pointer to the GdkWindow + log.info("nativeHandle="+nativeHandle); + + log.info("size="+ctypes.size_t.size); + log.info("psize="+ctypes.voidptr_t.size); + log.info("osvi size="+kernel32.OSVERSIONINFOEXW.size); + + let osvi = new kernel32.OSVERSIONINFOEXW(); + osvi.dwOSVersionInfoSize = kernel32.OSVERSIONINFOEXW.size; + if (kernel32.GetVersionExW(osvi.address())) { + log.debug("osvi.dwMajorVersion="+osvi.dwMajorVersion); + log.debug("osvi.dwMinorVersion="+osvi.dwMinorVersion); + } + + /* + * Windows 8 6.2 + * Windows 7 6.1 + * Windows Vista 6.0 + * Windows XP 5.1 + */ + let version = osvi.dwMajorVersion*10 + osvi.dwMinorVersion; // if (version >= 51) + + let nid = new shell32.NOTIFYICONDATAW(); + nid.cbSize = shell32.NOTIFYICONDATAW.size; + + let hwnd = user32.FindWindowW("MozillaWindowClass", win.document.title); + log.debug("hwnd FindWindow="+hwnd); + +/* + let hwnd = new ctypes.voidptr_t(ctypes.UInt64(nativeHandle)); + log.debug("hwnd nativeHandle="+hwnd); +*/ + + const BUF_SIZE = 255; + let buffer_t = ctypes.jschar.array(BUF_SIZE); // LPTSTR + + let title = new buffer_t(); + let len = user32.GetWindowTextW(hwnd, title, BUF_SIZE); + log.error("errno="+ctypes.errno+" winLastError="+ctypes.winLastError); + if (len) { + log.info("title="+title.readString()); + } + +/* + let consoleWin = kernel32.GetConsoleWindow(); + log.error("errno="+ctypes.errno+" winLastError="+ctypes.winLastError); + log.info("consoleWin="+consoleWin); + len = user32.GetWindowTextW(consoleWin, title, 127); + log.error("errno="+ctypes.errno+" winLastError="+ctypes.winLastError); + log.debug("len="+len); + log.info("title="+title.readString()); + + len = kernel32.GetConsoleTitleW(title, win_t.DWORD(127)); + log.error("errno="+ctypes.errno+" winLastError="+ctypes.winLastError); + log.debug("len="+len); + log.debug("len type="+typeof(len)); // "object" ??? + if (len) { + log.info("consoleTitle="+title.readString()); + } +*/ + + let result = user32.SendMessageW(hwnd, user32.WM_GETICON, user32.ICON_SMALL, 0); + // result is a ctypes.Int64. So we need to create a CData from it before + // casting it. + let icon = ctypes.cast(win_t.LRESULT(result), win_t.HICON); + let NULL = win_t.HICON(null); + log.debug("SendMessageW winLastError="+ctypes.winLastError); + if (firetray.js.strEquals(icon, NULL)) { // OS default icon + result = user32.GetClassLong(hwnd, user32.GCLP_HICONSM); + icon = ctypes.cast(win_t.ULONG_PTR(result), win_t.HICON); + log.debug("GetClassLong winLastError="+ctypes.winLastError); + } + if (firetray.js.strEquals(icon, NULL)) { // from the first resource -> ERROR_RESOURCE_TYPE_NOT_FOUND(1813) + icon = user32.LoadIconW(kernel32.GetModuleHandleW(null), + win_t.MAKEINTRESOURCE(0)); + log.debug("LoadIconW module winLastError="+ctypes.winLastError); + } + if (firetray.js.strEquals(icon, NULL)) { // OS default icon + icon = user32.LoadIconW(null, win_t.MAKEINTRESOURCE(user32.IDI_APPLICATION)); + log.debug("LoadIconW default winLastError="+ctypes.winLastError); + } + log.debug("icon="+icon); + +// BOOL mintrayr_CreateIcon(void *handle, mouseevent_callback_t callback) +// { +// HWND hwnd = (HWND)handle; +// if (!hwnd) { +// return FALSE; +// } + +// SetupWnd(hwnd); + +// NOTIFYICONDATAW *iconData = new(std::nothrow) NOTIFYICONDATAW; +// if (!iconData) { +// return FALSE; +// } +// // Init the icon data according to MSDN +// iconData->cbSize = sizeof(NOTIFYICONDATAW); + +// // Copy the title +// if (GetWindowText(hwnd, iconData->szTip, 127)) { +// iconData->szTip[127] = '\0'; // Better be safe than sorry :p +// } +// else{ +// iconData->szTip[0] = '\0'; +// } + +// // Get the window icon +// HICON icon = reinterpret_cast(::SendMessageW(hwnd, WM_GETICON, ICON_SMALL, 0)); +// if (icon == 0) { +// // Alternative method. Get from the window class +// icon = reinterpret_cast(::GetClassLongPtrW(hwnd, GCLP_HICONSM)); +// } +// // Alternative method: get the first icon from the main module (executable image of the process) +// if (icon == 0) { +// icon = ::LoadIcon(GetModuleHandleW(0), MAKEINTRESOURCE(0)); +// } +// // Alternative method. Use OS default icon +// if (icon == 0) { +// icon = ::LoadIcon(0, IDI_APPLICATION); +// } +// iconData->hIcon = icon; + +// // Set the rest of the members +// iconData->hWnd = hwnd; +// iconData->uCallbackMessage = WM_TRAYMESSAGE; +// iconData->uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; +// iconData->uVersion = 5; + +// // Install the icon +// ::Shell_NotifyIconW(NIM_ADD, iconData); +// ::Shell_NotifyIconW(NIM_SETVERSION, iconData); + +// SetupWnd(hwnd); +// ::SetPropW(hwnd, kIconData, reinterpret_cast(iconData)); +// ::SetPropW(hwnd, kIconMouseEventProc, reinterpret_cast(callback)); +// ::SetPropW(hwnd, kIcon, reinterpret_cast(0x1)); + + return; + + // register + let [whndbaseWin, gtkWin, gdkWin, xid] = firetray.Window.getWindowsFromChromeWindow(win); + this.windows[xid] = {}; + this.windows[xid].chromeWin = win; + this.windows[xid].baseWin = baseWin; + firetray.Window.checkSubscribedEventMasks(xid); + try { + this.gtkWindows.insert(xid, gtkWin); + this.gdkWindows.insert(xid, gdkWin); + firetray.PopupMenu.addWindowItem(xid); + } 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+"."); + } + this.windowsCount += 1; + // NOTE: no need to check for window state to set visibility because all + // windows *are* shown at startup + firetray.Window.updateVisibility(xid, true); + log.debug("window "+xid+" registered"); + // NOTE: shouldn't be necessary to gtk_widget_add_events(gtkWin, gdk.GDK_ALL_EVENTS_MASK); + + try { + // NOTE: we could try to catch the "delete-event" here and block + // delete_event_cb (in gtk2/nsWindow.cpp), but we prefer to use the + // provided 'close' JS event + + this.windows[xid].filterWindowCb = gdk.GdkFilterFunc_t(firetray.Window.filterWindow); + gdk.gdk_window_add_filter(gdkWin, this.windows[xid].filterWindowCb, null); + if (!firetray.Handler.appStarted) { + this.windows[xid].startupFilterCb = gdk.GdkFilterFunc_t(firetray.Window.startupFilter); + gdk.gdk_window_add_filter(gdkWin, this.windows[xid].startupFilterCb, null); + } + + 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; + } + + log.debug("AFTER"); firetray.Handler.dumpWindows(); + return xid; +}; + +firetray.Handler.unregisterWindow = function(win) { + log.debug("unregister window"); + let xid = firetray.Window.getXIDFromChromeWindow(win); + return firetray.Window.unregisterWindowByXID(xid); +}; + +firetray.Handler.showWindow = firetray.Window.show; +firetray.Handler.hideWindow = firetray.Window.hide; + +firetray.Handler.showHideAllWindows = function(gtkStatusIcon, userData) { + log.debug("showHideAllWindows: "+userData); + // NOTE: showHideAllWindows being a callback, we need to use + // 'firetray.Handler' explicitely instead of 'this' + + log.debug("visibleWindowsCount="+firetray.Handler.visibleWindowsCount); + log.debug("windowsCount="+firetray.Handler.windowsCount); + let visibilityRate = firetray.Handler.visibleWindowsCount/firetray.Handler.windowsCount; + log.debug("visibilityRate="+visibilityRate); + if ((0.5 < visibilityRate) && (visibilityRate < 1) + || visibilityRate === 0) { // TODO: should be configurable + firetray.Handler.showAllWindows(); + } else { + firetray.Handler.hideAllWindows(); + } + + let stopPropagation = true; + return stopPropagation; +}; diff --git a/testing/xtypes.c b/testing/xtypes.c index 26e8841..307533a 100644 --- a/testing/xtypes.c +++ b/testing/xtypes.c @@ -7,6 +7,7 @@ int main(int argc, char **argv) { printf("sizeof(void*)=%d\n",sizeof(void*)); printf("sizeof(char)=%d\n",sizeof(char)); + printf("sizeof(short)=%d\n",sizeof(short)); printf("sizeof(int)=%d\n",sizeof(int)); printf("sizeof(long)=%d\n",sizeof(long)); printf("sizeof(unsigned_long)=%d\n",sizeof(unsigned long));