From 29bf5a42bd0fd9c3365d9018cf43cfb3120e0e8f Mon Sep 17 00:00:00 2001 From: foudfou Date: Sun, 10 Jul 2011 12:45:36 +0200 Subject: [PATCH 1/5] attempt to get signals from tray icon using LibGObject needs refactoring ! --- src/chrome/content/overlay.js | 22 +++ src/modules/LibGObject.js | 160 ++++++++++++++++++ testing/Makefile | 17 +- testing/gtk_icon_example | Bin 66933 -> 68328 bytes ...{gkt_icon_example.c => gtk_icon_example.c} | 42 +++++ testing/hide.c | 53 ++++++ testing/trayicon.c | 109 ++++++++++++ 7 files changed, 401 insertions(+), 2 deletions(-) create mode 100644 src/modules/LibGObject.js rename testing/{gkt_icon_example.c => gtk_icon_example.c} (51%) create mode 100644 testing/hide.c create mode 100644 testing/trayicon.c diff --git a/src/chrome/content/overlay.js b/src/chrome/content/overlay.js index 404d3a5..903888e 100644 --- a/src/chrome/content/overlay.js +++ b/src/chrome/content/overlay.js @@ -1,11 +1,24 @@ /* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +// TODO: Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://moztray/commons.js"); Components.utils.import("resource://moztray/LibGtkStatusIcon.js"); +Components.utils.import("resource://moztray/LibGObject.js"); const MOZT_ICON_DIR = "chrome/skin/"; const MOZT_ICON_SUFFIX = "32.png"; + +var mozt_hideWinCb; +/* NOTE: arguments come obviously from the GCallbackFunction definition: + * [gpointer, guint, gpointer] + */ +var mozt_hideWinJs = function(aInstance, aTimestamp, aUserData) { + try { + alert("Hide"); + } catch(e) {Cu.reportError(ex);} +}; + mozt.Main = { onLoad: function() { @@ -29,6 +42,15 @@ mozt.Main = { var icon_filename = MOZT_ICON_DIR + mozApp + MOZT_ICON_SUFFIX; LibGtkStatusIcon.gtk_status_icon_set_from_file(this.tray_icon, icon_filename); + // gtk_status_icon_set_tooltip(tray_icon, + // "Example Tray Icon"); + // gtk_status_icon_set_visible(tray_icon, TRUE); + + mozt_hideWinCb = LibGObject.GCallbackFunction(mozt_hideWinJs); + + LibGObject.g_signal_connect(this.tray_icon, "activate", + mozt_hideWinCb, null); + mozt.Debug.dump('Moztray LOADED !'); this.initialized = true; diff --git a/src/modules/LibGObject.js b/src/modules/LibGObject.js new file mode 100644 index 0000000..0c3c8af --- /dev/null +++ b/src/modules/LibGObject.js @@ -0,0 +1,160 @@ +/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is messagingmenu-extension + * + * The Initial Developer of the Original Code is + * Mozilla Messaging, Ltd. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Mike Conley + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +var EXPORTED_SYMBOLS = ["LibGObject"]; + +const LIB_GOBJECT = "libgobject-2.0.so.0"; + +const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; + +Cu.import("resource://gre/modules/ctypes.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +XPCOMUtils.defineLazyGetter(this, "libgobject", function() { + var libgobject = ctypes.open(LIB_GOBJECT); + if (!libgobject) + throw "libgobject is unavailable"; + + return libgobject; +}); + +XPCOMUtils.defineLazyGetter(this, "GCallback", function() { + return ctypes.voidptr_t; +}); + +XPCOMUtils.defineLazyGetter(this, "gpointer", function() { + return ctypes.voidptr_t; +}); + +XPCOMUtils.defineLazyGetter(this, "gulong", function() { + return ctypes.unsigned_long; +}); + +XPCOMUtils.defineLazyGetter(this, "guint", function() { + return ctypes.unsigned_int; +}); + +XPCOMUtils.defineLazyGetter(this, "guint32", function() { + return ctypes.unsigned_int; +}); + +XPCOMUtils.defineLazyGetter(this, "gint", function() { + return ctypes.int; +}); + +XPCOMUtils.defineLazyGetter(this, "gchar", function() { + return ctypes.unsigned_char; +}); + +XPCOMUtils.defineLazyGetter(this, "gboolean", function() { + return gint; +}); + +XPCOMUtils.defineLazyGetter(this, "GConnectFlags", function() { + return guint; +}); + +XPCOMUtils.defineLazyGetter(this, "GClosureNotify", function() { + return gpointer; +}); + +XPCOMUtils.defineLazyGetter(this, "GCallbackFunction", function() { + var GCallbackFunction = + ctypes.FunctionType(ctypes.default_abi, + ctypes.void_t, + [gpointer, + guint, + gpointer]).ptr; + if (!GCallbackFunction) + throw "GCallbackFunction is unavailable"; + + return GCallbackFunction; +}); + +XPCOMUtils.defineLazyGetter(this, "g_signal_connect_data", function() { + var g_signal_connect_data = + libgobject.declare("g_signal_connect_data", + ctypes.default_abi, + gulong, + gpointer, // instance + gchar.ptr, // detailed_signal + GCallback, // handler + gpointer, // data + GClosureNotify, // NULL + GConnectFlags); // 0 + + if (!g_signal_connect_data) + throw "g_signal_connect_data is unavailable"; + + return g_signal_connect_data; +}); + +XPCOMUtils.defineLazyGetter(this, "g_object_unref", function() { + var g_object_unref = + libgobject.declare("g_object_unref", + ctypes.default_abi, + ctypes.void_t, + gpointer); + + if (!g_object_unref) + throw "g_object_unref is unavailable"; + + return g_object_unref; +}); + +var LibGObject = { + GCallback: GCallback, + GCallbackFunction: GCallbackFunction, + gpointer: gpointer, + gulong: gulong, + guint: guint, + guint32: guint32, + gint: gint, + gchar: gchar, + gboolean: gboolean, + GConnectFlags: GConnectFlags, + GClosureNotify: GClosureNotify, + g_object_unref: g_object_unref, + + g_signal_connect: function(instance, detailed_signal, handler, data) { + return g_signal_connect_data(instance, detailed_signal, + handler, data, null, 0); + } +}; diff --git a/testing/Makefile b/testing/Makefile index b257336..146b217 100644 --- a/testing/Makefile +++ b/testing/Makefile @@ -1,4 +1,17 @@ includes := $(shell pkg-config --libs --cflags gtk+-2.0) -all: - gcc $(includes) -o gtk_icon_example gkt_icon_example.c +.PHONY: all +all: gtk_icon_example trayicon hide + +.PHONY: clean +clean: + rm gtk_icon_example trayicon hide + +gtk_icon_example: gtk_icon_example.c + gcc $(includes) -o gtk_icon_example gtk_icon_example.c + +trayicon: trayicon.c + gcc $(includes) -o trayicon trayicon.c + +hide: hide.c + gcc $(includes) -o hide hide.c diff --git a/testing/gtk_icon_example b/testing/gtk_icon_example index a57224faa9468f66a45cddfa4b475662b64747f5..91ecccf414c0be880e1cf6e56ce37aed537f32c4 100755 GIT binary patch delta 16572 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 + #include #include "firefox.xpm" @@ -37,11 +39,51 @@ static GtkStatusIcon *create_tray_icon() { return tray_icon; } +/* +- Hide/Show window to avoid minimizing it to the task bar (yes, use gtk_widget_hide() and gtk_widget_show()) when the user clicks on the system tray icon +- Listen to the "window-state-event" (GObject's signal) to detect when minimizing and, instead of doing that, hide the window (ie, "minimize to the tray"). +*/ + +/* This callback quits the program */ +gint delete_event( GtkWidget *widget, + GdkEvent *event, + gpointer + data ) +{ + gtk_main_quit (); + return FALSE; +} + +static void winShowHide(GtkMenuItem *item, gpointer window) +{ + /* GdkWindow * tl_window = gdk_window_get_toplevel((GdkWindow*)window); */ + + /* GdkWindowState ws = gdk_window_get_state((GdkWindow*)tl_window); */ + /* printf("GdkWindowState: %d", ws); */ + + gdk_window_hide(window->window); + /* gtk_widget_show(GTK_WIDGET(window)); */ + /* gtk_widget_hide(GTK_WIDGET(window)); */ +} + int main(int argc, char **argv) { GtkStatusIcon *tray_icon; gtk_init(&argc, &argv); tray_icon = create_tray_icon(); + + GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), "GtkStatusIcon Example"); + gtk_widget_set_size_request (window, 200, -1); + + /* Set a handler for delete_event that immediately exits GTK. */ + g_signal_connect (G_OBJECT (window), "delete_event", + G_CALLBACK (delete_event), NULL); + + g_signal_connect(G_OBJECT(tray_icon), "activate", G_CALLBACK(winShowHide), window); + + gtk_widget_show_all (window); + gtk_main(); return 0; diff --git a/testing/hide.c b/testing/hide.c new file mode 100644 index 0000000..85b537d --- /dev/null +++ b/testing/hide.c @@ -0,0 +1,53 @@ +#include +#include + +#include + + +int main(int argc, char **argv) +{ + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *button; + + gtk_init(&argc, &argv); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(window), 10); + g_signal_connect(window, "delete_event", (GCallback)gtk_main_quit, 0); + + vbox = gtk_vbox_new(TRUE, 0); + gtk_container_add(GTK_CONTAINER(window), vbox); + + button = gtk_button_new_with_label("Hide"); + gtk_box_pack_start(GTK_BOX(vbox), button, TRUE,TRUE, 0); + g_signal_connect_swapped(button, "clicked", + (GCallback)gtk_widget_hide, window); + + button = gtk_button_new_from_stock(GTK_STOCK_QUIT); + gtk_box_pack_start(GTK_BOX(vbox), button, TRUE,TRUE, 0); + g_signal_connect(button, "clicked", (GCallback)gtk_main_quit, 0); + + gtk_window_set_decorated(GTK_WINDOW(window), FALSE); + + // gtk_window_set_default_size(GTK_WINDOW(window),500,500); + + // gtk_window_stick(GTK_WINDOW(window)); /* on all desktops or not */ + + gtk_window_set_keep_above(GTK_WINDOW(window), TRUE); + + //gtk_window_set_keep_below(GTK_WINDOW(window),TRUE); + + gtk_window_set_skip_taskbar_hint(GTK_WINDOW(window), TRUE); + gtk_window_set_skip_pager_hint(GTK_WINDOW(window), TRUE); + + gtk_window_move(GTK_WINDOW(window), 100, 100); + + // gtk_window_set_opacity(GTK_WINDOW(window), 0); /* not working hmmmm*/ + + gtk_widget_show_all(window); + + gtk_main(); + + return (EXIT_SUCCESS); +} diff --git a/testing/trayicon.c b/testing/trayicon.c new file mode 100644 index 0000000..351da1c --- /dev/null +++ b/testing/trayicon.c @@ -0,0 +1,109 @@ +// http://www.codeproject.com/KB/cross-platform/GTKTrayIcon.aspx +#include + +static void trayView(GtkMenuItem *item, gpointer user_data); +static void trayExit(GtkMenuItem *item, gpointer user_data); +static void trayIconActivated(GObject *trayIcon, gpointer data); +static void trayIconPopup(GtkStatusIcon *status_icon, guint button, guint32 activate_time, gpointer popUpMenu); +static void destroy (GtkWidget*, gpointer); +static gboolean delete_event (GtkWidget*, GdkEvent*, gpointer); +static gboolean window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer user_data); + +int main(int argc, char *argv[]) +{ + gtk_init (&argc, &argv); + + GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), "GtkStatusIcon Example"); + gtk_widget_set_size_request (window, 200, -1); + + //set try icon file + GtkStatusIcon *trayIcon = gtk_status_icon_new_from_file ("firefox32.png"); + //set popup menu for tray icon + GtkWidget *menu, *menuItemView, *menuItemExit; + menu = gtk_menu_new(); + menuItemView = gtk_menu_item_new_with_label ("View"); + menuItemExit = gtk_menu_item_new_with_label ("Exit"); + g_signal_connect (G_OBJECT (menuItemView), "activate", G_CALLBACK (trayView), window); + g_signal_connect (G_OBJECT (menuItemExit), "activate", G_CALLBACK (trayExit), NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuItemView); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuItemExit); + gtk_widget_show_all (menu); + //set tooltip + gtk_status_icon_set_tooltip (trayIcon, "MsgWatcherGTK"); + //connect handlers for mouse events + g_signal_connect(GTK_STATUS_ICON (trayIcon), "activate", GTK_SIGNAL_FUNC (trayIconActivated), window); + g_signal_connect(GTK_STATUS_ICON (trayIcon), "popup-menu", GTK_SIGNAL_FUNC (trayIconPopup), menu); + gtk_status_icon_set_visible(trayIcon, FALSE); //set icon initially invisible + + + GtkWidget *menuBar, *menuItemTopLvl, *mainMenu, *mainMenuItemExit; + menuBar = gtk_menu_bar_new (); + menuItemTopLvl = gtk_menu_item_new_with_label ("Menu"); + gtk_menu_shell_append (GTK_MENU_SHELL (menuBar), menuItemTopLvl); + + mainMenu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuItemTopLvl), mainMenu); + mainMenuItemExit = gtk_menu_item_new_with_label ("Quit"); + g_signal_connect (G_OBJECT (mainMenuItemExit), "activate", G_CALLBACK (trayExit), NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (mainMenu), mainMenuItemExit); + + g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); + g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (delete_event), trayIcon); + g_signal_connect (G_OBJECT (window), "window-state-event", G_CALLBACK (window_state_event), trayIcon); + gtk_container_add (GTK_CONTAINER (window), menuBar); + gtk_widget_show_all (window); + gtk_main (); + return 0; +} + +static void trayView(GtkMenuItem *item, gpointer window) +{ + gtk_widget_show(GTK_WIDGET(window)); + gtk_window_deiconify(GTK_WINDOW(window)); +} + +static void trayExit(GtkMenuItem *item, gpointer user_data) +{ + printf("exit"); + gtk_main_quit(); +} + +static void trayIconActivated(GObject *trayIcon, gpointer window) +{ + gtk_widget_show(GTK_WIDGET(window)); + gtk_window_deiconify(GTK_WINDOW(window)); +} + +static void trayIconPopup(GtkStatusIcon *status_icon, guint button, guint32 activate_time, gpointer popUpMenu) +{ + gtk_menu_popup(GTK_MENU(popUpMenu), NULL, NULL, gtk_status_icon_position_menu, status_icon, button, activate_time); +} + +static void destroy (GtkWidget *window, gpointer data) +{ + gtk_main_quit (); +} + +static gboolean delete_event (GtkWidget *window, GdkEvent *event, gpointer data) +{ + return FALSE; +} + +static gboolean window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer trayIcon) +{ + if(event->changed_mask == GDK_WINDOW_STATE_ICONIFIED && + (event->new_window_state == GDK_WINDOW_STATE_ICONIFIED + || event->new_window_state == (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_MAXIMIZED))) + { + gtk_widget_hide (GTK_WIDGET(widget)); + gtk_status_icon_set_visible(GTK_STATUS_ICON(trayIcon), TRUE); + } + else if(event->changed_mask == GDK_WINDOW_STATE_WITHDRAWN && + (event->new_window_state == GDK_WINDOW_STATE_ICONIFIED + || event->new_window_state == (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_MAXIMIZED))) + { + gtk_status_icon_set_visible(GTK_STATUS_ICON(trayIcon), FALSE); + } + return TRUE; +} From 1b68487af8164c77d51aae34c29f86f838a3c264 Mon Sep 17 00:00:00 2001 From: foudfou Date: Wed, 13 Jul 2011 01:23:58 +0200 Subject: [PATCH 2/5] add debug() facility to print to terminal stderr --- src/modules/LibC.js | 85 ++++++++++++++++++++++++++++++++++++++++++ src/modules/commons.js | 8 ++++ 2 files changed, 93 insertions(+) create mode 100644 src/modules/LibC.js diff --git a/src/modules/LibC.js b/src/modules/LibC.js new file mode 100644 index 0000000..a21261c --- /dev/null +++ b/src/modules/LibC.js @@ -0,0 +1,85 @@ +/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +var EXPORTED_SYMBOLS = ["LibC"]; + +const LIB_C = "libc.so.6"; + +const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; + +Cu.import("resource://gre/modules/ctypes.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +XPCOMUtils.defineLazyGetter(this, "libc", function() { + var libc = ctypes.open(LIB_C); + if (!libc) + throw "libc is unavailable"; + + return libc; +}); + +XPCOMUtils.defineLazyGetter(this, "FILE", function() { + return ctypes.StructType("FILE"); +}); + +XPCOMUtils.defineLazyGetter(this, "fdopen", function() { + var fdopen = libc.declare( + "fdopen", ctypes.default_abi, FILE.ptr, + ctypes.int, + ctypes.char.ptr + ); + + if (!fdopen) + throw "fdopen is unavailable"; + + return fdopen; +}); + + +XPCOMUtils.defineLazyGetter(this, "puts", function() { + var puts = libc.declare( + "puts", ctypes.default_abi, ctypes.int32_t, + ctypes.char.ptr + ); + + if (!puts) + throw "puts is unavailable"; + + return puts; +}); + +XPCOMUtils.defineLazyGetter(this, "fputs", function() { + var fputs = libc.declare( + "fputs", ctypes.default_abi, ctypes.int32_t, + ctypes.char.ptr, + FILE.ptr + ); + + if (!fputs) + throw "fputs is unavailable"; + + return fputs; +}); + +XPCOMUtils.defineLazyGetter(this, "fflush", function() { + var fflush = libc.declare( + "fflush", ctypes.default_abi, ctypes.int32_t, + FILE.ptr + ); + + if (!fflush) + throw "fflush is unavailable"; + + return fflush; +}); + +var LibC = { + stderr: this.fdopen(2, "a"), + + FILE: FILE, + fdopen: fdopen, + puts: puts, + fputs: fputs, + fflush: fflush, +} diff --git a/src/modules/commons.js b/src/modules/commons.js index 73d35cc..45278a8 100644 --- a/src/modules/commons.js +++ b/src/modules/commons.js @@ -10,6 +10,9 @@ var EXPORTED_SYMBOLS = [ "mozt", "Cc", "Ci" ]; const Cc = Components.classes; const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://moztray/LibC.js"); const FIREFOX_ID = "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"; const THUNDERBIRD_ID = "{3550f703-e582-4d05-9a08-453d09bdfdc6}"; @@ -64,6 +67,11 @@ mozt.Debug = { this.dump(str); }, + // dump to terminal (stderr) + debug: function(str) { + LibC.fputs(str + "\n", LibC.stderr); + LibC.fflush(LibC.stderr); + }, }; // build it ! mozt.Debug.init(); From f2245d1ca017d3d3a0a69cad36dfe58f3c56d1f1 Mon Sep 17 00:00:00 2001 From: foudfou Date: Mon, 18 Jul 2011 00:58:03 +0200 Subject: [PATCH 3/5] * add LibC for logging to stderr * try different approaches for hiding windows: - gather toplevel windows from nsIWindowMediator, but then unable to get NativeParentWindow (GdkWindow) in order to apply gdk_window_hide - damn it ! - gather toplevel GdkWindows, but don't know exactly how to find out which belong to the application... - gather toplevel GtkWindows, but seem to get too many windows from gtk_window_list_toplevels()... * problems understanding js-ctypes: - arguments passed to callbacks (see FunctionType), for ex: implementation of GFunc - definition of recursive structures, for ex: GtkWidget --- src/chrome/content/overlay.js | 155 ++++++++++++++++++++++-- src/chrome/content/overlay.xul | 2 +- src/modules/LibC.js | 19 +++ src/modules/LibGObject.js | 76 +++++++++++- src/modules/LibGdkWindow.js | 201 ++++++++++++++++++++++++++++++++ src/modules/LibGtkStatusIcon.js | 41 ++++++- src/modules/commons.js | 30 ++++- 7 files changed, 503 insertions(+), 21 deletions(-) create mode 100644 src/modules/LibGdkWindow.js diff --git a/src/chrome/content/overlay.js b/src/chrome/content/overlay.js index 903888e..6d622e5 100644 --- a/src/chrome/content/overlay.js +++ b/src/chrome/content/overlay.js @@ -1,24 +1,130 @@ /* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ // TODO: Components.utils.import("resource://gre/modules/Services.jsm"); -Components.utils.import("resource://moztray/commons.js"); -Components.utils.import("resource://moztray/LibGtkStatusIcon.js"); +Components.utils.import("resource://gre/modules/ctypes.jsm"); +Components.utils.import("resource://moztray/LibC.js"); Components.utils.import("resource://moztray/LibGObject.js"); +Components.utils.import("resource://moztray/LibGdkWindow.js"); +Components.utils.import("resource://moztray/LibGtkStatusIcon.js"); +Components.utils.import("resource://moztray/commons.js"); const MOZT_ICON_DIR = "chrome/skin/"; const MOZT_ICON_SUFFIX = "32.png"; -var mozt_hideWinCb; -/* NOTE: arguments come obviously from the GCallbackFunction definition: - * [gpointer, guint, gpointer] - */ -var mozt_hideWinJs = function(aInstance, aTimestamp, aUserData) { + +var mozt_getBaseWindow = function(win) { + var bw; try { - alert("Hide"); - } catch(e) {Cu.reportError(ex);} + bw = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIWebNavigation) + .QueryInterface(Components.interfaces.nsIDocShellTreeItem) + .treeOwner + .QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIXULWindow) + .docShell + .QueryInterface(Components.interfaces.nsIBaseWindow); + } catch (ex) { + bw = null; + setTimeout(function() {throw ex; }, 0); + // ignore no-interface exception + } + return bw; }; +var mozt_getAllWindows = function() { + try { + var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] + .getService(Components.interfaces.nsIWindowMediator); + } catch (err) { + alert(err); + return; + } + + var baseWindows = new Array(); + var e = wm.getEnumerator(null); + while (e.hasMoreElements()) { + var w = e.getNext(); + baseWindows[baseWindows.length] = mozt_getBaseWindow(w); + } + + return baseWindows; +}; + +var mozt_hideToTray = function() { + mozt.Debug.debug("mozt_hideToTray"); +/* + var toto = gBrowser.getBrowserForDocument(content.document) + .docShell + .QueryInterface(Components.interfaces.nsIBaseWindow) + .parentNativeWindow; + mozt.Debug.debug("toto: " + toto); +*/ + var baseWindows = mozt_getAllWindows(); + mozt.Debug.dump("baseWindows: " + baseWindows.length); + for(var i=0; i -