//<copyright>
// 
// Copyright (c) 1995
// Institute for Information Processing and Computer Supported New Media (IICM),
// Graz University of Technology, Austria.
// 
//</copyright>

//<file>
//
// Name:        remote.C
//
// Purpose:     VRweb remote calls
//
// Created:      6 Dec 1995   Michael Pichler
//
// Changed:      7 Dec 1995   Michael Pichler
//
// $Id: remote.C,v 1.2 1996/01/30 11:33:50 mpichler Exp $
//
//</file>



// implementation of remote calls to VRweb
//
// parts of this code are done in the same way as described for the
// Netscape API (http://home.netscape.com/newsref/std/x-remote.html)
//
// Copyright of the sample implementation follows
// (http://home.netscape.com/newsref/std/remote.c)
/*
 * Copyright © 1995 Netscape Communications Corporation, all rights reserved.
 * Created: Jamie Zawinski <jwz@netscape.com>, 24-Dec-94.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation.  No representations are made about the suitability of this
 * software for any purpose.  It is provided "as is" without express or 
 * implied warranty.
 *
 */


#include "remote.h"

#include <hyperg/hyperg/message.h>
#include <hyperg/hyperg/verbose.h>

#include <InterViews/display.h>
#include <InterViews/enter-scope.h>
#include <InterViews/event.h>
#include <InterViews/window.h>

#include <IV-X11/xdisplay.h>
#include <IV-X11/xwindow.h>
#include <IV-X11/xevent.h>
extern "C" {
#include <IV-X11/Xdefs.h>
#  include <X11/Xlib.h>
#  include <X11/Xatom.h>
#  if defined(SUN4) || defined(SUN4_GNU)
/* if /usr/include/X11/Xmu/WinUtil.h does not provide a prototype */
     extern Window XmuClientWindow(Display*, Window);
#  else
#    include <X11/Xmu/WinUtil.h>	/* XmuClientWindow */
#  endif
#include <IV-X11/Xundefs.h>
}
// may have to include "vroot.h"

#include <string.h>
#include <iostream.h>


static Atom xaRemoteVersion = 0;
static Atom xaRemoteCommand = 0;


/*** helpers ***/

static void remoteInitAtoms (XDisplay* dpy)
{
  if (!xaRemoteVersion)
    xaRemoteVersion = XInternAtom (dpy, RemoteVersionProperty, False);
  if (!xaRemoteCommand)
    xaRemoteCommand = XInternAtom (dpy, RemoteCommandProperty, False);
}


// remoteFindWindow - find a remote window
// returns nonzero on success and fills out the window ID

static int remoteFindWindow (DisplayRep* d, XWindow& window)
{
  remoteInitAtoms (d->display_);

  XWindow root = d->root_;

  window = 0;  // result

  XWindow root2, parent, *kids;
  unsigned int nkids;

  if (!XQueryTree (d->display_, d->root_, &root2, &parent, &kids, &nkids))
    return 0;

  if (root != root2 || parent || !kids || !nkids)
  { HgMessage::error ("XQueryTree failed");
    return 0;
  }

  for (int i = 0;  i < nkids;  i++)
  {
    Atom type;
    int format;
    unsigned long nitems, bytesafter;
    unsigned char* version = 0;

    XWindow w = XmuClientWindow (d->display_, kids [i]);  // libXmu (misc. utils)

    int status = XGetWindowProperty (
      d->display_, w, xaRemoteVersion, 0, 1024, False /* do not delete */,
      XA_STRING, &type, &format, &nitems, &bytesafter, &version
    );

    if (!version)
      continue;
    DEBUGNL ("found remote version: " << version);
    XFree (version);
    if (status == Success && type != None)
    {
      window = w;
      return 1;  // found
    }

  } // for all children of root window

  DEBUGNL ("no remote VRweb window found");
  return 0;  // not found

} // remoteFindWindow


/*** remoteSetVersion ***/

void remoteSetVersion (DisplayRep* d, WindowRep* w, const char* version)
{
  remoteInitAtoms (d->display_);

  if (version)
    XChangeProperty (
      d->display_, w->xwindow_,
      xaRemoteVersion, XA_STRING, 8, PropModeReplace,
      (unsigned char*) version, strlen (version)
    );
  else
    XDeleteProperty (d->display_, w->xwindow_, xaRemoteVersion);
}


/*** remoteSendCommand ***/

int remoteSendCommand (DisplayRep* d, const char* command)
{
  // go through all windows on display and look whether a VRweb is among them
  // a window in "hold" state will not respond
  remoteInitAtoms (d->display_);

  XWindow win = 0;
  if (!remoteFindWindow (d, win))
    return 0;

  DEBUGNL ("setting command " << command << "on window " << win);

  // send the command to the ready VRweb instance
  XChangeProperty (
    d->display_, win,
    xaRemoteCommand, XA_STRING, 8, PropModeReplace,
    (unsigned char*) command, strlen (command)
  );
  XFlush (d->display_);

  return 1;
}


/*** remoteRecieveCommand ***/

int remoteReceiveCommand (DisplayRep* d, WindowRep* w, const EventRep* e, RString& cmd)
{
  const XEvent& xe = e->xevent_;
  if (xe.type != PropertyNotify)  // only interested in PropertyNotify
    return 0;

  const XPropertyEvent& xev = xe.xproperty;
  if (xev.state == PropertyDelete)  // only interested in new/changed values
    return 0;

  remoteInitAtoms (d->display_);
  if (xev.atom != xaRemoteCommand)  // only interested in xaRemoteCommand
    return 0;

  Atom type;
  int format;
  unsigned long nitems, bytesafter;
  unsigned char* command;

  int status = XGetWindowProperty (
    d->display_, w->xwindow_, xaRemoteCommand, 0, 1024, True /* delete */,
    XA_STRING, &type, &format, &nitems, &bytesafter, &command
  );

  if (!command)
    return 0;

  if (status == Success && type != None)
  {
    cmd = RString ((const char*) command, nitems);
    XFree (command);
    return 1;  // successful
  }

  XFree (command);
  return 0;
}
