Files
roytam1 d56ce7399f import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1232506: Make dom/devicestorage really work with e10s. r=alchen (7f95105c5e)
- Bug 1208944 - Part 1. Dispatch CompositionEvent to Plugin. r=masayuki (85c062b417)
- Bug 1208944 - Part 2-a. Handle CompositionEvent on plugin. r=masayuki (ea2cebfca9)
- Bug 1208944 - Part 2-b. Workaround for OSX. r=masayuki (ca401cbc04)
- Bug 1208944 - Part 3. Allow IME window messages on plugin process. r=jmathies (571fd75010)
- Bug 1192844: Accept 0xCC padding in WindowsDllDetourPatcher::CreateTrampoline. r=m_kato (b34b6173d3)
- Bug 1201205 part 1: Add an AutoVirtualProtect helper class to make the next patch easier. r=m_kato (b384bd2412)
- Bug 1201205 part 2: Restore protection on the nop space separately from the function. r=m_kato (a822b2414b)
- Bug 1208944 - Part 4. nsWindowsDllInterceptor supports IMM32 API hook. r=ehsan (9b409ff15a)
- Bug 1208944 - Part 5. Send PluginEvent to content process. r=jmathies (4ee0341190)
- Bug 1208944 - Part 6. Get vaild TextRangeArray on compositionupdate. r=masayuki (18f184931c)
- Bug 1208944 - Part 7. Don't post WM_IME_REQUEST on windowless plugin since we don't convert pointer over process. r=masayuki (6b1a9ce71f)
- Bug 1208944 - Part 8. Don't get selection on start compostion when plugin has foucs. r=masayuki (daf400620e)
- Add Telemetry for the drawing models that plugins use. (bug 1229961 part 1, r=aklotz,vladan) (c9645a68ec)
- Enable direct plugin drawing by default. (bug 1229961 part 2, r=aklotz) (080c9337cb)
- Bug 1213845 - enable osk support on windows 8, but hide it behind a preference, r=jaws (fcb8dfb10b)
- Bug 1192248 - Fix wchar_t/char16_t mismatch WinIMEHandler.cpp. r=masayuki (13e61f3f0c)
- Bug 1226145 - actually check whether the on-screen keyboard is up rather than relying on internal state, r=masayuki (da090b605d)
- Bug 1208944 - Part 9. Hook IMM32 APIs on plugin process. r=masayuki (f15d73721f)
- Bug 1208944 - Part 10-a. Call CallWindowProc when WidgetPluginEvent isn't handled by plugin. r=masayuki (c54eaa50ed)
- Bug 1208944 - Part 10-b. Call DefaultProc When CompositionEvent isn't handled correctly by plugin. r=masayuki (0e77eaa40f)
- Bug 1157046 - Remove ARRAY_LENGTH in favor of MOZ_ARRAY_LENGTH; r=Waldo (a7f8ce3684)
- Bug 1196834 - Add a test that confirms plugin windows are hidden after switching from a remote to local tab. r=roc (a09d4a32af)
- Bug 1208944 - Part 11. Add test. r=jmathies (ed8e4c87d2)
- Bug 1231378 - part 1 - Fix uninitialized members of classes in docshell/*, r=smaug (fcd7615d97)
- Bug 1231378 - part 2 - Fix uninitialized members of classes in dom/*,r=smaug (40b354438f)
- Bug 1231378 - part 3 - Fix uninitialized members of classes in module/libjar and mfbt, r=smaug (ee15d8739a)
- Bug 1231378 - part 4 - Fix uninitialized members of classes in netwerk/widget/storage/uriloader/memory/tools, r=smaug (6aec559dd8)
- Bug 1238082 - Fix mode lines in dom/ipc. r=baku (a49aa3555b)
- Bug 1024149 - Use element size for upload texture when using SVG image. r=jgilbert r=roc (531bdd2406)
- Bug 1233922 - Skip Camera preinit for browser elements. r=fabrice (cd8ffbb112)
- Bug 1159327 - Enable accessibility more broadly with e10s and add an e10s a11y blacklist for clients with known issues. r=tbsaunde (374f49a942)
- Bug 1198459 - Prevent accessibility from initializing in content processes when e10s is running. r=tbsaunde (33bdfccd56)
- Bug 1115956 - Improve notice string for when e10s was disabled for accessibility. r=mconley (e5ff276d9e)
- Bug 1172491 - Let e10s be enabled in safe mode. r=felipe (bd0a3fbbd5)
- Bug 1226487 - Allow e10s to run on Beta. r=mconley (05103c816d)
- Bug 634063 - Use gfxPrefs for some layers acceleration prefs. r=nical (9a20bcd8d2)
- Bug 1198459 - Add support for disabling e10s if a11y was run in the previous session, or run in a session over the previous week. r=felipe (7154a021bd)
- Bug 1171171 - Make sure the graphics preferences are initialized early enough. r=billm (34801701aa)
- Bug 1171171: Move nsAppRunner's gfxPrefs #include out of windows-specific section. r=milan a=KWierso (492fa00f99)
- Bug 1182048 - Part 1: Allow e10s to be enabled,r=vlad (628949ad83)
- Bug 1182048 - Part 2: Implement e10s support for WebVR,r=vlad (a77d280b48)
- Bug 1207221 - Do not prevent the system app from vibrating when it is hidden. r=bz r=dhylands (f3d2306f41)
- Bug 1233902 - Check the TP list in sendBeacon(). r=gcp (bc279755ab)
- Bug 1216207 - Modify navigator.hasFeature method to implement new (9b4571468e)
- Bug 1217187 - Modify navigator.hasFeature method to detect new (d9ea58e65c)
- Bug 1125477 - Part 1: Modify dom/tv mochitest in order to enable e10s test. r=seanlin (7b535fddaa)
- Bug 1125477 - Part 2: Modify permission check of TV Manager API in order to remove dom.testing.tv_enabled_for_hosted_apps. r=seanlin;r=smaug (5719fdf3a7)
- Bug 1125477 - Part3: Remove permission removing code. r=seanlin (614de5dfd1)
- Bug 1223672 - NSec package cannot use device storage API. r=kchen (f1fc6711ea)
- Bug 1224609 - Ensure the primary screen is always returned in RecvScreenForBrowser if all else fails. r=wmccloskey (d562935754)
- Bug 1180288 - Use native filepickers for Graphene. r=khuey (0b9c78ce13)
- Bug 1201394 - Use cached preferences value in ProcessPriorityManager. r=gsvelto (d211492014)
- Bug 1212833 - Delay the MemoryPressure when an application goes to background. r=gsvelto (ce33de4324)
- Bug 1186812 (part 1) - Replace nsBaseHashtable::EnumerateRead() calls in dom/{ipc,plugins}/. r=jimm. (c061bb9d1b)
- Bug 1212984 - HangMonitorChild should delete its Transport. r=billm (3331593b2d)
- Bug 1186812 (part 2) - Replace nsBaseHashtable::EnumerateRead() calls in dom/{ipc,plugins}/. r=jimm. (fdac3f52cb)
- Bug 1215239 - Do not set ownApp for a browser element. r=bholley (e3cc250c3f)
- Bug 1241278 - Change Notification.requestPermission() to return a promise. r=baku (b0a86eeeb5)
- Bug 1249102. Make overrides of WorkerRunnable::PostRun a bit more consistent. r=khuey (a23bf9468f)
- Bug 1209812 (part 6) - Convert all gfxImageFormat values to SurfaceFormat equivalents. r=jrmuizel. (9a5da3597f)
- Bug 1239225 - Remove unused args from TextureImage's constructor and related functions. r=mattwoodrow. (26ff005ecb)
- Bug 1240708 - Various trivial coverity warning fixes. r=kats (74a485c2b8)
- Bug 1240708 - Various trivial coverity warning fixes (part 2). r=kats (34bcd568dc)
- Bug 1219494 - Part 3 gfx/gl with gfxCrash. r=mchang (268968a3d9)
- Bug 1232456 - Create EGL surface through widget; r=snorp (13634bebc6)
- Bug 1232456 - Renew EGL surface using existing compositor widget; r=snorp (2649b088d3)
- Bug 1187322 - Don't require accelerated OpenGL contexts for BasicCompositor on OS X. r=jrmuizel (87f92af2c8)
- Bug 1238753 - Use StartRemoteDrawingInRegion on Mac. r=mattwoodrow (22870ed043)
- Bug 1238755 - Avoid a copy when uploading the BasicCompositor result to a texture. r=mattwoodrow (0b6663ab61)
- Bug 890156 - patch 0.2 - Remove the (unused) aRect parameter from nsBaseWidget::BaseCreate. r=kats (1120763eef)
- Bug 1241983 - Make DOM Identity observe inner-window-destroyed not dom-window-destroyed; r=ferjm (7cf4cf3211)
- Bug 1236282 - Clip color layer drawing in BasicCompositor so that unbounded operators don't erase stuff outside the layer. r=Bas (a7e73d1d8d)
- Bug 1238753 - Make BasicCompositor respect changes to mInvalidRegion through StartRemoteDrawingWithRegion properly. r=mattwoodrow (36e20bccce)
- Bug 1238753 - Don't skip the call to StartRemoteDrawing in from BasicCompositor::BeginFrame if the invalid region is empty. r=mattwoodrow (783b25775f)
- Bug 1239137 - Return early from BasicCompositor::DrawQuad if transformBounds is empty. r=mattwoodrow (0815cfc28a)
- Bug 1239530 (part 1) - Remove PuppetWidget::Scroll(), which is dead. r=kats. (63ab8c32b6)
- Bug 1239530 (part 2) - Use LayoutDevice coordinates in {Start,End}RemoteDrawingInRegion() and related functions. r=kats. (609001767d)
- Bug 1239537 - Remove Compositor::GetWidgetSize(), which is unused. r=mattwoodrow. (25732d37b1)
- Bug 1242293 - Don't call EndRemoteDrawingInRegion if StartRemoteDrawingInRegion returns a null DrawTarget. r=mstange (8e297c3b84)
- import changes from mozilla: Bug 1211642: Whitelist test plugin for async plugin init; r=jimm (f02deaaeb8) (6689ce99c8)
2023-08-15 16:18:14 +08:00

806 lines
23 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=2:tabstop=8:
*/
/* vim:set ts=8 sw=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ArrayUtils.h"
#include "XRemoteClient.h"
#include "prmem.h"
#include "prprf.h"
#include "plstr.h"
#include "prsystem.h"
#include "mozilla/Logging.h"
#include "prenv.h"
#include "prdtoa.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <limits.h>
#include <X11/Xatom.h>
#define MOZILLA_VERSION_PROP "_MOZILLA_VERSION"
#define MOZILLA_LOCK_PROP "_MOZILLA_LOCK"
#define MOZILLA_COMMANDLINE_PROP "_MOZILLA_COMMANDLINE"
#define MOZILLA_RESPONSE_PROP "_MOZILLA_RESPONSE"
#define MOZILLA_USER_PROP "_MOZILLA_USER"
#define MOZILLA_PROFILE_PROP "_MOZILLA_PROFILE"
#define MOZILLA_PROGRAM_PROP "_MOZILLA_PROGRAM"
#ifdef IS_BIG_ENDIAN
#define TO_LITTLE_ENDIAN32(x) \
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
#else
#define TO_LITTLE_ENDIAN32(x) (x)
#endif
#ifndef MAX_PATH
#ifdef PATH_MAX
#define MAX_PATH PATH_MAX
#else
#define MAX_PATH 1024
#endif
#endif
using mozilla::LogLevel;
static PRLogModuleInfo *sRemoteLm = nullptr;
static int (*sOldHandler)(Display *, XErrorEvent *);
static bool sGotBadWindow;
XRemoteClient::XRemoteClient()
{
mDisplay = 0;
mInitialized = false;
mMozVersionAtom = 0;
mMozLockAtom = 0;
mMozCommandLineAtom = 0;
mMozResponseAtom = 0;
mMozWMStateAtom = 0;
mMozUserAtom = 0;
mMozProfileAtom = 0;
mMozProgramAtom = 0;
mLockData = 0;
if (!sRemoteLm)
sRemoteLm = PR_NewLogModule("XRemoteClient");
MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::XRemoteClient"));
}
XRemoteClient::~XRemoteClient()
{
MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::~XRemoteClient"));
if (mInitialized)
Shutdown();
}
// Minimize the roundtrips to the X-server
static const char *XAtomNames[] = {
MOZILLA_VERSION_PROP,
MOZILLA_LOCK_PROP,
MOZILLA_RESPONSE_PROP,
"WM_STATE",
MOZILLA_USER_PROP,
MOZILLA_PROFILE_PROP,
MOZILLA_PROGRAM_PROP,
MOZILLA_COMMANDLINE_PROP
};
static Atom XAtoms[MOZ_ARRAY_LENGTH(XAtomNames)];
nsresult
XRemoteClient::Init()
{
MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::Init"));
if (mInitialized)
return NS_OK;
// try to open the display
mDisplay = XOpenDisplay(0);
if (!mDisplay)
return NS_ERROR_FAILURE;
// get our atoms
XInternAtoms(mDisplay, const_cast<char**>(XAtomNames),
MOZ_ARRAY_LENGTH(XAtomNames), False, XAtoms);
int i = 0;
mMozVersionAtom = XAtoms[i++];
mMozLockAtom = XAtoms[i++];
mMozResponseAtom = XAtoms[i++];
mMozWMStateAtom = XAtoms[i++];
mMozUserAtom = XAtoms[i++];
mMozProfileAtom = XAtoms[i++];
mMozProgramAtom = XAtoms[i++];
mMozCommandLineAtom = XAtoms[i++];
mInitialized = true;
return NS_OK;
}
void
XRemoteClient::Shutdown (void)
{
MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::Shutdown"));
if (!mInitialized)
return;
// shut everything down
XCloseDisplay(mDisplay);
mDisplay = 0;
mInitialized = false;
if (mLockData) {
free(mLockData);
mLockData = 0;
}
}
static int
HandleBadWindow(Display *display, XErrorEvent *event)
{
if (event->error_code == BadWindow) {
sGotBadWindow = true;
return 0; // ignored
}
else {
return (*sOldHandler)(display, event);
}
}
nsresult
XRemoteClient::SendCommandLine (const char *aProgram, const char *aUsername,
const char *aProfile,
int32_t argc, char **argv,
const char* aDesktopStartupID,
char **aResponse, bool *aWindowFound)
{
MOZ_LOG(sRemoteLm, LogLevel::Debug, ("XRemoteClient::SendCommandLine"));
*aWindowFound = false;
// FindBestWindow() iterates down the window hierarchy, so catch X errors
// when windows get destroyed before being accessed.
sOldHandler = XSetErrorHandler(HandleBadWindow);
Window w = FindBestWindow(aProgram, aUsername, aProfile);
nsresult rv = NS_OK;
if (w) {
// ok, let the caller know that we at least found a window.
*aWindowFound = true;
// Ignore BadWindow errors up to this point. The last request from
// FindBestWindow() was a synchronous XGetWindowProperty(), so no need to
// Sync. Leave the error handler installed to detect if w gets destroyed.
sGotBadWindow = false;
// make sure we get the right events on that window
XSelectInput(mDisplay, w,
(PropertyChangeMask|StructureNotifyMask));
bool destroyed = false;
// get the lock on the window
rv = GetLock(w, &destroyed);
if (NS_SUCCEEDED(rv)) {
// send our command
rv = DoSendCommandLine(w, argc, argv, aDesktopStartupID, aResponse,
&destroyed);
// if the window was destroyed, don't bother trying to free the
// lock.
if (!destroyed)
FreeLock(w); // doesn't really matter what this returns
}
}
XSetErrorHandler(sOldHandler);
MOZ_LOG(sRemoteLm, LogLevel::Debug, ("SendCommandInternal returning 0x%x\n", rv));
return rv;
}
Window
XRemoteClient::CheckWindow(Window aWindow)
{
Atom type = None;
int format;
unsigned long nitems, bytesafter;
unsigned char *data;
Window innerWindow;
XGetWindowProperty(mDisplay, aWindow, mMozWMStateAtom,
0, 0, False, AnyPropertyType,
&type, &format, &nitems, &bytesafter, &data);
if (type) {
XFree(data);
return aWindow;
}
// didn't find it here so check the children of this window
innerWindow = CheckChildren(aWindow);
if (innerWindow)
return innerWindow;
return aWindow;
}
Window
XRemoteClient::CheckChildren(Window aWindow)
{
Window root, parent;
Window *children;
unsigned int nchildren;
unsigned int i;
Atom type = None;
int format;
unsigned long nitems, after;
unsigned char *data;
Window retval = None;
if (!XQueryTree(mDisplay, aWindow, &root, &parent, &children,
&nchildren))
return None;
// scan the list first before recursing into the list of windows
// which can get quite deep.
for (i=0; !retval && (i < nchildren); i++) {
XGetWindowProperty(mDisplay, children[i], mMozWMStateAtom,
0, 0, False, AnyPropertyType, &type, &format,
&nitems, &after, &data);
if (type) {
XFree(data);
retval = children[i];
}
}
// otherwise recurse into the list
for (i=0; !retval && (i < nchildren); i++) {
retval = CheckChildren(children[i]);
}
if (children)
XFree((char *)children);
return retval;
}
nsresult
XRemoteClient::GetLock(Window aWindow, bool *aDestroyed)
{
bool locked = false;
bool waited = false;
*aDestroyed = false;
nsresult rv = NS_OK;
if (!mLockData) {
char pidstr[32];
char sysinfobuf[SYS_INFO_BUFFER_LENGTH];
PR_snprintf(pidstr, sizeof(pidstr), "pid%d@", getpid());
PRStatus status;
status = PR_GetSystemInfo(PR_SI_HOSTNAME, sysinfobuf,
SYS_INFO_BUFFER_LENGTH);
if (status != PR_SUCCESS) {
return NS_ERROR_FAILURE;
}
// allocate enough space for the string plus the terminating
// char
mLockData = (char *)moz_xmalloc(strlen(pidstr) + strlen(sysinfobuf) + 1);
if (!mLockData)
return NS_ERROR_OUT_OF_MEMORY;
strcpy(mLockData, pidstr);
if (!strcat(mLockData, sysinfobuf))
return NS_ERROR_FAILURE;
}
do {
int result;
Atom actual_type;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char *data = 0;
XGrabServer(mDisplay);
result = XGetWindowProperty (mDisplay, aWindow, mMozLockAtom,
0, (65536 / sizeof (long)),
False, /* don't delete */
XA_STRING,
&actual_type, &actual_format,
&nitems, &bytes_after,
&data);
// aWindow may have been destroyed before XSelectInput was processed, in
// which case there may not be any DestroyNotify event in the queue to
// tell us. XGetWindowProperty() was synchronous so error responses have
// now been processed, setting sGotBadWindow.
if (sGotBadWindow) {
*aDestroyed = true;
rv = NS_ERROR_FAILURE;
}
else if (result != Success || actual_type == None) {
/* It's not now locked - lock it. */
XChangeProperty (mDisplay, aWindow, mMozLockAtom, XA_STRING, 8,
PropModeReplace,
(unsigned char *)mLockData,
strlen(mLockData));
locked = True;
}
XUngrabServer(mDisplay);
XFlush(mDisplay); // ungrab now!
if (!locked && !NS_FAILED(rv)) {
/* We tried to grab the lock this time, and failed because someone
else is holding it already. So, wait for a PropertyDelete event
to come in, and try again. */
MOZ_LOG(sRemoteLm, LogLevel::Debug,
("window 0x%x is locked by %s; waiting...\n",
(unsigned int) aWindow, data));
waited = True;
while (1) {
XEvent event;
int select_retval;
fd_set select_set;
struct timeval delay;
delay.tv_sec = 10;
delay.tv_usec = 0;
FD_ZERO(&select_set);
// add the x event queue to the select set
FD_SET(ConnectionNumber(mDisplay), &select_set);
select_retval = select(ConnectionNumber(mDisplay) + 1,
&select_set, nullptr, nullptr, &delay);
// did we time out?
if (select_retval == 0) {
MOZ_LOG(sRemoteLm, LogLevel::Debug, ("timed out waiting for window\n"));
rv = NS_ERROR_FAILURE;
break;
}
MOZ_LOG(sRemoteLm, LogLevel::Debug, ("xevent...\n"));
XNextEvent (mDisplay, &event);
if (event.xany.type == DestroyNotify &&
event.xdestroywindow.window == aWindow) {
*aDestroyed = true;
rv = NS_ERROR_FAILURE;
break;
}
else if (event.xany.type == PropertyNotify &&
event.xproperty.state == PropertyDelete &&
event.xproperty.window == aWindow &&
event.xproperty.atom == mMozLockAtom) {
/* Ok! Someone deleted their lock, so now we can try
again. */
MOZ_LOG(sRemoteLm, LogLevel::Debug,
("(0x%x unlocked, trying again...)\n",
(unsigned int) aWindow));
break;
}
}
}
if (data)
XFree(data);
} while (!locked && !NS_FAILED(rv));
if (waited && locked) {
MOZ_LOG(sRemoteLm, LogLevel::Debug, ("obtained lock.\n"));
} else if (*aDestroyed) {
MOZ_LOG(sRemoteLm, LogLevel::Debug,
("window 0x%x unexpectedly destroyed.\n",
(unsigned int) aWindow));
}
return rv;
}
Window
XRemoteClient::FindBestWindow(const char *aProgram, const char *aUsername,
const char *aProfile)
{
Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mDisplay));
Window bestWindow = 0;
Window root2, parent, *kids;
unsigned int nkids;
// Get a list of the children of the root window, walk the list
// looking for the best window that fits the criteria.
if (!XQueryTree(mDisplay, root, &root2, &parent, &kids, &nkids)) {
MOZ_LOG(sRemoteLm, LogLevel::Debug,
("XQueryTree failed in XRemoteClient::FindBestWindow"));
return 0;
}
if (!(kids && nkids)) {
MOZ_LOG(sRemoteLm, LogLevel::Debug, ("root window has no children"));
return 0;
}
// We'll walk the list of windows looking for a window that best
// fits the criteria here.
for (unsigned int i = 0; i < nkids; i++) {
Atom type;
int format;
unsigned long nitems, bytesafter;
unsigned char *data_return = 0;
Window w;
w = kids[i];
// find the inner window with WM_STATE on it
w = CheckWindow(w);
int status = XGetWindowProperty(mDisplay, w, mMozVersionAtom,
0, (65536 / sizeof (long)),
False, XA_STRING,
&type, &format, &nitems, &bytesafter,
&data_return);
if (!data_return)
continue;
double version = PR_strtod((char*) data_return, nullptr);
XFree(data_return);
if (!(version >= 5.1 && version < 6))
continue;
data_return = 0;
if (status != Success || type == None)
continue;
// If someone passed in a program name, check it against this one
// unless it's "any" in which case, we don't care. If someone did
// pass in a program name and this window doesn't support that
// protocol, we don't include it in our list.
if (aProgram && strcmp(aProgram, "any")) {
status = XGetWindowProperty(mDisplay, w, mMozProgramAtom,
0, (65536 / sizeof(long)),
False, XA_STRING,
&type, &format, &nitems, &bytesafter,
&data_return);
// If the return name is not the same as what someone passed in,
// we don't want this window.
if (data_return) {
if (strcmp(aProgram, (const char *)data_return)) {
XFree(data_return);
continue;
}
// This is actually the success condition.
XFree(data_return);
}
else {
// Doesn't support the protocol, even though the user
// requested it. So we're not going to use this window.
continue;
}
}
// Check to see if it has the user atom on that window. If there
// is then we need to make sure that it matches what we have.
const char *username;
if (aUsername) {
username = aUsername;
}
else {
username = PR_GetEnv("LOGNAME");
}
if (username) {
status = XGetWindowProperty(mDisplay, w, mMozUserAtom,
0, (65536 / sizeof(long)),
False, XA_STRING,
&type, &format, &nitems, &bytesafter,
&data_return);
// if there's a username compare it with what we have
if (data_return) {
// If the IDs aren't equal, we don't want this window.
if (strcmp(username, (const char *)data_return)) {
XFree(data_return);
continue;
}
XFree(data_return);
}
}
// Check to see if there's a profile name on this window. If
// there is, then we need to make sure it matches what someone
// passed in.
if (aProfile) {
status = XGetWindowProperty(mDisplay, w, mMozProfileAtom,
0, (65536 / sizeof(long)),
False, XA_STRING,
&type, &format, &nitems, &bytesafter,
&data_return);
// If there's a profile compare it with what we have
if (data_return) {
// If the profiles aren't equal, we don't want this window.
if (strcmp(aProfile, (const char *)data_return)) {
XFree(data_return);
continue;
}
XFree(data_return);
}
}
// Check to see if the window supports the new command-line passing
// protocol, if that is requested.
// If we got this far, this is the best window. It passed
// all the tests.
bestWindow = w;
break;
}
if (kids)
XFree((char *) kids);
return bestWindow;
}
nsresult
XRemoteClient::FreeLock(Window aWindow)
{
int result;
Atom actual_type;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char *data = 0;
result = XGetWindowProperty(mDisplay, aWindow, mMozLockAtom,
0, (65536 / sizeof(long)),
True, /* atomic delete after */
XA_STRING,
&actual_type, &actual_format,
&nitems, &bytes_after,
&data);
if (result != Success) {
MOZ_LOG(sRemoteLm, LogLevel::Debug,
("unable to read and delete " MOZILLA_LOCK_PROP
" property\n"));
return NS_ERROR_FAILURE;
}
else if (!data || !*data){
MOZ_LOG(sRemoteLm, LogLevel::Debug,
("invalid data on " MOZILLA_LOCK_PROP
" of window 0x%x.\n",
(unsigned int) aWindow));
return NS_ERROR_FAILURE;
}
else if (strcmp((char *)data, mLockData)) {
MOZ_LOG(sRemoteLm, LogLevel::Debug,
(MOZILLA_LOCK_PROP " was stolen! Expected \"%s\", saw \"%s\"!\n",
mLockData, data));
return NS_ERROR_FAILURE;
}
if (data)
XFree(data);
return NS_OK;
}
/* like strcpy, but return the char after the final null */
static char*
estrcpy(const char* s, char* d)
{
while (*s)
*d++ = *s++;
*d++ = '\0';
return d;
}
nsresult
XRemoteClient::DoSendCommandLine(Window aWindow, int32_t argc, char **argv,
const char* aDesktopStartupID,
char **aResponse, bool *aDestroyed)
{
*aDestroyed = false;
char cwdbuf[MAX_PATH];
if (!getcwd(cwdbuf, MAX_PATH))
return NS_ERROR_UNEXPECTED;
// the commandline property is constructed as an array of int32_t
// followed by a series of null-terminated strings:
//
// [argc][offsetargv0][offsetargv1...]<workingdir>\0<argv[0]>\0argv[1]...\0
// (offset is from the beginning of the buffer)
static char desktopStartupPrefix[] = " DESKTOP_STARTUP_ID=";
int32_t argvlen = strlen(cwdbuf);
for (int i = 0; i < argc; ++i) {
int32_t len = strlen(argv[i]);
if (i == 0 && aDesktopStartupID) {
len += sizeof(desktopStartupPrefix) - 1 + strlen(aDesktopStartupID);
}
argvlen += len;
}
int32_t* buffer = (int32_t*) moz_xmalloc(argvlen + argc + 1 +
sizeof(int32_t) * (argc + 1));
if (!buffer)
return NS_ERROR_OUT_OF_MEMORY;
buffer[0] = TO_LITTLE_ENDIAN32(argc);
char *bufend = (char*) (buffer + argc + 1);
bufend = estrcpy(cwdbuf, bufend);
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
int32_t debug_argc = TO_LITTLE_ENDIAN32(*buffer);
char *debug_workingdir = (char*) (buffer + argc + 1);
printf("Sending command line:\n"
" working dir: %s\n"
" argc:\t%i",
debug_workingdir,
debug_argc);
int32_t *debug_offset = buffer + 1;
for (int debug_i = 0; debug_i < debug_argc; ++debug_i)
printf(" argv[%i]:\t%s\n", debug_i,
((char*) buffer) + TO_LITTLE_ENDIAN32(debug_offset[debug_i]));
#endif
XChangeProperty (mDisplay, aWindow, mMozCommandLineAtom, XA_STRING, 8,
PropModeReplace, (unsigned char *) buffer,
bufend - ((char*) buffer));
free(buffer);
if (!WaitForResponse(aWindow, aResponse, aDestroyed, mMozCommandLineAtom))
return NS_ERROR_FAILURE;
return NS_OK;
}
bool
XRemoteClient::WaitForResponse(Window aWindow, char **aResponse,
bool *aDestroyed, Atom aCommandAtom)
{
bool done = false;
bool accepted = false;
while (!done) {
XEvent event;
XNextEvent (mDisplay, &event);
if (event.xany.type == DestroyNotify &&
event.xdestroywindow.window == aWindow) {
/* Print to warn user...*/
MOZ_LOG(sRemoteLm, LogLevel::Debug,
("window 0x%x was destroyed.\n",
(unsigned int) aWindow));
*aResponse = strdup("Window was destroyed while reading response.");
*aDestroyed = true;
return false;
}
else if (event.xany.type == PropertyNotify &&
event.xproperty.state == PropertyNewValue &&
event.xproperty.window == aWindow &&
event.xproperty.atom == mMozResponseAtom) {
Atom actual_type;
int actual_format;
unsigned long nitems, bytes_after;
unsigned char *data = 0;
Bool result;
result = XGetWindowProperty (mDisplay, aWindow, mMozResponseAtom,
0, (65536 / sizeof (long)),
True, /* atomic delete after */
XA_STRING,
&actual_type, &actual_format,
&nitems, &bytes_after,
&data);
if (result != Success) {
MOZ_LOG(sRemoteLm, LogLevel::Debug,
("failed reading " MOZILLA_RESPONSE_PROP
" from window 0x%0x.\n",
(unsigned int) aWindow));
*aResponse = strdup("Internal error reading response from window.");
done = true;
}
else if (!data || strlen((char *) data) < 5) {
MOZ_LOG(sRemoteLm, LogLevel::Debug,
("invalid data on " MOZILLA_RESPONSE_PROP
" property of window 0x%0x.\n",
(unsigned int) aWindow));
*aResponse = strdup("Server returned invalid data in response.");
done = true;
}
else if (*data == '1') { /* positive preliminary reply */
MOZ_LOG(sRemoteLm, LogLevel::Debug, ("%s\n", data + 4));
/* keep going */
done = false;
}
else if (!strncmp ((char *)data, "200", 3)) { /* positive completion */
*aResponse = strdup((char *)data);
accepted = true;
done = true;
}
else if (*data == '2') { /* positive completion */
MOZ_LOG(sRemoteLm, LogLevel::Debug, ("%s\n", data + 4));
*aResponse = strdup((char *)data);
accepted = true;
done = true;
}
else if (*data == '3') { /* positive intermediate reply */
MOZ_LOG(sRemoteLm, LogLevel::Debug,
("internal error: "
"server wants more information? (%s)\n",
data));
*aResponse = strdup((char *)data);
done = true;
}
else if (*data == '4' || /* transient negative completion */
*data == '5') { /* permanent negative completion */
MOZ_LOG(sRemoteLm, LogLevel::Debug, ("%s\n", data + 4));
*aResponse = strdup((char *)data);
done = true;
}
else {
MOZ_LOG(sRemoteLm, LogLevel::Debug,
("unrecognised " MOZILLA_RESPONSE_PROP
" from window 0x%x: %s\n",
(unsigned int) aWindow, data));
*aResponse = strdup((char *)data);
done = true;
}
if (data)
XFree(data);
}
else if (event.xany.type == PropertyNotify &&
event.xproperty.window == aWindow &&
event.xproperty.state == PropertyDelete &&
event.xproperty.atom == aCommandAtom) {
MOZ_LOG(sRemoteLm, LogLevel::Debug,
("(server 0x%x has accepted "
MOZILLA_COMMANDLINE_PROP ".)\n",
(unsigned int) aWindow));
}
}
return accepted;
}