/* -*- 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/ctypesMap.jsm"); Cu.import("resource://firetray/ctypes/winnt/win32.jsm"); Cu.import("resource://firetray/ctypes/winnt/user32.jsm"); Cu.import("resource://firetray/winnt/FiretrayWin32.jsm"); Cu.import("resource://firetray/commons.js"); firetray.Handler.subscribeLibsForClosing([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"); let baseWin = firetray.Handler.getWindowInterface(win, "nsIBaseWindow"); let nativeHandle = baseWin.nativeHandle; let hwnd = nativeHandle ? new ctypes.voidptr_t(ctypes.UInt64(nativeHandle)) : user32.FindWindowW("MozillaWindowClass", win.document.title); log.debug("=== hwnd="+hwnd); // 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; };