firefox/firefox-2.0-startup-notify.patch
2007-09-25 03:36:23 +00:00

1122 lines
37 KiB
Diff

https://bugzilla.mozilla.org/show_bug.cgi?id=223492
--- config/autoconf.mk.in 2006-09-14 14:07:03.000000000 -0400
+++ config/autoconf.mk.in 2007-07-03 18:01:36.000000000 -0400
@@ -223,6 +223,10 @@
MOZ_GNOMEUI_CFLAGS = @MOZ_GNOMEUI_CFLAGS@
MOZ_GNOMEUI_LIBS = @MOZ_GNOMEUI_LIBS@
+MOZ_ENABLE_STARTUP_NOTIFICATION = @MOZ_ENABLE_STARTUP_NOTIFICATION@
+MOZ_STARTUP_NOTIFICATION_CFLAGS = @MOZ_STARTUP_NOTIFICATION_CFLAGS@
+MOZ_STARTUP_NOTIFICATION_LIBS = @MOZ_STARTUP_NOTIFICATION_LIBS@
+
MOZ_GNOMEVFS_CFLAGS = @MOZ_GNOMEVFS_CFLAGS@
MOZ_GNOMEVFS_LIBS = @MOZ_GNOMEVFS_LIBS@
--- toolkit/components/remote/nsGTKRemoteService.cpp 2006-01-05 22:19:20.000000000 -0500
+++ toolkit/components/remote/nsGTKRemoteService.cpp 2007-07-05 17:34:41.000000000 -0400
@@ -50,7 +50,9 @@
#include "nsIBaseWindow.h"
#include "nsIDocShell.h"
+#include "nsIDocument.h"
#include "nsIDOMWindow.h"
+#include "nsPIDOMWindow.h"
#include "nsIGenericFactory.h"
#include "nsILocalFile.h"
#include "nsIObserverService.h"
@@ -58,6 +60,8 @@
#include "nsIServiceManager.h"
#include "nsIWeakReference.h"
#include "nsIWidget.h"
+#include "nsIAppShellService.h"
+#include "nsAppShellCID.h"
#include "nsCOMPtr.h"
#include "nsString.h"
@@ -65,6 +69,10 @@
#include "prenv.h"
#include "nsCRT.h"
+#ifdef MOZ_WIDGET_GTK2
+#include "nsGTKToolkit.h"
+#endif
+
#ifdef MOZ_XUL_APP
#include "nsICommandLineRunner.h"
#include "nsXULAppAPI.h"
@@ -155,20 +163,46 @@
return PL_DHASH_NEXT;
}
+static nsIWidget* GetMainWidget(nsIDOMWindow* aWindow)
+{
+ // get the native window for this instance
+ nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
+ NS_ENSURE_TRUE(window, nsnull);
+ nsCOMPtr<nsIDocument> doc(do_QueryInterface(window->GetExtantDocument()));
+ NS_ENSURE_TRUE(doc, nsnull);
+ nsCOMPtr<nsISupports> container = doc->GetContainer();
+ nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(container));
+ NS_ENSURE_TRUE(baseWindow, nsnull);
+
+ nsCOMPtr<nsIWidget> mainWidget;
+ baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
+ return mainWidget;
+}
+
+static nsGTKToolkit* GetGTKToolkit()
+{
+ nsCOMPtr<nsIAppShellService> svc = do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
+ if (!svc)
+ return nsnull;
+ nsCOMPtr<nsIDOMWindowInternal> window;
+ svc->GetHiddenDOMWindow(getter_AddRefs(window));
+ if (!window)
+ return nsnull;
+ nsIWidget* widget = GetMainWidget(window);
+ if (!widget)
+ return nsnull;
+ nsIToolkit* toolkit = widget->GetToolkit();
+ if (!toolkit)
+ return nsnull;
+ return NS_STATIC_CAST(nsGTKToolkit*, toolkit);
+}
+
+
NS_IMETHODIMP
nsGTKRemoteService::RegisterWindow(nsIDOMWindow* aWindow)
{
// get the native window for this instance
- nsCOMPtr<nsIScriptGlobalObject> scriptObject
- (do_QueryInterface(aWindow));
- NS_ENSURE_TRUE(scriptObject, NS_ERROR_FAILURE);
-
- nsCOMPtr<nsIBaseWindow> baseWindow
- (do_QueryInterface(scriptObject->GetDocShell()));
- NS_ENSURE_TRUE(baseWindow, NS_ERROR_FAILURE);
-
- nsCOMPtr<nsIWidget> mainWidget;
- baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
+ nsIWidget* mainWidget = GetMainWidget(aWindow);
NS_ENSURE_TRUE(mainWidget, NS_ERROR_FAILURE);
// walk up the widget tree and find the toplevel window in the
@@ -201,7 +235,6 @@
return NS_OK;
}
-
NS_IMETHODIMP
nsGTKRemoteService::Shutdown()
{
@@ -260,7 +293,7 @@
#ifndef MOZ_XUL_APP
const char*
-nsGTKRemoteService::HandleCommand(char* aCommand, nsIDOMWindow* aWindow)
+nsGTKRemoteService::HandleCommand(char* aCommand, nsIDOMWindow* aWindow, PRUint32 aTimestamp)
{
nsresult rv;
@@ -283,8 +316,60 @@
}
#else //MOZ_XUL_APP
+
+// Set desktop startup ID to the passed ID, if there is one, so that any created
+// windows get created with the right window manager metadata, and any windows
+// that get new tabs and are activated also get the right WM metadata.
+// If there is no desktop startup ID, then use the X event's timestamp
+// for _NET_ACTIVE_WINDOW when the window gets focused or shown.
+static void
+SetDesktopStartupIDOrTimestamp(const nsACString& aDesktopStartupID,
+ PRUint32 aTimestamp) {
+#ifdef MOZ_WIDGET_GTK2
+ nsGTKToolkit* toolkit = GetGTKToolkit();
+ if (!toolkit)
+ return;
+ if (!aDesktopStartupID.IsEmpty()) {
+ toolkit->SetDesktopStartupID(aDesktopStartupID);
+ } else {
+ toolkit->SetFocusTimestamp(aTimestamp);
+ }
+#endif
+}
+
+static PRBool
+FindExtensionParameterInCommand(const char* aParameterName,
+ const nsACString& aCommand,
+ char aSeparator,
+ nsACString* aValue)
+{
+ nsCAutoString searchFor;
+ searchFor.Append(aSeparator);
+ searchFor.Append(aParameterName);
+ searchFor.Append('=');
+
+ nsACString::const_iterator start, end;
+ aCommand.BeginReading(start);
+ aCommand.EndReading(end);
+ if (!FindInReadable(searchFor, start, end))
+ return PR_FALSE;
+
+ nsACString::const_iterator charStart, charEnd;
+ charStart = end;
+ aCommand.EndReading(charEnd);
+ nsACString::const_iterator idStart = charStart, idEnd;
+ if (FindCharInReadable(aSeparator, charStart, charEnd)) {
+ idEnd = charStart;
+ } else {
+ idEnd = charEnd;
+ }
+ *aValue = nsDependentCSubstring(idStart, idEnd);
+ return PR_TRUE;
+}
+
const char*
-nsGTKRemoteService::HandleCommand(char* aCommand, nsIDOMWindow* aWindow)
+nsGTKRemoteService::HandleCommand(char* aCommand, nsIDOMWindow* aWindow,
+ PRUint32 aTimestamp)
{
nsresult rv;
@@ -314,6 +399,12 @@
#endif
if (!command.EqualsLiteral("ping")) {
+ nsCAutoString desktopStartupID;
+ nsDependentCString cmd(aCommand);
+ FindExtensionParameterInCommand("DESKTOP_STARTUP_ID",
+ cmd, '\n',
+ &desktopStartupID);
+
char* argv[3] = {"dummyappname", "-remote", aCommand};
rv = cmdline->Init(3, argv, nsnull, nsICommandLine::STATE_REMOTE_EXPLICIT);
if (NS_FAILED(rv))
@@ -322,6 +413,8 @@
if (aWindow)
cmdline->SetWindowContext(aWindow);
+ SetDesktopStartupIDOrTimestamp(desktopStartupID, aTimestamp);
+
rv = cmdline->Run();
if (NS_ERROR_ABORT == rv)
return "500 command not parseable";
@@ -333,7 +426,8 @@
}
const char*
-nsGTKRemoteService::HandleCommandLine(char* aBuffer, nsIDOMWindow* aWindow)
+nsGTKRemoteService::HandleCommandLine(char* aBuffer, nsIDOMWindow* aWindow,
+ PRUint32 aTimestamp)
{
nsresult rv;
@@ -364,6 +458,8 @@
if (NS_FAILED(rv))
return "509 internal error";
+ nsCAutoString desktopStartupID;
+
char **argv = (char**) malloc(sizeof(char*) * argc);
if (!argv) return "509 internal error";
@@ -372,6 +468,12 @@
for (int i = 0; i < argc; ++i) {
argv[i] = aBuffer + TO_LITTLE_ENDIAN32(offset[i]);
+ if (i == 0) {
+ nsDependentCString cmd(argv[0]);
+ FindExtensionParameterInCommand("DESKTOP_STARTUP_ID",
+ cmd, ' ',
+ &desktopStartupID);
+ }
#ifdef DEBUG_bsmedberg
printf(" argv[%i]:\t%s\n", i, argv[i]);
#endif
@@ -386,7 +488,10 @@
if (aWindow)
cmdline->SetWindowContext(aWindow);
+ SetDesktopStartupIDOrTimestamp(desktopStartupID, aTimestamp);
+
rv = cmdline->Run();
+
if (NS_ERROR_ABORT == rv)
return "500 command not parseable";
@@ -486,7 +591,7 @@
return FALSE;
// cool, we got the property data.
- const char *response = HandleCommand(data, window);
+ const char *response = HandleCommand(data, window, pevent->time);
// put the property onto the window as the response
XChangeProperty (GDK_DISPLAY(), GDK_WINDOW_XWINDOW(pevent->window),
@@ -531,7 +636,7 @@
return FALSE;
// cool, we got the property data.
- const char *response = HandleCommandLine(data, window);
+ const char *response = HandleCommandLine(data, window, pevent->time);
// put the property onto the window as the response
XChangeProperty (GDK_DISPLAY(), GDK_WINDOW_XWINDOW(pevent->window),
--- toolkit/components/remote/nsGTKRemoteService.h 2005-04-04 19:11:42.000000000 -0400
+++ toolkit/components/remote/nsGTKRemoteService.h 2007-07-03 18:01:36.000000000 -0400
@@ -80,10 +80,12 @@
nsIWeakReference* aData,
void* aClosure);
- static const char* HandleCommand(char* aCommand, nsIDOMWindow* aWindow);
+ static const char* HandleCommand(char* aCommand, nsIDOMWindow* aWindow,
+ PRUint32 aTimestamp);
#ifdef MOZ_XUL_APP
- static const char* HandleCommandLine(char* aBuffer, nsIDOMWindow* aWindow);
+ static const char* HandleCommandLine(char* aBuffer, nsIDOMWindow* aWindow,
+ PRUint32 aTimestamp);
#endif
static gboolean HandlePropertyChange(GtkWidget *widget,
--- toolkit/components/remote/Makefile.in 2005-04-08 00:59:36.000000000 -0400
+++ toolkit/components/remote/Makefile.in 2007-07-05 17:45:55.000000000 -0400
@@ -56,7 +56,9 @@
string \
appcomps \
toolkitcomps \
- appcomps \
+ appshell \
+ layout \
+ content \
xulapp \
widget \
gfx \
--- toolkit/library/Makefile.in 2007-04-03 10:32:27.000000000 -0400
+++ toolkit/library/Makefile.in 2007-07-03 18:01:36.000000000 -0400
@@ -357,6 +357,10 @@
EXTRA_DSO_LDOPTS += $(MOZ_XPRINT_LDFLAGS)
endif
+ifdef MOZ_ENABLE_STARTUP_NOTIFICATION
+EXTRA_DSO_LDOPTS += $(MOZ_STARTUP_NOTIFICATION_LIBS)
+endif
+
ifdef MOZ_ENABLE_PANGO
EXTRA_DSO_LDOPTS += $(MOZ_PANGO_LIBS)
endif
--- toolkit/xre/nsAppRunner.cpp 2007-04-30 13:26:58.000000000 -0400
+++ toolkit/xre/nsAppRunner.cpp 2007-07-05 17:48:51.000000000 -0400
@@ -72,6 +72,7 @@
#include "nsIComponentRegistrar.h"
#include "nsIContentHandler.h"
#include "nsIDialogParamBlock.h"
+#include "nsIDocument.h"
#include "nsIDOMWindow.h"
#include "nsIEventQueueService.h"
#include "nsIExtensionManager.h"
@@ -99,6 +100,11 @@
#ifdef XP_WIN
#include "nsIWinAppHelper.h"
#endif
+#include "nsPIDOMWindow.h"
+#include "nsIBaseWindow.h"
+#include "nsIWidget.h"
+#include "nsIDocShell.h"
+#include "nsAppShellCID.h"
#include "nsCRT.h"
#include "nsCOMPtr.h"
@@ -262,6 +268,9 @@
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2)
#include <gtk/gtk.h>
#endif //MOZ_WIDGET_GTK || MOZ_WIDGET_GTK2
+#if defined(MOZ_WIDGET_GTK2)
+#include "nsGTKToolkit.h"
+#endif
#if defined(MOZ_WIDGET_QT)
#include <qapplication.h>
@@ -1105,7 +1114,7 @@
// use int here instead of a PR type since it will be returned
// from main - just to keep types consistent
static int
-HandleRemoteArgument(const char* remote)
+HandleRemoteArgument(const char* remote, const char* aDesktopStartupID)
{
nsresult rv;
ArgResult ar;
@@ -1146,7 +1155,7 @@
nsXPIDLCString response;
PRBool success = PR_FALSE;
rv = client.SendCommand(program.get(), username, profile, remote,
- getter_Copies(response), &success);
+ aDesktopStartupID, getter_Copies(response), &success);
// did the command fail?
if (NS_FAILED(rv)) {
PR_fprintf(PR_STDERR, "Error: Failed to send command: %s\n",
@@ -1163,7 +1172,7 @@
}
static PRBool
-RemoteCommandLine()
+RemoteCommandLine(const char* aDesktopStartupID)
{
nsresult rv;
ArgResult ar;
@@ -1195,7 +1204,7 @@
nsXPIDLCString response;
PRBool success = PR_FALSE;
rv = client.SendCommandLine(program.get(), username, nsnull,
- gArgc, gArgv,
+ gArgc, gArgv, aDesktopStartupID,
getter_Copies(response), &success);
// did the command fail?
if (NS_FAILED(rv) || !success)
@@ -2059,6 +2068,53 @@
#ifdef MOZ_WIDGET_GTK2
#include "prlink.h"
typedef void (*_g_set_application_name_fn)(const gchar *application_name);
+typedef void (*_gtk_window_set_auto_startup_notification_fn)(gboolean setting);
+
+static PRFuncPtr FindFunction(const char* aName)
+{
+ PRLibrary *lib = nsnull;
+ PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(aName, &lib);
+ // Since the library was already loaded, we can safely unload it here.
+ if (lib) {
+ PR_UnloadLibrary(lib);
+ }
+ return result;
+}
+
+static nsIWidget* GetMainWidget(nsIDOMWindow* aWindow)
+{
+ // get the native window for this instance
+ nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
+ NS_ENSURE_TRUE(window, nsnull);
+ nsCOMPtr<nsIDocument> doc(do_QueryInterface(window->GetExtantDocument()));
+ NS_ENSURE_TRUE(doc, nsnull);
+ nsCOMPtr<nsISupports> container = doc->GetContainer();
+ nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(container));
+ NS_ENSURE_TRUE(baseWindow, nsnull);
+
+ nsCOMPtr<nsIWidget> mainWidget;
+ baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
+ return mainWidget;
+}
+
+static nsGTKToolkit* GetGTKToolkit()
+{
+ nsCOMPtr<nsIAppShellService> svc = do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
+ if (!svc)
+ return nsnull;
+ nsCOMPtr<nsIDOMWindowInternal> window;
+ svc->GetHiddenDOMWindow(getter_AddRefs(window));
+ if (!window)
+ return nsnull;
+ nsIWidget* widget = GetMainWidget(window);
+ if (!widget)
+ return nsnull;
+ nsIToolkit* toolkit = widget->GetToolkit();
+ if (!toolkit)
+ return nsnull;
+ return NS_STATIC_CAST(nsGTKToolkit*, toolkit);
+}
+
#endif
int
@@ -2235,6 +2291,16 @@
if (CheckArg("install"))
gdk_rgb_set_install(TRUE);
+#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2) || defined(MOZ_ENABLE_XREMOTE)
+ // Stash DESKTOP_STARTUP_ID in malloc'ed memory becaus gtk_init will clear it.
+#define HAVE_DESKTOP_STARTUP_ID
+ const char* desktopStartupIDEnv = PR_GetEnv("DESKTOP_STARTUP_ID");
+ nsCAutoString desktopStartupID;
+ if (desktopStartupIDEnv) {
+ desktopStartupID.Assign(desktopStartupIDEnv);
+ }
+#endif
+
// Initialize GTK+1/2 here for splash
#if defined(MOZ_WIDGET_GTK)
gtk_set_locale();
@@ -2243,15 +2309,15 @@
#if defined(MOZ_WIDGET_GTK2)
// g_set_application_name () is only defined in glib2.2 and higher.
- PRLibrary *glib2 = nsnull;
- _g_set_application_name_fn _g_set_application_name =
- (_g_set_application_name_fn)PR_FindFunctionSymbolAndLibrary("g_set_application_name", &glib2);
+ _g_set_application_name_fn _g_set_application_name =
+ (_g_set_application_name_fn)FindFunction("g_set_application_name");
if (_g_set_application_name) {
_g_set_application_name(gAppData->name);
}
- if (glib2) {
- PR_UnloadLibrary(glib2);
- }
+ _gtk_window_set_auto_startup_notification_fn _gtk_window_set_auto_startup_notification =
+ (_gtk_window_set_auto_startup_notification_fn)FindFunction("gtk_window_set_auto_startup_notification");
+ if (_gtk_window_set_auto_startup_notification)
+ _gtk_window_set_auto_startup_notification(PR_FALSE);
#endif
gtk_widget_set_default_visual(gdk_rgb_get_visual());
@@ -2315,13 +2381,15 @@
PR_fprintf(PR_STDERR, "Error: -remote requires an argument\n");
return 1;
}
+ const char* desktopStartupIDPtr =
+ desktopStartupID.IsEmpty() ? nsnull : desktopStartupID.get();
if (ar) {
- return HandleRemoteArgument(xremotearg);
+ return HandleRemoteArgument(xremotearg, desktopStartupIDPtr);
}
if (!PR_GetEnv("MOZ_NO_REMOTE")) {
// Try to remote the entire command line. If this fails, start up normally.
- if (RemoteCommandLine())
+ if (RemoteCommandLine(desktopStartupIDPtr))
return 0;
}
#endif
@@ -2533,6 +2601,13 @@
NS_TIMELINE_LEAVE("appStartup->CreateHiddenWindow");
NS_ENSURE_SUCCESS(rv, 1);
+#if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK2)
+ nsRefPtr<nsGTKToolkit> toolkit = GetGTKToolkit();
+ if (toolkit && !desktopStartupID.IsEmpty()) {
+ toolkit->SetDesktopStartupID(desktopStartupID);
+ }
+#endif
+
// Extension Compatibility Checking and Startup
if (gAppData->flags & NS_XRE_ENABLE_EXTENSION_MANAGER) {
nsCOMPtr<nsIExtensionManager> em(do_GetService("@mozilla.org/extensions/manager;1"));
@@ -2713,6 +2788,21 @@
}
#endif
+#if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_TOOLKIT_GTK2)
+ nsGTKToolkit* toolkit = GetGTKToolkit();
+ if (toolkit) {
+ nsCAutoString currentDesktopStartupID;
+ toolkit->GetDesktopStartupID(&currentDesktopStartupID);
+ if (!currentDesktopStartupID.IsEmpty()) {
+ nsCAutoString desktopStartupEnv;
+ desktopStartupEnv.AssignLiteral("DESKTOP_STARTUP_ID=");
+ desktopStartupEnv.Append(currentDesktopStartupID);
+ // Leak it with extreme prejudice!
+ PR_SetEnv(ToNewCString(desktopStartupEnv));
+ }
+ }
+#endif
+
rv = LaunchChild(nativeApp, appInitiatedRestart, upgraded ? -1 : 0);
return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
}
--- toolkit/xre/Makefile.in 2007-02-06 02:13:20.000000000 -0500
+++ toolkit/xre/Makefile.in 2007-07-03 18:01:36.000000000 -0400
@@ -69,6 +69,7 @@
shellservice \
string \
uriloader \
+ layout \
widget \
windowwatcher \
xpcom \
--- configure.in 2007-04-03 11:40:02.000000000 -0400
+++ configure.in 2007-07-03 18:01:36.000000000 -0400
@@ -125,6 +125,7 @@
GNOMEUI_VERSION=2.2.0
GCONF_VERSION=1.2.1
LIBGNOME_VERSION=2.0
+STARTUP_NOTIFICATION_VERSION=0.8
dnl Set various checks
dnl ========================================================
@@ -4156,6 +4157,41 @@
AC_SUBST(MOZ_DEFAULT_TOOLKIT)
+dnl ========================================================
+dnl = startup-notification support module
+dnl ========================================================
+
+if test "$MOZ_ENABLE_GTK2"
+then
+ MOZ_ENABLE_STARTUP_NOTIFICATION=
+
+ MOZ_ARG_ENABLE_BOOL(startup-notification,
+ [ --enable-startup-notification Enable startup-notification support (default: disabled) ],
+ MOZ_ENABLE_STARTUP_NOTIFICATION=force,
+ MOZ_ENABLE_STARTUP_NOTIFICATION=)
+ if test "$MOZ_ENABLE_STARTUP_NOTIFICATION"
+ then
+ PKG_CHECK_MODULES(MOZ_STARTUP_NOTIFICATION,
+ libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_VERSION,
+ [MOZ_ENABLE_STARTUP_NOTIFICATION=1], [
+ if test "$MOZ_ENABLE_STARTUP_NOTIFICATION" = "force"
+ then
+ AC_MSG_ERROR([* * * Could not find startup-notification >= $STARTUP_NOTIFICATION_VERSION])
+ fi
+ MOZ_ENABLE_STARTUP_NOTIFICATION=
+ ])
+ fi
+
+ if test "$MOZ_ENABLE_STARTUP_NOTIFICATION"; then
+ AC_DEFINE(MOZ_ENABLE_STARTUP_NOTIFICATION)
+ fi
+
+ TK_LIBS="$TK_LIBS $MOZ_STARTUP_NOTIFICATION_LIBS"
+fi
+AC_SUBST(MOZ_ENABLE_STARTUP_NOTIFICATION)
+AC_SUBST(MOZ_STARTUP_NOTIFICATION_CFLAGS)
+AC_SUBST(MOZ_STARTUP_NOTIFICATION_LIBS)
+
AC_SUBST(GTK_CONFIG)
AC_SUBST(TK_CFLAGS)
AC_SUBST(TK_LIBS)
--- widget/src/gtk2/nsWindow.cpp 2007-04-19 14:46:03.000000000 -0400
+++ widget/src/gtk2/nsWindow.cpp 2007-07-03 18:01:36.000000000 -0400
@@ -40,7 +40,7 @@
#include "prlink.h"
#include "nsWindow.h"
-#include "nsToolkit.h"
+#include "nsGTKToolkit.h"
#include "nsIRenderingContext.h"
#include "nsIRegion.h"
#include "nsIRollupListener.h"
@@ -58,6 +58,11 @@
#include <gdk/gdkx.h>
#include <gdk/gdkkeysyms.h>
+#ifdef MOZ_ENABLE_STARTUP_NOTIFICATION
+#define SN_API_NOT_YET_FROZEN
+#include <startup-notification-1.0/libsn/sn.h>
+#endif
+
#include "gtk2xtbin.h"
#include "nsIPrefService.h"
@@ -660,6 +665,75 @@
return NS_ERROR_NOT_IMPLEMENTED;
}
+typedef void (* SetUserTimeFunc)(GdkWindow* aWindow, guint32 aTimestamp);
+
+// This will become obsolete when new GTK APIs are widely supported,
+// as described here: http://bugzilla.gnome.org/show_bug.cgi?id=347375
+static void
+SetUserTimeAndStartupIDForActivatedWindow(GtkWidget* aWindow)
+{
+ nsCOMPtr<nsIToolkit> toolkit;
+ NS_GetCurrentToolkit(getter_AddRefs(toolkit));
+ if (!toolkit)
+ return;
+
+ nsGTKToolkit* GTKToolkit = NS_STATIC_CAST(nsGTKToolkit*,
+ NS_STATIC_CAST(nsIToolkit*, toolkit));
+ nsCAutoString desktopStartupID;
+ GTKToolkit->GetDesktopStartupID(&desktopStartupID);
+ if (desktopStartupID.IsEmpty()) {
+ // We don't have the data we need. Fall back to an
+ // approximation ... using the timestamp of the remote command
+ // being received as a guess for the timestamp of the user event
+ // that triggered it.
+ PRUint32 timestamp = GTKToolkit->GetFocusTimestamp();
+ if (timestamp) {
+ gdk_window_focus(aWindow->window, timestamp);
+ GTKToolkit->SetFocusTimestamp(0);
+ }
+ return;
+ }
+
+#ifdef MOZ_ENABLE_STARTUP_NOTIFICATION
+ GdkDrawable* drawable = GDK_DRAWABLE(aWindow->window);
+ GtkWindow* win = GTK_WINDOW(aWindow);
+ if (!win) {
+ NS_WARNING("Passed in widget was not a GdkWindow!");
+ return;
+ }
+ GdkScreen* screen = gtk_window_get_screen(win);
+ SnDisplay* snd =
+ sn_display_new(gdk_x11_drawable_get_xdisplay(drawable), nsnull, nsnull);
+ if (!snd)
+ return;
+ SnLauncheeContext* ctx =
+ sn_launchee_context_new(snd, gdk_screen_get_number(screen),
+ desktopStartupID.get());
+ if (!ctx) {
+ sn_display_unref(snd);
+ return;
+ }
+
+ if (sn_launchee_context_get_id_has_timestamp(ctx)) {
+ PRLibrary* gtkLibrary;
+ SetUserTimeFunc setUserTimeFunc = (SetUserTimeFunc)
+ PR_FindFunctionSymbolAndLibrary("gdk_x11_window_set_user_time", &gtkLibrary);
+ if (setUserTimeFunc) {
+ setUserTimeFunc(aWindow->window, sn_launchee_context_get_timestamp(ctx));
+ PR_UnloadLibrary(gtkLibrary);
+ }
+ }
+
+ sn_launchee_context_setup_window(ctx, gdk_x11_drawable_get_xid(drawable));
+ sn_launchee_context_complete(ctx);
+
+ sn_launchee_context_unref(ctx);
+ sn_display_unref(snd);
+#endif
+
+ GTKToolkit->SetDesktopStartupID(EmptyCString());
+}
+
NS_IMETHODIMP
nsWindow::SetFocus(PRBool aRaise)
{
@@ -680,6 +754,10 @@
// set properly.
GtkWidget *toplevelWidget = gtk_widget_get_toplevel(owningWidget);
+ if (toplevelWidget && aRaise) {
+ SetUserTimeAndStartupIDForActivatedWindow(toplevelWidget);
+ }
+
if (gRaiseWindows && aRaise && toplevelWidget &&
!GTK_WIDGET_HAS_FOCUS(owningWidget) &&
!GTK_WIDGET_HAS_FOCUS(toplevelWidget)) {
@@ -1167,7 +1245,7 @@
case NS_NATIVE_GRAPHIC: {
NS_ASSERTION(nsnull != mToolkit, "NULL toolkit, unable to get a GC");
- return (void *)NS_STATIC_CAST(nsToolkit *, mToolkit)->GetSharedGC();
+ return (void *)NS_STATIC_CAST(nsGTKToolkit *, mToolkit)->GetSharedGC();
break;
}
@@ -2802,13 +2880,18 @@
// is shown.
// XXX that may or may not be true for GTK+ 2.x
if (mTransparencyBitmap) {
- ApplyTransparencyBitmap();
+ ApplyTransparencyBitmap();
}
// unset our flag now that our window has been shown
mNeedsShow = PR_FALSE;
if (mIsTopLevel) {
+ // Set up usertime/startupID metadata for the created window.
+ if (mWindowType != eWindowType_invisible) {
+ SetUserTimeAndStartupIDForActivatedWindow(mShell);
+ }
+
moz_drawingarea_set_visibility(mDrawingarea, aAction);
gtk_widget_show(GTK_WIDGET(mContainer));
gtk_widget_show(mShell);
--- widget/src/gtk2/Makefile.in 2006-06-17 11:16:14.000000000 -0400
+++ widget/src/gtk2/Makefile.in 2007-07-03 18:01:36.000000000 -0400
@@ -97,6 +97,7 @@
$(MOZ_COMPONENT_LIBS) \
-lgkgfx \
-lgtkxtbin \
+ $(MOZ_STARTUP_NOTIFICATION_LIBS) \
$(XLDFLAGS) \
$(XLIBS) \
$(MOZ_GTK2_LIBS)
@@ -107,14 +108,15 @@
EXPORTS = \
nsIGdkPixbufImage.h \
+ nsGTKToolkit.h \
mozdrawingarea.h \
mozcontainer.h \
$(NULL)
include $(topsrcdir)/config/rules.mk
-CFLAGS += $(MOZ_GTK2_CFLAGS)
-CXXFLAGS += $(MOZ_GTK2_CFLAGS)
+CFLAGS += $(MOZ_GTK2_CFLAGS) $(MOZ_STARTUP_NOTIFICATION_CFLAGS)
+CXXFLAGS += $(MOZ_GTK2_CFLAGS) $(MOZ_STARTUP_NOTIFICATION_CFLAGS)
DEFINES += -DUSE_XIM
--- widget/src/gtk2/nsToolkit.cpp 2004-04-18 18:00:17.000000000 -0400
+++ widget/src/gtk2/nsToolkit.cpp 2007-07-03 18:01:36.000000000 -0400
@@ -38,7 +38,7 @@
* ***** END LICENSE BLOCK ***** */
#include "nscore.h" // needed for 'nsnull'
-#include "nsToolkit.h"
+#include "nsGTKToolkit.h"
//
// Static thread local storage index of the Toolkit
@@ -51,9 +51,10 @@
// constructor
//
//-------------------------------------------------------------------------
-nsToolkit::nsToolkit()
+nsGTKToolkit::nsGTKToolkit()
{
mSharedGC = nsnull;
+ mFocusTimestamp = 0;
}
//-------------------------------------------------------------------------
@@ -61,7 +62,7 @@
// destructor
//
//-------------------------------------------------------------------------
-nsToolkit::~nsToolkit()
+nsGTKToolkit::~nsGTKToolkit()
{
if (mSharedGC) {
gdk_gc_unref(mSharedGC);
@@ -77,9 +78,9 @@
//
//-------------------------------------------------------------------------
-NS_IMPL_ISUPPORTS1(nsToolkit, nsIToolkit)
+NS_IMPL_ISUPPORTS1(nsGTKToolkit, nsIToolkit)
-void nsToolkit::CreateSharedGC(void)
+void nsGTKToolkit::CreateSharedGC(void)
{
GdkPixmap *pixmap;
@@ -91,7 +92,7 @@
gdk_pixmap_unref(pixmap);
}
-GdkGC *nsToolkit::GetSharedGC(void)
+GdkGC *nsGTKToolkit::GetSharedGC(void)
{
return gdk_gc_ref(mSharedGC);
}
@@ -100,7 +101,7 @@
//
//
//-------------------------------------------------------------------------
-NS_IMETHODIMP nsToolkit::Init(PRThread *aThread)
+NS_IMETHODIMP nsGTKToolkit::Init(PRThread *aThread)
{
CreateSharedGC();
@@ -135,7 +136,7 @@
// Create a new toolkit for this thread...
//
if (!toolkit) {
- toolkit = new nsToolkit();
+ toolkit = new nsGTKToolkit();
if (!toolkit) {
rv = NS_ERROR_OUT_OF_MEMORY;
--- widget/src/xremoteclient/mozilla-xremote-client.cpp 2005-04-04 15:08:51.000000000 -0400
+++ widget/src/xremoteclient/mozilla-xremote-client.cpp 2007-07-03 18:01:36.000000000 -0400
@@ -40,6 +40,7 @@
#include <stdlib.h>
#include <string.h>
#include <plgetopt.h>
+#include <prenv.h>
#ifdef MOZ_WIDGET_PHOTON
#include "PhRemoteClient.h"
#else
@@ -99,7 +100,7 @@
// send the command - it doesn't get any easier than this
PRBool success = PR_FALSE;
char *error = 0;
- rv = client.SendCommand(browser, username, profile, command,
+ rv = client.SendCommand(browser, username, profile, command, nsnull,
&error, &success);
// failed to send command
--- widget/src/xremoteclient/XRemoteClient.cpp 2006-03-30 03:01:13.000000000 -0500
+++ widget/src/xremoteclient/XRemoteClient.cpp 2007-07-03 18:01:36.000000000 -0400
@@ -173,6 +173,7 @@
nsresult
XRemoteClient::SendCommand (const char *aProgram, const char *aUsername,
const char *aProfile, const char *aCommand,
+ const char* aDesktopStartupID,
char **aResponse, PRBool *aWindowFound)
{
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommand"));
@@ -198,7 +199,7 @@
if (NS_SUCCEEDED(rv)) {
// send our command
- rv = DoSendCommand(w, aCommand, aResponse, &destroyed);
+ rv = DoSendCommand(w, aCommand, aDesktopStartupID, aResponse, &destroyed);
// if the window was destroyed, don't bother trying to free the
// lock.
@@ -217,6 +218,7 @@
XRemoteClient::SendCommandLine (const char *aProgram, const char *aUsername,
const char *aProfile,
PRInt32 argc, char **argv,
+ const char* aDesktopStartupID,
char **aResponse, PRBool *aWindowFound)
{
PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommandLine"));
@@ -242,7 +244,7 @@
if (NS_SUCCEEDED(rv)) {
// send our command
- rv = DoSendCommandLine(w, argc, argv, aResponse, &destroyed);
+ rv = DoSendCommandLine(w, argc, argv, aDesktopStartupID, aResponse, &destroyed);
// if the window was destroyed, don't bother trying to free the
// lock.
@@ -643,6 +645,7 @@
nsresult
XRemoteClient::DoSendCommand(Window aWindow, const char *aCommand,
+ const char* aDesktopStartupID,
char **aResponse, PRBool *aDestroyed)
{
*aDestroyed = PR_FALSE;
@@ -651,9 +654,28 @@
("(writing " MOZILLA_COMMAND_PROP " \"%s\" to 0x%x)\n",
aCommand, (unsigned int) aWindow));
+ // We add the DESKTOP_STARTUP_ID setting as an extra line of
+ // the command string. Firefox ignores all lines but the first.
+ static char desktopStartupPrefix[] = "\nDESKTOP_STARTUP_ID=";
+
+ PRInt32 len = strlen(aCommand);
+ if (aDesktopStartupID) {
+ len += sizeof(desktopStartupPrefix) - 1 + strlen(aDesktopStartupID);
+ }
+ char* buffer = (char*)malloc(len + 1);
+ if (!buffer)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ strcpy(buffer, aCommand);
+ if (aDesktopStartupID) {
+ strcat(buffer, desktopStartupPrefix);
+ strcat(buffer, aDesktopStartupID);
+ }
+
XChangeProperty (mDisplay, aWindow, mMozCommandAtom, XA_STRING, 8,
- PropModeReplace, (unsigned char *)aCommand,
- strlen(aCommand));
+ PropModeReplace, (unsigned char *)buffer, len);
+
+ free(buffer);
if (!WaitForResponse(aWindow, aResponse, aDestroyed, mMozCommandAtom))
return NS_ERROR_FAILURE;
@@ -663,7 +685,7 @@
/* like strcpy, but return the char after the final null */
static char*
-estrcpy(char* s, char* d)
+estrcpy(const char* s, char* d)
{
while (*s)
*d++ = *s++;
@@ -674,6 +696,7 @@
nsresult
XRemoteClient::DoSendCommandLine(Window aWindow, PRInt32 argc, char **argv,
+ const char* aDesktopStartupID,
char **aResponse, PRBool *aDestroyed)
{
int i;
@@ -690,9 +713,16 @@
// [argc][offsetargv0][offsetargv1...]<workingdir>\0<argv[0]>\0argv[1]...\0
// (offset is from the beginning of the buffer)
+ static char desktopStartupPrefix[] = " DESKTOP_STARTUP_ID=";
+
PRInt32 argvlen = strlen(cwdbuf);
- for (i = 0; i < argc; ++i)
- argvlen += strlen(argv[i]);
+ for (i = 0; i < argc; ++i) {
+ PRInt32 len = strlen(argv[i]);
+ if (i == 0 && aDesktopStartupID) {
+ len += sizeof(desktopStartupPrefix) - 1 + strlen(aDesktopStartupID);
+ }
+ argvlen += len;
+ }
PRInt32* buffer = (PRInt32*) malloc(argvlen + argc + 1 +
sizeof(PRInt32) * (argc + 1));
@@ -708,6 +738,10 @@
for (int i = 0; i < argc; ++i) {
buffer[i + 1] = TO_LITTLE_ENDIAN32(bufend - ((char*) buffer));
bufend = estrcpy(argv[i], bufend);
+ if (i == 0 && aDesktopStartupID) {
+ bufend = estrcpy(desktopStartupPrefix, bufend - 1);
+ bufend = estrcpy(aDesktopStartupID, bufend - 1);
+ }
}
#ifdef DEBUG_bsmedberg
--- widget/src/xremoteclient/nsRemoteClient.h 2005-04-04 15:08:51.000000000 -0400
+++ widget/src/xremoteclient/nsRemoteClient.h 2007-07-03 18:01:36.000000000 -0400
@@ -76,6 +76,10 @@
* @param aCommand This is the command that is passed to the server.
* Please see the additional information located at:
* http://www.mozilla.org/unix/remote.html
+ *
+ * @param aDesktopStartupID the contents of the DESKTOP_STARTUP_ID environment
+ * variable defined by the Startup Notification specification
+ * http://standards.freedesktop.org/startup-notification-spec/startup-notification-0.1.txt
*
* @param aResponse If there is a response, it will be here. This
* includes error messages. The string is allocated using stdlib
@@ -85,11 +89,16 @@
*/
virtual nsresult SendCommand(const char *aProgram, const char *aUsername,
const char *aProfile, const char *aCommand,
+ const char* aDesktopStartupID,
char **aResponse, PRBool *aSucceeded) = 0;
/**
* Send a complete command line to a running instance.
*
+ * @param aDesktopStartupID the contents of the DESKTOP_STARTUP_ID environment
+ * variable defined by the Startup Notification specification
+ * http://standards.freedesktop.org/startup-notification-spec/startup-notification-0.1.txt
+ *
* @see sendCommand
* @param argc The number of command-line arguments.
*
@@ -97,6 +106,7 @@
virtual nsresult SendCommandLine(const char *aProgram, const char *aUsername,
const char *aProfile,
PRInt32 argc, char **argv,
+ const char* aDesktopStartupID,
char **aResponse, PRBool *aSucceeded) = 0;
};
--- widget/src/xremoteclient/XRemoteClient.h 2006-03-30 03:01:13.000000000 -0500
+++ widget/src/xremoteclient/XRemoteClient.h 2007-07-03 18:01:36.000000000 -0400
@@ -48,10 +48,12 @@
virtual nsresult Init();
virtual nsresult SendCommand(const char *aProgram, const char *aUsername,
const char *aProfile, const char *aCommand,
+ const char* aDesktopStartupID,
char **aResponse, PRBool *aSucceeded);
virtual nsresult SendCommandLine(const char *aProgram, const char *aUsername,
const char *aProfile,
PRInt32 argc, char **argv,
+ const char* aDesktopStartupID,
char **aResponse, PRBool *aSucceeded);
void Shutdown();
@@ -67,10 +69,12 @@
PRBool aSupportsCommandLine);
nsresult DoSendCommand (Window aWindow,
const char *aCommand,
+ const char* aDesktopStartupID,
char **aResponse,
PRBool *aDestroyed);
nsresult DoSendCommandLine(Window aWindow,
PRInt32 argc, char **argv,
+ const char* aDesktopStartupID,
char **aResponse,
PRBool *aDestroyed);
PRBool WaitForResponse (Window aWindow, char **aResponse,
--- /dev/null 2007-07-05 17:03:04.116204904 -0400
+++ widget/src/gtk2/nsGTKToolkit.h 2007-07-03 18:01:36.000000000 -0400
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+/* ***** 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 mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * 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 ***** */
+
+#ifndef GTKTOOLKIT_H
+#define GTKTOOLKIT_H
+
+#include "nsIToolkit.h"
+#include "nsString.h"
+#include <gtk/gtk.h>
+
+/**
+ * Wrapper around the thread running the message pump.
+ * The toolkit abstraction is necessary because the message pump must
+ * execute within the same thread that created the widget under Win32.
+ */
+
+class nsGTKToolkit : public nsIToolkit
+{
+public:
+ nsGTKToolkit();
+ virtual ~nsGTKToolkit();
+
+ NS_DECL_ISUPPORTS
+
+ NS_IMETHOD Init(PRThread *aThread);
+
+ void CreateSharedGC(void);
+ GdkGC *GetSharedGC(void);
+
+ /**
+ * Get/set our value of DESKTOP_STARTUP_ID. When non-empty, this is applied
+ * to the next toplevel window to be shown or focused (and then immediately
+ * cleared).
+ */
+ void SetDesktopStartupID(const nsACString& aID) { mDesktopStartupID = aID; }
+ void GetDesktopStartupID(nsACString* aID) { *aID = mDesktopStartupID; }
+
+ /**
+ * Get/set the timestamp value to be used, if non-zero, to focus the
+ * next top-level window to be shown or focused (upon which it is cleared).
+ */
+ void SetFocusTimestamp(PRUint32 aTimestamp) { mFocusTimestamp = aTimestamp; }
+ PRUint32 GetFocusTimestamp() { return mFocusTimestamp; }
+
+private:
+ GdkGC *mSharedGC;
+ nsCString mDesktopStartupID;
+ PRUint32 mFocusTimestamp;
+};
+
+#endif // GTKTOOLKIT_H