Revision: 75836
          http://sourceforge.net/p/brlcad/code/75836
Author:   starseeker
Date:     2020-05-19 03:34:33 +0000 (Tue, 19 May 2020)
Log Message:
-----------
Use of fbserv_obj isn't as widespread as I thought - the actual 'fbserv' 
command doesn't appear to use it.  It's used by Archer through libtclcad, and 4 
libged commands reference the data structure - fb2pix, fbclear, pix2fb, and 
png2fb.  Need to examine those in more detail to see how to achieve what they 
are doing without recourse to ged_fbsp, but temporarily commenting those out it 
is possible to move fbserv_obj to libtclcad.  It's referencing the internal 
details of libdm/fb, so the API separation isn't clean in that sense, but it 
does push all use of Tcl associated with that object up into libtclcad.  That 
in turn lets us remove all remaining inclusions of tcl.h and friends from the 
core libdm/fb library.  Most of the backends still use it, but we can now (sans 
the four previously mentioned commands) do a libged build completely without 
Tcl/Tk.

Modified Paths:
--------------
    brlcad/branches/dm-fb-merge/include/dm.h
    brlcad/branches/dm-fb-merge/include/ged/defines.h
    brlcad/branches/dm-fb-merge/include/ged/framebuffer.h
    brlcad/branches/dm-fb-merge/include/tclcad.h
    brlcad/branches/dm-fb-merge/src/libdm/CMakeLists.txt
    brlcad/branches/dm-fb-merge/src/libdm/dm-generic.c
    brlcad/branches/dm-fb-merge/src/libdm/knob.c
    brlcad/branches/dm-fb-merge/src/libdm/labels.c
    brlcad/branches/dm-fb-merge/src/libdm/null/dm-Null.c
    brlcad/branches/dm-fb-merge/src/libdm/options.c
    brlcad/branches/dm-fb-merge/src/libdm/plot/CMakeLists.txt
    brlcad/branches/dm-fb-merge/src/libdm/tests/CMakeLists.txt
    brlcad/branches/dm-fb-merge/src/libdm/txt/CMakeLists.txt
    brlcad/branches/dm-fb-merge/src/libged/CMakeLists.txt
    brlcad/branches/dm-fb-merge/src/libged/ged.c
    brlcad/branches/dm-fb-merge/src/libtclcad/CMakeLists.txt
    brlcad/branches/dm-fb-merge/src/libtclcad/tclcad_obj.c
    brlcad/branches/dm-fb-merge/src/rt/viewedge.c

Added Paths:
-----------
    brlcad/branches/dm-fb-merge/src/libtclcad/fbserv_obj.c

Removed Paths:
-------------
    brlcad/branches/dm-fb-merge/src/libdm/fbserv_obj.c

Modified: brlcad/branches/dm-fb-merge/include/dm.h
===================================================================
--- brlcad/branches/dm-fb-merge/include/dm.h    2020-05-18 19:20:19 UTC (rev 
75835)
+++ brlcad/branches/dm-fb-merge/include/dm.h    2020-05-19 03:34:33 UTC (rev 
75836)
@@ -38,9 +38,6 @@
 
 __BEGIN_DECLS
 
-/* Use fbserv */
-#define USE_FBSERV 1
-
 #define DM_NULL (struct dm *)NULL
 
 /* the font used depends on the size of the window opened */
@@ -318,7 +315,6 @@
 
 #include "bsocket.h"
 
-#include "tcl.h"
 #include "pkg.h"
 #include "bu/magic.h"
 #include "bu/vls.h"
@@ -505,50 +501,6 @@
 
 #define MSG_NORETURN    100
 
-
-/* Framebuffer server object */
-
-#define NET_LONG_LEN 4 /**< @brief # bytes to network long */
-#define MAX_CLIENTS 32
-#define MAX_PORT_TRIES 100
-#define FBS_CALLBACK_NULL (void (*)())NULL
-#define FBSERV_OBJ_NULL (struct fbserv_obj *)NULL
-
-struct fbserv_listener {
-    int fbsl_fd;                        /**< @brief socket to listen for 
connections */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-    Tcl_Channel fbsl_chan;
-#endif
-    int fbsl_port;                      /**< @brief port number to listen on */
-    int fbsl_listen;                    /**< @brief !0 means listen for 
connections */
-    struct fbserv_obj *fbsl_fbsp;       /**< @brief points to its fbserv 
object */
-};
-
-
-struct fbserv_client {
-    int fbsc_fd;
-#if defined(_WIN32) && !defined(__CYGWIN__)
-    Tcl_Channel fbsc_chan;
-    Tcl_FileProc *fbsc_handler;
-#endif
-    struct pkg_conn *fbsc_pkg;
-    struct fbserv_obj *fbsc_fbsp;       /**< @brief points to its fbserv 
object */
-};
-
-
-struct fbserv_obj {
-    struct fb *fbs_fbp;                        /**< @brief framebuffer pointer 
*/
-    void *fbs_interp;             /**< @brief tcl interpreter */
-    struct fbserv_listener fbs_listener;                /**< @brief data for 
listening */
-    struct fbserv_client fbs_clients[MAX_CLIENTS];      /**< @brief connected 
clients */
-    void (*fbs_callback)(void *clientData);             /**< @brief callback 
function */
-    void *fbs_clientData;
-    int fbs_mode;                       /**< @brief 0-off, 1-underlay, 
2-interlay, 3-overlay */
-};
-
-DM_EXPORT extern int fbs_open(struct fbserv_obj *fbsp, int port);
-DM_EXPORT extern int fbs_close(struct fbserv_obj *fbsp);
-
 __END_DECLS
 
 #endif /* DM_H */

Modified: brlcad/branches/dm-fb-merge/include/ged/defines.h
===================================================================
--- brlcad/branches/dm-fb-merge/include/ged/defines.h   2020-05-18 19:20:19 UTC 
(rev 75835)
+++ brlcad/branches/dm-fb-merge/include/ged/defines.h   2020-05-19 03:34:33 UTC 
(rev 75836)
@@ -202,7 +202,6 @@
 
     struct ged_drawable                *ged_gdp;
     struct bview               *ged_gvp;
-    struct fbserv_obj          *ged_fbsp; /* FIXME: this shouldn't be here */
     struct bu_hash_tbl         *ged_selections; /**< @brief object name -> 
struct rt_object_selections */
 
     void                       *ged_dmp;

Modified: brlcad/branches/dm-fb-merge/include/ged/framebuffer.h
===================================================================
--- brlcad/branches/dm-fb-merge/include/ged/framebuffer.h       2020-05-18 
19:20:19 UTC (rev 75835)
+++ brlcad/branches/dm-fb-merge/include/ged/framebuffer.h       2020-05-19 
03:34:33 UTC (rev 75836)
@@ -33,29 +33,8 @@
 
 __BEGIN_DECLS
 
+#if 0
 
-
-#define GED_CHECK_FBSERV(_gedp, _flags) \
-    if (_gedp->ged_fbsp == NULL) { \
-       int ged_check_view_quiet = (_flags) & GED_QUIET; \
-       if (!ged_check_view_quiet) { \
-           bu_vls_trunc((_gedp)->ged_result_str, 0); \
-           bu_vls_printf((_gedp)->ged_result_str, "A framebuffer server object 
does not exist."); \
-       } \
-       return (_flags); \
-    }
-
-#define GED_CHECK_FBSERV_FBP(_gedp, _flags) \
-    if (_gedp->ged_fbsp->fbs_fbp == NULL) { \
-       int ged_check_view_quiet = (_flags) & GED_QUIET; \
-       if (!ged_check_view_quiet) { \
-           bu_vls_trunc((_gedp)->ged_result_str, 0); \
-           bu_vls_printf((_gedp)->ged_result_str, "A framebuffer IO structure 
does not exist."); \
-       } \
-       return (_flags); \
-    }
-
-
 /**
  * Fb2pix writes a framebuffer image to a .pix file.
  */
@@ -77,8 +56,8 @@
  */
 GED_EXPORT extern int ged_png2fb(struct ged *gedp, int argc, const char 
*argv[]);
 
+#endif
 
-
 __END_DECLS
 
 #endif /* GED_FRAMEBUFFER_H */

Modified: brlcad/branches/dm-fb-merge/include/tclcad.h
===================================================================
--- brlcad/branches/dm-fb-merge/include/tclcad.h        2020-05-18 19:20:19 UTC 
(rev 75835)
+++ brlcad/branches/dm-fb-merge/include/tclcad.h        2020-05-19 03:34:33 UTC 
(rev 75836)
@@ -86,6 +86,53 @@
 #define TCLCAD_OBJ_FB_MODE_INTERLAY 2
 #define TCLCAD_OBJ_FB_MODE_OVERLAY  3
 
+/* Use fbserv */
+#define USE_FBSERV 1
+
+/* Framebuffer server object */
+
+#define NET_LONG_LEN 4 /**< @brief # bytes to network long */
+#define MAX_CLIENTS 32
+#define MAX_PORT_TRIES 100
+#define FBS_CALLBACK_NULL (void (*)())NULL
+#define FBSERV_OBJ_NULL (struct fbserv_obj *)NULL
+
+struct fbserv_listener {
+    int fbsl_fd;                        /**< @brief socket to listen for 
connections */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+    Tcl_Channel fbsl_chan;
+#endif
+    int fbsl_port;                      /**< @brief port number to listen on */
+    int fbsl_listen;                    /**< @brief !0 means listen for 
connections */
+    struct fbserv_obj *fbsl_fbsp;       /**< @brief points to its fbserv 
object */
+};
+
+
+struct fbserv_client {
+    int fbsc_fd;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+    Tcl_Channel fbsc_chan;
+    Tcl_FileProc *fbsc_handler;
+#endif
+    struct pkg_conn *fbsc_pkg;
+    struct fbserv_obj *fbsc_fbsp;       /**< @brief points to its fbserv 
object */
+};
+
+
+struct fbserv_obj {
+    struct fb *fbs_fbp;                        /**< @brief framebuffer pointer 
*/
+    void *fbs_interp;             /**< @brief tcl interpreter */
+    struct fbserv_listener fbs_listener;                /**< @brief data for 
listening */
+    struct fbserv_client fbs_clients[MAX_CLIENTS];      /**< @brief connected 
clients */
+    void (*fbs_callback)(void *clientData);             /**< @brief callback 
function */
+    void *fbs_clientData;
+    int fbs_mode;                       /**< @brief 0-off, 1-underlay, 
2-interlay, 3-overlay */
+};
+
+DM_EXPORT extern int fbs_open(struct fbserv_obj *fbsp, int port);
+DM_EXPORT extern int fbs_close(struct fbserv_obj *fbsp);
+
+
 struct ged_dm_view {
     struct bu_list             l;
     struct bu_vls              gdv_callback;

Modified: brlcad/branches/dm-fb-merge/src/libdm/CMakeLists.txt
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/CMakeLists.txt        2020-05-18 
19:20:19 UTC (rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libdm/CMakeLists.txt        2020-05-19 
03:34:33 UTC (rev 75836)
@@ -7,8 +7,6 @@
   ${RT_INCLUDE_DIRS}
   ${X11_INCLUDE_DIR}
   ${PNG_INCLUDE_DIRS}
-  ${TCL_INCLUDE_PATH}
-  ${TK_INCLUDE_PATH}
   )
 
 # local includes
@@ -67,7 +65,6 @@
   fb_paged_io.c
   fb_rect.c
   fb_util.c
-  fbserv_obj.c
   grid.c
   if_disk.c
   if_mem.c
@@ -82,7 +79,7 @@
   )
 set_property(SOURCE dm_obj.c APPEND PROPERTY COMPILE_DEFINITIONS 
FB_USE_INTERNAL_API)
 set_property(SOURCE dm_init.cpp APPEND PROPERTY COMPILE_DEFINITIONS 
"DM_PLUGIN_SUFFIX=\"${CMAKE_SHARED_LIBRARY_SUFFIX}\"")
-BRLCAD_ADDLIB(libdm "${LIBDM_SRCS}" 
"librt;libbu;libpkg;${TCL_LIBRARY};${TK_LIBRARY};${OPENGL_LIBRARIES};${PNG_LIBRARIES}")
+BRLCAD_ADDLIB(libdm "${LIBDM_SRCS}" 
"librt;libbu;libpkg;${OPENGL_LIBRARIES};${PNG_LIBRARIES}")
 set_target_properties(libdm PROPERTIES VERSION 20.0.1 SOVERSION 20)
 
 #if(BRLCAD_ENABLE_OSG)
@@ -92,9 +89,6 @@
 #  endif(CPP_DLL_DEFINES)
 #endif(BRLCAD_ENABLE_OSG)
 
-if (TARGET tk)
-  add_dependencies(libdm tk)
-endif (TARGET tk)
 if (TARGET profont_ProFont_ttf_cp)
   add_dependencies(libdm profont_ProFont_ttf_cp)
 endif (TARGET profont_ProFont_ttf_cp)

Modified: brlcad/branches/dm-fb-merge/src/libdm/dm-generic.c
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/dm-generic.c  2020-05-18 19:20:19 UTC 
(rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libdm/dm-generic.c  2020-05-19 03:34:33 UTC 
(rev 75836)
@@ -27,11 +27,6 @@
 
 #include <string.h>
 
-#include "tcl.h"
-#ifdef HAVE_TK
-#  include "tk.h"
-#endif
-
 #include "vmath.h"
 #include "dm.h"
 #include "rt/solid.h"

Deleted: brlcad/branches/dm-fb-merge/src/libdm/fbserv_obj.c
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/fbserv_obj.c  2020-05-18 19:20:19 UTC 
(rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libdm/fbserv_obj.c  2020-05-19 03:34:33 UTC 
(rev 75836)
@@ -1,1113 +0,0 @@
-/*                    F B S E R V _ O B J . C
- * BRL-CAD
- *
- * Copyright (c) 2004-2020 United States Government as represented by
- * the U.S. Army Research Laboratory.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this file; see the file named COPYING for more
- * information.
- */
-/** @addtogroup libstruct fb */
-/** @{ */
-/** @file fbserv_obj.c
- *
- * A framebuffer server object contains the attributes and
- * methods for implementing an fbserv. This code was developed
- * in large part by modifying the stand-alone version of fbserv.
- *
- * TODO - other than the backends themselves (which are now plugins
- * and so relatively independent) fbserv is the last piece of the
- * libdm/libfb stack making core use of Tcl.  Unlike the dm_obj,
- * fb_obj and tcl files the use of Tcl here is an implmeentation
- * detail of the functional purpose of the file rather than the
- * primary purpose of the code, and as such this belongs in
- * libdm rather than libtclcad.  That means we need to find a way
- * to achieve the functionality present here without relying on
- * Tcl/Tk - either by embedding the necessary logic in libbu (as
- * was done with Tcl list parsing) or replacing the functionality
- * with something that achieves the same goal.  Will have to see
- * if there are any implicit requirements for the Tcl communication
- * in calling codes as well.
- */
-/** @} */
-
-#include "common.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <tcl.h>
-#include "bio.h"
-#include "bnetwork.h"
-
-#include "raytrace.h"
-#include "dm.h"
-
-#include "dm.h"
-#include "./include/private.h"
-
-
-static struct fb *curr_fbp;            /* current framebuffer pointer */
-
-
-/*
- * Communication error.  An error occurred on the PKG link.
- */
-HIDDEN void
-comm_error(const char *str)
-{
-    bu_log("%s", str);
-}
-
-
-HIDDEN void
-drop_client(struct fbserv_obj *fbsp, int sub)
-{
-    if (fbsp->fbs_clients[sub].fbsc_pkg != PKC_NULL) {
-       pkg_close(fbsp->fbs_clients[sub].fbsc_pkg);
-       fbsp->fbs_clients[sub].fbsc_pkg = PKC_NULL;
-    }
-
-    if (fbsp->fbs_clients[sub].fbsc_fd != 0) {
-#if defined(_WIN32) && !defined(__CYGWIN__)
-       Tcl_DeleteChannelHandler(fbsp->fbs_clients[sub].fbsc_chan, 
fbsp->fbs_clients[sub].fbsc_handler, 
(ClientData)fbsp->fbs_clients[sub].fbsc_fd);
-
-       Tcl_Close((Tcl_Interp *)fbsp->fbs_interp, 
fbsp->fbs_clients[sub].fbsc_chan);
-       fbsp->fbs_clients[sub].fbsc_chan = NULL;
-#else
-       Tcl_DeleteFileHandler(fbsp->fbs_clients[sub].fbsc_fd);
-#endif
-
-       fbsp->fbs_clients[sub].fbsc_fd = 0;
-    }
-}
-
-
-/*
- * Process arrivals from existing clients.
- */
-HIDDEN void
-existing_client_handler(ClientData clientData, int UNUSED(mask))
-{
-    register int i;
-    struct fbserv_client *fbscp = (struct fbserv_client *)clientData;
-    struct fbserv_obj *fbsp = fbscp->fbsc_fbsp;
-    int fd = fbscp->fbsc_fd;
-
-    curr_fbp = fbsp->fbs_fbp;
-
-    for (i = MAX_CLIENTS - 1; i >= 0; i--) {
-       if (fbsp->fbs_clients[i].fbsc_fd == 0)
-           continue;
-
-       if ((pkg_process(fbsp->fbs_clients[i].fbsc_pkg)) < 0)
-           bu_log("pkg_process error encountered (1)\n");
-
-       if (fbsp->fbs_clients[i].fbsc_fd != fd)
-           continue;
-
-       if (pkg_suckin(fbsp->fbs_clients[i].fbsc_pkg) <= 0) {
-           /* Probably EOF */
-           drop_client(fbsp, i);
-
-           continue;
-       }
-
-       if ((pkg_process(fbsp->fbs_clients[i].fbsc_pkg)) < 0)
-           bu_log("pkg_process error encountered (2)\n");
-    }
-
-    if (fbsp->fbs_callback != (void (*)(void *))FBS_CALLBACK_NULL) {
-       /* need to cast func pointer explicitly to get the function call */
-       void (*cfp)(void *);
-       cfp = (void (*)(void *))fbsp->fbs_callback;
-       cfp(fbsp->fbs_clientData);
-    }
-}
-
-
-HIDDEN void
-setup_socket(int fd)
-{
-    int on     = 1;
-    int retval = 0;
-
-#if defined(SO_KEEPALIVE)
-    /* FIXME: better to show an error message but need thread considerations 
for strerror */
-    if ((retval = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 
sizeof(on))) < 0) {
-       bu_log("setsockopt (SO_KEEPALIVE) error return: %d", retval);
-    }
-#endif
-#if defined(SO_RCVBUF)
-    /* try to set our buffers up larger */
-    {
-       int m = -1;
-       int n = -1;
-       int val;
-       int size;
-
-       for (size = 256; size > 16; size /= 2) {
-           val = size * 1024;
-           m = setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
-                          (char *)&val, sizeof(val));
-           val = size * 1024;
-           n = setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
-                          (char *)&val, sizeof(val));
-           if (m >= 0 && n >= 0) break;
-       }
-
-       if (m < 0 || n < 0)
-           bu_log("setup_socket: setsockopt()");
-    }
-#endif
-}
-
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-HIDDEN void
-new_client(struct fbserv_obj *fbsp, struct pkg_conn *pcp, Tcl_Channel chan)
-{
-    int i;
-
-    if (pcp == PKC_ERROR)
-       return;
-
-    for (i = MAX_CLIENTS - 1; i >= 0; i--) {
-       /* this slot is being used */
-       if (fbsp->fbs_clients[i].fbsc_fd != 0)
-           continue;
-
-       /* Found an available slot */
-       fbsp->fbs_clients[i].fbsc_fd = pcp->pkc_fd;
-       fbsp->fbs_clients[i].fbsc_pkg = pcp;
-       fbsp->fbs_clients[i].fbsc_fbsp = fbsp;
-       setup_socket(pcp->pkc_fd);
-
-       fbsp->fbs_clients[i].fbsc_chan = chan;
-       fbsp->fbs_clients[i].fbsc_handler = existing_client_handler;
-       Tcl_CreateChannelHandler(fbsp->fbs_clients[i].fbsc_chan, TCL_READABLE,
-                                fbsp->fbs_clients[i].fbsc_handler,
-                                (ClientData)&fbsp->fbs_clients[i]);
-       return;
-    }
-
-    bu_log("new_client: too many clients\n");
-    pkg_close(pcp);
-}
-
-#else /* if defined(_WIN32) && !defined(__CYGWIN__) */
-HIDDEN void
-new_client(struct fbserv_obj *fbsp, struct pkg_conn *pcp, Tcl_Channel 
UNUSED(chan))
-{
-    int i;
-
-    if (pcp == PKC_ERROR)
-       return;
-
-    for (i = MAX_CLIENTS - 1; i >= 0; i--) {
-       /* this slot is being used */
-       if (fbsp->fbs_clients[i].fbsc_fd != 0)
-           continue;
-
-       /* Found an available slot */
-       fbsp->fbs_clients[i].fbsc_fd = pcp->pkc_fd;
-       fbsp->fbs_clients[i].fbsc_pkg = pcp;
-       fbsp->fbs_clients[i].fbsc_fbsp = fbsp;
-       setup_socket(pcp->pkc_fd);
-
-       Tcl_CreateFileHandler(fbsp->fbs_clients[i].fbsc_fd, TCL_READABLE,
-                             existing_client_handler, 
(ClientData)&fbsp->fbs_clients[i]);
-       return;
-    }
-
-    bu_log("new_client: too many clients\n");
-    pkg_close(pcp);
-}
-#endif /* if defined(_WIN32) && !defined(__CYGWIN__) */
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-HIDDEN struct pkg_conn *
-fbs_makeconn(int fd, const struct pkg_switch *switchp)
-{
-    register struct pkg_conn *pc;
-#ifdef HAVE_WINSOCK_H
-    WSADATA wsaData;
-    WORD wVersionRequested; /* initialize Windows socket networking,
-                            * increment reference count.
-                            */
-#endif
-
-    if ((pc = (struct pkg_conn *)malloc(sizeof(struct pkg_conn))) == PKC_NULL) 
{
-       comm_error("fbs_makeconn: malloc failure\n");
-       return PKC_ERROR;
-    }
-
-#ifdef HAVE_WINSOCK_H
-    wVersionRequested = MAKEWORD(1, 1);
-    if (WSAStartup(wVersionRequested, &wsaData) != 0) {
-       comm_error("fbs_makeconn:  could not find a usable WinSock DLL\n");
-       return PKC_ERROR;
-    }
-#endif
-
-    memset((char *)pc, 0, sizeof(struct pkg_conn));
-    pc->pkc_magic = PKG_MAGIC;
-    pc->pkc_fd = fd;
-    pc->pkc_switch = switchp;
-    pc->pkc_errlog = 0;
-    pc->pkc_left = -1;
-    pc->pkc_buf = (char *)0;
-    pc->pkc_curpos = (char *)0;
-    pc->pkc_strpos = 0;
-    pc->pkc_incur = pc->pkc_inend = 0;
-
-    return pc;
-}
-#endif
-
-
-/*
- * This is where we go for message types we don't understand.
- */
-HIDDEN void
-fbs_rfbunknown(struct pkg_conn *pcp, char *buf)
-{
-    bu_log("fbserv: unable to handle message type %d\n", pcp->pkc_type);
-    if (buf) {
-       (void)free(buf);
-    }
-}
-
-
-/******** Here's where the hooks lead *********/
-
-HIDDEN void
-fbs_rfbopen(struct pkg_conn *pcp, char *buf)
-{
-    char rbuf[5*NET_LONG_LEN+1];
-    int want;
-
-    /* Don't really open a new framebuffer --- use existing one */
-    (void)pkg_plong(&rbuf[0*NET_LONG_LEN], 0); /* ret */
-    (void)pkg_plong(&rbuf[1*NET_LONG_LEN], curr_fbp->i->if_max_width);
-    (void)pkg_plong(&rbuf[2*NET_LONG_LEN], curr_fbp->i->if_max_height);
-    (void)pkg_plong(&rbuf[3*NET_LONG_LEN], curr_fbp->i->if_width);
-    (void)pkg_plong(&rbuf[4*NET_LONG_LEN], curr_fbp->i->if_height);
-
-    want = 5*NET_LONG_LEN;
-    if (pkg_send(MSG_RETURN, rbuf, want, pcp) != want)
-       comm_error("pkg_send fb_open reply\n");
-
-    if (buf) {
-       (void)free(buf);
-    }
-}
-
-
-void
-fbs_rfbclose(struct pkg_conn *pcp, char *buf)
-{
-    char rbuf[NET_LONG_LEN+1];
-
-    /*
-     * We are playing FB server so we don't really close the frame
-     * buffer.  We should flush output however.
-     */
-    (void)fb_flush(curr_fbp);
-    (void)pkg_plong(&rbuf[0], 0);              /* return success */
-
-    /* Don't check for errors, linger mode or other events may have
-     * already closed down all the file descriptors.  If communication
-     * has broken, other end will know we are gone.
-     */
-    (void)pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-
-    if (buf) {
-       (void)free(buf);
-    }
-}
-
-
-void
-fbs_rfbfree(struct pkg_conn *pcp, char *buf)
-{
-    char rbuf[NET_LONG_LEN+1];
-
-    /* Don't really free framebuffer */
-    if (pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp) != NET_LONG_LEN)
-       comm_error("pkg_send fb_free reply\n");
-
-    if (buf) {
-       (void)free(buf);
-    }
-}
-
-
-void
-fbs_rfbclear(struct pkg_conn *pcp, char *buf)
-{
-    RGBpixel bg;
-    char rbuf[NET_LONG_LEN+1];
-
-    if (!buf) {
-       bu_log("fbs_rfbclear: null buffer\n");
-       return;
-    }
-
-    bg[RED] = buf[0];
-    bg[GRN] = buf[1];
-    bg[BLU] = buf[2];
-
-    (void)pkg_plong(rbuf, fb_clear(curr_fbp, bg));
-    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-
-    (void)free(buf);
-}
-
-
-void
-fbs_rfbread(struct pkg_conn *pcp, char *buf)
-{
-    int x, y;
-    size_t num;
-    int ret;
-    static unsigned char *scanbuf = NULL;
-    static size_t buflen = 0;
-
-    if (!buf) {
-       bu_log("fbs_rfbread: null buffer\n");
-       return;
-    }
-
-    x = pkg_glong(&buf[0*NET_LONG_LEN]);
-    y = pkg_glong(&buf[1*NET_LONG_LEN]);
-    num = (size_t)pkg_glong(&buf[2*NET_LONG_LEN]);
-
-    if (num*sizeof(RGBpixel) > buflen) {
-       if (scanbuf != NULL)
-           free((char *)scanbuf);
-       buflen = num*sizeof(RGBpixel);
-       if (buflen < 1024*sizeof(RGBpixel))
-           buflen = 1024*sizeof(RGBpixel);
-       if ((scanbuf = (unsigned char *)malloc(buflen)) == NULL) {
-           fb_log("fb_read: malloc failed!");
-           (void)free(buf);
-           buflen = 0;
-           return;
-       }
-    }
-
-    ret = fb_read(curr_fbp, x, y, scanbuf, num);
-    if (ret < 0) ret = 0;              /* map error indications */
-    /* sending a 0-length package indicates error */
-    pkg_send(MSG_RETURN, (char *)scanbuf, ret*sizeof(RGBpixel), pcp);
-    (void)free(buf);
-}
-
-
-void
-fbs_rfbwrite(struct pkg_conn *pcp, char *buf)
-{
-    long x, y, num;
-    char rbuf[NET_LONG_LEN+1];
-    int ret;
-    int type;
-
-    if (!buf) {
-       bu_log("fbs_rfbwrite: null buffer\n");
-       return;
-    }
-
-    x = pkg_glong(&buf[0*NET_LONG_LEN]);
-    y = pkg_glong(&buf[1*NET_LONG_LEN]);
-    num = pkg_glong(&buf[2*NET_LONG_LEN]);
-    type = pcp->pkc_type;
-    ret = fb_write(curr_fbp, x, y, (unsigned char *)&buf[3*NET_LONG_LEN], 
(size_t)num);
-
-    if (type < MSG_NORETURN) {
-       (void)pkg_plong(&rbuf[0*NET_LONG_LEN], ret);
-       pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-    }
-    (void)free(buf);
-}
-
-
-void
-fbs_rfbreadrect(struct pkg_conn *pcp, char *buf)
-{
-    int xmin, ymin;
-    int width, height;
-    size_t num;
-    int ret;
-    static unsigned char *scanbuf = NULL;
-    static size_t buflen = 0;
-
-    if (!buf) {
-       bu_log("fbs_rfbreadrect: null buffer\n");
-       return;
-    }
-
-    xmin = pkg_glong(&buf[0*NET_LONG_LEN]);
-    ymin = pkg_glong(&buf[1*NET_LONG_LEN]);
-    width = pkg_glong(&buf[2*NET_LONG_LEN]);
-    height = pkg_glong(&buf[3*NET_LONG_LEN]);
-    num = width * height;
-
-    if (num*sizeof(RGBpixel) > buflen) {
-       if (scanbuf != NULL)
-           free((char *)scanbuf);
-       buflen = num*sizeof(RGBpixel);
-       if (buflen < 1024*sizeof(RGBpixel))
-           buflen = 1024*sizeof(RGBpixel);
-       if ((scanbuf = (unsigned char *)malloc(buflen)) == NULL) {
-           fb_log("fb_read: malloc failed!");
-           (void)free(buf);
-           buflen = 0;
-           return;
-       }
-    }
-
-    ret = fb_readrect(curr_fbp, xmin, ymin, width, height, scanbuf);
-    if (ret < 0) ret = 0;              /* map error indications */
-    /* sending a 0-length package indicates error */
-    pkg_send(MSG_RETURN, (char *)scanbuf, ret*sizeof(RGBpixel), pcp);
-    (void)free(buf);
-}
-
-
-void
-fbs_rfbwriterect(struct pkg_conn *pcp, char *buf)
-{
-    int x, y;
-    int width, height;
-    char rbuf[NET_LONG_LEN+1];
-    int ret;
-    int type;
-
-    if (!buf) {
-       bu_log("fbs_rfbwriterect: null buffer\n");
-       return;
-    }
-
-    x = pkg_glong(&buf[0*NET_LONG_LEN]);
-    y = pkg_glong(&buf[1*NET_LONG_LEN]);
-    width = pkg_glong(&buf[2*NET_LONG_LEN]);
-    height = pkg_glong(&buf[3*NET_LONG_LEN]);
-
-    type = pcp->pkc_type;
-    ret = fb_writerect(curr_fbp, x, y, width, height,
-                      (unsigned char *)&buf[4*NET_LONG_LEN]);
-
-    if (type < MSG_NORETURN) {
-       (void)pkg_plong(&rbuf[0*NET_LONG_LEN], ret);
-       pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-    }
-    (void)free(buf);
-}
-
-
-void
-fbs_rfbbwreadrect(struct pkg_conn *pcp, char *buf)
-{
-    int xmin, ymin;
-    int width, height;
-    int num;
-    int ret;
-    static unsigned char *scanbuf = NULL;
-    static int buflen = 0;
-
-    if (!buf) {
-       bu_log("fbs_rfbbwreadrect: null buffer\n");
-       return;
-    }
-
-    xmin = pkg_glong(&buf[0*NET_LONG_LEN]);
-    ymin = pkg_glong(&buf[1*NET_LONG_LEN]);
-    width = pkg_glong(&buf[2*NET_LONG_LEN]);
-    height = pkg_glong(&buf[3*NET_LONG_LEN]);
-    num = width * height;
-
-    if (num > buflen) {
-       if (scanbuf != NULL)
-           free((char *)scanbuf);
-       buflen = num;
-       if (buflen < 1024)
-           buflen = 1024;
-       if ((scanbuf = (unsigned char *)malloc(buflen)) == NULL) {
-           fb_log("fbs_rfbbwreadrect: malloc failed!");
-           (void)free(buf);
-           buflen = 0;
-           return;
-       }
-    }
-
-    ret = fb_bwreadrect(curr_fbp, xmin, ymin, width, height, scanbuf);
-    if (ret < 0) ret = 0;              /* map error indications */
-    /* sending a 0-length package indicates error */
-    pkg_send(MSG_RETURN, (char *)scanbuf, ret, pcp);
-    (void)free(buf);
-}
-
-
-void
-fbs_rfbbwwriterect(struct pkg_conn *pcp, char *buf)
-{
-    int x, y;
-    int width, height;
-    char rbuf[NET_LONG_LEN+1];
-    int ret;
-    int type;
-
-    if (!buf) {
-       bu_log("fbs_rfbbwwriterect: null buffer\n");
-       return;
-    }
-
-    x = pkg_glong(&buf[0*NET_LONG_LEN]);
-    y = pkg_glong(&buf[1*NET_LONG_LEN]);
-    width = pkg_glong(&buf[2*NET_LONG_LEN]);
-    height = pkg_glong(&buf[3*NET_LONG_LEN]);
-
-    type = pcp->pkc_type;
-    ret = fb_writerect(curr_fbp, x, y, width, height,
-                      (unsigned char *)&buf[4*NET_LONG_LEN]);
-
-    if (type < MSG_NORETURN) {
-       (void)pkg_plong(&rbuf[0*NET_LONG_LEN], ret);
-       pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-    }
-    (void)free(buf);
-}
-
-
-void
-fbs_rfbcursor(struct pkg_conn *pcp, char *buf)
-{
-    int mode, x, y;
-    char rbuf[NET_LONG_LEN+1];
-
-    if (!buf) {
-       bu_log("fbs_rfbcursor: null buffer\n");
-       return;
-    }
-
-    mode = pkg_glong(&buf[0*NET_LONG_LEN]);
-    x = pkg_glong(&buf[1*NET_LONG_LEN]);
-    y = pkg_glong(&buf[2*NET_LONG_LEN]);
-
-    (void)pkg_plong(&rbuf[0], fb_cursor(curr_fbp, mode, x, y));
-    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-    (void)free(buf);
-}
-
-
-void
-fbs_rfbgetcursor(struct pkg_conn *pcp, char *buf)
-{
-    int ret;
-    int mode, x, y;
-    char rbuf[4*NET_LONG_LEN+1];
-
-    ret = fb_getcursor(curr_fbp, &mode, &x, &y);
-    (void)pkg_plong(&rbuf[0*NET_LONG_LEN], ret);
-    (void)pkg_plong(&rbuf[1*NET_LONG_LEN], mode);
-    (void)pkg_plong(&rbuf[2*NET_LONG_LEN], x);
-    (void)pkg_plong(&rbuf[3*NET_LONG_LEN], y);
-    pkg_send(MSG_RETURN, rbuf, 4*NET_LONG_LEN, pcp);
-
-    if (buf) {
-       (void)free(buf);
-    }
-}
-
-
-void
-fbs_rfbsetcursor(struct pkg_conn *pcp, char *buf)
-{
-    char rbuf[NET_LONG_LEN+1];
-    int ret;
-    int xbits, ybits;
-    int xorig, yorig;
-
-    if (!buf) {
-       bu_log("fbs_rfsetcursor: null buffer\n");
-       return;
-    }
-
-    xbits = pkg_glong(&buf[0*NET_LONG_LEN]);
-    ybits = pkg_glong(&buf[1*NET_LONG_LEN]);
-    xorig = pkg_glong(&buf[2*NET_LONG_LEN]);
-    yorig = pkg_glong(&buf[3*NET_LONG_LEN]);
-
-    ret = fb_setcursor(curr_fbp, (unsigned char *)&buf[4*NET_LONG_LEN],
-                      xbits, ybits, xorig, yorig);
-
-    if (pcp->pkc_type < MSG_NORETURN) {
-       (void)pkg_plong(&rbuf[0*NET_LONG_LEN], ret);
-       pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-    }
-    (void)free(buf);
-}
-
-
-/*OLD*/
-void
-fbs_rfbscursor(struct pkg_conn *pcp, char *buf)
-{
-    int mode, x, y;
-    char rbuf[NET_LONG_LEN+1];
-
-    if (!buf) {
-       bu_log("fbs_rfbscursor: null buffer\n");
-       return;
-    }
-
-    mode = pkg_glong(&buf[0*NET_LONG_LEN]);
-    x = pkg_glong(&buf[1*NET_LONG_LEN]);
-    y = pkg_glong(&buf[2*NET_LONG_LEN]);
-
-    (void)pkg_plong(&rbuf[0], fb_scursor(curr_fbp, mode, x, y));
-    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-    (void)free(buf);
-}
-
-
-/*OLD*/
-void
-fbs_rfbwindow(struct pkg_conn *pcp, char *buf)
-{
-    int x, y;
-    char rbuf[NET_LONG_LEN+1];
-
-    if (!buf) {
-       bu_log("fbs_rfbwindow: null buffer\n");
-       return;
-    }
-
-    x = pkg_glong(&buf[0*NET_LONG_LEN]);
-    y = pkg_glong(&buf[1*NET_LONG_LEN]);
-
-    (void)pkg_plong(&rbuf[0], fb_window(curr_fbp, x, y));
-    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-
-    (void)free(buf);
-}
-
-
-/*OLD*/
-void
-fbs_rfbzoom(struct pkg_conn *pcp, char *buf)
-{
-    int x, y;
-    char rbuf[NET_LONG_LEN+1];
-
-    if (!buf) {
-       bu_log("fbs_rfbzoom: null buffer\n");
-       return;
-    }
-
-    x = pkg_glong(&buf[0*NET_LONG_LEN]);
-    y = pkg_glong(&buf[1*NET_LONG_LEN]);
-
-    (void)pkg_plong(&rbuf[0], fb_zoom(curr_fbp, x, y));
-    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-    (void)free(buf);
-}
-
-
-void
-fbs_rfbview(struct pkg_conn *pcp, char *buf)
-{
-    int ret;
-    int xcenter, ycenter, xzoom, yzoom;
-    char rbuf[NET_LONG_LEN+1];
-
-    if (!buf) {
-       bu_log("fbs_rfbview: null buffer\n");
-       return;
-    }
-
-    xcenter = pkg_glong(&buf[0*NET_LONG_LEN]);
-    ycenter = pkg_glong(&buf[1*NET_LONG_LEN]);
-    xzoom = pkg_glong(&buf[2*NET_LONG_LEN]);
-    yzoom = pkg_glong(&buf[3*NET_LONG_LEN]);
-
-    ret = fb_view(curr_fbp, xcenter, ycenter, xzoom, yzoom);
-    (void)pkg_plong(&rbuf[0], ret);
-    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-    (void)free(buf);
-}
-
-
-void
-fbs_rfbgetview(struct pkg_conn *pcp, char *buf)
-{
-    int ret;
-    int xcenter, ycenter, xzoom, yzoom;
-    char rbuf[5*NET_LONG_LEN+1];
-
-    ret = fb_getview(curr_fbp, &xcenter, &ycenter, &xzoom, &yzoom);
-    (void)pkg_plong(&rbuf[0*NET_LONG_LEN], ret);
-    (void)pkg_plong(&rbuf[1*NET_LONG_LEN], xcenter);
-    (void)pkg_plong(&rbuf[2*NET_LONG_LEN], ycenter);
-    (void)pkg_plong(&rbuf[3*NET_LONG_LEN], xzoom);
-    (void)pkg_plong(&rbuf[4*NET_LONG_LEN], yzoom);
-    pkg_send(MSG_RETURN, rbuf, 5*NET_LONG_LEN, pcp);
-
-    if (buf) {
-       (void)free(buf);
-    }
-}
-
-
-void
-fbs_rfbrmap(struct pkg_conn *pcp, char *buf)
-{
-    register int i;
-    char rbuf[NET_LONG_LEN+1];
-    ColorMap map;
-    unsigned char cm[256*2*3];
-
-    (void)pkg_plong(&rbuf[0*NET_LONG_LEN], fb_rmap(curr_fbp, &map));
-    for (i = 0; i < 256; i++) {
-       (void)pkg_pshort((char *)(cm+2*(0+i)), map.cm_red[i]);
-       (void)pkg_pshort((char *)(cm+2*(256+i)), map.cm_green[i]);
-       (void)pkg_pshort((char *)(cm+2*(512+i)), map.cm_blue[i]);
-    }
-    pkg_send(MSG_DATA, (char *)cm, sizeof(cm), pcp);
-    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-
-    if (buf) {
-       (void)free(buf);
-    }
-}
-
-
-/*
- * Accept a color map sent by the client, and write it to the
- * framebuffer.  Network format is to send each entry as a network
- * (IBM) order 2-byte short, 256 red shorts, followed by 256 green and
- * 256 blue, for a total of 3*256*2 bytes.
- */
-void
-fbs_rfbwmap(struct pkg_conn *pcp, char *buf)
-{
-    int i;
-    char rbuf[NET_LONG_LEN+1];
-    long ret;
-    ColorMap map;
-
-    if (!buf) {
-       bu_log("fbs_rfbwmap: null buffer\n");
-       return;
-    }
-
-    if (pcp->pkc_len == 0) {
-       ret = fb_wmap(curr_fbp, COLORMAP_NULL);
-    } else {
-       for (i = 0; i < 256; i++) {
-           map.cm_red[i] = pkg_gshort(buf+2*(0+i));
-           map.cm_green[i] = pkg_gshort(buf+2*(256+i));
-           map.cm_blue[i] = pkg_gshort(buf+2*(512+i));
-       }
-       ret = fb_wmap(curr_fbp, &map);
-    }
-    (void)pkg_plong(&rbuf[0], ret);
-    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-    (void)free(buf);
-}
-
-
-void
-fbs_rfbflush(struct pkg_conn *pcp, char *buf)
-{
-    int ret;
-    char rbuf[NET_LONG_LEN+1];
-
-    ret = fb_flush(curr_fbp);
-
-    if (pcp->pkc_type < MSG_NORETURN) {
-       (void)pkg_plong(rbuf, ret);
-       pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-    }
-
-    if (buf) {
-       (void)free(buf);
-    }
-}
-
-
-void
-fbs_rfbpoll(struct pkg_conn *pcp, char *buf)
-{
-    if (pcp == PKC_ERROR) {
-       return;
-    }
-
-    (void)fb_poll(curr_fbp);
-    if (buf) {
-       (void)free(buf);
-    }
-}
-
-
-/*
- * At one time at least we couldn't send a zero length PKG message
- * back and forth, so we receive a dummy long here.
- */
-void
-fbs_rfbhelp(struct pkg_conn *pcp, char *buf)
-{
-    long ret;
-    char rbuf[NET_LONG_LEN+1];
-
-    if (!buf) {
-       bu_log("fbs_rfbhelp: null buffer\n");
-       return;
-    }
-
-    (void)pkg_glong(&buf[0*NET_LONG_LEN]);
-
-    ret = fb_help(curr_fbp);
-    (void)pkg_plong(&rbuf[0], ret);
-    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
-    (void)free(buf);
-}
-
-
-/*
- * Accept any new client connections.
- */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-HIDDEN void
-new_client_handler(ClientData clientData,
-                  Tcl_Channel chan,
-                  char *UNUSED(host),
-                  int UNUSED(port))
-{
-    struct fbserv_listener *fbslp = (struct fbserv_listener *)clientData;
-    struct fbserv_obj *fbsp = fbslp->fbsl_fbsp;
-    uintptr_t fd = (uintptr_t)fbslp->fbsl_fd;
-
-    static struct pkg_switch pswitch[] = {
-       { MSG_FBOPEN, fbs_rfbopen, "Open Framebuffer", NULL },
-       { MSG_FBCLOSE, fbs_rfbclose, "Close Framebuffer", NULL },
-       { MSG_FBCLEAR, fbs_rfbclear, "Clear Framebuffer", NULL },
-       { MSG_FBREAD, fbs_rfbread, "Read Pixels", NULL },
-       { MSG_FBWRITE, fbs_rfbwrite, "Write Pixels", NULL },
-       { MSG_FBWRITE + MSG_NORETURN, fbs_rfbwrite, "Asynch write", NULL },
-       { MSG_FBCURSOR, fbs_rfbcursor, "Cursor", NULL },
-       { MSG_FBGETCURSOR, fbs_rfbgetcursor, "Get Cursor", NULL },  /*NEW*/
-       { MSG_FBSCURSOR, fbs_rfbscursor, "Screen Cursor", NULL }, /*OLD*/
-       { MSG_FBWINDOW, fbs_rfbwindow, "Window", NULL },  /*OLD*/
-       { MSG_FBZOOM, fbs_rfbzoom, "Zoom", NULL },  /*OLD*/
-       { MSG_FBVIEW, fbs_rfbview, "View", NULL },  /*NEW*/
-       { MSG_FBGETVIEW, fbs_rfbgetview, "Get View", NULL },  /*NEW*/
-       { MSG_FBRMAP, fbs_rfbrmap, "R Map", NULL },
-       { MSG_FBWMAP, fbs_rfbwmap, "W Map", NULL },
-       { MSG_FBHELP, fbs_rfbhelp, "Help Request", NULL },
-       { MSG_ERROR, fbs_rfbunknown, "Error Message", NULL },
-       { MSG_CLOSE, fbs_rfbunknown, "Close Connection", NULL },
-       { MSG_FBREADRECT, fbs_rfbreadrect, "Read Rectangle", NULL },
-       { MSG_FBWRITERECT, fbs_rfbwriterect, "Write Rectangle", NULL },
-       { MSG_FBWRITERECT + MSG_NORETURN, fbs_rfbwriterect, "Write Rectangle", 
NULL },
-       { MSG_FBBWREADRECT, fbs_rfbbwreadrect, "Read BW Rectangle", NULL },
-       { MSG_FBBWWRITERECT, fbs_rfbbwwriterect, "Write BW Rectangle", NULL },
-       { MSG_FBBWWRITERECT+MSG_NORETURN, fbs_rfbbwwriterect, "Write BW 
Rectangle", NULL },
-       { MSG_FBFLUSH, fbs_rfbflush, "Flush Output", NULL },
-       { MSG_FBFLUSH + MSG_NORETURN, fbs_rfbflush, "Flush Output", NULL },
-       { MSG_FBFREE, fbs_rfbfree, "Free Resources", NULL },
-       { MSG_FBPOLL, fbs_rfbpoll, "Handle Events", NULL },
-       { MSG_FBSETCURSOR, fbs_rfbsetcursor, "Set Cursor Shape", NULL },
-       { MSG_FBSETCURSOR + MSG_NORETURN, fbs_rfbsetcursor, "Set Cursor Shape", 
NULL },
-       { 0, NULL, NULL, NULL }
-    };
-
-    if (Tcl_GetChannelHandle(chan, TCL_READABLE, (ClientData *)&fd) == TCL_OK)
-       new_client(fbsp, fbs_makeconn((int)fd, pswitch), chan);
-}
-#else /* if defined(_WIN32) && !defined(__CYGWIN__) */
-HIDDEN void
-new_client_handler(ClientData clientData,
-                  int UNUSED(port))
-{
-    struct fbserv_listener *fbslp = (struct fbserv_listener *)clientData;
-    struct fbserv_obj *fbsp = fbslp->fbsl_fbsp;
-    int fd = fbslp->fbsl_fd;
-
-    static struct pkg_switch pswitch[] = {
-       { MSG_FBOPEN, fbs_rfbopen, "Open Framebuffer", NULL },
-       { MSG_FBCLOSE, fbs_rfbclose, "Close Framebuffer", NULL },
-       { MSG_FBCLEAR, fbs_rfbclear, "Clear Framebuffer", NULL },
-       { MSG_FBREAD, fbs_rfbread, "Read Pixels", NULL },
-       { MSG_FBWRITE, fbs_rfbwrite, "Write Pixels", NULL },
-       { MSG_FBWRITE + MSG_NORETURN, fbs_rfbwrite, "Asynch write", NULL },
-       { MSG_FBCURSOR, fbs_rfbcursor, "Cursor", NULL },
-       { MSG_FBGETCURSOR, fbs_rfbgetcursor, "Get Cursor", NULL },  /*NEW*/
-       { MSG_FBSCURSOR, fbs_rfbscursor, "Screen Cursor", NULL }, /*OLD*/
-       { MSG_FBWINDOW, fbs_rfbwindow, "Window", NULL },  /*OLD*/
-       { MSG_FBZOOM, fbs_rfbzoom, "Zoom", NULL },  /*OLD*/
-       { MSG_FBVIEW, fbs_rfbview, "View", NULL },  /*NEW*/
-       { MSG_FBGETVIEW, fbs_rfbgetview, "Get View", NULL },  /*NEW*/
-       { MSG_FBRMAP, fbs_rfbrmap, "R Map", NULL },
-       { MSG_FBWMAP, fbs_rfbwmap, "W Map", NULL },
-       { MSG_FBHELP, fbs_rfbhelp, "Help Request", NULL },
-       { MSG_ERROR, fbs_rfbunknown, "Error Message", NULL },
-       { MSG_CLOSE, fbs_rfbunknown, "Close Connection", NULL },
-       { MSG_FBREADRECT, fbs_rfbreadrect, "Read Rectangle", NULL },
-       { MSG_FBWRITERECT, fbs_rfbwriterect, "Write Rectangle", NULL },
-       { MSG_FBWRITERECT + MSG_NORETURN, fbs_rfbwriterect, "Write Rectangle", 
NULL },
-       { MSG_FBBWREADRECT, fbs_rfbbwreadrect, "Read BW Rectangle", NULL },
-       { MSG_FBBWWRITERECT, fbs_rfbbwwriterect, "Write BW Rectangle", NULL },
-       { MSG_FBBWWRITERECT+MSG_NORETURN, fbs_rfbbwwriterect, "Write BW 
Rectangle", NULL },
-       { MSG_FBFLUSH, fbs_rfbflush, "Flush Output", NULL },
-       { MSG_FBFLUSH + MSG_NORETURN, fbs_rfbflush, "Flush Output", NULL },
-       { MSG_FBFREE, fbs_rfbfree, "Free Resources", NULL },
-       { MSG_FBPOLL, fbs_rfbpoll, "Handle Events", NULL },
-       { MSG_FBSETCURSOR, fbs_rfbsetcursor, "Set Cursor Shape", NULL },
-       { MSG_FBSETCURSOR + MSG_NORETURN, fbs_rfbsetcursor, "Set Cursor Shape", 
NULL },
-       { 0, NULL, NULL, NULL }
-    };
-
-    new_client(fbsp, pkg_getclient(fd, pswitch, comm_error, 0), 0);
-}
-#endif /* if defined(_WIN32) && !defined(__CYGWIN__) */
-
-int
-fbs_open(struct fbserv_obj *fbsp, int port)
-{
-    int i;
-    struct bu_vls vls = BU_VLS_INIT_ZERO;
-    char hostname[32] = {0};
-    Tcl_DString ds;
-    int failed = 0;
-    int available_port = port;
-
-    /* Already listening; nothing more to do. */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-    if (fbsp->fbs_listener.fbsl_chan != NULL) {
-       return TCL_OK;
-    }
-#else /* if defined(_WIN32) && !defined(__CYGWIN__) */
-    if (fbsp->fbs_listener.fbsl_fd >= 0) {
-       return TCL_OK;
-    }
-#endif /* if defined(_WIN32) && !defined(__CYGWIN__) */
-
-    /* XXX hardwired for now */
-    sprintf(hostname, "localhost");
-
-    if (available_port < 0) {
-       available_port = 5559;
-    } else if (available_port < 1024) {
-       available_port += 5559;
-    }
-
-    Tcl_DStringInit(&ds);
-
-    /* Try a reasonable number of times to hang a listen */
-    for (i = 0; i < MAX_PORT_TRIES; ++i) {
-       /*
-        * Hang an unending listen for PKG connections
-        */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-       fbsp->fbs_listener.fbsl_chan = Tcl_OpenTcpServer((Tcl_Interp 
*)fbsp->fbs_interp, available_port, hostname, new_client_handler, 
(ClientData)&fbsp->fbs_listener);
-       if (fbsp->fbs_listener.fbsl_chan == NULL) {
-           /* This clobbers the result string which probably has junk
-            * related to the failed open.
-            */
-           Tcl_DStringResult((Tcl_Interp *)fbsp->fbs_interp, &ds);
-       } else {
-           break;
-       }
-#else /* if defined(_WIN32) && !defined(__CYGWIN__) */
-       char portname[32] = {0};
-       sprintf(portname, "%d", available_port);
-       fbsp->fbs_listener.fbsl_fd = pkg_permserver(portname, 0, 0, comm_error);
-       if (fbsp->fbs_listener.fbsl_fd >= 0)
-           break;
-#endif /* if defined(_WIN32) && !defined(__CYGWIN__) */
-
-       ++available_port;
-    }
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-    if (fbsp->fbs_listener.fbsl_chan == NULL) {
-       failed = 1;
-    }
-#else /* if defined(_WIN32) && !defined(__CYGWIN__) */
-    if (fbsp->fbs_listener.fbsl_fd < 0) {
-       failed = 1;
-    }
-#endif /* if defined(_WIN32) && !defined(__CYGWIN__) */
-
-    if (failed) {
-       bu_vls_printf(&vls, "fbs_open: failed to hang a listen on ports %d - 
%d\n", port, available_port);
-       Tcl_AppendResult((Tcl_Interp *)fbsp->fbs_interp, bu_vls_addr(&vls), 
(char *)NULL);
-       bu_vls_free(&vls);
-
-       fbsp->fbs_listener.fbsl_port = -1;
-
-       return TCL_ERROR;
-    }
-
-    fbsp->fbs_listener.fbsl_port = available_port;
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-    Tcl_GetChannelHandle(fbsp->fbs_listener.fbsl_chan, TCL_READABLE, 
(ClientData *)&fbsp->fbs_listener.fbsl_fd);
-#else /* if defined(_WIN32) && !defined(__CYGWIN__) */
-    Tcl_CreateFileHandler(fbsp->fbs_listener.fbsl_fd, TCL_READABLE, 
(Tcl_FileProc *)new_client_handler, (ClientData)&fbsp->fbs_listener);
-#endif /* if defined(_WIN32) && !defined(__CYGWIN__) */
-
-    return TCL_OK;
-}
-
-
-int
-fbs_close(struct fbserv_obj *fbsp)
-{
-    int i;
-
-    /* first drop all clients */
-    for (i = 0; i < MAX_CLIENTS; ++i)
-       drop_client(fbsp, i);
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-    if (fbsp->fbs_listener.fbsl_chan != NULL) {
-       Tcl_ChannelProc *callback = (Tcl_ChannelProc *)new_client_handler;
-       Tcl_DeleteChannelHandler(fbsp->fbs_listener.fbsl_chan, callback, 
(ClientData)fbsp->fbs_listener.fbsl_fd);
-       Tcl_Close((Tcl_Interp *)fbsp->fbs_interp, fbsp->fbs_listener.fbsl_chan);
-       fbsp->fbs_listener.fbsl_chan = NULL;
-    }
-#else
-    Tcl_DeleteFileHandler(fbsp->fbs_listener.fbsl_fd);
-#endif
-
-    if (0 <= fbsp->fbs_listener.fbsl_fd)
-       close(fbsp->fbs_listener.fbsl_fd);
-    fbsp->fbs_listener.fbsl_fd = -1;
-    fbsp->fbs_listener.fbsl_port = -1;
-
-    return TCL_OK;
-}
-
-
-/*
- * Local Variables:
- * mode: C
- * tab-width: 8
- * indent-tabs-mode: t
- * c-file-style: "stroustrup"
- * End:
- * ex: shiftwidth=4 tabstop=8
- */

Modified: brlcad/branches/dm-fb-merge/src/libdm/knob.c
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/knob.c        2020-05-18 19:20:19 UTC 
(rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libdm/knob.c        2020-05-19 03:34:33 UTC 
(rev 75836)
@@ -25,7 +25,6 @@
 
 #include "common.h"
 
-#include "tcl.h"
 #include "vmath.h"
 #include "dm.h"
 

Modified: brlcad/branches/dm-fb-merge/src/libdm/labels.c
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/labels.c      2020-05-18 19:20:19 UTC 
(rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libdm/labels.c      2020-05-19 03:34:33 UTC 
(rev 75836)
@@ -548,8 +548,8 @@
               const char *name,
               mat_t viewmat,
               int *labelsColor,
-              int (*LabelsHook)(struct dm *, struct rt_wdb *, const char *, 
mat_t, int *, ClientData),
-              ClientData labelsHookClientdata)
+              int (*LabelsHook)(struct dm *, struct rt_wdb *, const char *, 
mat_t, int *, void *),
+              void *labelsHookClientdata)
 {
 #define MAX_PL 8+1
     struct rt_point_labels pl[MAX_PL];
@@ -559,7 +559,7 @@
     struct db_tree_state ts;
     struct db_full_path path;
 
-    if (LabelsHook != (int (*)(struct dm *, struct rt_wdb *, const char *, 
mat_t, int *, ClientData))0)
+    if (LabelsHook != (int (*)(struct dm *, struct rt_wdb *, const char *, 
mat_t, int *, void *))0)
        return LabelsHook(dmp, wdbp, name,
                          viewmat, labelsColor,
                          labelsHookClientdata);

Modified: brlcad/branches/dm-fb-merge/src/libdm/null/dm-Null.c
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/null/dm-Null.c        2020-05-18 
19:20:19 UTC (rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libdm/null/dm-Null.c        2020-05-19 
03:34:33 UTC (rev 75836)
@@ -27,7 +27,6 @@
 #  include <sys/time.h>
 #endif
 
-#include "tcl.h"
 #include "vmath.h"
 #include "dm.h"
 #include "../null/dm-Null.h"

Modified: brlcad/branches/dm-fb-merge/src/libdm/options.c
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/options.c     2020-05-18 19:20:19 UTC 
(rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libdm/options.c     2020-05-19 03:34:33 UTC 
(rev 75836)
@@ -27,8 +27,6 @@
 
 #include <stdlib.h>
 
-#include "tcl.h"
-
 #include "bu/getopt.h"
 #include "bu/str.h"
 #include "vmath.h"

Modified: brlcad/branches/dm-fb-merge/src/libdm/plot/CMakeLists.txt
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/plot/CMakeLists.txt   2020-05-18 
19:20:19 UTC (rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libdm/plot/CMakeLists.txt   2020-05-19 
03:34:33 UTC (rev 75836)
@@ -3,6 +3,7 @@
   ${BRLCAD_BINARY_DIR}/include
   ${BRLCAD_SOURCE_DIR}/include
   ${BU_INCLUDE_DIRS}
+  ${TCL_INCLUDE_PATH}
   )
 
 set(PLOT_SRCS
@@ -12,7 +13,7 @@
 add_definitions(-DDM_PLUGIN)
 
 add_library(dm-plot SHARED ${PLOT_SRCS})
-target_link_libraries(dm-plot libdm libbu)
+target_link_libraries(dm-plot libdm libbu ${TCL_LIBRARY})
 if (CPP_DLL_DEFINES)
   set_property(TARGET dm-plot APPEND PROPERTY COMPILE_DEFINITIONS 
"DM_DLL_EXPORTS")
 endif (CPP_DLL_DEFINES)

Modified: brlcad/branches/dm-fb-merge/src/libdm/tests/CMakeLists.txt
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/tests/CMakeLists.txt  2020-05-18 
19:20:19 UTC (rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libdm/tests/CMakeLists.txt  2020-05-19 
03:34:33 UTC (rev 75836)
@@ -38,6 +38,10 @@
 BRLCAD_ADDEXEC(dm_test dm_test.c "libdm;libbu" TEST)
 
 if (BRLCAD_ENABLE_TK)
+  include_directories(
+    ${TCL_INCLUDE_PATH}
+    ${TK_INCLUDE_PATH}
+    )
   BRLCAD_ADDEXEC(tcl_img tcl_img.cpp 
"libdm;libbu;${TCL_LIBRARY};${TK_LIBRARY}" TEST_USEDATA)
   BRLCAD_ADDEXEC(tcl_tevent tcl_tevent.cpp 
"libdm;libbu;${TCL_LIBRARY};${TK_LIBRARY}" TEST_USEDATA)
 endif (BRLCAD_ENABLE_TK)

Modified: brlcad/branches/dm-fb-merge/src/libdm/txt/CMakeLists.txt
===================================================================
--- brlcad/branches/dm-fb-merge/src/libdm/txt/CMakeLists.txt    2020-05-18 
19:20:19 UTC (rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libdm/txt/CMakeLists.txt    2020-05-19 
03:34:33 UTC (rev 75836)
@@ -3,6 +3,7 @@
   ${BRLCAD_BINARY_DIR}/include
   ${BRLCAD_SOURCE_DIR}/include
   ${BU_INCLUDE_DIRS}
+  ${TCL_INCLUDE_PATH}
   )
 
 set(TXT_SRCS
@@ -13,7 +14,7 @@
 add_definitions(-DDM_PLUGIN)
 
 add_library(dm-txt SHARED ${TXT_SRCS})
-target_link_libraries(dm-txt libdm libbu)
+target_link_libraries(dm-txt libdm libbu ${TCL_LIBRARY})
 if (CPP_DLL_DEFINES)
   set_property(TARGET dm-txt APPEND PROPERTY COMPILE_DEFINITIONS 
"DM_DLL_EXPORTS")
 endif (CPP_DLL_DEFINES)

Modified: brlcad/branches/dm-fb-merge/src/libged/CMakeLists.txt
===================================================================
--- brlcad/branches/dm-fb-merge/src/libged/CMakeLists.txt       2020-05-18 
19:20:19 UTC (rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libged/CMakeLists.txt       2020-05-19 
03:34:33 UTC (rev 75836)
@@ -151,8 +151,8 @@
   facedef.c
   facetize_log.c
   facetize.cpp
-  fb2pix.c
-  fbclear.c
+  #fb2pix.c
+  #fbclear.c
   find.c
   form.c
   fracture.c
@@ -239,12 +239,12 @@
   pathlist.c
   pathsum.c
   perspective.c
-  pix2fb.c
+  #pix2fb.c
   plot.c
   pmat.c
   pmodel2view.c
   png.c
-  png2fb.c
+  #png2fb.c
   pnts_util.c
   pnts.cpp
   polyclip.cpp

Modified: brlcad/branches/dm-fb-merge/src/libged/ged.c
===================================================================
--- brlcad/branches/dm-fb-merge/src/libged/ged.c        2020-05-18 19:20:19 UTC 
(rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libged/ged.c        2020-05-19 03:34:33 UTC 
(rev 75836)
@@ -276,7 +276,6 @@
 
     /* (in)sanity */
     gedp->ged_gvp = NULL;
-    gedp->ged_fbsp = NULL;
     gedp->ged_dmp = NULL;
     gedp->ged_refresh_clientdata = NULL;
     gedp->ged_refresh_handler = NULL;

Modified: brlcad/branches/dm-fb-merge/src/libtclcad/CMakeLists.txt
===================================================================
--- brlcad/branches/dm-fb-merge/src/libtclcad/CMakeLists.txt    2020-05-18 
19:20:19 UTC (rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libtclcad/CMakeLists.txt    2020-05-19 
03:34:33 UTC (rev 75836)
@@ -34,6 +34,7 @@
   cmdhist_obj.c
   dm_obj.c
   fb_obj.c
+  fbserv_obj.c
   dm_tcl.c
   )
 set_property(SOURCE tclcad_obj.c APPEND PROPERTY COMPILE_DEFINITIONS 
FB_USE_INTERNAL_API)

Copied: brlcad/branches/dm-fb-merge/src/libtclcad/fbserv_obj.c (from rev 75835, 
brlcad/branches/dm-fb-merge/src/libdm/fbserv_obj.c)
===================================================================
--- brlcad/branches/dm-fb-merge/src/libtclcad/fbserv_obj.c                      
        (rev 0)
+++ brlcad/branches/dm-fb-merge/src/libtclcad/fbserv_obj.c      2020-05-19 
03:34:33 UTC (rev 75836)
@@ -0,0 +1,1112 @@
+/*                    F B S E R V _ O B J . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2004-2020 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ */
+/** @addtogroup libstruct fb */
+/** @{ */
+/** @file fbserv_obj.c
+ *
+ * A framebuffer server object contains the attributes and
+ * methods for implementing an fbserv. This code was developed
+ * in large part by modifying the stand-alone version of fbserv.
+ *
+ * TODO - other than the backends themselves (which are now plugins
+ * and so relatively independent) fbserv is the last piece of the
+ * libdm/libfb stack making core use of Tcl.  Unlike the dm_obj,
+ * fb_obj and tcl files the use of Tcl here is an implmeentation
+ * detail of the functional purpose of the file rather than the
+ * primary purpose of the code, and as such this belongs in
+ * libdm rather than libtclcad.  That means we need to find a way
+ * to achieve the functionality present here without relying on
+ * Tcl/Tk - either by embedding the necessary logic in libbu (as
+ * was done with Tcl list parsing) or replacing the functionality
+ * with something that achieves the same goal.  Will have to see
+ * if there are any implicit requirements for the Tcl communication
+ * in calling codes as well.
+ */
+/** @} */
+
+#include "common.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <tcl.h>
+#include "bio.h"
+#include "bnetwork.h"
+
+#include "raytrace.h"
+#include "dm.h"
+#include "tclcad.h"
+#include "../libdm/include/private.h"
+
+
+static struct fb *curr_fbp;            /* current framebuffer pointer */
+
+
+/*
+ * Communication error.  An error occurred on the PKG link.
+ */
+HIDDEN void
+comm_error(const char *str)
+{
+    bu_log("%s", str);
+}
+
+
+HIDDEN void
+drop_client(struct fbserv_obj *fbsp, int sub)
+{
+    if (fbsp->fbs_clients[sub].fbsc_pkg != PKC_NULL) {
+       pkg_close(fbsp->fbs_clients[sub].fbsc_pkg);
+       fbsp->fbs_clients[sub].fbsc_pkg = PKC_NULL;
+    }
+
+    if (fbsp->fbs_clients[sub].fbsc_fd != 0) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       Tcl_DeleteChannelHandler(fbsp->fbs_clients[sub].fbsc_chan, 
fbsp->fbs_clients[sub].fbsc_handler, 
(ClientData)fbsp->fbs_clients[sub].fbsc_fd);
+
+       Tcl_Close((Tcl_Interp *)fbsp->fbs_interp, 
fbsp->fbs_clients[sub].fbsc_chan);
+       fbsp->fbs_clients[sub].fbsc_chan = NULL;
+#else
+       Tcl_DeleteFileHandler(fbsp->fbs_clients[sub].fbsc_fd);
+#endif
+
+       fbsp->fbs_clients[sub].fbsc_fd = 0;
+    }
+}
+
+
+/*
+ * Process arrivals from existing clients.
+ */
+HIDDEN void
+existing_client_handler(ClientData clientData, int UNUSED(mask))
+{
+    register int i;
+    struct fbserv_client *fbscp = (struct fbserv_client *)clientData;
+    struct fbserv_obj *fbsp = fbscp->fbsc_fbsp;
+    int fd = fbscp->fbsc_fd;
+
+    curr_fbp = fbsp->fbs_fbp;
+
+    for (i = MAX_CLIENTS - 1; i >= 0; i--) {
+       if (fbsp->fbs_clients[i].fbsc_fd == 0)
+           continue;
+
+       if ((pkg_process(fbsp->fbs_clients[i].fbsc_pkg)) < 0)
+           bu_log("pkg_process error encountered (1)\n");
+
+       if (fbsp->fbs_clients[i].fbsc_fd != fd)
+           continue;
+
+       if (pkg_suckin(fbsp->fbs_clients[i].fbsc_pkg) <= 0) {
+           /* Probably EOF */
+           drop_client(fbsp, i);
+
+           continue;
+       }
+
+       if ((pkg_process(fbsp->fbs_clients[i].fbsc_pkg)) < 0)
+           bu_log("pkg_process error encountered (2)\n");
+    }
+
+    if (fbsp->fbs_callback != (void (*)(void *))FBS_CALLBACK_NULL) {
+       /* need to cast func pointer explicitly to get the function call */
+       void (*cfp)(void *);
+       cfp = (void (*)(void *))fbsp->fbs_callback;
+       cfp(fbsp->fbs_clientData);
+    }
+}
+
+
+HIDDEN void
+setup_socket(int fd)
+{
+    int on     = 1;
+    int retval = 0;
+
+#if defined(SO_KEEPALIVE)
+    /* FIXME: better to show an error message but need thread considerations 
for strerror */
+    if ((retval = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 
sizeof(on))) < 0) {
+       bu_log("setsockopt (SO_KEEPALIVE) error return: %d", retval);
+    }
+#endif
+#if defined(SO_RCVBUF)
+    /* try to set our buffers up larger */
+    {
+       int m = -1;
+       int n = -1;
+       int val;
+       int size;
+
+       for (size = 256; size > 16; size /= 2) {
+           val = size * 1024;
+           m = setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
+                          (char *)&val, sizeof(val));
+           val = size * 1024;
+           n = setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
+                          (char *)&val, sizeof(val));
+           if (m >= 0 && n >= 0) break;
+       }
+
+       if (m < 0 || n < 0)
+           bu_log("setup_socket: setsockopt()");
+    }
+#endif
+}
+
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+HIDDEN void
+new_client(struct fbserv_obj *fbsp, struct pkg_conn *pcp, Tcl_Channel chan)
+{
+    int i;
+
+    if (pcp == PKC_ERROR)
+       return;
+
+    for (i = MAX_CLIENTS - 1; i >= 0; i--) {
+       /* this slot is being used */
+       if (fbsp->fbs_clients[i].fbsc_fd != 0)
+           continue;
+
+       /* Found an available slot */
+       fbsp->fbs_clients[i].fbsc_fd = pcp->pkc_fd;
+       fbsp->fbs_clients[i].fbsc_pkg = pcp;
+       fbsp->fbs_clients[i].fbsc_fbsp = fbsp;
+       setup_socket(pcp->pkc_fd);
+
+       fbsp->fbs_clients[i].fbsc_chan = chan;
+       fbsp->fbs_clients[i].fbsc_handler = existing_client_handler;
+       Tcl_CreateChannelHandler(fbsp->fbs_clients[i].fbsc_chan, TCL_READABLE,
+                                fbsp->fbs_clients[i].fbsc_handler,
+                                (ClientData)&fbsp->fbs_clients[i]);
+       return;
+    }
+
+    bu_log("new_client: too many clients\n");
+    pkg_close(pcp);
+}
+
+#else /* if defined(_WIN32) && !defined(__CYGWIN__) */
+HIDDEN void
+new_client(struct fbserv_obj *fbsp, struct pkg_conn *pcp, Tcl_Channel 
UNUSED(chan))
+{
+    int i;
+
+    if (pcp == PKC_ERROR)
+       return;
+
+    for (i = MAX_CLIENTS - 1; i >= 0; i--) {
+       /* this slot is being used */
+       if (fbsp->fbs_clients[i].fbsc_fd != 0)
+           continue;
+
+       /* Found an available slot */
+       fbsp->fbs_clients[i].fbsc_fd = pcp->pkc_fd;
+       fbsp->fbs_clients[i].fbsc_pkg = pcp;
+       fbsp->fbs_clients[i].fbsc_fbsp = fbsp;
+       setup_socket(pcp->pkc_fd);
+
+       Tcl_CreateFileHandler(fbsp->fbs_clients[i].fbsc_fd, TCL_READABLE,
+                             existing_client_handler, 
(ClientData)&fbsp->fbs_clients[i]);
+       return;
+    }
+
+    bu_log("new_client: too many clients\n");
+    pkg_close(pcp);
+}
+#endif /* if defined(_WIN32) && !defined(__CYGWIN__) */
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+HIDDEN struct pkg_conn *
+fbs_makeconn(int fd, const struct pkg_switch *switchp)
+{
+    register struct pkg_conn *pc;
+#ifdef HAVE_WINSOCK_H
+    WSADATA wsaData;
+    WORD wVersionRequested; /* initialize Windows socket networking,
+                            * increment reference count.
+                            */
+#endif
+
+    if ((pc = (struct pkg_conn *)malloc(sizeof(struct pkg_conn))) == PKC_NULL) 
{
+       comm_error("fbs_makeconn: malloc failure\n");
+       return PKC_ERROR;
+    }
+
+#ifdef HAVE_WINSOCK_H
+    wVersionRequested = MAKEWORD(1, 1);
+    if (WSAStartup(wVersionRequested, &wsaData) != 0) {
+       comm_error("fbs_makeconn:  could not find a usable WinSock DLL\n");
+       return PKC_ERROR;
+    }
+#endif
+
+    memset((char *)pc, 0, sizeof(struct pkg_conn));
+    pc->pkc_magic = PKG_MAGIC;
+    pc->pkc_fd = fd;
+    pc->pkc_switch = switchp;
+    pc->pkc_errlog = 0;
+    pc->pkc_left = -1;
+    pc->pkc_buf = (char *)0;
+    pc->pkc_curpos = (char *)0;
+    pc->pkc_strpos = 0;
+    pc->pkc_incur = pc->pkc_inend = 0;
+
+    return pc;
+}
+#endif
+
+
+/*
+ * This is where we go for message types we don't understand.
+ */
+HIDDEN void
+fbs_rfbunknown(struct pkg_conn *pcp, char *buf)
+{
+    bu_log("fbserv: unable to handle message type %d\n", pcp->pkc_type);
+    if (buf) {
+       (void)free(buf);
+    }
+}
+
+
+/******** Here's where the hooks lead *********/
+
+HIDDEN void
+fbs_rfbopen(struct pkg_conn *pcp, char *buf)
+{
+    char rbuf[5*NET_LONG_LEN+1];
+    int want;
+
+    /* Don't really open a new framebuffer --- use existing one */
+    (void)pkg_plong(&rbuf[0*NET_LONG_LEN], 0); /* ret */
+    (void)pkg_plong(&rbuf[1*NET_LONG_LEN], curr_fbp->i->if_max_width);
+    (void)pkg_plong(&rbuf[2*NET_LONG_LEN], curr_fbp->i->if_max_height);
+    (void)pkg_plong(&rbuf[3*NET_LONG_LEN], curr_fbp->i->if_width);
+    (void)pkg_plong(&rbuf[4*NET_LONG_LEN], curr_fbp->i->if_height);
+
+    want = 5*NET_LONG_LEN;
+    if (pkg_send(MSG_RETURN, rbuf, want, pcp) != want)
+       comm_error("pkg_send fb_open reply\n");
+
+    if (buf) {
+       (void)free(buf);
+    }
+}
+
+
+void
+fbs_rfbclose(struct pkg_conn *pcp, char *buf)
+{
+    char rbuf[NET_LONG_LEN+1];
+
+    /*
+     * We are playing FB server so we don't really close the frame
+     * buffer.  We should flush output however.
+     */
+    (void)fb_flush(curr_fbp);
+    (void)pkg_plong(&rbuf[0], 0);              /* return success */
+
+    /* Don't check for errors, linger mode or other events may have
+     * already closed down all the file descriptors.  If communication
+     * has broken, other end will know we are gone.
+     */
+    (void)pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+
+    if (buf) {
+       (void)free(buf);
+    }
+}
+
+
+void
+fbs_rfbfree(struct pkg_conn *pcp, char *buf)
+{
+    char rbuf[NET_LONG_LEN+1];
+
+    /* Don't really free framebuffer */
+    if (pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp) != NET_LONG_LEN)
+       comm_error("pkg_send fb_free reply\n");
+
+    if (buf) {
+       (void)free(buf);
+    }
+}
+
+
+void
+fbs_rfbclear(struct pkg_conn *pcp, char *buf)
+{
+    RGBpixel bg;
+    char rbuf[NET_LONG_LEN+1];
+
+    if (!buf) {
+       bu_log("fbs_rfbclear: null buffer\n");
+       return;
+    }
+
+    bg[RED] = buf[0];
+    bg[GRN] = buf[1];
+    bg[BLU] = buf[2];
+
+    (void)pkg_plong(rbuf, fb_clear(curr_fbp, bg));
+    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+
+    (void)free(buf);
+}
+
+
+void
+fbs_rfbread(struct pkg_conn *pcp, char *buf)
+{
+    int x, y;
+    size_t num;
+    int ret;
+    static unsigned char *scanbuf = NULL;
+    static size_t buflen = 0;
+
+    if (!buf) {
+       bu_log("fbs_rfbread: null buffer\n");
+       return;
+    }
+
+    x = pkg_glong(&buf[0*NET_LONG_LEN]);
+    y = pkg_glong(&buf[1*NET_LONG_LEN]);
+    num = (size_t)pkg_glong(&buf[2*NET_LONG_LEN]);
+
+    if (num*sizeof(RGBpixel) > buflen) {
+       if (scanbuf != NULL)
+           free((char *)scanbuf);
+       buflen = num*sizeof(RGBpixel);
+       if (buflen < 1024*sizeof(RGBpixel))
+           buflen = 1024*sizeof(RGBpixel);
+       if ((scanbuf = (unsigned char *)malloc(buflen)) == NULL) {
+           fb_log("fb_read: malloc failed!");
+           (void)free(buf);
+           buflen = 0;
+           return;
+       }
+    }
+
+    ret = fb_read(curr_fbp, x, y, scanbuf, num);
+    if (ret < 0) ret = 0;              /* map error indications */
+    /* sending a 0-length package indicates error */
+    pkg_send(MSG_RETURN, (char *)scanbuf, ret*sizeof(RGBpixel), pcp);
+    (void)free(buf);
+}
+
+
+void
+fbs_rfbwrite(struct pkg_conn *pcp, char *buf)
+{
+    long x, y, num;
+    char rbuf[NET_LONG_LEN+1];
+    int ret;
+    int type;
+
+    if (!buf) {
+       bu_log("fbs_rfbwrite: null buffer\n");
+       return;
+    }
+
+    x = pkg_glong(&buf[0*NET_LONG_LEN]);
+    y = pkg_glong(&buf[1*NET_LONG_LEN]);
+    num = pkg_glong(&buf[2*NET_LONG_LEN]);
+    type = pcp->pkc_type;
+    ret = fb_write(curr_fbp, x, y, (unsigned char *)&buf[3*NET_LONG_LEN], 
(size_t)num);
+
+    if (type < MSG_NORETURN) {
+       (void)pkg_plong(&rbuf[0*NET_LONG_LEN], ret);
+       pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+    }
+    (void)free(buf);
+}
+
+
+void
+fbs_rfbreadrect(struct pkg_conn *pcp, char *buf)
+{
+    int xmin, ymin;
+    int width, height;
+    size_t num;
+    int ret;
+    static unsigned char *scanbuf = NULL;
+    static size_t buflen = 0;
+
+    if (!buf) {
+       bu_log("fbs_rfbreadrect: null buffer\n");
+       return;
+    }
+
+    xmin = pkg_glong(&buf[0*NET_LONG_LEN]);
+    ymin = pkg_glong(&buf[1*NET_LONG_LEN]);
+    width = pkg_glong(&buf[2*NET_LONG_LEN]);
+    height = pkg_glong(&buf[3*NET_LONG_LEN]);
+    num = width * height;
+
+    if (num*sizeof(RGBpixel) > buflen) {
+       if (scanbuf != NULL)
+           free((char *)scanbuf);
+       buflen = num*sizeof(RGBpixel);
+       if (buflen < 1024*sizeof(RGBpixel))
+           buflen = 1024*sizeof(RGBpixel);
+       if ((scanbuf = (unsigned char *)malloc(buflen)) == NULL) {
+           fb_log("fb_read: malloc failed!");
+           (void)free(buf);
+           buflen = 0;
+           return;
+       }
+    }
+
+    ret = fb_readrect(curr_fbp, xmin, ymin, width, height, scanbuf);
+    if (ret < 0) ret = 0;              /* map error indications */
+    /* sending a 0-length package indicates error */
+    pkg_send(MSG_RETURN, (char *)scanbuf, ret*sizeof(RGBpixel), pcp);
+    (void)free(buf);
+}
+
+
+void
+fbs_rfbwriterect(struct pkg_conn *pcp, char *buf)
+{
+    int x, y;
+    int width, height;
+    char rbuf[NET_LONG_LEN+1];
+    int ret;
+    int type;
+
+    if (!buf) {
+       bu_log("fbs_rfbwriterect: null buffer\n");
+       return;
+    }
+
+    x = pkg_glong(&buf[0*NET_LONG_LEN]);
+    y = pkg_glong(&buf[1*NET_LONG_LEN]);
+    width = pkg_glong(&buf[2*NET_LONG_LEN]);
+    height = pkg_glong(&buf[3*NET_LONG_LEN]);
+
+    type = pcp->pkc_type;
+    ret = fb_writerect(curr_fbp, x, y, width, height,
+                      (unsigned char *)&buf[4*NET_LONG_LEN]);
+
+    if (type < MSG_NORETURN) {
+       (void)pkg_plong(&rbuf[0*NET_LONG_LEN], ret);
+       pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+    }
+    (void)free(buf);
+}
+
+
+void
+fbs_rfbbwreadrect(struct pkg_conn *pcp, char *buf)
+{
+    int xmin, ymin;
+    int width, height;
+    int num;
+    int ret;
+    static unsigned char *scanbuf = NULL;
+    static int buflen = 0;
+
+    if (!buf) {
+       bu_log("fbs_rfbbwreadrect: null buffer\n");
+       return;
+    }
+
+    xmin = pkg_glong(&buf[0*NET_LONG_LEN]);
+    ymin = pkg_glong(&buf[1*NET_LONG_LEN]);
+    width = pkg_glong(&buf[2*NET_LONG_LEN]);
+    height = pkg_glong(&buf[3*NET_LONG_LEN]);
+    num = width * height;
+
+    if (num > buflen) {
+       if (scanbuf != NULL)
+           free((char *)scanbuf);
+       buflen = num;
+       if (buflen < 1024)
+           buflen = 1024;
+       if ((scanbuf = (unsigned char *)malloc(buflen)) == NULL) {
+           fb_log("fbs_rfbbwreadrect: malloc failed!");
+           (void)free(buf);
+           buflen = 0;
+           return;
+       }
+    }
+
+    ret = fb_bwreadrect(curr_fbp, xmin, ymin, width, height, scanbuf);
+    if (ret < 0) ret = 0;              /* map error indications */
+    /* sending a 0-length package indicates error */
+    pkg_send(MSG_RETURN, (char *)scanbuf, ret, pcp);
+    (void)free(buf);
+}
+
+
+void
+fbs_rfbbwwriterect(struct pkg_conn *pcp, char *buf)
+{
+    int x, y;
+    int width, height;
+    char rbuf[NET_LONG_LEN+1];
+    int ret;
+    int type;
+
+    if (!buf) {
+       bu_log("fbs_rfbbwwriterect: null buffer\n");
+       return;
+    }
+
+    x = pkg_glong(&buf[0*NET_LONG_LEN]);
+    y = pkg_glong(&buf[1*NET_LONG_LEN]);
+    width = pkg_glong(&buf[2*NET_LONG_LEN]);
+    height = pkg_glong(&buf[3*NET_LONG_LEN]);
+
+    type = pcp->pkc_type;
+    ret = fb_writerect(curr_fbp, x, y, width, height,
+                      (unsigned char *)&buf[4*NET_LONG_LEN]);
+
+    if (type < MSG_NORETURN) {
+       (void)pkg_plong(&rbuf[0*NET_LONG_LEN], ret);
+       pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+    }
+    (void)free(buf);
+}
+
+
+void
+fbs_rfbcursor(struct pkg_conn *pcp, char *buf)
+{
+    int mode, x, y;
+    char rbuf[NET_LONG_LEN+1];
+
+    if (!buf) {
+       bu_log("fbs_rfbcursor: null buffer\n");
+       return;
+    }
+
+    mode = pkg_glong(&buf[0*NET_LONG_LEN]);
+    x = pkg_glong(&buf[1*NET_LONG_LEN]);
+    y = pkg_glong(&buf[2*NET_LONG_LEN]);
+
+    (void)pkg_plong(&rbuf[0], fb_cursor(curr_fbp, mode, x, y));
+    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+    (void)free(buf);
+}
+
+
+void
+fbs_rfbgetcursor(struct pkg_conn *pcp, char *buf)
+{
+    int ret;
+    int mode, x, y;
+    char rbuf[4*NET_LONG_LEN+1];
+
+    ret = fb_getcursor(curr_fbp, &mode, &x, &y);
+    (void)pkg_plong(&rbuf[0*NET_LONG_LEN], ret);
+    (void)pkg_plong(&rbuf[1*NET_LONG_LEN], mode);
+    (void)pkg_plong(&rbuf[2*NET_LONG_LEN], x);
+    (void)pkg_plong(&rbuf[3*NET_LONG_LEN], y);
+    pkg_send(MSG_RETURN, rbuf, 4*NET_LONG_LEN, pcp);
+
+    if (buf) {
+       (void)free(buf);
+    }
+}
+
+
+void
+fbs_rfbsetcursor(struct pkg_conn *pcp, char *buf)
+{
+    char rbuf[NET_LONG_LEN+1];
+    int ret;
+    int xbits, ybits;
+    int xorig, yorig;
+
+    if (!buf) {
+       bu_log("fbs_rfsetcursor: null buffer\n");
+       return;
+    }
+
+    xbits = pkg_glong(&buf[0*NET_LONG_LEN]);
+    ybits = pkg_glong(&buf[1*NET_LONG_LEN]);
+    xorig = pkg_glong(&buf[2*NET_LONG_LEN]);
+    yorig = pkg_glong(&buf[3*NET_LONG_LEN]);
+
+    ret = fb_setcursor(curr_fbp, (unsigned char *)&buf[4*NET_LONG_LEN],
+                      xbits, ybits, xorig, yorig);
+
+    if (pcp->pkc_type < MSG_NORETURN) {
+       (void)pkg_plong(&rbuf[0*NET_LONG_LEN], ret);
+       pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+    }
+    (void)free(buf);
+}
+
+
+/*OLD*/
+void
+fbs_rfbscursor(struct pkg_conn *pcp, char *buf)
+{
+    int mode, x, y;
+    char rbuf[NET_LONG_LEN+1];
+
+    if (!buf) {
+       bu_log("fbs_rfbscursor: null buffer\n");
+       return;
+    }
+
+    mode = pkg_glong(&buf[0*NET_LONG_LEN]);
+    x = pkg_glong(&buf[1*NET_LONG_LEN]);
+    y = pkg_glong(&buf[2*NET_LONG_LEN]);
+
+    (void)pkg_plong(&rbuf[0], fb_scursor(curr_fbp, mode, x, y));
+    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+    (void)free(buf);
+}
+
+
+/*OLD*/
+void
+fbs_rfbwindow(struct pkg_conn *pcp, char *buf)
+{
+    int x, y;
+    char rbuf[NET_LONG_LEN+1];
+
+    if (!buf) {
+       bu_log("fbs_rfbwindow: null buffer\n");
+       return;
+    }
+
+    x = pkg_glong(&buf[0*NET_LONG_LEN]);
+    y = pkg_glong(&buf[1*NET_LONG_LEN]);
+
+    (void)pkg_plong(&rbuf[0], fb_window(curr_fbp, x, y));
+    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+
+    (void)free(buf);
+}
+
+
+/*OLD*/
+void
+fbs_rfbzoom(struct pkg_conn *pcp, char *buf)
+{
+    int x, y;
+    char rbuf[NET_LONG_LEN+1];
+
+    if (!buf) {
+       bu_log("fbs_rfbzoom: null buffer\n");
+       return;
+    }
+
+    x = pkg_glong(&buf[0*NET_LONG_LEN]);
+    y = pkg_glong(&buf[1*NET_LONG_LEN]);
+
+    (void)pkg_plong(&rbuf[0], fb_zoom(curr_fbp, x, y));
+    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+    (void)free(buf);
+}
+
+
+void
+fbs_rfbview(struct pkg_conn *pcp, char *buf)
+{
+    int ret;
+    int xcenter, ycenter, xzoom, yzoom;
+    char rbuf[NET_LONG_LEN+1];
+
+    if (!buf) {
+       bu_log("fbs_rfbview: null buffer\n");
+       return;
+    }
+
+    xcenter = pkg_glong(&buf[0*NET_LONG_LEN]);
+    ycenter = pkg_glong(&buf[1*NET_LONG_LEN]);
+    xzoom = pkg_glong(&buf[2*NET_LONG_LEN]);
+    yzoom = pkg_glong(&buf[3*NET_LONG_LEN]);
+
+    ret = fb_view(curr_fbp, xcenter, ycenter, xzoom, yzoom);
+    (void)pkg_plong(&rbuf[0], ret);
+    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+    (void)free(buf);
+}
+
+
+void
+fbs_rfbgetview(struct pkg_conn *pcp, char *buf)
+{
+    int ret;
+    int xcenter, ycenter, xzoom, yzoom;
+    char rbuf[5*NET_LONG_LEN+1];
+
+    ret = fb_getview(curr_fbp, &xcenter, &ycenter, &xzoom, &yzoom);
+    (void)pkg_plong(&rbuf[0*NET_LONG_LEN], ret);
+    (void)pkg_plong(&rbuf[1*NET_LONG_LEN], xcenter);
+    (void)pkg_plong(&rbuf[2*NET_LONG_LEN], ycenter);
+    (void)pkg_plong(&rbuf[3*NET_LONG_LEN], xzoom);
+    (void)pkg_plong(&rbuf[4*NET_LONG_LEN], yzoom);
+    pkg_send(MSG_RETURN, rbuf, 5*NET_LONG_LEN, pcp);
+
+    if (buf) {
+       (void)free(buf);
+    }
+}
+
+
+void
+fbs_rfbrmap(struct pkg_conn *pcp, char *buf)
+{
+    register int i;
+    char rbuf[NET_LONG_LEN+1];
+    ColorMap map;
+    unsigned char cm[256*2*3];
+
+    (void)pkg_plong(&rbuf[0*NET_LONG_LEN], fb_rmap(curr_fbp, &map));
+    for (i = 0; i < 256; i++) {
+       (void)pkg_pshort((char *)(cm+2*(0+i)), map.cm_red[i]);
+       (void)pkg_pshort((char *)(cm+2*(256+i)), map.cm_green[i]);
+       (void)pkg_pshort((char *)(cm+2*(512+i)), map.cm_blue[i]);
+    }
+    pkg_send(MSG_DATA, (char *)cm, sizeof(cm), pcp);
+    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+
+    if (buf) {
+       (void)free(buf);
+    }
+}
+
+
+/*
+ * Accept a color map sent by the client, and write it to the
+ * framebuffer.  Network format is to send each entry as a network
+ * (IBM) order 2-byte short, 256 red shorts, followed by 256 green and
+ * 256 blue, for a total of 3*256*2 bytes.
+ */
+void
+fbs_rfbwmap(struct pkg_conn *pcp, char *buf)
+{
+    int i;
+    char rbuf[NET_LONG_LEN+1];
+    long ret;
+    ColorMap map;
+
+    if (!buf) {
+       bu_log("fbs_rfbwmap: null buffer\n");
+       return;
+    }
+
+    if (pcp->pkc_len == 0) {
+       ret = fb_wmap(curr_fbp, COLORMAP_NULL);
+    } else {
+       for (i = 0; i < 256; i++) {
+           map.cm_red[i] = pkg_gshort(buf+2*(0+i));
+           map.cm_green[i] = pkg_gshort(buf+2*(256+i));
+           map.cm_blue[i] = pkg_gshort(buf+2*(512+i));
+       }
+       ret = fb_wmap(curr_fbp, &map);
+    }
+    (void)pkg_plong(&rbuf[0], ret);
+    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+    (void)free(buf);
+}
+
+
+void
+fbs_rfbflush(struct pkg_conn *pcp, char *buf)
+{
+    int ret;
+    char rbuf[NET_LONG_LEN+1];
+
+    ret = fb_flush(curr_fbp);
+
+    if (pcp->pkc_type < MSG_NORETURN) {
+       (void)pkg_plong(rbuf, ret);
+       pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+    }
+
+    if (buf) {
+       (void)free(buf);
+    }
+}
+
+
+void
+fbs_rfbpoll(struct pkg_conn *pcp, char *buf)
+{
+    if (pcp == PKC_ERROR) {
+       return;
+    }
+
+    (void)fb_poll(curr_fbp);
+    if (buf) {
+       (void)free(buf);
+    }
+}
+
+
+/*
+ * At one time at least we couldn't send a zero length PKG message
+ * back and forth, so we receive a dummy long here.
+ */
+void
+fbs_rfbhelp(struct pkg_conn *pcp, char *buf)
+{
+    long ret;
+    char rbuf[NET_LONG_LEN+1];
+
+    if (!buf) {
+       bu_log("fbs_rfbhelp: null buffer\n");
+       return;
+    }
+
+    (void)pkg_glong(&buf[0*NET_LONG_LEN]);
+
+    ret = fb_help(curr_fbp);
+    (void)pkg_plong(&rbuf[0], ret);
+    pkg_send(MSG_RETURN, rbuf, NET_LONG_LEN, pcp);
+    (void)free(buf);
+}
+
+
+/*
+ * Accept any new client connections.
+ */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+HIDDEN void
+new_client_handler(ClientData clientData,
+                  Tcl_Channel chan,
+                  char *UNUSED(host),
+                  int UNUSED(port))
+{
+    struct fbserv_listener *fbslp = (struct fbserv_listener *)clientData;
+    struct fbserv_obj *fbsp = fbslp->fbsl_fbsp;
+    uintptr_t fd = (uintptr_t)fbslp->fbsl_fd;
+
+    static struct pkg_switch pswitch[] = {
+       { MSG_FBOPEN, fbs_rfbopen, "Open Framebuffer", NULL },
+       { MSG_FBCLOSE, fbs_rfbclose, "Close Framebuffer", NULL },
+       { MSG_FBCLEAR, fbs_rfbclear, "Clear Framebuffer", NULL },
+       { MSG_FBREAD, fbs_rfbread, "Read Pixels", NULL },
+       { MSG_FBWRITE, fbs_rfbwrite, "Write Pixels", NULL },
+       { MSG_FBWRITE + MSG_NORETURN, fbs_rfbwrite, "Asynch write", NULL },
+       { MSG_FBCURSOR, fbs_rfbcursor, "Cursor", NULL },
+       { MSG_FBGETCURSOR, fbs_rfbgetcursor, "Get Cursor", NULL },  /*NEW*/
+       { MSG_FBSCURSOR, fbs_rfbscursor, "Screen Cursor", NULL }, /*OLD*/
+       { MSG_FBWINDOW, fbs_rfbwindow, "Window", NULL },  /*OLD*/
+       { MSG_FBZOOM, fbs_rfbzoom, "Zoom", NULL },  /*OLD*/
+       { MSG_FBVIEW, fbs_rfbview, "View", NULL },  /*NEW*/
+       { MSG_FBGETVIEW, fbs_rfbgetview, "Get View", NULL },  /*NEW*/
+       { MSG_FBRMAP, fbs_rfbrmap, "R Map", NULL },
+       { MSG_FBWMAP, fbs_rfbwmap, "W Map", NULL },
+       { MSG_FBHELP, fbs_rfbhelp, "Help Request", NULL },
+       { MSG_ERROR, fbs_rfbunknown, "Error Message", NULL },
+       { MSG_CLOSE, fbs_rfbunknown, "Close Connection", NULL },
+       { MSG_FBREADRECT, fbs_rfbreadrect, "Read Rectangle", NULL },
+       { MSG_FBWRITERECT, fbs_rfbwriterect, "Write Rectangle", NULL },
+       { MSG_FBWRITERECT + MSG_NORETURN, fbs_rfbwriterect, "Write Rectangle", 
NULL },
+       { MSG_FBBWREADRECT, fbs_rfbbwreadrect, "Read BW Rectangle", NULL },
+       { MSG_FBBWWRITERECT, fbs_rfbbwwriterect, "Write BW Rectangle", NULL },
+       { MSG_FBBWWRITERECT+MSG_NORETURN, fbs_rfbbwwriterect, "Write BW 
Rectangle", NULL },
+       { MSG_FBFLUSH, fbs_rfbflush, "Flush Output", NULL },
+       { MSG_FBFLUSH + MSG_NORETURN, fbs_rfbflush, "Flush Output", NULL },
+       { MSG_FBFREE, fbs_rfbfree, "Free Resources", NULL },
+       { MSG_FBPOLL, fbs_rfbpoll, "Handle Events", NULL },
+       { MSG_FBSETCURSOR, fbs_rfbsetcursor, "Set Cursor Shape", NULL },
+       { MSG_FBSETCURSOR + MSG_NORETURN, fbs_rfbsetcursor, "Set Cursor Shape", 
NULL },
+       { 0, NULL, NULL, NULL }
+    };
+
+    if (Tcl_GetChannelHandle(chan, TCL_READABLE, (ClientData *)&fd) == TCL_OK)
+       new_client(fbsp, fbs_makeconn((int)fd, pswitch), chan);
+}
+#else /* if defined(_WIN32) && !defined(__CYGWIN__) */
+HIDDEN void
+new_client_handler(ClientData clientData,
+                  int UNUSED(port))
+{
+    struct fbserv_listener *fbslp = (struct fbserv_listener *)clientData;
+    struct fbserv_obj *fbsp = fbslp->fbsl_fbsp;
+    int fd = fbslp->fbsl_fd;
+
+    static struct pkg_switch pswitch[] = {
+       { MSG_FBOPEN, fbs_rfbopen, "Open Framebuffer", NULL },
+       { MSG_FBCLOSE, fbs_rfbclose, "Close Framebuffer", NULL },
+       { MSG_FBCLEAR, fbs_rfbclear, "Clear Framebuffer", NULL },
+       { MSG_FBREAD, fbs_rfbread, "Read Pixels", NULL },
+       { MSG_FBWRITE, fbs_rfbwrite, "Write Pixels", NULL },
+       { MSG_FBWRITE + MSG_NORETURN, fbs_rfbwrite, "Asynch write", NULL },
+       { MSG_FBCURSOR, fbs_rfbcursor, "Cursor", NULL },
+       { MSG_FBGETCURSOR, fbs_rfbgetcursor, "Get Cursor", NULL },  /*NEW*/
+       { MSG_FBSCURSOR, fbs_rfbscursor, "Screen Cursor", NULL }, /*OLD*/
+       { MSG_FBWINDOW, fbs_rfbwindow, "Window", NULL },  /*OLD*/
+       { MSG_FBZOOM, fbs_rfbzoom, "Zoom", NULL },  /*OLD*/
+       { MSG_FBVIEW, fbs_rfbview, "View", NULL },  /*NEW*/
+       { MSG_FBGETVIEW, fbs_rfbgetview, "Get View", NULL },  /*NEW*/
+       { MSG_FBRMAP, fbs_rfbrmap, "R Map", NULL },
+       { MSG_FBWMAP, fbs_rfbwmap, "W Map", NULL },
+       { MSG_FBHELP, fbs_rfbhelp, "Help Request", NULL },
+       { MSG_ERROR, fbs_rfbunknown, "Error Message", NULL },
+       { MSG_CLOSE, fbs_rfbunknown, "Close Connection", NULL },
+       { MSG_FBREADRECT, fbs_rfbreadrect, "Read Rectangle", NULL },
+       { MSG_FBWRITERECT, fbs_rfbwriterect, "Write Rectangle", NULL },
+       { MSG_FBWRITERECT + MSG_NORETURN, fbs_rfbwriterect, "Write Rectangle", 
NULL },
+       { MSG_FBBWREADRECT, fbs_rfbbwreadrect, "Read BW Rectangle", NULL },
+       { MSG_FBBWWRITERECT, fbs_rfbbwwriterect, "Write BW Rectangle", NULL },
+       { MSG_FBBWWRITERECT+MSG_NORETURN, fbs_rfbbwwriterect, "Write BW 
Rectangle", NULL },
+       { MSG_FBFLUSH, fbs_rfbflush, "Flush Output", NULL },
+       { MSG_FBFLUSH + MSG_NORETURN, fbs_rfbflush, "Flush Output", NULL },
+       { MSG_FBFREE, fbs_rfbfree, "Free Resources", NULL },
+       { MSG_FBPOLL, fbs_rfbpoll, "Handle Events", NULL },
+       { MSG_FBSETCURSOR, fbs_rfbsetcursor, "Set Cursor Shape", NULL },
+       { MSG_FBSETCURSOR + MSG_NORETURN, fbs_rfbsetcursor, "Set Cursor Shape", 
NULL },
+       { 0, NULL, NULL, NULL }
+    };
+
+    new_client(fbsp, pkg_getclient(fd, pswitch, comm_error, 0), 0);
+}
+#endif /* if defined(_WIN32) && !defined(__CYGWIN__) */
+
+int
+fbs_open(struct fbserv_obj *fbsp, int port)
+{
+    int i;
+    struct bu_vls vls = BU_VLS_INIT_ZERO;
+    char hostname[32] = {0};
+    Tcl_DString ds;
+    int failed = 0;
+    int available_port = port;
+
+    /* Already listening; nothing more to do. */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+    if (fbsp->fbs_listener.fbsl_chan != NULL) {
+       return TCL_OK;
+    }
+#else /* if defined(_WIN32) && !defined(__CYGWIN__) */
+    if (fbsp->fbs_listener.fbsl_fd >= 0) {
+       return TCL_OK;
+    }
+#endif /* if defined(_WIN32) && !defined(__CYGWIN__) */
+
+    /* XXX hardwired for now */
+    sprintf(hostname, "localhost");
+
+    if (available_port < 0) {
+       available_port = 5559;
+    } else if (available_port < 1024) {
+       available_port += 5559;
+    }
+
+    Tcl_DStringInit(&ds);
+
+    /* Try a reasonable number of times to hang a listen */
+    for (i = 0; i < MAX_PORT_TRIES; ++i) {
+       /*
+        * Hang an unending listen for PKG connections
+        */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       fbsp->fbs_listener.fbsl_chan = Tcl_OpenTcpServer((Tcl_Interp 
*)fbsp->fbs_interp, available_port, hostname, new_client_handler, 
(ClientData)&fbsp->fbs_listener);
+       if (fbsp->fbs_listener.fbsl_chan == NULL) {
+           /* This clobbers the result string which probably has junk
+            * related to the failed open.
+            */
+           Tcl_DStringResult((Tcl_Interp *)fbsp->fbs_interp, &ds);
+       } else {
+           break;
+       }
+#else /* if defined(_WIN32) && !defined(__CYGWIN__) */
+       char portname[32] = {0};
+       sprintf(portname, "%d", available_port);
+       fbsp->fbs_listener.fbsl_fd = pkg_permserver(portname, 0, 0, comm_error);
+       if (fbsp->fbs_listener.fbsl_fd >= 0)
+           break;
+#endif /* if defined(_WIN32) && !defined(__CYGWIN__) */
+
+       ++available_port;
+    }
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+    if (fbsp->fbs_listener.fbsl_chan == NULL) {
+       failed = 1;
+    }
+#else /* if defined(_WIN32) && !defined(__CYGWIN__) */
+    if (fbsp->fbs_listener.fbsl_fd < 0) {
+       failed = 1;
+    }
+#endif /* if defined(_WIN32) && !defined(__CYGWIN__) */
+
+    if (failed) {
+       bu_vls_printf(&vls, "fbs_open: failed to hang a listen on ports %d - 
%d\n", port, available_port);
+       Tcl_AppendResult((Tcl_Interp *)fbsp->fbs_interp, bu_vls_addr(&vls), 
(char *)NULL);
+       bu_vls_free(&vls);
+
+       fbsp->fbs_listener.fbsl_port = -1;
+
+       return TCL_ERROR;
+    }
+
+    fbsp->fbs_listener.fbsl_port = available_port;
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+    Tcl_GetChannelHandle(fbsp->fbs_listener.fbsl_chan, TCL_READABLE, 
(ClientData *)&fbsp->fbs_listener.fbsl_fd);
+#else /* if defined(_WIN32) && !defined(__CYGWIN__) */
+    Tcl_CreateFileHandler(fbsp->fbs_listener.fbsl_fd, TCL_READABLE, 
(Tcl_FileProc *)new_client_handler, (ClientData)&fbsp->fbs_listener);
+#endif /* if defined(_WIN32) && !defined(__CYGWIN__) */
+
+    return TCL_OK;
+}
+
+
+int
+fbs_close(struct fbserv_obj *fbsp)
+{
+    int i;
+
+    /* first drop all clients */
+    for (i = 0; i < MAX_CLIENTS; ++i)
+       drop_client(fbsp, i);
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+    if (fbsp->fbs_listener.fbsl_chan != NULL) {
+       Tcl_ChannelProc *callback = (Tcl_ChannelProc *)new_client_handler;
+       Tcl_DeleteChannelHandler(fbsp->fbs_listener.fbsl_chan, callback, 
(ClientData)fbsp->fbs_listener.fbsl_fd);
+       Tcl_Close((Tcl_Interp *)fbsp->fbs_interp, fbsp->fbs_listener.fbsl_chan);
+       fbsp->fbs_listener.fbsl_chan = NULL;
+    }
+#else
+    Tcl_DeleteFileHandler(fbsp->fbs_listener.fbsl_fd);
+#endif
+
+    if (0 <= fbsp->fbs_listener.fbsl_fd)
+       close(fbsp->fbs_listener.fbsl_fd);
+    fbsp->fbs_listener.fbsl_fd = -1;
+    fbsp->fbs_listener.fbsl_port = -1;
+
+    return TCL_OK;
+}
+
+
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */

Modified: brlcad/branches/dm-fb-merge/src/libtclcad/tclcad_obj.c
===================================================================
--- brlcad/branches/dm-fb-merge/src/libtclcad/tclcad_obj.c      2020-05-18 
19:20:19 UTC (rev 75835)
+++ brlcad/branches/dm-fb-merge/src/libtclcad/tclcad_obj.c      2020-05-19 
03:34:33 UTC (rev 75836)
@@ -1169,8 +1169,8 @@
     {"faceplate",      "center_dot|prim_labels|view_params|view_scale 
color|draw [val(s)]", TO_UNLIMITED, to_faceplate, GED_FUNC_PTR_NULL},
     {"facetize",       (char *)0, TO_UNLIMITED, to_pass_through_func, 
ged_facetize},
     {"voxelize",       (char *)0, TO_UNLIMITED, to_pass_through_func, 
ged_voxelize},
-    {"fb2pix",         "[-h -i -c] [-s squaresize] [-w width] [-n height] 
[file.pix]", TO_UNLIMITED, to_view_func, ged_fb2pix},
-    {"fbclear",        "[r g b]", TO_UNLIMITED, to_view_func, ged_fbclear},
+    //{"fb2pix",       "[-h -i -c] [-s squaresize] [-w width] [-n height] 
[file.pix]", TO_UNLIMITED, to_view_func, ged_fb2pix},
+    //{"fbclear",      "[r g b]", TO_UNLIMITED, to_view_func, ged_fbclear},
     {"find_arb_edge",  "arb vx vy ptol", 5, to_view_func, 
ged_find_arb_edge_nearest_pnt},
     {"find_bot_edge",  "bot vx vy", 5, to_view_func, 
ged_find_bot_edge_nearest_pnt},
     {"find_bot_pnt",   "bot vx vy", 5, to_view_func, 
ged_find_bot_pnt_nearest_pnt},
@@ -1315,7 +1315,7 @@
     {"pathlist",       (char *)0, TO_UNLIMITED, to_pass_through_func, 
ged_pathlist},
     {"paths",  (char *)0, TO_UNLIMITED, to_pass_through_func, ged_pathsum},
     {"perspective",    "[angle]", 3, to_view_func_plus, ged_perspective},
-    {"pix2fb",         "[options] [file.pix]", TO_UNLIMITED, to_view_func, 
ged_pix2fb},
+    //{"pix2fb",       "[options] [file.pix]", TO_UNLIMITED, to_view_func, 
ged_pix2fb},
     {"plot",   "[options] file.pl", 16, to_view_func, ged_plot},
     {"pmat",   "[mat]", 3, to_view_func, ged_pmat},
     {"pmodel2view",    "vname", 2, to_view_func, ged_pmodel2view},
@@ -1323,7 +1323,7 @@
     {"pix",    "file", TO_UNLIMITED, to_pix, GED_FUNC_PTR_NULL},
     {"png",    "file", TO_UNLIMITED, to_png, GED_FUNC_PTR_NULL},
 #endif
-    {"png2fb",         "[options] [file.png]", TO_UNLIMITED, to_view_func, 
ged_png2fb},
+    //{"png2fb",       "[options] [file.png]", TO_UNLIMITED, to_view_func, 
ged_png2fb},
     {"pngwf",  "[options] file.png", 16, to_view_func, ged_png},
     {"poly_circ_mode", "x y", TO_UNLIMITED, to_poly_circ_mode, 
GED_FUNC_PTR_NULL},
     {"poly_cont_build",        "x y", TO_UNLIMITED, to_poly_cont_build, 
GED_FUNC_PTR_NULL},
@@ -14924,7 +14924,7 @@
 
     /* Copy argv into av while skipping argv[1] (i.e. the view name) */
     gedp->ged_gvp = gdvp->gdv_view;
-    gedp->ged_fbsp = &gdvp->gdv_fbs;
+    //gedp->ged_fbsp = &gdvp->gdv_fbs;
     gedp->ged_refresh_clientdata = (void *)gdvp;
     av[0] = (char *)argv[0];
     ac = argc-1;

Modified: brlcad/branches/dm-fb-merge/src/rt/viewedge.c
===================================================================
--- brlcad/branches/dm-fb-merge/src/rt/viewedge.c       2020-05-18 19:20:19 UTC 
(rev 75835)
+++ brlcad/branches/dm-fb-merge/src/rt/viewedge.c       2020-05-19 03:34:33 UTC 
(rev 75836)
@@ -425,7 +425,7 @@
 
        bu_log("rtedge: loading occlusion geometry from %s.\n", file);
 
-       if (bu_argv_from_tcl_list(bu_vls_addr(&occlusion_objects), &split_argc, 
&objs) == TCL_ERROR) {
+       if (bu_argv_from_tcl_list(bu_vls_addr(&occlusion_objects), &split_argc, 
&objs) == 0) {
            bu_log("rtedge: occlusion list = %s\n",
                   bu_vls_addr(&occlusion_objects));
            bu_exit(EXIT_FAILURE, "rtedge: could not parse occlusion objects 
list.\n");

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to