1998-03-28 02:44:41 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Netscape Public License
|
|
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
|
|
* http://www.mozilla.org/NPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* NPL.
|
|
|
|
*
|
|
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
|
|
* Communications Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
|
|
* Reserved.
|
|
|
|
*/
|
|
|
|
/* */
|
|
|
|
/**/
|
|
|
|
|
|
|
|
#ifdef NON_SOURCE_RELEASE
|
|
|
|
/*
|
|
|
|
WARNING WARNING WARNING!
|
|
|
|
========================
|
|
|
|
|
|
|
|
This file is the same as our remote control reference implementation.
|
|
|
|
|
|
|
|
That means that it must compile standalone as per the instructions
|
|
|
|
below. That means that this code can't depend on any of the private,
|
|
|
|
internal Netscape libraries: only libc and libX11.
|
|
|
|
|
|
|
|
That means that if you make any changes to this file, you must also
|
|
|
|
update "http://home.netscape.com/newsref/std/remote.c". Also, tick
|
|
|
|
the minor-minor version number, below.
|
|
|
|
*/
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* remote.c --- remote control of Netscape Navigator for Unix.
|
|
|
|
* version 1.1.3, for Netscape Navigator 1.1 and newer.
|
|
|
|
*
|
|
|
|
* Created: Jamie Zawinski <jwz@netscape.com>, 24-Dec-94.
|
|
|
|
*
|
|
|
|
* To compile:
|
|
|
|
*
|
|
|
|
* cc -o netscape-remote remote.c -DSTANDALONE -lXmu -lX11
|
|
|
|
*
|
|
|
|
* To use:
|
|
|
|
*
|
|
|
|
* netscape-remote -help
|
|
|
|
*
|
|
|
|
* Documentation for the protocol which this code implements may be found at:
|
|
|
|
*
|
|
|
|
* http://home.netscape.com/newsref/std/x-remote.html
|
|
|
|
*
|
|
|
|
* Bugs and commentary to x_cbug@netscape.com.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#include <X11/Xmu/WinUtil.h> /* for XmuClientWindow() */
|
|
|
|
|
|
|
|
|
|
|
|
/* vroot.h is a header file which lets a client get along with `virtual root'
|
|
|
|
window managers like swm, tvtwm, olvwm, etc. If you don't have this header
|
|
|
|
file, you can find it at "http://home.netscape.com/newsref/std/vroot.h".
|
|
|
|
If you don't care about supporting virtual root window managers, you can
|
|
|
|
comment this line out.
|
|
|
|
*/
|
|
|
|
#include "vroot.h"
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef STANDALONE
|
|
|
|
static const char *progname = 0;
|
|
|
|
static const char *expected_mozilla_version = "1.1";
|
|
|
|
#else /* !STANDALONE */
|
|
|
|
extern const char *progname;
|
1998-07-15 10:19:36 +00:00
|
|
|
/* Next line not needed - defined in remote-s.c */
|
|
|
|
/* extern const char *expected_mozilla_version; */
|
1998-03-28 02:44:41 +00:00
|
|
|
#endif /* !STANDALONE */
|
|
|
|
|
|
|
|
#define MOZILLA_VERSION_PROP "_MOZILLA_VERSION"
|
|
|
|
#define MOZILLA_LOCK_PROP "_MOZILLA_LOCK"
|
|
|
|
#define MOZILLA_COMMAND_PROP "_MOZILLA_COMMAND"
|
|
|
|
#define MOZILLA_RESPONSE_PROP "_MOZILLA_RESPONSE"
|
|
|
|
static Atom XA_MOZILLA_VERSION = 0;
|
|
|
|
static Atom XA_MOZILLA_LOCK = 0;
|
|
|
|
static Atom XA_MOZILLA_COMMAND = 0;
|
|
|
|
static Atom XA_MOZILLA_RESPONSE = 0;
|
|
|
|
|
|
|
|
static void
|
|
|
|
mozilla_remote_init_atoms (Display *dpy)
|
|
|
|
{
|
|
|
|
if (! XA_MOZILLA_VERSION)
|
|
|
|
XA_MOZILLA_VERSION = XInternAtom (dpy, MOZILLA_VERSION_PROP, False);
|
|
|
|
if (! XA_MOZILLA_LOCK)
|
|
|
|
XA_MOZILLA_LOCK = XInternAtom (dpy, MOZILLA_LOCK_PROP, False);
|
|
|
|
if (! XA_MOZILLA_COMMAND)
|
|
|
|
XA_MOZILLA_COMMAND = XInternAtom (dpy, MOZILLA_COMMAND_PROP, False);
|
|
|
|
if (! XA_MOZILLA_RESPONSE)
|
|
|
|
XA_MOZILLA_RESPONSE = XInternAtom (dpy, MOZILLA_RESPONSE_PROP, False);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Window
|
|
|
|
mozilla_remote_find_window (Display *dpy)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
|
|
|
|
Window root2, parent, *kids;
|
|
|
|
unsigned int nkids;
|
|
|
|
Window result = 0;
|
|
|
|
Window tenative = 0;
|
|
|
|
unsigned char *tenative_version = 0;
|
|
|
|
|
|
|
|
if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: XQueryTree failed on display %s\n", progname,
|
|
|
|
DisplayString (dpy));
|
|
|
|
exit (2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* root != root2 is possible with virtual root WMs. */
|
|
|
|
|
|
|
|
if (! (kids && nkids))
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: root window has no children on display %s\n",
|
|
|
|
progname, DisplayString (dpy));
|
|
|
|
exit (2);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = nkids-1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
Atom type;
|
|
|
|
int format;
|
|
|
|
unsigned long nitems, bytesafter;
|
|
|
|
unsigned char *version = 0;
|
|
|
|
Window w = XmuClientWindow (dpy, kids[i]);
|
|
|
|
int status = XGetWindowProperty (dpy, w, XA_MOZILLA_VERSION,
|
|
|
|
0, (65536 / sizeof (long)),
|
|
|
|
False, XA_STRING,
|
|
|
|
&type, &format, &nitems, &bytesafter,
|
|
|
|
&version);
|
|
|
|
if (! version)
|
|
|
|
continue;
|
|
|
|
if (strcmp ((char *) version, expected_mozilla_version) &&
|
|
|
|
!tenative)
|
|
|
|
{
|
|
|
|
tenative = w;
|
|
|
|
tenative_version = version;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
XFree (version);
|
|
|
|
if (status == Success && type != None)
|
|
|
|
{
|
|
|
|
result = w;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result && tenative)
|
|
|
|
{
|
|
|
|
fprintf (stderr,
|
|
|
|
"%s: warning: both version %s (0x%x) and version\n"
|
|
|
|
"\t%s (0x%x) are running. Using version %s.\n",
|
|
|
|
progname, tenative_version, (unsigned int) tenative,
|
|
|
|
expected_mozilla_version, (unsigned int) result,
|
|
|
|
expected_mozilla_version);
|
|
|
|
XFree (tenative_version);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else if (tenative)
|
|
|
|
{
|
|
|
|
fprintf (stderr,
|
|
|
|
"%s: warning: expected version %s but found version\n"
|
|
|
|
"\t%s (0x%x) instead.\n",
|
|
|
|
progname, expected_mozilla_version,
|
|
|
|
tenative_version, (unsigned int) tenative);
|
|
|
|
XFree (tenative_version);
|
|
|
|
return tenative;
|
|
|
|
}
|
|
|
|
else if (result)
|
|
|
|
{
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: not running on display %s\n", progname,
|
|
|
|
DisplayString (dpy));
|
|
|
|
exit (1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
mozilla_remote_check_window (Display *dpy, Window window)
|
|
|
|
{
|
|
|
|
Atom type;
|
|
|
|
int format;
|
|
|
|
unsigned long nitems, bytesafter;
|
|
|
|
unsigned char *version = 0;
|
|
|
|
int status = XGetWindowProperty (dpy, window, XA_MOZILLA_VERSION,
|
|
|
|
0, (65536 / sizeof (long)),
|
|
|
|
False, XA_STRING,
|
|
|
|
&type, &format, &nitems, &bytesafter,
|
|
|
|
&version);
|
|
|
|
if (status != Success || !version)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: window 0x%x is not a Netscape window.\n",
|
|
|
|
progname, (unsigned int) window);
|
|
|
|
exit (6);
|
|
|
|
}
|
|
|
|
else if (strcmp ((char *) version, expected_mozilla_version))
|
|
|
|
{
|
|
|
|
fprintf (stderr,
|
|
|
|
"%s: warning: window 0x%x is Netscape version %s;\n"
|
|
|
|
"\texpected version %s.\n",
|
|
|
|
progname, (unsigned int) window,
|
|
|
|
version, expected_mozilla_version);
|
|
|
|
}
|
|
|
|
XFree (version);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *lock_data = 0;
|
|
|
|
|
|
|
|
static void
|
|
|
|
mozilla_remote_obtain_lock (Display *dpy, Window window)
|
|
|
|
{
|
|
|
|
Bool locked = False;
|
|
|
|
Bool waited = False;
|
|
|
|
|
|
|
|
if (! lock_data)
|
|
|
|
{
|
|
|
|
lock_data = (char *) malloc (255);
|
|
|
|
sprintf (lock_data, "pid%d@", getpid ());
|
|
|
|
if (gethostname (lock_data + strlen (lock_data), 100))
|
|
|
|
{
|
|
|
|
perror ("gethostname");
|
|
|
|
exit (-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
Atom actual_type;
|
|
|
|
int actual_format;
|
|
|
|
unsigned long nitems, bytes_after;
|
|
|
|
unsigned char *data = 0;
|
|
|
|
|
|
|
|
XGrabServer (dpy); /* ################################# DANGER! */
|
|
|
|
|
|
|
|
result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
|
|
|
|
0, (65536 / sizeof (long)),
|
|
|
|
False, /* don't delete */
|
|
|
|
XA_STRING,
|
|
|
|
&actual_type, &actual_format,
|
|
|
|
&nitems, &bytes_after,
|
|
|
|
&data);
|
|
|
|
if (result != Success || actual_type == None)
|
|
|
|
{
|
|
|
|
/* It's not now locked - lock it. */
|
|
|
|
#ifdef DEBUG_PROPS
|
|
|
|
fprintf (stderr, "%s: (writing " MOZILLA_LOCK_PROP
|
|
|
|
" \"%s\" to 0x%x)\n",
|
|
|
|
progname, lock_data, (unsigned int) window);
|
|
|
|
#endif
|
|
|
|
XChangeProperty (dpy, window, XA_MOZILLA_LOCK, XA_STRING, 8,
|
|
|
|
PropModeReplace, (unsigned char *) lock_data,
|
|
|
|
strlen (lock_data));
|
|
|
|
locked = True;
|
|
|
|
}
|
|
|
|
|
|
|
|
XUngrabServer (dpy); /* ################################# danger over */
|
|
|
|
XSync (dpy, False);
|
|
|
|
|
|
|
|
if (! locked)
|
|
|
|
{
|
|
|
|
/* 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. */
|
|
|
|
|
|
|
|
fprintf (stderr, "%s: window 0x%x is locked by %s; waiting...\n",
|
|
|
|
progname, (unsigned int) window, data);
|
|
|
|
waited = True;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
XEvent event;
|
|
|
|
XNextEvent (dpy, &event);
|
|
|
|
if (event.xany.type == DestroyNotify &&
|
|
|
|
event.xdestroywindow.window == window)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: window 0x%x unexpectedly destroyed.\n",
|
|
|
|
progname, (unsigned int) window);
|
|
|
|
exit (6);
|
|
|
|
}
|
|
|
|
else if (event.xany.type == PropertyNotify &&
|
|
|
|
event.xproperty.state == PropertyDelete &&
|
|
|
|
event.xproperty.window == window &&
|
|
|
|
event.xproperty.atom == XA_MOZILLA_LOCK)
|
|
|
|
{
|
|
|
|
/* Ok! Someone deleted their lock, so now we can try
|
|
|
|
again. */
|
|
|
|
#ifdef DEBUG_PROPS
|
|
|
|
fprintf (stderr, "%s: (0x%x unlocked, trying again...)\n",
|
|
|
|
progname, (unsigned int) window);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (data)
|
|
|
|
XFree (data);
|
|
|
|
}
|
|
|
|
while (! locked);
|
|
|
|
|
|
|
|
if (waited)
|
|
|
|
fprintf (stderr, "%s: obtained lock.\n", progname);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
mozilla_remote_free_lock (Display *dpy, Window window)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
Atom actual_type;
|
|
|
|
int actual_format;
|
|
|
|
unsigned long nitems, bytes_after;
|
|
|
|
unsigned char *data = 0;
|
|
|
|
|
|
|
|
#ifdef DEBUG_PROPS
|
|
|
|
fprintf (stderr, "%s: (deleting " MOZILLA_LOCK_PROP
|
|
|
|
" \"%s\" from 0x%x)\n",
|
|
|
|
progname, lock_data, (unsigned int) window);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
|
|
|
|
0, (65536 / sizeof (long)),
|
|
|
|
True, /* atomic delete after */
|
|
|
|
XA_STRING,
|
|
|
|
&actual_type, &actual_format,
|
|
|
|
&nitems, &bytes_after,
|
|
|
|
&data);
|
|
|
|
if (result != Success)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: unable to read and delete " MOZILLA_LOCK_PROP
|
|
|
|
" property\n",
|
|
|
|
progname);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (!data || !*data)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: invalid data on " MOZILLA_LOCK_PROP
|
|
|
|
" of window 0x%x.\n",
|
|
|
|
progname, (unsigned int) window);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (strcmp ((char *) data, lock_data))
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: " MOZILLA_LOCK_PROP
|
|
|
|
" was stolen! Expected \"%s\", saw \"%s\"!\n",
|
|
|
|
progname, lock_data, data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data)
|
|
|
|
XFree (data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
mozilla_remote_command (Display *dpy, Window window, const char *command,
|
|
|
|
Bool raise_p)
|
|
|
|
{
|
|
|
|
int result = 6;
|
|
|
|
Bool done = False;
|
|
|
|
char *new_command = 0;
|
|
|
|
|
|
|
|
/* The -noraise option is implemented by passing a "noraise" argument
|
|
|
|
to each command to which it should apply.
|
|
|
|
*/
|
|
|
|
if (! raise_p)
|
|
|
|
{
|
|
|
|
char *close;
|
|
|
|
new_command = (char *) malloc (strlen (command) + 20);
|
|
|
|
strcpy (new_command, command);
|
|
|
|
close = strrchr (new_command, ')');
|
|
|
|
if (close)
|
|
|
|
strcpy (close, ", noraise)");
|
|
|
|
else
|
|
|
|
strcat (new_command, "(noraise)");
|
|
|
|
command = new_command;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_PROPS
|
|
|
|
fprintf (stderr, "%s: (writing " MOZILLA_COMMAND_PROP " \"%s\" to 0x%x)\n",
|
|
|
|
progname, command, (unsigned int) window);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
XChangeProperty (dpy, window, XA_MOZILLA_COMMAND, XA_STRING, 8,
|
|
|
|
PropModeReplace, (unsigned char *) command,
|
|
|
|
strlen (command));
|
|
|
|
|
|
|
|
while (!done)
|
|
|
|
{
|
|
|
|
XEvent event;
|
|
|
|
XNextEvent (dpy, &event);
|
|
|
|
if (event.xany.type == DestroyNotify &&
|
|
|
|
event.xdestroywindow.window == window)
|
|
|
|
{
|
|
|
|
/* Print to warn user...*/
|
|
|
|
fprintf (stderr, "%s: window 0x%x was destroyed.\n",
|
|
|
|
progname, (unsigned int) window);
|
|
|
|
result = 6;
|
|
|
|
goto DONE;
|
|
|
|
}
|
|
|
|
else if (event.xany.type == PropertyNotify &&
|
|
|
|
event.xproperty.state == PropertyNewValue &&
|
|
|
|
event.xproperty.window == window &&
|
|
|
|
event.xproperty.atom == XA_MOZILLA_RESPONSE)
|
|
|
|
{
|
|
|
|
Atom actual_type;
|
|
|
|
int actual_format;
|
|
|
|
unsigned long nitems, bytes_after;
|
|
|
|
unsigned char *data = 0;
|
|
|
|
|
|
|
|
result = XGetWindowProperty (dpy, window, XA_MOZILLA_RESPONSE,
|
|
|
|
0, (65536 / sizeof (long)),
|
|
|
|
True, /* atomic delete after */
|
|
|
|
XA_STRING,
|
|
|
|
&actual_type, &actual_format,
|
|
|
|
&nitems, &bytes_after,
|
|
|
|
&data);
|
|
|
|
#ifdef DEBUG_PROPS
|
|
|
|
if (result == Success && data && *data)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: (server sent " MOZILLA_RESPONSE_PROP
|
|
|
|
" \"%s\" to 0x%x.)\n",
|
|
|
|
progname, data, (unsigned int) window);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (result != Success)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: failed reading " MOZILLA_RESPONSE_PROP
|
|
|
|
" from window 0x%0x.\n",
|
|
|
|
progname, (unsigned int) window);
|
|
|
|
result = 6;
|
|
|
|
done = True;
|
|
|
|
}
|
|
|
|
else if (!data || strlen((char *) data) < 5)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: invalid data on " MOZILLA_RESPONSE_PROP
|
|
|
|
" property of window 0x%0x.\n",
|
|
|
|
progname, (unsigned int) window);
|
|
|
|
result = 6;
|
|
|
|
done = True;
|
|
|
|
}
|
|
|
|
else if (*data == '1') /* positive preliminary reply */
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: %s\n", progname, data + 4);
|
|
|
|
/* keep going */
|
|
|
|
done = False;
|
|
|
|
}
|
|
|
|
#if 1
|
|
|
|
else if (!strncmp ((char *)data, "200", 3)) /* positive completion */
|
|
|
|
{
|
|
|
|
result = 0;
|
|
|
|
done = True;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else if (*data == '2') /* positive completion */
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: %s\n", progname, data + 4);
|
|
|
|
result = 0;
|
|
|
|
done = True;
|
|
|
|
}
|
|
|
|
else if (*data == '3') /* positive intermediate reply */
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: internal error: "
|
|
|
|
"server wants more information? (%s)\n",
|
|
|
|
progname, data);
|
|
|
|
result = 3;
|
|
|
|
done = True;
|
|
|
|
}
|
|
|
|
else if (*data == '4' || /* transient negative completion */
|
|
|
|
*data == '5') /* permanent negative completion */
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: %s\n", progname, data + 4);
|
|
|
|
result = (*data - '0');
|
|
|
|
done = True;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf (stderr,
|
|
|
|
"%s: unrecognized " MOZILLA_RESPONSE_PROP
|
|
|
|
" from window 0x%x: %s\n",
|
|
|
|
progname, (unsigned int) window, data);
|
|
|
|
result = 6;
|
|
|
|
done = True;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data)
|
|
|
|
XFree (data);
|
|
|
|
}
|
|
|
|
#ifdef DEBUG_PROPS
|
|
|
|
else if (event.xany.type == PropertyNotify &&
|
|
|
|
event.xproperty.window == window &&
|
|
|
|
event.xproperty.state == PropertyDelete &&
|
|
|
|
event.xproperty.atom == XA_MOZILLA_COMMAND)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: (server 0x%x has accepted "
|
|
|
|
MOZILLA_COMMAND_PROP ".)\n",
|
|
|
|
progname, (unsigned int) window);
|
|
|
|
}
|
|
|
|
#endif /* DEBUG_PROPS */
|
|
|
|
}
|
|
|
|
|
|
|
|
DONE:
|
|
|
|
|
|
|
|
if (new_command)
|
|
|
|
free (new_command);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
mozilla_remote_commands (Display *dpy, Window window, char **commands)
|
|
|
|
{
|
|
|
|
Bool raise_p = True;
|
|
|
|
int status = 0;
|
|
|
|
mozilla_remote_init_atoms (dpy);
|
|
|
|
|
|
|
|
if (window == 0)
|
|
|
|
window = mozilla_remote_find_window (dpy);
|
|
|
|
else
|
|
|
|
mozilla_remote_check_window (dpy, window);
|
|
|
|
|
|
|
|
XSelectInput (dpy, window, (PropertyChangeMask|StructureNotifyMask));
|
|
|
|
|
|
|
|
mozilla_remote_obtain_lock (dpy, window);
|
|
|
|
|
|
|
|
while (*commands)
|
|
|
|
{
|
|
|
|
if (!strcmp (*commands, "-raise"))
|
|
|
|
raise_p = True;
|
|
|
|
else if (!strcmp (*commands, "-noraise"))
|
|
|
|
raise_p = False;
|
|
|
|
else
|
|
|
|
status = mozilla_remote_command (dpy, window, *commands, raise_p);
|
|
|
|
|
|
|
|
if (status != 0)
|
|
|
|
break;
|
|
|
|
commands++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* When status = 6, it means the window has been destroyed */
|
|
|
|
/* It is invalid to free the lock when window is destroyed. */
|
|
|
|
|
|
|
|
if ( status != 6 )
|
|
|
|
mozilla_remote_free_lock (dpy, window);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef STANDALONE
|
|
|
|
|
|
|
|
static void
|
|
|
|
usage (void)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "usage: %s [ options ... ]\n\
|
|
|
|
where options include:\n\
|
|
|
|
\n\
|
|
|
|
-help to show this message.\n\
|
|
|
|
-display <dpy> to specify the X server to use.\n\
|
|
|
|
-remote <remote-command> to execute a command in an already-running\n\
|
|
|
|
Netscape process. See the manual for a\n\
|
|
|
|
list of valid commands.\n\
|
|
|
|
-id <window-id> the id of an X window to which the -remote\n\
|
|
|
|
commands should be sent; if unspecified,\n\
|
|
|
|
the first window found will be used.\n\
|
|
|
|
-raise whether following -remote commands should\n\
|
|
|
|
cause the window to raise itself to the top\n\
|
|
|
|
(this is the default.)\n\
|
|
|
|
-noraise the opposite of -raise: following -remote\n\
|
|
|
|
commands will not auto-raise the window.\n\
|
|
|
|
",
|
|
|
|
progname);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
main (int argc, char **argv)
|
|
|
|
{
|
|
|
|
Display *dpy;
|
|
|
|
char *dpy_string = 0;
|
|
|
|
char **remote_commands = 0;
|
|
|
|
int remote_command_count = 0;
|
|
|
|
int remote_command_size = 0;
|
|
|
|
unsigned long remote_window = 0;
|
|
|
|
Bool sync_p = False;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
progname = strrchr (argv[0], '/');
|
|
|
|
if (progname)
|
|
|
|
progname++;
|
|
|
|
else
|
|
|
|
progname = argv[0];
|
|
|
|
|
|
|
|
/* Hack the -help and -version arguments before opening the display. */
|
|
|
|
for (i = 1; i < argc; i++)
|
|
|
|
{
|
|
|
|
if (!strcasecmp (argv [i], "-h") ||
|
|
|
|
!strcasecmp (argv [i], "-help"))
|
|
|
|
{
|
|
|
|
usage ();
|
|
|
|
exit (0);
|
|
|
|
}
|
|
|
|
else if (!strcmp (argv [i], "-d") ||
|
|
|
|
!strcmp (argv [i], "-dpy") ||
|
|
|
|
!strcmp (argv [i], "-disp") ||
|
|
|
|
!strcmp (argv [i], "-display"))
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
dpy_string = argv [i];
|
|
|
|
}
|
|
|
|
else if (!strcmp (argv [i], "-sync") ||
|
|
|
|
!strcmp (argv [i], "-synchronize"))
|
|
|
|
{
|
|
|
|
sync_p = True;
|
|
|
|
}
|
|
|
|
else if (!strcmp (argv [i], "-remote"))
|
|
|
|
{
|
|
|
|
if (remote_command_count == remote_command_size)
|
|
|
|
{
|
|
|
|
remote_command_size += 20;
|
|
|
|
remote_commands =
|
|
|
|
(remote_commands
|
|
|
|
? realloc (remote_commands,
|
|
|
|
remote_command_size * sizeof (char *))
|
|
|
|
: calloc (remote_command_size, sizeof (char *)));
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
if (!argv[i] || *argv[i] == '-' || *argv[i] == 0)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: invalid `-remote' option \"%s\"\n",
|
|
|
|
progname, argv[i] ? argv[i] : "");
|
|
|
|
usage ();
|
|
|
|
exit (-1);
|
|
|
|
}
|
|
|
|
remote_commands [remote_command_count++] = argv[i];
|
|
|
|
}
|
|
|
|
else if (!strcmp (argv [i], "-raise") ||
|
|
|
|
!strcmp (argv [i], "-noraise"))
|
|
|
|
{
|
|
|
|
char *r = argv [i];
|
|
|
|
if (remote_command_count == remote_command_size)
|
|
|
|
{
|
|
|
|
remote_command_size += 20;
|
|
|
|
remote_commands =
|
|
|
|
(remote_commands
|
|
|
|
? realloc (remote_commands,
|
|
|
|
remote_command_size * sizeof (char *))
|
|
|
|
: calloc (remote_command_size, sizeof (char *)));
|
|
|
|
}
|
|
|
|
remote_commands [remote_command_count++] = r;
|
|
|
|
}
|
|
|
|
else if (!strcmp (argv [i], "-id"))
|
|
|
|
{
|
|
|
|
char c;
|
|
|
|
if (remote_command_count > 0)
|
|
|
|
{
|
|
|
|
fprintf (stderr,
|
|
|
|
"%s: the `-id' option must preceed all `-remote' options.\n",
|
|
|
|
progname);
|
|
|
|
usage ();
|
|
|
|
exit (-1);
|
|
|
|
}
|
|
|
|
else if (remote_window != 0)
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: only one `-id' option may be used.\n",
|
|
|
|
progname);
|
|
|
|
usage ();
|
|
|
|
exit (-1);
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
if (argv[i] &&
|
|
|
|
1 == sscanf (argv[i], " %ld %c", &remote_window, &c))
|
|
|
|
;
|
|
|
|
else if (argv[i] &&
|
|
|
|
1 == sscanf (argv[i], " 0x%lx %c", &remote_window, &c))
|
|
|
|
;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf (stderr, "%s: invalid `-id' option \"%s\"\n",
|
|
|
|
progname, argv[i] ? argv[i] : "");
|
|
|
|
usage ();
|
|
|
|
exit (-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dpy = XOpenDisplay (dpy_string);
|
|
|
|
if (! dpy)
|
|
|
|
exit (-1);
|
|
|
|
|
|
|
|
if (sync_p)
|
|
|
|
XSynchronize (dpy, True);
|
|
|
|
|
|
|
|
exit (mozilla_remote_commands (dpy, (Window) remote_window,
|
|
|
|
remote_commands));
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* STANDALONE */
|