michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:expandtab:shiftwidth=2:tabstop=8: michael@0: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsGTKRemoteService.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "nsIBaseWindow.h" michael@0: #include "nsIDocShell.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "mozilla/ModuleUtils.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIWeakReference.h" michael@0: #include "nsIWidget.h" michael@0: #include "nsIAppShellService.h" michael@0: #include "nsAppShellCID.h" michael@0: michael@0: #include "nsCOMPtr.h" michael@0: michael@0: #include "nsGTKToolkit.h" michael@0: michael@0: NS_IMPL_ISUPPORTS(nsGTKRemoteService, michael@0: nsIRemoteService, michael@0: nsIObserver) michael@0: michael@0: NS_IMETHODIMP michael@0: nsGTKRemoteService::Startup(const char* aAppName, const char* aProfileName) michael@0: { michael@0: NS_ASSERTION(aAppName, "Don't pass a null appname!"); michael@0: sRemoteImplementation = this; michael@0: michael@0: if (mServerWindow) return NS_ERROR_ALREADY_INITIALIZED; michael@0: michael@0: XRemoteBaseStartup(aAppName, aProfileName); michael@0: michael@0: mServerWindow = gtk_invisible_new(); michael@0: gtk_widget_realize(mServerWindow); michael@0: HandleCommandsFor(mServerWindow, nullptr); michael@0: michael@0: mWindows.EnumerateRead(StartupHandler, this); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: PLDHashOperator michael@0: nsGTKRemoteService::StartupHandler(GtkWidget* aKey, michael@0: nsIWeakReference* aData, michael@0: void* aClosure) michael@0: { michael@0: GtkWidget* widget = (GtkWidget*) aKey; michael@0: nsGTKRemoteService* aThis = (nsGTKRemoteService*) aClosure; michael@0: michael@0: aThis->HandleCommandsFor(widget, aData); michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: static nsIWidget* GetMainWidget(nsIDOMWindow* aWindow) michael@0: { michael@0: // get the native window for this instance michael@0: nsCOMPtr window(do_QueryInterface(aWindow)); michael@0: NS_ENSURE_TRUE(window, nullptr); michael@0: michael@0: nsCOMPtr baseWindow michael@0: (do_QueryInterface(window->GetDocShell())); michael@0: NS_ENSURE_TRUE(baseWindow, nullptr); michael@0: michael@0: nsCOMPtr mainWidget; michael@0: baseWindow->GetMainWidget(getter_AddRefs(mainWidget)); michael@0: return mainWidget; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsGTKRemoteService::RegisterWindow(nsIDOMWindow* aWindow) michael@0: { michael@0: nsIWidget* mainWidget = GetMainWidget(aWindow); michael@0: NS_ENSURE_TRUE(mainWidget, NS_ERROR_FAILURE); michael@0: michael@0: GtkWidget* widget = michael@0: (GtkWidget*) mainWidget->GetNativeData(NS_NATIVE_SHELLWIDGET); michael@0: NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr weak = do_GetWeakReference(aWindow); michael@0: NS_ENSURE_TRUE(weak, NS_ERROR_FAILURE); michael@0: michael@0: mWindows.Put(widget, weak); michael@0: michael@0: // If Startup() has already been called, immediately register this window. michael@0: if (mServerWindow) { michael@0: HandleCommandsFor(widget, weak); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsGTKRemoteService::Shutdown() michael@0: { michael@0: if (!mServerWindow) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: gtk_widget_destroy(mServerWindow); michael@0: mServerWindow = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Set desktop startup ID to the passed ID, if there is one, so that any created michael@0: // windows get created with the right window manager metadata, and any windows michael@0: // that get new tabs and are activated also get the right WM metadata. michael@0: // The timestamp will be used if there is no desktop startup ID, or if we're michael@0: // raising an existing window rather than showing a new window for the first time. michael@0: void michael@0: nsGTKRemoteService::SetDesktopStartupIDOrTimestamp(const nsACString& aDesktopStartupID, michael@0: uint32_t aTimestamp) { michael@0: nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit(); michael@0: if (!toolkit) michael@0: return; michael@0: michael@0: if (!aDesktopStartupID.IsEmpty()) { michael@0: toolkit->SetDesktopStartupID(aDesktopStartupID); michael@0: } michael@0: michael@0: toolkit->SetFocusTimestamp(aTimestamp); michael@0: } michael@0: michael@0: michael@0: void michael@0: nsGTKRemoteService::HandleCommandsFor(GtkWidget* widget, michael@0: nsIWeakReference* aWindow) michael@0: { michael@0: g_signal_connect(G_OBJECT(widget), "property_notify_event", michael@0: G_CALLBACK(HandlePropertyChange), aWindow); michael@0: michael@0: gtk_widget_add_events(widget, GDK_PROPERTY_CHANGE_MASK); michael@0: michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: Window window = GDK_WINDOW_XWINDOW(widget->window); michael@0: #else michael@0: Window window = gdk_x11_window_get_xid(gtk_widget_get_window(widget)); michael@0: #endif michael@0: nsXRemoteService::HandleCommandsFor(window); michael@0: michael@0: } michael@0: michael@0: gboolean michael@0: nsGTKRemoteService::HandlePropertyChange(GtkWidget *aWidget, michael@0: GdkEventProperty *pevent, michael@0: nsIWeakReference *aThis) michael@0: { michael@0: if (pevent->state == GDK_PROPERTY_NEW_VALUE) { michael@0: Atom changedAtom = gdk_x11_atom_to_xatom(pevent->atom); michael@0: michael@0: #if (MOZ_WIDGET_GTK == 2) michael@0: XID window = GDK_WINDOW_XWINDOW(pevent->window); michael@0: #else michael@0: XID window = gdk_x11_window_get_xid(gtk_widget_get_window(aWidget)); michael@0: #endif michael@0: return HandleNewProperty(window, michael@0: GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), michael@0: pevent->time, changedAtom, aThis); michael@0: } michael@0: return FALSE; michael@0: } michael@0: michael@0: michael@0: // {C0773E90-5799-4eff-AD03-3EBCD85624AC} michael@0: #define NS_REMOTESERVICE_CID \ michael@0: { 0xc0773e90, 0x5799, 0x4eff, { 0xad, 0x3, 0x3e, 0xbc, 0xd8, 0x56, 0x24, 0xac } } michael@0: michael@0: NS_GENERIC_FACTORY_CONSTRUCTOR(nsGTKRemoteService) michael@0: NS_DEFINE_NAMED_CID(NS_REMOTESERVICE_CID); michael@0: michael@0: static const mozilla::Module::CIDEntry kRemoteCIDs[] = { michael@0: { &kNS_REMOTESERVICE_CID, false, nullptr, nsGTKRemoteServiceConstructor }, michael@0: { nullptr } michael@0: }; michael@0: michael@0: static const mozilla::Module::ContractIDEntry kRemoteContracts[] = { michael@0: { "@mozilla.org/toolkit/remote-service;1", &kNS_REMOTESERVICE_CID }, michael@0: { nullptr } michael@0: }; michael@0: michael@0: static const mozilla::Module kRemoteModule = { michael@0: mozilla::Module::kVersion, michael@0: kRemoteCIDs, michael@0: kRemoteContracts michael@0: }; michael@0: michael@0: NSMODULE_DEFN(RemoteServiceModule) = &kRemoteModule;