/src/mozilla-central/toolkit/components/remote/nsRemoteService.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim:expandtab:shiftwidth=2:tabstop=8: |
3 | | */ |
4 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
5 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
6 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
7 | | |
8 | | #include "nsGTKRemoteService.h" |
9 | | #ifdef MOZ_ENABLE_DBUS |
10 | | #include "nsDBusRemoteService.h" |
11 | | #endif |
12 | | #include "nsRemoteService.h" |
13 | | |
14 | | #include <gtk/gtk.h> |
15 | | #include <gdk/gdk.h> |
16 | | #include <gdk/gdkx.h> |
17 | | |
18 | | #include "nsIServiceManager.h" |
19 | | #include "nsIAppShellService.h" |
20 | | #include "nsAppShellCID.h" |
21 | | #include "nsInterfaceHashtable.h" |
22 | | #include "mozilla/ModuleUtils.h" |
23 | | #include "nsIWeakReference.h" |
24 | | #include "nsGTKToolkit.h" |
25 | | #include "nsICommandLineRunner.h" |
26 | | #include "nsCommandLine.h" |
27 | | #include "nsString.h" |
28 | | #include "nsIFile.h" |
29 | | |
30 | | NS_IMPL_ISUPPORTS(nsRemoteService, |
31 | | nsIRemoteService, |
32 | | nsIObserver) |
33 | | |
34 | | NS_IMETHODIMP |
35 | | nsRemoteService::Startup(const char* aAppName, const char* aProfileName) |
36 | 0 | { |
37 | 0 | #if defined(MOZ_ENABLE_DBUS) |
38 | 0 | nsresult rv; |
39 | 0 | mDBusRemoteService = new nsDBusRemoteService(); |
40 | 0 | rv = mDBusRemoteService->Startup(aAppName, aProfileName); |
41 | 0 | if (NS_FAILED(rv)) { |
42 | 0 | mDBusRemoteService = nullptr; |
43 | 0 | } |
44 | 0 | #endif |
45 | 0 |
|
46 | 0 | if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) { |
47 | 0 | mGtkRemoteService = new nsGTKRemoteService(); |
48 | 0 | mGtkRemoteService->Startup(aAppName, aProfileName); |
49 | 0 | } |
50 | 0 |
|
51 | 0 | if (!mDBusRemoteService && !mGtkRemoteService) |
52 | 0 | return NS_ERROR_FAILURE; |
53 | 0 | |
54 | 0 | nsCOMPtr<nsIObserverService> obs(do_GetService("@mozilla.org/observer-service;1")); |
55 | 0 | if (obs) { |
56 | 0 | obs->AddObserver(this, "xpcom-shutdown", false); |
57 | 0 | obs->AddObserver(this, "quit-application", false); |
58 | 0 | } |
59 | 0 |
|
60 | 0 | return NS_OK; |
61 | 0 | } |
62 | | |
63 | | NS_IMETHODIMP |
64 | | nsRemoteService::RegisterWindow(mozIDOMWindow* aWindow) |
65 | 0 | { |
66 | 0 | // Note: RegisterWindow() is not implemented/needed by DBus service. |
67 | 0 | if (mGtkRemoteService) { |
68 | 0 | mGtkRemoteService->RegisterWindow(aWindow); |
69 | 0 | } |
70 | 0 | return NS_OK; |
71 | 0 | } |
72 | | |
73 | | NS_IMETHODIMP |
74 | | nsRemoteService::Shutdown() |
75 | 0 | { |
76 | 0 | #if defined(MOZ_ENABLE_DBUS) |
77 | 0 | if (mDBusRemoteService) { |
78 | 0 | mDBusRemoteService->Shutdown(); |
79 | 0 | mDBusRemoteService = nullptr; |
80 | 0 | } |
81 | 0 | #endif |
82 | 0 | if (mGtkRemoteService) { |
83 | 0 | mGtkRemoteService->Shutdown(); |
84 | 0 | mGtkRemoteService = nullptr; |
85 | 0 | } |
86 | 0 | return NS_OK; |
87 | 0 | } |
88 | | |
89 | | nsRemoteService::~nsRemoteService() |
90 | 0 | { |
91 | 0 | Shutdown(); |
92 | 0 | } |
93 | | |
94 | | NS_IMETHODIMP |
95 | | nsRemoteService::Observe(nsISupports* aSubject, |
96 | | const char *aTopic, |
97 | | const char16_t *aData) |
98 | 0 | { |
99 | 0 | // This can be xpcom-shutdown or quit-application, but it's the same either |
100 | 0 | // way. |
101 | 0 | Shutdown(); |
102 | 0 | return NS_OK; |
103 | 0 | } |
104 | | |
105 | | // Set desktop startup ID to the passed ID, if there is one, so that any created |
106 | | // windows get created with the right window manager metadata, and any windows |
107 | | // that get new tabs and are activated also get the right WM metadata. |
108 | | // The timestamp will be used if there is no desktop startup ID, or if we're |
109 | | // raising an existing window rather than showing a new window for the first time. |
110 | | void |
111 | | nsRemoteService::SetDesktopStartupIDOrTimestamp(const nsACString& aDesktopStartupID, |
112 | 0 | uint32_t aTimestamp) { |
113 | 0 | nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit(); |
114 | 0 | if (!toolkit) |
115 | 0 | return; |
116 | 0 | |
117 | 0 | if (!aDesktopStartupID.IsEmpty()) { |
118 | 0 | toolkit->SetDesktopStartupID(aDesktopStartupID); |
119 | 0 | } |
120 | 0 |
|
121 | 0 | toolkit->SetFocusTimestamp(aTimestamp); |
122 | 0 | } |
123 | | |
124 | | static bool |
125 | | FindExtensionParameterInCommand(const char* aParameterName, |
126 | | const nsACString& aCommand, |
127 | | char aSeparator, |
128 | | nsACString* aValue) |
129 | 0 | { |
130 | 0 | nsAutoCString searchFor; |
131 | 0 | searchFor.Append(aSeparator); |
132 | 0 | searchFor.Append(aParameterName); |
133 | 0 | searchFor.Append('='); |
134 | 0 |
|
135 | 0 | nsACString::const_iterator start, end; |
136 | 0 | aCommand.BeginReading(start); |
137 | 0 | aCommand.EndReading(end); |
138 | 0 | if (!FindInReadable(searchFor, start, end)) |
139 | 0 | return false; |
140 | 0 | |
141 | 0 | nsACString::const_iterator charStart, charEnd; |
142 | 0 | charStart = end; |
143 | 0 | aCommand.EndReading(charEnd); |
144 | 0 | nsACString::const_iterator idStart = charStart, idEnd; |
145 | 0 | if (FindCharInReadable(aSeparator, charStart, charEnd)) { |
146 | 0 | idEnd = charStart; |
147 | 0 | } else { |
148 | 0 | idEnd = charEnd; |
149 | 0 | } |
150 | 0 | *aValue = nsDependentCSubstring(idStart, idEnd); |
151 | 0 | return true; |
152 | 0 | } |
153 | | |
154 | | const char* |
155 | | nsRemoteService::HandleCommandLine(const char* aBuffer, nsIDOMWindow* aWindow, |
156 | | uint32_t aTimestamp) |
157 | 0 | { |
158 | 0 | nsCOMPtr<nsICommandLineRunner> cmdline(new nsCommandLine()); |
159 | 0 |
|
160 | 0 | // the commandline property is constructed as an array of int32_t |
161 | 0 | // followed by a series of null-terminated strings: |
162 | 0 | // |
163 | 0 | // [argc][offsetargv0][offsetargv1...]<workingdir>\0<argv[0]>\0argv[1]...\0 |
164 | 0 | // (offset is from the beginning of the buffer) |
165 | 0 |
|
166 | 0 | int32_t argc = TO_LITTLE_ENDIAN32(*reinterpret_cast<const int32_t*>(aBuffer)); |
167 | 0 | const char *wd = aBuffer + ((argc + 1) * sizeof(int32_t)); |
168 | 0 |
|
169 | 0 | nsCOMPtr<nsIFile> lf; |
170 | 0 | nsresult rv = NS_NewNativeLocalFile(nsDependentCString(wd), true, |
171 | 0 | getter_AddRefs(lf)); |
172 | 0 | if (NS_FAILED(rv)) |
173 | 0 | return "509 internal error"; |
174 | 0 | |
175 | 0 | nsAutoCString desktopStartupID; |
176 | 0 |
|
177 | 0 | const char **argv = (const char**) malloc(sizeof(char*) * argc); |
178 | 0 | if (!argv) return "509 internal error"; |
179 | 0 | |
180 | 0 | const int32_t *offset = reinterpret_cast<const int32_t*>(aBuffer) + 1; |
181 | 0 |
|
182 | 0 | for (int i = 0; i < argc; ++i) { |
183 | 0 | argv[i] = aBuffer + TO_LITTLE_ENDIAN32(offset[i]); |
184 | 0 |
|
185 | 0 | if (i == 0) { |
186 | 0 | nsDependentCString cmd(argv[0]); |
187 | 0 | FindExtensionParameterInCommand("DESKTOP_STARTUP_ID", |
188 | 0 | cmd, ' ', |
189 | 0 | &desktopStartupID); |
190 | 0 | } |
191 | 0 | } |
192 | 0 |
|
193 | 0 | rv = cmdline->Init(argc, argv, lf, nsICommandLine::STATE_REMOTE_AUTO); |
194 | 0 |
|
195 | 0 | free (argv); |
196 | 0 | if (NS_FAILED(rv)) { |
197 | 0 | return "509 internal error"; |
198 | 0 | } |
199 | 0 | |
200 | 0 | if (aWindow) |
201 | 0 | cmdline->SetWindowContext(aWindow); |
202 | 0 |
|
203 | 0 | SetDesktopStartupIDOrTimestamp(desktopStartupID, aTimestamp); |
204 | 0 |
|
205 | 0 | rv = cmdline->Run(); |
206 | 0 |
|
207 | 0 | if (NS_ERROR_ABORT == rv) |
208 | 0 | return "500 command not parseable"; |
209 | 0 | |
210 | 0 | if (NS_FAILED(rv)) |
211 | 0 | return "509 internal error"; |
212 | 0 | |
213 | 0 | return "200 executed command"; |
214 | 0 | } |
215 | | |
216 | | // {C0773E90-5799-4eff-AD03-3EBCD85624AC} |
217 | | #define NS_REMOTESERVICE_CID \ |
218 | | { 0xc0773e90, 0x5799, 0x4eff, { 0xad, 0x3, 0x3e, 0xbc, 0xd8, 0x56, 0x24, 0xac } } |
219 | | |
220 | | NS_GENERIC_FACTORY_CONSTRUCTOR(nsRemoteService) |
221 | | NS_DEFINE_NAMED_CID(NS_REMOTESERVICE_CID); |
222 | | |
223 | | static const mozilla::Module::CIDEntry kRemoteCIDs[] = { |
224 | | { &kNS_REMOTESERVICE_CID, false, nullptr, nsRemoteServiceConstructor }, |
225 | | { nullptr } |
226 | | }; |
227 | | |
228 | | static const mozilla::Module::ContractIDEntry kRemoteContracts[] = { |
229 | | { "@mozilla.org/toolkit/remote-service;1", &kNS_REMOTESERVICE_CID }, |
230 | | { nullptr } |
231 | | }; |
232 | | |
233 | | static const mozilla::Module kRemoteModule = { |
234 | | mozilla::Module::kVersion, |
235 | | kRemoteCIDs, |
236 | | kRemoteContracts |
237 | | }; |
238 | | |
239 | | NSMODULE_DEFN(RemoteServiceModule) = &kRemoteModule; |