Revision: 75858
          http://sourceforge.net/p/brlcad/code/75858
Author:   starseeker
Date:     2020-05-21 00:44:47 +0000 (Thu, 21 May 2020)
Log Message:
-----------
Merge trunk changes through r75857

Modified Paths:
--------------
    brlcad/branches/bioh/misc/CMake/BRLCAD_Targets.cmake
    brlcad/branches/bioh/regress/pkg/CMakeLists.txt
    brlcad/branches/bioh/regress/pkg/regress_pkg.cpp
    brlcad/branches/bioh/src/art/art.h
    brlcad/branches/bioh/src/libdm/dm-tk.c
    brlcad/branches/bioh/src/libdm/tests/tcl_img.cpp
    brlcad/branches/bioh/src/libfb/CMakeLists.txt

Added Paths:
-----------
    brlcad/branches/bioh/src/libfb/if_tk.cpp

Removed Paths:
-------------
    brlcad/branches/bioh/regress/pkg/regress_pkg_client.cpp
    brlcad/branches/bioh/regress/pkg/regress_pkg_protocol.h
    brlcad/branches/bioh/regress/pkg/regress_pkg_server.cpp
    brlcad/branches/bioh/src/libfb/if_tk.c

Property Changed:
----------------
    brlcad/branches/bioh/
    brlcad/branches/bioh/regress/

Index: brlcad/branches/bioh
===================================================================
--- brlcad/branches/bioh        2020-05-21 00:32:25 UTC (rev 75857)
+++ brlcad/branches/bioh        2020-05-21 00:44:47 UTC (rev 75858)

Property changes on: brlcad/branches/bioh
___________________________________________________________________
Modified: svn:mergeinfo
## -7,4 +7,4 ##
 /brlcad/branches/osg:62110-62113
 /brlcad/branches/prep-cache:68236-68933
 /brlcad/branches/tcltk86:68300-75257
-/brlcad/trunk:75720-75834
\ No newline at end of property
+/brlcad/trunk:75720-75857
\ No newline at end of property
Modified: brlcad/branches/bioh/misc/CMake/BRLCAD_Targets.cmake
===================================================================
--- brlcad/branches/bioh/misc/CMake/BRLCAD_Targets.cmake        2020-05-21 
00:32:25 UTC (rev 75857)
+++ brlcad/branches/bioh/misc/CMake/BRLCAD_Targets.cmake        2020-05-21 
00:44:47 UTC (rev 75858)
@@ -464,6 +464,13 @@
     add_library(${libname}-obj OBJECT ${lsrcslist})
     set(lsrcslist $<TARGET_OBJECTS:${libname}-obj>)
     set_target_properties(${libname}-obj PROPERTIES FOLDER "BRL-CAD OBJECT 
Libraries${SUBFOLDER}")
+
+    if(CPP_DLL_DEFINES)
+      string(REPLACE "lib" "" LOWERCORE "${libname}")
+      string(TOUPPER ${LOWERCORE} UPPER_CORE)
+      set_property(TARGET ${libname}-obj APPEND PROPERTY COMPILE_DEFINITIONS 
"${UPPER_CORE}_DLL_EXPORTS")
+    endif(CPP_DLL_DEFINES)
+
     if(NOT "${libslist}" STREQUAL "" AND NOT "${libslist}" STREQUAL "NONE")
       foreach(ll ${libslist})
        if (TARGET ${ll})
@@ -471,10 +478,14 @@
        endif (TARGET ${ll})
       endforeach(ll ${libslist})
     endif(NOT "${libslist}" STREQUAL "" AND NOT "${libslist}" STREQUAL "NONE")
+
   endif(USE_OBJECT_LIBS)
 
+  # Handle the shared library
   if(L_SHARED OR (BUILD_SHARED_LIBS AND NOT L_STATIC))
+
     add_library(${libname} SHARED ${lsrcslist} ${L_SHARED_SRCS})
+
     if(CPP_DLL_DEFINES)
       string(REPLACE "lib" "" LOWERCORE "${libname}")
       string(TOUPPER ${LOWERCORE} UPPER_CORE)
@@ -481,6 +492,7 @@
       set_property(TARGET ${libname} APPEND PROPERTY COMPILE_DEFINITIONS 
"${UPPER_CORE}_DLL_EXPORTS")
       set_property(GLOBAL APPEND PROPERTY ${libname}_DLL_DEFINES 
"${UPPER_CORE}_DLL_IMPORTS")
     endif(CPP_DLL_DEFINES)
+
   endif(L_SHARED OR (BUILD_SHARED_LIBS AND NOT L_STATIC))
 
   if(L_STATIC OR (BUILD_STATIC_LIBS AND NOT L_SHARED))

Index: brlcad/branches/bioh/regress
===================================================================
--- brlcad/branches/bioh/regress        2020-05-21 00:32:25 UTC (rev 75857)
+++ brlcad/branches/bioh/regress        2020-05-21 00:44:47 UTC (rev 75858)

Property changes on: brlcad/branches/bioh/regress
___________________________________________________________________
Modified: svn:mergeinfo
## -7,4 +7,4 ##
 /brlcad/branches/osg/regress:62110-62113
 /brlcad/branches/prep-cache/regress:68236-68933
 /brlcad/branches/tcltk86/regress:68300-75257
-/brlcad/trunk/regress:75728-75834
\ No newline at end of property
+/brlcad/trunk/regress:75728-75857
\ No newline at end of property
Modified: brlcad/branches/bioh/regress/pkg/CMakeLists.txt
===================================================================
--- brlcad/branches/bioh/regress/pkg/CMakeLists.txt     2020-05-21 00:32:25 UTC 
(rev 75857)
+++ brlcad/branches/bioh/regress/pkg/CMakeLists.txt     2020-05-21 00:44:47 UTC 
(rev 75858)
@@ -5,25 +5,11 @@
   ${PKG_INCLUDE_DIRS}
   )
 
-add_executable(regress_pkg_server regress_pkg_server.cpp)
-target_link_libraries(regress_pkg_server libbu libpkg)
-set_target_properties(regress_pkg_server PROPERTIES FOLDER "BRL-CAD Regression 
Tests/libpkg")
-
-add_executable(regress_pkg_client regress_pkg_client.cpp)
-target_link_libraries(regress_pkg_client libbu libpkg)
-set_target_properties(regress_pkg_client PROPERTIES FOLDER "BRL-CAD Regression 
Tests/libpkg")
-
-# CMake executes programs in series, and since the client and server need
-# to be running in parallel for this to work we have to do something else.
-# We use a single C++ utility program to handle the launch and report the
-# results.
-add_executable(regress_pkg regress_pkg.cpp)
-target_link_libraries(regress_pkg libbu ${CMAKE_THREAD_LIBS_INIT})
+BRLCAD_ADDEXEC(regress_pkg regress_pkg.cpp 
"libpkg;libbu;${CMAKE_THREAD_LIBS_INIT}" NO_INSTALL)
 set_target_properties(regress_pkg PROPERTIES FOLDER "BRL-CAD Regression 
Tests/libpkg")
-add_dependencies(regress_pkg regress_pkg_server regress_pkg_client)
 
 add_test(NAME regress-pkg
-  COMMAND $<TARGET_FILE:regress_pkg> $<TARGET_FILE:regress_pkg_server> 
$<TARGET_FILE:regress_pkg_client>
+  COMMAND $<TARGET_FILE:regress_pkg>
   )
 set_tests_properties(regress-pkg PROPERTIES LABELS "Regression")
 
@@ -32,13 +18,13 @@
 else (CMAKE_CONFIGURATION_TYPES)
   add_custom_target(regress-pkg COMMAND ${CMAKE_CTEST_COMMAND} -R ^regress-pkg 
--output-on-failure)
 endif (CMAKE_CONFIGURATION_TYPES)
-add_dependencies(regress-pkg libbu libpkg)
+add_dependencies(regress-pkg regress_pkg)
+
 set_target_properties(regress-pkg PROPERTIES FOLDER "BRL-CAD Regression Tests")
 set_target_properties(regress-pkg PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD 1)
 
 CMAKEFILES(
   CMakeLists.txt
-  regress_pkg_protocol.h
   )
 # Local Variables:
 # tab-width: 8

Modified: brlcad/branches/bioh/regress/pkg/regress_pkg.cpp
===================================================================
--- brlcad/branches/bioh/regress/pkg/regress_pkg.cpp    2020-05-21 00:32:25 UTC 
(rev 75857)
+++ brlcad/branches/bioh/regress/pkg/regress_pkg.cpp    2020-05-21 00:44:47 UTC 
(rev 75858)
@@ -1,48 +1,351 @@
 /*                 R E G R E S S _ P K G . C P P
  * BRL-CAD
  *
- * Published in 2020 by the United States Government.
- * This work is in the public domain.
+ * Copyright (c) 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.
  */
 /** @file regress_pkg.cpp
  *
- * Contol program that launches the regression test client and server for
- * libpkg, and returns the overall results.
+ * Brief description
  *
  */
 
-#include <cstdlib>
+#define MAGIC_ID       "RPKG"
+#define MSG_HELO       1
+#define MSG_DATA       2
+#define MSG_CIAO       3
+#define MAX_PORT_DIGITS      5
+
+#include "common.h"
+
 #include <iostream>
 #include <thread>
-#include <vector>
+
+/* system headers */
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include "bio.h"
+
+/* interface headers */
 #include "bu/app.h"
+#include "bu/getopt.h"
+#include "bu/log.h"
+#include "bu/malloc.h"
+#include "bu/snooze.h"
+#include "bu/str.h"
+#include "bu/time.h"
+#include "bu/vls.h"
+#include "pkg.h"
 
+/*
+ * callback when a HELO message packet is received.
+ *
+ * We should not encounter this packet specifically since we listened
+ * for it before beginning processing of packets as part of a simple
+ * handshake setup.
+ */
+void
+server_helo(struct pkg_conn *UNUSED(connection), char *UNUSED(buf))
+{
+    bu_exit(-1, "Unexpected HELO encountered\n");
+}
+
+/* callback when a DATA message packet is received */
+void
+server_data(struct pkg_conn *UNUSED(connection), char *buf)
+{
+    bu_log("Received message from client: %s\n", buf);
+    free(buf);
+}
+
+
+/* callback when a CIAO message packet is received */
+void
+server_ciao(struct pkg_conn *UNUSED(connection), char *buf)
+{
+    bu_log("CIAO encountered: %s\n", buf);
+    free(buf);
+}
+
+int
+server_main(int UNUSED(argc), const char *UNUSED(argv)) {
+    int port = 2000;
+    struct pkg_conn *client;
+    int netfd;
+    char portname[MAX_PORT_DIGITS + 1] = {0};
+    /* int pkg_result  = 0; */
+    struct bu_vls buffer = BU_VLS_INIT_ZERO;
+    char *msgbuffer;
+    long bytes = 0;
+    /** our server callbacks for each message type */
+    struct pkg_switch callbacks[] = {
+       {MSG_HELO, server_helo, "HELO", NULL},
+       {MSG_DATA, server_data, "DATA", NULL},
+       {MSG_CIAO, server_ciao, "CIAO", NULL},
+       {0, 0, (char *)0, (void*)0}
+    };
+
+    /* ignore broken pipes, on platforms where we have SIGPIPE */
+#ifdef SIGPIPE
+    (void)signal(SIGPIPE, SIG_IGN);
+#endif
+
+    /* start up the server on the given port */
+    snprintf(portname, MAX_PORT_DIGITS, "%d", port);
+    netfd = pkg_permserver(portname, "tcp", 0, 0);
+    if (netfd < 0) {
+       bu_exit(-1, "Unable to start the server");
+    }
+
+    /* listen for a good client indefinitely.  this is a simple
+     * handshake that waits for a HELO message from the client.  if it
+     * doesn't get one, the server continues to wait.
+     */
+    int64_t timer = bu_gettime();
+    bu_log("Listening on port %d\n", port);
+    do {
+       client = pkg_getclient(netfd, callbacks, NULL, 1);
+       if (client == PKC_NULL) {
+           int wait_time = 5;
+           if ((bu_gettime() - timer) > BU_SEC2USEC(wait_time)) {
+               bu_log("Connection inactive for > %d seconds, quitting.\n", 
wait_time);
+               bu_exit(1, "Timeout - inactive");
+           }
+           bu_log("No client input available, waiting...\n");
+           bu_snooze(BU_SEC2USEC((double)wait_time / 10.0));
+           continue;
+       } else if (client == PKC_ERROR) {
+           pkg_close(client);
+           client = PKC_NULL;
+           bu_log("ERROR: no clients connected to server after %d seconds 
waiting\n");
+           bu_exit(-1, "Server exiting\n");
+           continue;
+       }
+
+       // Something happened - reset idle timer
+       timer = bu_gettime();
+
+       /* got a connection, process it */
+       msgbuffer = pkg_bwaitfor (MSG_HELO, client);
+       if (msgbuffer == NULL) {
+           bu_log("Failed to process the client connection, still waiting\n");
+           pkg_close(client);
+           client = PKC_NULL;
+       } else {
+           bu_log("msgbuffer: %s\n", msgbuffer);
+           /* validate magic header that client should have sent */
+           if (!BU_STR_EQUAL(msgbuffer, MAGIC_ID)) {
+               bu_log("Bizarre corruption, received a HELO without at matching 
MAGIC ID!\n");
+               pkg_close(client);
+               client = PKC_NULL;
+           }
+       }
+    } while (client == PKC_NULL);
+
+    /* send the first message to the server */
+    bu_vls_sprintf(&buffer, "This is a message from the server.");
+    bytes = pkg_send(MSG_DATA, bu_vls_addr(&buffer), 
(size_t)bu_vls_strlen(&buffer)+1, client);
+    if (bytes < 0) goto failure;
+
+    /* send another message to the server */
+    bu_vls_sprintf(&buffer, "Yet another message from the server.");
+    bytes = pkg_send(MSG_DATA, bu_vls_addr(&buffer), 
(size_t)bu_vls_strlen(&buffer)+1, client);
+    if (bytes < 0) goto failure;
+
+    /* Tell the client we're done */
+    bytes = pkg_send(MSG_CIAO, "DONE", 5, client);
+    if (bytes < 0) {
+       bu_exit(-1, "Connection to client seems faulty.\n");
+    }
+
+    /* Wait to hear from the client */
+    do {
+       (void)pkg_process(client);
+       (void)pkg_suckin(client);
+       (void)pkg_process(client);
+    } while (client->pkc_type != MSG_CIAO);
+
+
+    /* Confirm the client is done */
+    (void)pkg_bwaitfor(MSG_CIAO , client);
+
+    /* shut down the server, one-time use */
+    pkg_close(client);
+    return 0;
+
+failure:
+    pkg_close(client);
+    bu_vls_free(&buffer);
+    bu_exit(-1, "Unable to successfully send message.\n");
+
+    return -1;
+}
+
+/* callback when an unexpected message packet is received. */
+void
+client_unexpected(struct pkg_conn *UNUSED(connection), char *UNUSED(buf))
+{
+    bu_exit(-1, "Unexpected message package encountered\n");
+}
+
+/* callback when a DATA message packet is received */
+void
+client_data(struct pkg_conn *connection, char *buf)
+{
+    bu_log("Received file data: %s\n", buf);
+    bu_vls_printf((struct bu_vls *)connection->pkc_user_data, "\n%s\n", buf);
+    free(buf);
+}
+
+/* callback when a CIAO message packet is received */
+void
+client_ciao(struct pkg_conn *UNUSED(connection), char *buf)
+{
+    bu_log("CIAO received from server: %s\n", buf);
+    free(buf);
+}
+
+int
+client_main(int UNUSED(argc), const char **UNUSED(argv)) {
+    int port = 2000;
+    const char *server = "127.0.0.1";
+    struct bu_vls all_msgs = BU_VLS_INIT_ZERO;
+    struct pkg_conn *connection = PKC_ERROR;
+    char s_port[MAX_PORT_DIGITS + 1] = {0};
+    long bytes = 0;
+    int pkg_result = 0;
+
+    /** our callbacks for each message type */
+    struct pkg_switch callbacks[] = {
+       {MSG_HELO, client_unexpected, "HELO", NULL},
+       {MSG_DATA, client_data, "DATA", NULL},
+       {MSG_CIAO, client_ciao, "CIAO", NULL},
+       {0, 0, (char *)0, (void*)0}
+    };
+
+    /* Collect data from more than one server communication for later use */
+    callbacks[1].pks_user_data = (void *)&all_msgs;
+
+    /* fire up the client */
+    bu_log("Connecting to %s, port %d\n", server, port);
+    snprintf(s_port, MAX_PORT_DIGITS, "%d", port);
+
+    int wait_time = 5;
+    int64_t timer = bu_gettime();
+
+    connection = pkg_open(server, s_port, "tcp", NULL, NULL, NULL, NULL);
+    while (connection == PKC_ERROR && (bu_gettime() - timer) < 
BU_SEC2USEC(wait_time)) {
+       bu_snooze(BU_SEC2USEC((double)wait_time / 10.0));
+       connection = pkg_open(server, s_port, "tcp", NULL, NULL, NULL, NULL);
+    }
+
+    if (connection == PKC_ERROR) {
+       bu_log("Connection to %s, port %d, failed.\n", server, port);
+       bu_log("ERROR: unable to connect to server after %d seconds trying\n", 
wait_time);
+       bu_exit(-1, "Client exiting\n");
+    }
+
+    connection->pkc_switch = callbacks;
+
+    /* let the server know we're cool. */
+    bytes = pkg_send(MSG_HELO, MAGIC_ID, strlen(MAGIC_ID) + 1, connection);
+    if (bytes < 0) {
+       pkg_close(connection);
+       bu_log("Connection to %s, port %d, seems faulty.\n", server, port);
+       bu_exit(-1, "ERROR: Unable to communicate with the server\n");
+    }
+
+    /* Server should have a message to send us.
+    */
+    bu_log("Processing data from server\n");
+    do {
+       /* process packets potentially received in a processing callback */
+       pkg_result = pkg_process(connection);
+       if (pkg_result < 0) {
+           bu_log("Unable to process packets? Weird.\n");
+       } else if (pkg_result > 0) {
+           bu_log("Processed %d packet%s\n", pkg_result, pkg_result == 1 ? "" 
: "s");
+       }
+
+       /* suck in data from the network */
+       pkg_result = pkg_suckin(connection);
+       if (pkg_result < 0) {
+           bu_log("Seemed to have trouble sucking in packets.\n");
+           break;
+       } else if (pkg_result == 0) {
+           bu_log("Client closed the connection.\n");
+           break;
+       }
+
+       /* process new packets received */
+       pkg_result = pkg_process(connection);
+       if (pkg_result < 0) {
+           bu_log("Unable to process packets? Weird.\n");
+       } else if (pkg_result > 0) {
+           bu_log("Processed %d packet%s\n", pkg_result, pkg_result == 1 ? "" 
: "s");
+       }
+
+    } while (connection->pkc_type != MSG_CIAO);
+
+    /* server's done, send our own message back to it */
+    bytes = pkg_send(MSG_DATA, "Message from client", 20, connection);
+
+    /* let the server know we're done. */
+    bytes = pkg_send(MSG_CIAO, "DONE", 5, connection);
+    bytes = pkg_send(MSG_CIAO, "BYE", 4, connection);
+    if (bytes < 0) {
+       bu_exit(-1, "Unable to cleanly disconnect from %s, port %d.\n", server, 
port);
+    }
+
+    /* flush output and close */
+    pkg_close(connection);
+
+    bu_log("All messages: %s\n", bu_vls_addr(&all_msgs));
+
+    bu_vls_free(&all_msgs);
+    return 0;
+}
+
 class cmd_result {
     public:
        int cmd_ret = 0;
-       std::string cmd;
 };
 
 void
 run_server(cmd_result &r)
 {
-    std::string rcmd = std::string("\"") + r.cmd + std::string("\"");
-    r.cmd_ret = std::system(rcmd.c_str());
+    std::cout << "SERVER thread starting" << std::endl;
+    r.cmd_ret = server_main(0, NULL);
+    std::cout << "SERVER thread ending" << std::endl;
 }
 
 void
 run_client(cmd_result &r)
 {
-    std::string rcmd = std::string("\"") + r.cmd + std::string("\"");
-    r.cmd_ret = std::system(rcmd.c_str());
+    std::cout << "CLIENT thread starting" << std::endl;
+    r.cmd_ret = client_main(0, NULL);
+    std::cout << "CLIENT thread ending" << std::endl;
 }
 
 int
 main(int argc, const char *argv[])
 {
-    if (argc != 3) {
-       std::cout << "Usage: regress_pkg server client\n";
+    if (argc != 1) {
+       std::cout << "Usage: regress_pkg\n";
        return -1;
     }
 
@@ -50,19 +353,22 @@
 
     // Set up the information the threads will need
     cmd_result s, c;
-    s.cmd = std::string(argv[1]);
-    c.cmd = std::string(argv[2]);
 
     // Launch the client and server
-    std::vector<std::thread> t;
-    t.push_back(std::thread(run_server, std::ref(s)));
-    t.push_back(std::thread(run_client, std::ref(c)));
+    std::cout << "Launching server" << std::endl;
+    std::thread server(run_server, std::ref(s));
+    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
 
-    // Wait for both commands to finish up
-    for (int i = 0; i < 2; i++) {
-       t[i].join();
-    }
+    std::cout << "Launching client" << std::endl;
+    std::thread client(run_client, std::ref(c));
+    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
 
+    // Wait for both to finish up, client first so we know it tried
+    std::cout << "Waiting for client to exit" << std::endl;
+    client.join();
+    std::cout << "Waiting for server to exit" << std::endl;
+    server.join();
+
     // If either client or server had a problem, overall test fails
     return (s.cmd_ret || c.cmd_ret) ? 1 : 0;
 }

Deleted: brlcad/branches/bioh/regress/pkg/regress_pkg_client.cpp
===================================================================
--- brlcad/branches/bioh/regress/pkg/regress_pkg_client.cpp     2020-05-21 
00:32:25 UTC (rev 75857)
+++ brlcad/branches/bioh/regress/pkg/regress_pkg_client.cpp     2020-05-21 
00:44:47 UTC (rev 75858)
@@ -1,168 +0,0 @@
-/*            R E G R E S S _ P K G _ C L I E N T . C
- * BRL-CAD
- *
- * Copyright (c) 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.
- */
-/** @file regress_pkg_client.c
- *
- * Client application for libpkg regression test.
- *
- */
-
-#include "common.h"
-
-/* system headers */
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include "bio.h"
-
-/* interface headers */
-#include "bu/app.h"
-#include "bu/log.h"
-#include "bu/malloc.h"
-#include "bu/getopt.h"
-#include "bu/file.h"
-#include "bu/vls.h"
-#include "pkg.h"
-#include "regress_pkg_protocol.h"
-
-/* callback when an unexpected message packet is received. */
-void
-client_unexpected(struct pkg_conn *UNUSED(connection), char *UNUSED(buf))
-{
-    bu_exit(-1, "Unexpected message package encountered\n");
-}
-
-/* callback when a DATA message packet is received */
-void
-client_data(struct pkg_conn *connection, char *buf)
-{
-    bu_log("Received file data: %s\n", buf);
-    bu_vls_printf((struct bu_vls *)connection->pkc_user_data, "\n%s\n", buf);
-    free(buf);
-}
-
-/* callback when a CIAO message packet is received */
-void
-client_ciao(struct pkg_conn *UNUSED(connection), char *buf)
-{
-    bu_log("CIAO received from server: %s\n", buf);
-    free(buf);
-}
-
-int
-main(int UNUSED(argc), const char *argv[]) {
-    int port = 2000;
-    const char *server = "127.0.0.1";
-    struct bu_vls all_msgs = BU_VLS_INIT_ZERO;
-    struct pkg_conn *connection;
-    char s_port[MAX_PORT_DIGITS + 1] = {0};
-    long bytes = 0;
-    int pkg_result = 0;
-
-    /** our callbacks for each message type */
-    struct pkg_switch callbacks[] = {
-       {MSG_HELO, client_unexpected, "HELO", NULL},
-       {MSG_DATA, client_data, "DATA", NULL},
-       {MSG_CIAO, client_ciao, "CIAO", NULL},
-       {0, 0, (char *)0, (void*)0}
-    };
-
-    bu_setprogname(argv[0]);
-
-    /* Collect data from more than one server communication for later use */
-    callbacks[1].pks_user_data = (void *)&all_msgs;
-
-    /* fire up the client */
-    bu_log("Connecting to %s, port %d\n", server, port);
-    snprintf(s_port, MAX_PORT_DIGITS, "%d", port);
-    connection = pkg_open(server, s_port, "tcp", NULL, NULL, NULL, NULL);
-    if (connection == PKC_ERROR) {
-       bu_log("Connection to %s, port %d, failed.\n", server, port);
-       bu_exit(-1, "ERROR: Unable to open a connection to the server\n");
-    }
-    connection->pkc_switch = callbacks;
-
-    /* let the server know we're cool. */
-    bytes = pkg_send(MSG_HELO, MAGIC_ID, strlen(MAGIC_ID) + 1, connection);
-    if (bytes < 0) {
-       pkg_close(connection);
-       bu_log("Connection to %s, port %d, seems faulty.\n", server, port);
-       bu_exit(-1, "ERROR: Unable to communicate with the server\n");
-    }
-
-    /* Server should have a message to send us.
-    */
-    bu_log("Processing data from server\n");
-    do {
-       /* process packets potentially received in a processing callback */
-       pkg_result = pkg_process(connection);
-       if (pkg_result < 0) {
-           bu_log("Unable to process packets? Weird.\n");
-       } else if (pkg_result > 0) {
-           bu_log("Processed %d packet%s\n", pkg_result, pkg_result == 1 ? "" 
: "s");
-       }
-
-       /* suck in data from the network */
-       pkg_result = pkg_suckin(connection);
-       if (pkg_result < 0) {
-           bu_log("Seemed to have trouble sucking in packets.\n");
-           break;
-       } else if (pkg_result == 0) {
-           bu_log("Client closed the connection.\n");
-           break;
-       }
-
-       /* process new packets received */
-       pkg_result = pkg_process(connection);
-       if (pkg_result < 0) {
-           bu_log("Unable to process packets? Weird.\n");
-       } else if (pkg_result > 0) {
-           bu_log("Processed %d packet%s\n", pkg_result, pkg_result == 1 ? "" 
: "s");
-       }
-
-    } while (connection->pkc_type != MSG_CIAO);
-
-    /* server's done, send our own message back to it */
-    bytes = pkg_send(MSG_DATA, "Message from client", 20, connection);
-
-    /* let the server know we're done. */
-    bytes = pkg_send(MSG_CIAO, "DONE", 5, connection);
-    bytes = pkg_send(MSG_CIAO, "BYE", 4, connection);
-    if (bytes < 0) {
-       bu_exit(-1, "Unable to cleanly disconnect from %s, port %d.\n", server, 
port);
-    }
-
-    /* flush output and close */
-    pkg_close(connection);
-
-    bu_log("All messages: %s\n", bu_vls_addr(&all_msgs));
-
-    bu_vls_free(&all_msgs);
-    return 0;
-}
-
-/*
- * Local Variables:
- * mode: C
- * tab-width: 8
- * indent-tabs-mode: t
- * c-file-style: "stroustrup"
- * End:
- * ex: shiftwidth=4 tabstop=8
- */

Deleted: brlcad/branches/bioh/regress/pkg/regress_pkg_protocol.h
===================================================================
--- brlcad/branches/bioh/regress/pkg/regress_pkg_protocol.h     2020-05-21 
00:32:25 UTC (rev 75857)
+++ brlcad/branches/bioh/regress/pkg/regress_pkg_protocol.h     2020-05-21 
00:44:47 UTC (rev 75858)
@@ -1,29 +0,0 @@
-/*          R E G R E S S _ P K G _ P R O T O C O L . H
- * BRL-CAD
- *
- * Published in 2020 by the United States Government.
- * This work is in the public domain.
- *
- */
-/** @file regress_pkg_protocol.h
- *
- * Network protocol and common definitons for the libpkg
- * regression test client and server
- *
- */
-
-#define MAGIC_ID       "RPKG"
-#define MSG_HELO       1
-#define MSG_DATA       2
-#define MSG_CIAO       3
-#define MAX_PORT_DIGITS      5
-
-/*
- * Local Variables:
- * mode: C
- * tab-width: 8
- * indent-tabs-mode: t
- * c-file-style: "stroustrup"
- * End:
- * ex: shiftwidth=4 tabstop=8
- */

Deleted: brlcad/branches/bioh/regress/pkg/regress_pkg_server.cpp
===================================================================
--- brlcad/branches/bioh/regress/pkg/regress_pkg_server.cpp     2020-05-21 
00:32:25 UTC (rev 75857)
+++ brlcad/branches/bioh/regress/pkg/regress_pkg_server.cpp     2020-05-21 
00:44:47 UTC (rev 75858)
@@ -1,189 +0,0 @@
-/*            R E G R E S S _ P K G _ S E R V E R . C
- * BRL-CAD
- *
- * Copyright (c) 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.
- */
-/** @file regress_pkg_server.c
- *
- * Server program for the libpkg regression test.  This is similar to the
- * libpkg example - the main difference being that it exits immediately with an
- * error when anything goes wrong.
- *
- */
-
-#include "common.h"
-
-/* system headers */
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include "bio.h"
-
-/* interface headers */
-#include "bu/app.h"
-#include "bu/log.h"
-#include "bu/str.h"
-#include "bu/malloc.h"
-#include "bu/getopt.h"
-#include "bu/vls.h"
-#include "bu/snooze.h"
-#include "pkg.h"
-#include "regress_pkg_protocol.h"
-
-/*
- * callback when a HELO message packet is received.
- *
- * We should not encounter this packet specifically since we listened
- * for it before beginning processing of packets as part of a simple
- * handshake setup.
- */
-void
-server_helo(struct pkg_conn *UNUSED(connection), char *UNUSED(buf))
-{
-    bu_exit(-1, "Unexpected HELO encountered\n");
-}
-
-/* callback when a DATA message packet is received */
-void
-server_data(struct pkg_conn *UNUSED(connection), char *buf)
-{
-    bu_log("Received message from client: %s\n", buf);
-    free(buf);
-}
-
-
-/* callback when a CIAO message packet is received */
-void
-server_ciao(struct pkg_conn *UNUSED(connection), char *buf)
-{
-    bu_log("CIAO encountered: %s\n", buf);
-    free(buf);
-}
-
-int
-main(int UNUSED(argc), const char *argv[]) {
-    int port = 2000;
-    struct pkg_conn *client;
-    int netfd;
-    char portname[MAX_PORT_DIGITS + 1] = {0};
-    /* int pkg_result  = 0; */
-    struct bu_vls buffer = BU_VLS_INIT_ZERO;
-    char *msgbuffer;
-    long bytes = 0;
-    /** our server callbacks for each message type */
-    struct pkg_switch callbacks[] = {
-       {MSG_HELO, server_helo, "HELO", NULL},
-       {MSG_DATA, server_data, "DATA", NULL},
-       {MSG_CIAO, server_ciao, "CIAO", NULL},
-       {0, 0, (char *)0, (void*)0}
-    };
-
-    bu_setprogname(argv[0]);
-
-    /* ignore broken pipes, on platforms where we have SIGPIPE */
-#ifdef SIGPIPE
-    (void)signal(SIGPIPE, SIG_IGN);
-#endif
-
-    /* start up the server on the given port */
-    snprintf(portname, MAX_PORT_DIGITS, "%d", port);
-    netfd = pkg_permserver(portname, "tcp", 0, 0);
-    if (netfd < 0) {
-       bu_exit(-1, "Unable to start the server");
-    }
-
-    /* listen for a good client indefinitely.  this is a simple
-     * handshake that waits for a HELO message from the client.  if it
-     * doesn't get one, the server continues to wait.
-     */
-    bu_log("Listening on port %d\n", port);
-    do {
-       client = pkg_getclient(netfd, callbacks, NULL, 0);
-       if (client == PKC_NULL) {
-           bu_log("Connection seems to be busy, waiting...\n");
-           bu_snooze(BU_SEC2USEC(10));
-           continue;
-       } else if (client == PKC_ERROR) {
-           pkg_close(client);
-           client = PKC_NULL;
-           bu_exit(-1, "Fatal error accepting client connection.\n");
-           continue;
-       }
-
-       /* got a connection, process it */
-       msgbuffer = pkg_bwaitfor (MSG_HELO, client);
-       if (msgbuffer == NULL) {
-           bu_log("Failed to process the client connection, still waiting\n");
-           pkg_close(client);
-           client = PKC_NULL;
-       } else {
-           bu_log("msgbuffer: %s\n", msgbuffer);
-           /* validate magic header that client should have sent */
-           if (!BU_STR_EQUAL(msgbuffer, MAGIC_ID)) {
-               bu_log("Bizarre corruption, received a HELO without at matching 
MAGIC ID!\n");
-               pkg_close(client);
-               client = PKC_NULL;
-           }
-       }
-    } while (client == PKC_NULL);
-
-    /* send the first message to the server */
-    bu_vls_sprintf(&buffer, "This is a message from the server.");
-    bytes = pkg_send(MSG_DATA, bu_vls_addr(&buffer), 
(size_t)bu_vls_strlen(&buffer)+1, client);
-    if (bytes < 0) goto failure;
-
-    /* send another message to the server */
-    bu_vls_sprintf(&buffer, "Yet another message from the server.");
-    bytes = pkg_send(MSG_DATA, bu_vls_addr(&buffer), 
(size_t)bu_vls_strlen(&buffer)+1, client);
-    if (bytes < 0) goto failure;
-
-    /* Tell the client we're done */
-    bytes = pkg_send(MSG_CIAO, "DONE", 5, client);
-    if (bytes < 0) {
-       bu_exit(-1, "Connection to client seems faulty.\n");
-    }
-
-    /* Wait to hear from the client */
-    do {
-       (void)pkg_process(client);
-       (void)pkg_suckin(client);
-       (void)pkg_process(client);
-    } while (client->pkc_type != MSG_CIAO);
-
-
-    /* Confirm the client is done */
-    (void)pkg_bwaitfor(MSG_CIAO , client);
-
-    /* shut down the server, one-time use */
-    pkg_close(client);
-    return 0;
-
-failure:
-    pkg_close(client);
-    bu_vls_free(&buffer);
-    bu_exit(-1, "Unable to successfully send message.\n");
-}
-
-/*
- * Local Variables:
- * mode: C
- * tab-width: 8
- * indent-tabs-mode: t
- * c-file-style: "stroustrup"
- * End:
- * ex: shiftwidth=4 tabstop=8
- */

Modified: brlcad/branches/bioh/src/art/art.h
===================================================================
--- brlcad/branches/bioh/src/art/art.h  2020-05-21 00:32:25 UTC (rev 75857)
+++ brlcad/branches/bioh/src/art/art.h  2020-05-21 00:44:47 UTC (rev 75858)
@@ -111,8 +111,8 @@
 namespace asf = foundation;
 namespace asr = renderer;
 
-extern "C" int APPLESEED_DLL_EXPORT brlcad_hit(struct application* ap, struct 
partition* PartHeadp, struct seg* UNUSED(segs));
-extern "C" int APPLESEED_DLL_EXPORT brlcad_miss(struct application* 
UNUSED(ap));
+int APPLESEED_DLL_EXPORT brlcad_hit(struct application* ap, struct partition* 
PartHeadp, struct seg* UNUSED(segs));
+int APPLESEED_DLL_EXPORT brlcad_miss(struct application* UNUSED(ap));
 
 class APPLESEED_DLL_EXPORT BrlcadObject : public asr::ProceduralObject
 {

Modified: brlcad/branches/bioh/src/libdm/dm-tk.c
===================================================================
--- brlcad/branches/bioh/src/libdm/dm-tk.c      2020-05-21 00:32:25 UTC (rev 
75857)
+++ brlcad/branches/bioh/src/libdm/dm-tk.c      2020-05-21 00:44:47 UTC (rev 
75858)
@@ -1,7 +1,7 @@
-/*                          D M - T K . C
+/*                       D M - T K . C
  * BRL-CAD
  *
- * Copyright (c) 1988-2020 United States Government as represented by
+ * 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
@@ -19,438 +19,123 @@
  */
 /** @file libdm/dm-tk.c
  *
- * A Display Manager that should work wherever tk does.
- *
  */
 
 #include "common.h"
 
-#ifdef DM_TK
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <limits.h>
-#include <string.h>
-
-/* FIXME: suboptimal, just picked the first mac-specific config symbol
- * encountered to know when to turn on the AquaTk X bindings from Tk.
- */
-#ifdef HAVE_MACH_THREAD_POLICY_H
-#  define MAC_OSX_TK 1
+#ifdef HAVE_SYS_TIME_H
+#  include <sys/time.h>
 #endif
 
-/* Even on a platform that has no real X, I should be able to use the
- * Xutil that comes with Tk
- */
-#include <tk.h>
-#include <X11/Xutil.h>
-#include <X11/X.h>
-
-#ifdef HAVE_X11_XOSDEFS_H
-#  include <X11/Xfuncproto.h>
-#  include <X11/Xosdefs.h>
-#endif
-
-#if defined(linux)
-#  undef X_NOT_STDC_ENV
-#  undef X_NOT_POSIX
-#endif
-
+#include "tcl.h"
 #include "vmath.h"
-#include "bn.h"
 #include "dm.h"
-#include "dm-tk.h"
-#include "dm-X.h"
 #include "dm-Null.h"
-#include "dm/dm_xvars.h"
 #include "dm_private.h"
-#include "rt/solid.h"
 
-#define PLOTBOUND 1000.0       /* Max magnification in Rot matrix */
 
-static fastf_t min_short = (fastf_t)SHRT_MIN;
-static fastf_t max_short = (fastf_t)SHRT_MAX;
+int
+tk_close(struct dm_internal *UNUSED(dmp))
+{
+    return 0;
+}
 
-extern int vectorThreshold;    /* defined in libdm/tcl.c */
 
-
-/**
- * @proc tk_close
- *
- * Gracefully release the display.
- */
-HIDDEN int
-tk_close(struct dm_internal *dmp)
+int
+tk_drawBegin(struct dm_internal *UNUSED(dmp))
 {
-    if (((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy) {
-       if (((struct x_vars *)dmp->dm_vars.priv_vars)->gc)
-           Tk_FreeGC(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-                     ((struct x_vars *)dmp->dm_vars.priv_vars)->gc);
+    return 0;
+}
 
-       if (((struct x_vars *)dmp->dm_vars.priv_vars)->pix)
-           Tk_FreePixmap(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-                         ((struct x_vars *)dmp->dm_vars.priv_vars)->pix);
 
-       /*XXX Possibly need to free the colormap */
-       if (((struct dm_xvars *)dmp->dm_vars.pub_vars)->cmap)
-           Tk_FreeColormap(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-                         ((struct dm_xvars *)dmp->dm_vars.pub_vars)->cmap);
+int
+tk_drawEnd(struct dm_internal *UNUSED(dmp))
+{
+    return 0;
+}
 
-       if (((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin)
-           Tk_DestroyWindow(((struct dm_xvars 
*)dmp->dm_vars.pub_vars)->xtkwin);
 
-    }
+int
+tk_normal(struct dm_internal *UNUSED(dmp))
+{
+    return 0;
+}
 
-    bu_vls_free(&dmp->dm_pathName);
-    bu_vls_free(&dmp->dm_tkName);
-    bu_vls_free(&dmp->dm_dName);
-    bu_free(dmp->dm_vars.priv_vars, "tk_close: tk_vars");
-    bu_free(dmp->dm_vars.pub_vars, "tk_close: dm_tkvars");
-    bu_free(dmp, "tk_close: dmp");
 
-    return BRLCAD_OK;
+int
+tk_loadMatrix(struct dm_internal *UNUSED(dmp), fastf_t *UNUSED(mat), int 
UNUSED(which_eye))
+{
+    return 0;
 }
 
 
-/**
- * @proc tk_drawBegin
- * This white-washes the dm's pixmap with the background color.
- */
-HIDDEN int
-tk_drawBegin(struct dm_internal *dmp)
+int
+tk_loadPMatrix(struct dm_internal *UNUSED(dmp), fastf_t *UNUSED(mat))
 {
-    XGCValues gcv;
+    return 0;
+}
 
-    if (dmp->dm_debugLevel)
-       bu_log("tk_drawBegin()\n");
 
-    /* clear pixmap */
-    gcv.foreground = ((struct x_vars *)dmp->dm_vars.priv_vars)->bg;
-    XChangeGC(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-             ((struct x_vars *)dmp->dm_vars.priv_vars)->gc,
-             GCForeground, &gcv);
-    XFillRectangle(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-                  ((struct x_vars *)dmp->dm_vars.priv_vars)->pix,
-                  ((struct x_vars *)dmp->dm_vars.priv_vars)->gc, 0,
-                  0, dmp->dm_width + 1,
-                  dmp->dm_height + 1);
+int
+tk_drawString2D(struct dm_internal *UNUSED(dmp), const char *UNUSED(str), 
fastf_t UNUSED(x), fastf_t UNUSED(y), int UNUSED(size), int UNUSED(use_aspect))
+{
+    return 0;
+}
 
-    /* reset foreground */
 
-    gcv.foreground = ((struct x_vars *)dmp->dm_vars.priv_vars)->fg;
-    XChangeGC(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-             ((struct x_vars *)dmp->dm_vars.priv_vars)->gc,
-             GCForeground, &gcv);
-
-    return BRLCAD_OK;
+int
+tk_drawLine2D(struct dm_internal *UNUSED(dmp), fastf_t UNUSED(x_1), fastf_t 
UNUSED(y_1), fastf_t UNUSED(x_2), fastf_t UNUSED(y_2))
+{
+    return 0;
 }
 
 
-/**
- * tk_drawEnd
- * This copies the pixmap into the window.
- */
-HIDDEN int
-tk_drawEnd(struct dm_internal *dmp)
+int
+tk_drawLine3D(struct dm_internal *UNUSED(dmp), point_t UNUSED(pt1), point_t 
UNUSED(pt2))
 {
-    if (dmp->dm_debugLevel)
-       bu_log("tk_drawEnd()\n");
+    return 0;
+}
 
-    XCopyArea(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-             ((struct x_vars *)dmp->dm_vars.priv_vars)->pix,
-             ((struct dm_xvars *)dmp->dm_vars.pub_vars)->win,
-             ((struct x_vars *)dmp->dm_vars.priv_vars)->gc,
-             0, 0, dmp->dm_width,
-             dmp->dm_height, 0, 0);
 
+int
+tk_drawLines3D(struct dm_internal *UNUSED(dmp), int UNUSED(npoints), point_t 
*UNUSED(points), int UNUSED(sflag))
+{
+    return 0;
+}
 
-    /* Prevent lag between events and updates */
-    XSync(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy, 0);
 
-    return BRLCAD_OK;
+int
+tk_drawPoint2D(struct dm_internal *UNUSED(dmp), fastf_t UNUSED(x), fastf_t 
UNUSED(y))
+{
+    return 0;
 }
 
 
-/**
- * @proc tk_loadMatrix
- *
- * Load a new transformation matrix.  This will be followed by
- * many calls to tk_drawVList().
- */
-/* ARGSUSED */
-HIDDEN int
-tk_loadMatrix(struct dm_internal *dmp, fastf_t *mat, int which_eye)
+int
+tk_drawPoint3D(struct dm_internal *UNUSED(dmp), point_t UNUSED(point))
 {
-    if (dmp->dm_debugLevel) {
-       bu_log("tk_loadMatrix()\n");
+    return 0;
+}
 
-       bu_log("which eye = %d\t", which_eye);
-       bu_log("transformation matrix = \n");
 
-       bu_log("%g %g %g %g\n", mat[0], mat[1], mat[2], mat[3]);
-       bu_log("%g %g %g %g\n", mat[4], mat[5], mat[6], mat[7]);
-       bu_log("%g %g %g %g\n", mat[8], mat[9], mat[10], mat[11]);
-       bu_log("%g %g %g %g\n", mat[12], mat[13], mat[14], mat[15]);
-    }
-
-    MAT_COPY(((struct x_vars *)dmp->dm_vars.priv_vars)->mod_mat, mat);
-    return BRLCAD_OK;
+int
+tk_drawPoints3D(struct dm_internal *UNUSED(dmp), int UNUSED(npoints), point_t 
*UNUSED(points))
+{
+    return 0;
 }
 
 
-/**
- * tk_drawVList
- *
- */
-
-HIDDEN int
-tk_drawVList(struct dm_internal *dmp, struct bn_vlist *vp)
+int
+tk_drawVList(struct dm_internal *UNUSED(dmp), struct bn_vlist *UNUSED(vp))
 {
-    static vect_t spnt, lpnt, pnt;
-    struct bn_vlist *tvp;
-    XSegment segbuf[1024];             /* XDrawSegments list */
-    XSegment *segp;                    /* current segment */
-    int nseg;                  /* number of segments */
-    fastf_t delta;
-    point_t *pt_prev = NULL;
-    point_t tlate;
-    fastf_t dist_prev=1.0;
-    static int nvectors = 0;
+    return 0;
+}
 
-    struct x_vars *privars = (struct x_vars *)dmp->dm_vars.priv_vars;
 
-    if (dmp->dm_debugLevel) {
-       bu_log("tk_drawVList()\n");
-       bu_log("vp - %p, perspective - %d\n", (void *)vp, dmp->dm_perspective);
-    }
-
-    /* delta is used in clipping to insure clipped endpoint is slightly
-     * in front of eye plane (perspective mode only).
-     * This value is a SWAG that seems to work OK.
-     */
-    delta = (privars->xmat)[15]*0.0001;
-    if (delta < 0.0)
-       delta = -delta;
-    if (delta < SQRT_SMALL_FASTF)
-       delta = SQRT_SMALL_FASTF;
-
-    nseg = 0;
-    segp = segbuf;
-    for (BU_LIST_FOR(tvp, bn_vlist, &vp->l)) {
-       int i;
-       int nused = tvp->nused;
-       int *cmd = tvp->cmd;
-       point_t *pt = tvp->pt;
-       fastf_t dist;
-
-       /* Viewing region is from -1.0 to +1.0 */
-       /* 2^31 ~= 2e9 -- dynamic range of a long int */
-       /* 2^(31-11) = 2^20 ~= 1e6 */
-       /* Integerize and let the X server do the clipping */
-       for (i = 0; i < nused; i++, cmd++, pt++) {
-           switch (*cmd) {
-               case BN_VLIST_POLY_START:
-               case BN_VLIST_POLY_VERTNORM:
-               case BN_VLIST_TRI_START:
-               case BN_VLIST_TRI_VERTNORM:
-                   continue;
-               case BN_VLIST_MODEL_MAT:
-                   privars->xmat = &(privars->mod_mat[0]);
-                   continue;
-               case BN_VLIST_DISPLAY_MAT:
-                   MAT4X3PNT(tlate, privars->mod_mat, *pt);
-                   privars->disp_mat[3] = tlate[0];
-                   privars->disp_mat[7] = tlate[1];
-                   privars->disp_mat[11] = tlate[2];
-                   privars->xmat = &(privars->disp_mat[0]);
-                   continue;
-               case BN_VLIST_POLY_MOVE:
-               case BN_VLIST_LINE_MOVE:
-               case BN_VLIST_TRI_MOVE:
-                   /* Move, not draw */
-                   if (dmp->dm_debugLevel > 2) {
-                       bu_log("before transformation:\n");
-                       bu_log("pt - %lf %lf %lf\n", V3ARGS(*pt));
-                   }
-
-                   if (dmp->dm_perspective > 0) {
-                       /* cannot apply perspective transformation to
-                        * points behind eye plane!!!!
-                        */
-                       dist = VDOT(*pt, &(privars->xmat)[12]) + 
privars->xmat[15];
-                       if (dist <= 0.0) {
-                           pt_prev = pt;
-                           dist_prev = dist;
-                           continue;
-                       } else {
-                           MAT4X3PNT(lpnt, privars->xmat, *pt);
-                           dist_prev = dist;
-                           pt_prev = pt;
-                       }
-                   } else {
-                           MAT4X3PNT(lpnt, privars->xmat, *pt);
-                   }
-
-                   lpnt[0] *= 2047;
-                   lpnt[1] *= 2047 * dmp->dm_aspect;
-                   lpnt[2] *= 2047;
-                   continue;
-               case BN_VLIST_POLY_DRAW:
-               case BN_VLIST_POLY_END:
-               case BN_VLIST_LINE_DRAW:
-               case BN_VLIST_TRI_DRAW:
-               case BN_VLIST_TRI_END:
-                   /* draw */
-                   if (dmp->dm_debugLevel > 2) {
-                       bu_log("before transformation:\n");
-                       bu_log("pt - %lf %lf %lf\n", V3ARGS(*pt));
-                   }
-
-                   if (dmp->dm_perspective > 0) {
-                       /* cannot apply perspective transformation to
-                        * points behind eye plane!!!!
-                        */
-                       dist = VDOT(*pt, &(privars->xmat)[12]) + 
privars->xmat[15];
-                       if (dmp->dm_debugLevel > 2)
-                           bu_log("dist=%g, dist_prev=%g\n", dist, dist_prev);
-                       if (dist <= 0.0) {
-                           if (dist_prev <= 0.0) {
-                               /* nothing to plot */
-                               dist_prev = dist;
-                               pt_prev = pt;
-                               continue;
-                           } else {
-                               if (pt_prev) {
-                               fastf_t alpha;
-                               vect_t diff;
-                               point_t tmp_pt;
-
-                               /* clip this end */
-                               VSUB2(diff, *pt, *pt_prev);
-                               alpha = (dist_prev - delta) / (dist_prev - 
dist);
-                               VJOIN1(tmp_pt, *pt_prev, alpha, diff);
-                               MAT4X3PNT(pnt, privars->xmat, tmp_pt);
-                               }
-                           }
-                       } else {
-                           if (dist_prev <= 0.0) {
-                               if (pt_prev) {
-                               fastf_t alpha;
-                               vect_t diff;
-                               point_t tmp_pt;
-
-                               /* clip other end */
-                               VSUB2(diff, *pt, *pt_prev);
-                               alpha = (-dist_prev + delta) / (dist - 
dist_prev);
-                               VJOIN1(tmp_pt, *pt_prev, alpha, diff);
-                               MAT4X3PNT(pnt, privars->xmat, tmp_pt);
-                               lpnt[0] *= 2047;
-                               lpnt[1] *= 2047 * dmp->dm_aspect;
-                               lpnt[2] *= 2047;
-                               MAT4X3PNT(pnt, privars->xmat, *pt);
-                               }
-                           } else {
-                               MAT4X3PNT(pnt, privars->xmat, *pt);
-                           }
-                       }
-                       dist_prev = dist;
-                   } else {
-                       MAT4X3PNT(pnt, privars->xmat, *pt);
-                   }
-
-                   pnt[0] *= 2047;
-                   pnt[1] *= 2047 * dmp->dm_aspect;
-                   pnt[2] *= 2047;
-
-                   /* save pnt --- it might get changed by clip() */
-                   VMOVE(spnt, pnt);
-                   pt_prev = pt;
-
-                   if (dmp->dm_debugLevel > 2) {
-                       bu_log("before clipping:\n");
-                       bu_log("clipmin - %lf %lf %lf\n",
-                              dmp->dm_clipmin[X],
-                              dmp->dm_clipmin[Y],
-                              dmp->dm_clipmin[Z]);
-                       bu_log("clipmax - %lf %lf %lf\n",
-                              dmp->dm_clipmax[X],
-                              dmp->dm_clipmax[Y],
-                              dmp->dm_clipmax[Z]);
-                       bu_log("pt1 - %lf %lf %lf\n", lpnt[X], lpnt[Y], 
lpnt[Z]);
-                       bu_log("pt2 - %lf %lf %lf\n", pnt[X], pnt[Y], pnt[Z]);
-                   }
-
-                   if (dmp->dm_zclip) {
-                       if (vclip(lpnt, pnt,
-                                 dmp->dm_clipmin,
-                                 dmp->dm_clipmax) == 0) {
-                           VMOVE(lpnt, spnt);
-                           continue;
-                       }
-                   } else {
-                       /* Check to see if lpnt or pnt contain values that 
exceed
-                          the capacity of a short (segbuf is an array of 
XSegments which
-                          contain shorts). If so, do clipping now. Otherwise, 
let the
-                          X server do the clipping */
-                       if (lpnt[0] < min_short || max_short < lpnt[0] ||
-                           lpnt[1] < min_short || max_short < lpnt[1] ||
-                           pnt[0] < min_short || max_short < pnt[0] ||
-                           pnt[1] < min_short || max_short < pnt[1]) {
-                           /* if the entire line segment will not be visible 
then ignore it */
-                           if (clip(&lpnt[0], &lpnt[1], &pnt[0], &pnt[1]) == 
-1) {
-                               VMOVE(lpnt, spnt);
-                               continue;
-                           }
-                       }
-                   }
-
-                   if (dmp->dm_debugLevel > 2) {
-                       bu_log("after clipping:\n");
-                       bu_log("pt1 - %lf %lf %lf\n", lpnt[X], lpnt[Y], 
lpnt[Z]);
-                       bu_log("pt2 - %lf %lf %lf\n", pnt[X], pnt[Y], pnt[Z]);
-                   }
-
-                   /* convert to X window coordinates */
-                   segp->x1 = (short)GED_TO_Xx(dmp, lpnt[0]);
-                   segp->y1 = (short)GED_TO_Xy(dmp, lpnt[1]);
-                   segp->x2 = (short)GED_TO_Xx(dmp, pnt[0]);
-                   segp->y2 = (short)GED_TO_Xy(dmp, pnt[1]);
-
-                   nseg++;
-                   segp++;
-                   VMOVE(lpnt, spnt);
-
-                   if (nseg == 1024) {
-                       XDrawSegments(((struct dm_xvars 
*)dmp->dm_vars.pub_vars)->dpy,
-                                     ((struct x_vars 
*)dmp->dm_vars.priv_vars)->pix,
-                                     ((struct x_vars 
*)dmp->dm_vars.priv_vars)->gc, segbuf, nseg);
-
-                       nseg = 0;
-                       segp = segbuf;
-                   }
-                   break;
-           }
-       }
-
-       nvectors += nused;
-       if (nvectors >= vectorThreshold) {
-           if (dmp->dm_debugLevel)
-               bu_log("tk_drawVList(): handle Tcl events\n");
-
-           nvectors = 0;
-
-           /* Handle events in the queue */
-           while (Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT));
-       }
-    }
-
-    if (nseg) {
-       XDrawSegments(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-                     ((struct x_vars *)dmp->dm_vars.priv_vars)->pix,
-                     ((struct x_vars *)dmp->dm_vars.priv_vars)->gc, segbuf, 
nseg);
-    }
-
-    return BRLCAD_OK;
+int
+tk_drawVListHiddenLine(struct dm_internal *UNUSED(dmp), struct bn_vlist 
*UNUSED(vp))
+{
+    return 0;
 }
 
 
@@ -457,372 +142,147 @@
 int
 tk_draw(struct dm_internal *dmp, struct bn_vlist *(*callback_function)(void 
*), void **data)
 {
-    struct bn_vlist *vp;
-    if (!callback_function) {
-       if (data) {
-           vp = (struct bn_vlist *)data;
-           tk_drawVList(dmp, vp);
-       }
-    } else {
-       if (!data) {
-           return BRLCAD_ERROR;
-       } else {
-           (void)callback_function(data);
-       }
-    }
-    return BRLCAD_OK;
+    return dmp == NULL && callback_function == NULL && data == NULL;
 }
 
 
-/*
- * Restore the display processor to a normal mode of operation
- * (i.e., not scaled, rotated, displaced, etc.).
- */
-HIDDEN int
-tk_normal(struct dm_internal *dmp)
+int
+tk_setFGColor(struct dm_internal *UNUSED(dmp), unsigned char UNUSED(r), 
unsigned char UNUSED(g), unsigned char UNUSED(b), int UNUSED(strict), fastf_t 
UNUSED(transparency))
 {
-    if (dmp->dm_debugLevel)
-       bu_log("tk_normal()\n");
-
-    return BRLCAD_OK;
+    return 0;
 }
 
 
-/*
- * Output a string into the displaylist.
- * The starting position of the beam is as specified.
- */
-/* ARGSUSED */
-HIDDEN int
-tk_drawString2D(struct dm_internal *dmp, const char *str, fastf_t x, fastf_t 
y, int size, int use_aspect)
+int
+tk_setBGColor(struct dm_internal *UNUSED(dmp), unsigned char UNUSED(r), 
unsigned char UNUSED(g), unsigned char UNUSED(b))
 {
-    int sx, sy;
+    return 0;
+}
 
-    if (dmp->dm_debugLevel) {
-       bu_log("tk_drawString2D():\n");
-       bu_log("\tstr - %s\n", str);
-       bu_log("\tx - %g\n", x);
-       bu_log("\ty - %g\n", y);
-       bu_log("\tsize - %d\n", size);
 
-       bu_log("color = %lu\n", ((struct x_vars *)dmp->dm_vars.priv_vars)->fg);
-       /* bu_log("real_color = %d\n", ((struct x_vars 
*)dmp->dm_vars.priv_vars)->gc->foreground); */
-
-       if (use_aspect) {
-           bu_log("\tuse_aspect - %d\t\taspect ratio - %g\n", use_aspect, 
dmp->dm_aspect);
-       } else
-           bu_log("\tuse_aspect - 0");
-    }
-
-    sx = dm_Normal2Xx(dmp, x);
-    sy = dm_Normal2Xy(dmp, y, use_aspect);
-
-
-    Tk_DrawChars(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-                ((struct x_vars *)dmp->dm_vars.priv_vars)->pix,
-                ((struct x_vars *)dmp->dm_vars.priv_vars)->gc,
-                ((struct dm_xvars *)dmp->dm_vars.pub_vars)->tkfontstruct,
-                str, strlen(str), sx, sy);
-
-    return BRLCAD_OK;
+int
+tk_setLineAttr(struct dm_internal *UNUSED(dmp), int UNUSED(width), int 
UNUSED(style))
+{
+    return 0;
 }
 
 
-HIDDEN int
-tk_drawLine2D(struct dm_internal *dmp, fastf_t xpos1, fastf_t ypos1, fastf_t 
xpos2, fastf_t ypos2)
+int
+tk_configureWin(struct dm_internal *UNUSED(dmp), int UNUSED(force))
 {
-    int sx1, sy1, sx2, sy2;
-
-    sx1 = dm_Normal2Xx(dmp, xpos1);
-    sx2 = dm_Normal2Xx(dmp, xpos2);
-    sy1 = dm_Normal2Xy(dmp, ypos1, 0);
-    sy2 = dm_Normal2Xy(dmp, ypos2, 0);
-
-    if (dmp->dm_debugLevel) {
-       bu_log("tk_drawLine2D()\n");
-       bu_log("x1 = %g, y1 = %g\n", xpos1, ypos1);
-       bu_log("x2 = %g, y2 = %g\n", xpos2, ypos2);
-       bu_log("sx1 = %d, sy1 = %d\n", sx1, sy1);
-       bu_log("sx2 = %d, sy2 = %d\n", sx2, sy2);
-       bu_log("color = %lu\n", ((struct x_vars *)dmp->dm_vars.priv_vars)->fg);
-    }
-
-    XDrawLine(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-             ((struct x_vars *)dmp->dm_vars.priv_vars)->pix,
-             ((struct x_vars *)dmp->dm_vars.priv_vars)->gc,
-             sx1, sy1, sx2, sy2);
-
-    return BRLCAD_OK;
+    return 0;
 }
 
 
-HIDDEN int
-tk_drawLine3D(struct dm_internal *dmp, point_t UNUSED(pt1), point_t 
UNUSED(pt2))
+int
+tk_setWinBounds(struct dm_internal *UNUSED(dmp), fastf_t *UNUSED(w))
 {
-    if (!dmp)
-       return BRLCAD_ERROR;
-
-    return BRLCAD_OK;
+    return 0;
 }
 
 
-HIDDEN int
-tk_drawLines3D(struct dm_internal *dmp, int npoints, point_t *points, int 
UNUSED(sflag))
+int
+tk_setLight(struct dm_internal *UNUSED(dmp), int UNUSED(light_on))
 {
-    if (!dmp || npoints < 0 || (npoints > 0 && !points))
-       return BRLCAD_ERROR;
-
-    return BRLCAD_OK;
+    return 0;
 }
 
 
-HIDDEN int
-tk_drawPoint2D(struct dm_internal *dmp, fastf_t x, fastf_t y)
+int
+tk_setTransparency(struct dm_internal *UNUSED(dmp), int UNUSED(transparency))
 {
-    int sx, sy;
-
-    sx = dm_Normal2Xx(dmp, x);
-    sy = dm_Normal2Xy(dmp, y, 0);
-
-    if (dmp->dm_debugLevel) {
-       bu_log("tk_drawPoint2D()\n");
-       bu_log("x = %g, y = %g\n", x, y);
-       bu_log("sx = %d, sy = %d\n", sx, sy);
-    }
-
-    XDrawPoint(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-              ((struct x_vars *)dmp->dm_vars.priv_vars)->pix,
-              ((struct x_vars *)dmp->dm_vars.priv_vars)->gc, sx, sy);
-
-    return BRLCAD_OK;
+    return 0;
 }
 
 
-HIDDEN int
-tk_setFGColor(struct dm_internal *dmp, unsigned char r, unsigned char g, 
unsigned char b, int strict, fastf_t transparency)
+int
+tk_setDepthMask(struct dm_internal *UNUSED(dmp), int UNUSED(mask))
 {
-    XColor color;
-
-    INIT_XCOLOR(&color);
-
-    if (!dmp) {
-       bu_log("WARNING: NULL display (r/g/b => %d/%d/%d; strict => %d; 
transparency => %f)\n", r, g, b, strict, transparency);
-       return BRLCAD_ERROR;
-    }
-
-    if (dmp->dm_debugLevel)
-       bu_log("tk_setFGColor(%d %d %d)\n", r, g, b);
-
-    dmp->dm_fg[0] = r;
-    dmp->dm_fg[1] = g;
-    dmp->dm_fg[2] = b;
-
-    color.red = r << 8;
-    color.green = g << 8;
-    color.blue = b << 8;
-
-    ((struct x_vars *)dmp->dm_vars.priv_vars)->fg = Tk_GetColorByValue
-       (((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin, &color)->pixel;
-
-    XSetForeground(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-                  ((struct x_vars *)dmp->dm_vars.priv_vars)->gc,
-                  ((struct x_vars *)dmp->dm_vars.priv_vars)->fg);
-
-    return BRLCAD_OK;
+    return 0;
 }
 
 
-HIDDEN int
-tk_setBGColor(struct dm_internal *dmp, unsigned char r, unsigned char g, 
unsigned char b)
+int
+tk_setZBuffer(struct dm_internal *UNUSED(dmp), int UNUSED(zbuffer_on))
 {
-    XColor color;
-
-    INIT_XCOLOR(&color);
-
-    if (!dmp) {
-       bu_log("WARNING: NULL display (r/g/b==%d/%d/%d)\n", r, g, b);
-       return BRLCAD_ERROR;
-    }
-
-    if (dmp->dm_debugLevel)
-       bu_log("tk_setBGColor()\n");
-
-    dmp->dm_bg[0] = r;
-    dmp->dm_bg[1] = g;
-    dmp->dm_bg[2] = b;
-
-    color.red = r << 8;
-    color.green = g << 8;
-    color.blue = b << 8;
-
-    XSetBackground(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-                  ((struct x_vars *)dmp->dm_vars.priv_vars)->gc,
-                  Tk_GetColorByValue(((struct dm_xvars 
*)dmp->dm_vars.pub_vars)->xtkwin,
-                                     &color)->pixel);
-
-    return BRLCAD_OK;
+    return 0;
 }
 
 
-HIDDEN int
-tk_setLineAttr(struct dm_internal *dmp, int width, int style)
+int
+tk_debug(struct dm_internal *UNUSED(dmp), int UNUSED(lvl))
 {
-    int linestyle;
-
-    if (dmp->dm_debugLevel)
-       bu_log("tk_setLineAttr(width: %d, style: %d)\n", width, style);
-
-    dmp->dm_lineWidth = width;
-    dmp->dm_lineStyle = style;
-
-    if (width < 1)
-       width = 1;
-
-    if (style == DM_DASHED_LINE)
-       linestyle = LineOnOffDash;
-    else
-       linestyle = LineSolid;
-
-    XSetLineAttributes(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-                      ((struct x_vars *)dmp->dm_vars.priv_vars)->gc,
-                      width, linestyle, CapButt, JoinMiter);
-
-    return BRLCAD_OK;
+    return 0;
 }
 
-
-/* ARGSUSED */
-HIDDEN int
-tk_debug(struct dm_internal *dmp, int lvl)
+int
+tk_logfile(struct dm_internal *UNUSED(dmp), const char *UNUSED(filename))
 {
-    dmp->dm_debugLevel = lvl;
-
-    return BRLCAD_OK;
+    return 0;
 }
 
-HIDDEN int
-tk_logfile(struct dm_internal *dmp, const char *filename)
+int
+tk_beginDList(struct dm_internal *UNUSED(dmp), unsigned int UNUSED(list))
 {
-    bu_vls_sprintf(&dmp->dm_log, "%s", filename);
-
-    return BRLCAD_OK;
+    return 0;
 }
 
 
-
-HIDDEN int
-tk_setWinBounds(struct dm_internal *dmp, fastf_t *w)
+int
+tk_endDList(struct dm_internal *UNUSED(dmp))
 {
-    if (dmp->dm_debugLevel)
-       bu_log("tk_setWinBounds()\n");
+    return 0;
+}
 
-    dmp->dm_clipmin[0] = w[0];
-    dmp->dm_clipmin[1] = w[2];
-    dmp->dm_clipmin[2] = w[4];
-    dmp->dm_clipmax[0] = w[1];
-    dmp->dm_clipmax[1] = w[3];
-    dmp->dm_clipmax[2] = w[5];
 
-    return BRLCAD_OK;
+int
+tk_drawDList(unsigned int UNUSED(list))
+{
+    return 0;
 }
 
 
-HIDDEN int
-tk_configureWin_guts(struct dm_internal *dmp, int force)
+int
+tk_freeDLists(struct dm_internal *UNUSED(dmp), unsigned int UNUSED(list), int 
UNUSED(range))
 {
-    int h, w;
+    return 0;
+}
 
-    /* nothing to do */
-    h = Tk_Height(((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin);
-    w = Tk_Width(((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin);
 
-    if (!force && dmp->dm_width==w && dmp->dm_height == h)
-       return BRLCAD_OK;
+int
+tk_genDLists(struct dm_internal *UNUSED(dmp), size_t UNUSED(range))
+{
+    return 0;
+}
 
-    dmp->dm_width=w;
-    dmp->dm_width=h;
 
-    dmp->dm_aspect = (fastf_t)dmp->dm_width / (fastf_t)dmp->dm_height;
-
-    if (dmp->dm_debugLevel) {
-       bu_log("tk_configureWin_guts()\n");
-       bu_log("width = %d, height = %d\n", dmp->dm_width, dmp->dm_height);
-    }
-
-    Tk_FreePixmap(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-                 ((struct x_vars *)dmp->dm_vars.priv_vars)->pix);
-    ((struct x_vars *)dmp->dm_vars.priv_vars)->pix =
-       Tk_GetPixmap(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-                    DefaultRootWindow(((struct dm_xvars 
*)dmp->dm_vars.pub_vars)->dpy),
-                    dmp->dm_width,
-                    dmp->dm_height,
-                    Tk_Depth(((struct dm_xvars 
*)dmp->dm_vars.pub_vars)->xtkwin));
-
-    /* First time through, load a font or quit */
-    if (((struct dm_xvars *)dmp->dm_vars.pub_vars)->tkfontset == 0) {
-
-       ((struct dm_xvars *)dmp->dm_vars.pub_vars)->tkfontstruct =
-           Tk_GetFont(dmp->dm_interp, ((struct dm_xvars 
*)dmp->dm_vars.pub_vars)->xtkwin, FONT9);
-
-       if (((struct dm_xvars *)dmp->dm_vars.pub_vars)->tkfontstruct == NULL) {
-           /* Try hardcoded backup font */
-
-           ((struct dm_xvars *)dmp->dm_vars.pub_vars)->tkfontstruct =
-               Tk_GetFont(dmp->dm_interp, ((struct dm_xvars 
*)dmp->dm_vars.pub_vars)->xtkwin, FONTBACK);
-
-           if (((struct dm_xvars *)dmp->dm_vars.pub_vars)->tkfontstruct == 
NULL) {
-               bu_log("dm-Tk: Can't open font '%s' or '%s'\n", FONT9, 
FONTBACK);
-               return BRLCAD_ERROR;
-           }
-       }
-       ((struct dm_xvars *)dmp->dm_vars.pub_vars)->tkfontset = 1;
-    }
-
-    /* XXX:  I removed the font-sizing routine from dm-X from here.  Something
-       should be devised to replace it.  --TJM*/
-
-    return BRLCAD_OK;
+int
+tk_getDisplayImage(struct dm_internal *UNUSED(dmp), unsigned char 
**UNUSED(image))
+{
+    return 0;
 }
 
 
-HIDDEN int
-tk_configureWin(struct dm_internal *dmp, int force)
+int
+tk_reshape(struct dm_internal *UNUSED(dmp), int UNUSED(width), int 
UNUSED(height))
 {
-    /* don't force */
-    return tk_configureWin_guts(dmp, force);
+    return 0;
 }
 
 
-HIDDEN int
-tk_setLight(struct dm_internal *dmp, int light_on)
+int
+tk_makeCurrent(struct dm_internal *UNUSED(dmp))
 {
-    if (dmp->dm_debugLevel)
-       bu_log("tk_setLight:\n");
-
-    dmp->dm_light = light_on;
-
-    return BRLCAD_OK;
+    return 0;
 }
 
 
-HIDDEN int
-tk_setZBuffer(struct dm_internal *dmp, int zbuffer_on)
+int
+tk_openFb(struct dm_internal *UNUSED(dmp))
 {
-    if (dmp->dm_debugLevel)
-       bu_log("tk_setZBuffer:\n");
-
-    dmp->dm_zbuffer = zbuffer_on;
-
-    return BRLCAD_OK;
+    return 0;
 }
 
-struct bu_structparse Tk_vparse[] = {
-    {"%g",  1, "bound",         DM_O(dm_bound),         dm_generic_hook, NULL, 
NULL},
-    {"%d",  1, "useBound",      DM_O(dm_boundFlag),     dm_generic_hook, NULL, 
NULL},
-    {"%d",  1, "zclip",         DM_O(dm_zclip),         dm_generic_hook, NULL, 
NULL},
-    {"%d",  1, "debug",         DM_O(dm_debugLevel),    dm_generic_hook, NULL, 
NULL},
-    {"",    0, (char *)0,       0,                      
BU_STRUCTPARSE_FUNC_NULL, NULL, NULL}
-};
 
 struct dm_internal dm_tk = {
     tk_close,
@@ -830,16 +290,16 @@
     tk_drawEnd,
     tk_normal,
     tk_loadMatrix,
-    null_loadPMatrix,
+    tk_loadPMatrix,
     tk_drawString2D,
     tk_drawLine2D,
     tk_drawLine3D,
     tk_drawLines3D,
     tk_drawPoint2D,
-    null_drawPoint3D,
-    null_drawPoints3D,
+    tk_drawPoint3D,
+    tk_drawPoints3D,
     tk_drawVList,
-    tk_drawVList,
+    tk_drawVListHiddenLine,
     tk_draw,
     tk_setFGColor,
     tk_setBGColor,
@@ -847,40 +307,40 @@
     tk_configureWin,
     tk_setWinBounds,
     tk_setLight,
-    null_setTransparency,
-    null_setDepthMask,
+    tk_setTransparency,
+    tk_setDepthMask,
     tk_setZBuffer,
     tk_debug,
     tk_logfile,
-    null_beginDList,
-    null_endDList,
-    null_drawDList,
-    null_freeDLists,
-    null_genDLists,
+    tk_beginDList,
+    tk_endDList,
+    tk_drawDList,
+    tk_freeDLists,
+    tk_genDLists,
     NULL,
-    null_getDisplayImage,      /* display to image function */
-    null_reshape,
-    null_makeCurrent,
-    null_openFb,
+    tk_getDisplayImage,
+    tk_reshape,
+    tk_makeCurrent,
+    tk_openFb,
     NULL,
     NULL,
     0,
     0,                         /* no displaylist */
     0,                         /* no stereo */
-    PLOTBOUND,                 /* zoom-in limit */
+    0.0,                       /* zoom-in limit */
     1,                         /* bound flag */
-    "Tk",
-    "Tk Abstraction Layer",
-    DM_TYPE_TK,
-    1,
+    "nu",
+    "Tk Display",
+    DM_TYPE_NULL,
+    0,/* top */
+    0,/* width */
+    0,/* height */
+    0,/* bytes per pixel */
+    0,/* bits per channel */
     0,
     0,
-    0, /* bytes per pixel */
-    0, /* bits per channel */
     0,
     0,
-    1.0, /* aspect ratio */
-    0,
     {0, 0},
     NULL,
     NULL,
@@ -889,8 +349,8 @@
     BU_VLS_INIT_ZERO,          /* bu_vls short name drawing window */
     {0, 0, 0},                 /* bg color */
     {0, 0, 0},                 /* fg color */
-    {GED_MIN, GED_MIN, GED_MIN},       /* clipmin */
-    {GED_MAX, GED_MAX, GED_MAX},       /* clipmax */
+    {0.0, 0.0, 0.0},           /* clipmin */
+    {0.0, 0.0, 0.0},           /* clipmax */
     0,                         /* no debugging */
     BU_VLS_INIT_ZERO,          /* bu_vls logfile */
     0,                         /* no perspective */
@@ -901,222 +361,19 @@
     0,                         /* no zclipping */
     1,                          /* clear back buffer after drawing and swap */
     0,                          /* not overriding the auto font size */
-    Tk_vparse,
+    BU_STRUCTPARSE_NULL,
     FB_NULL,
     0                          /* Tcl interpreter */
 };
 
-
 struct dm_internal *tk_open_dm(Tcl_Interp *interp, int argc, char **argv);
 
-/* Display Manager package interface */
-
-
-/*
- * Fire up the display manager, and the display processor.
- *
- */
 struct dm_internal *
-tk_open_dm(Tcl_Interp *interp, int argc, char **argv)
+tk_open_dm(Tcl_Interp *UNUSED(interp), int UNUSED(argc), char **UNUSED(argv))
 {
-    static int count = 0;
-    int make_square = -1;
-    XGCValues gcv;
-
-    struct bu_vls str = BU_VLS_INIT_ZERO;
-    struct bu_vls init_proc_vls = BU_VLS_INIT_ZERO;
-    struct dm_internal *dmp = (struct dm_internal *)NULL;
-    Tk_Window tkwin;
-    Display *dpy = (Display *)NULL;
-    XColor fg, bg;
-
-    INIT_XCOLOR(&fg);
-    INIT_XCOLOR(&bg);
-
-    if ((tkwin = Tk_MainWindow(interp)) == NULL) {
-       return DM_NULL;
-    }
-
-    BU_ALLOC(dmp, struct dm_internal);
-
-    *dmp = dm_tk; /* struct copy */
-    dmp->dm_interp = interp;
-
-    BU_ALLOC(dmp->dm_vars.pub_vars, struct dm_xvars);
-    BU_ALLOC(dmp->dm_vars.priv_vars, struct tk_vars);
-
-    bu_vls_init(&dmp->dm_pathName);
-    bu_vls_init(&dmp->dm_tkName);
-    bu_vls_init(&dmp->dm_dName);
-
-    dm_processOptions(dmp, &init_proc_vls, --argc, ++argv);
-
-    if (bu_vls_strlen(&dmp->dm_pathName) == 0) {
-       bu_vls_printf(&dmp->dm_pathName, ".dm_tk%d", count);
-    }
-
-    ++count;
-    if (bu_vls_strlen(&dmp->dm_dName) == 0) {
-       char *dp;
-
-       dp = DisplayString(Tk_Display(tkwin));
-
-       if (dp)
-           bu_vls_strcpy(&dmp->dm_dName, dp);
-       else
-           bu_vls_strcpy(&dmp->dm_dName, ":0.0");
-    }
-    if (bu_vls_strlen(&init_proc_vls) == 0)
-       bu_vls_strcpy(&init_proc_vls, "bind_dm");
-
-    /* initialize dm specific variables */
-    ((struct dm_xvars *)dmp->dm_vars.pub_vars)->devmotionnotify = LASTEvent;
-    ((struct dm_xvars *)dmp->dm_vars.pub_vars)->devbuttonpress = LASTEvent;
-    ((struct dm_xvars *)dmp->dm_vars.pub_vars)->devbuttonrelease = LASTEvent;
-    dmp->dm_aspect = 1.0;
-
-    ((struct dm_xvars *)dmp->dm_vars.pub_vars)->tkfontset = 0;
-
-    if (dmp->dm_top) {
-       /* Make xtkwin a toplevel window */
-       ((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin = 
Tk_CreateWindowFromPath(interp, tkwin,
-                                                                               
     bu_vls_addr(&dmp->dm_pathName),
-                                                                               
     bu_vls_addr(&dmp->dm_dName));
-       ((struct dm_xvars *)dmp->dm_vars.pub_vars)->top = ((struct dm_xvars 
*)dmp->dm_vars.pub_vars)->xtkwin;
-    } else {
-       char *cp;
-
-       cp = strrchr(bu_vls_addr(&dmp->dm_pathName), (int)'.');
-       if (cp == bu_vls_addr(&dmp->dm_pathName)) {
-           ((struct dm_xvars *)dmp->dm_vars.pub_vars)->top = tkwin;
-       } else {
-           struct bu_vls top_vls = BU_VLS_INIT_ZERO;
-
-           bu_vls_strncpy(&top_vls, (const char 
*)bu_vls_addr(&dmp->dm_pathName), cp - bu_vls_addr(&dmp->dm_pathName));
-
-           ((struct dm_xvars *)dmp->dm_vars.pub_vars)->top =
-               Tk_NameToWindow(interp, bu_vls_addr(&top_vls), tkwin);
-           bu_vls_free(&top_vls);
-       }
-
-       /* Make xtkwin an embedded window */
-       ((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin =
-           Tk_CreateWindow(interp, ((struct dm_xvars 
*)dmp->dm_vars.pub_vars)->top,
-                           cp + 1, (char *)NULL);
-    }
-
-    if (((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin == NULL) {
-       bu_log("tk_open: Failed to open %s\n", bu_vls_addr(&dmp->dm_pathName));
-       (void)tk_close(dmp);
-       return DM_NULL;
-    }
-
-    bu_vls_printf(&dmp->dm_tkName, "%s",
-                 (char *)Tk_Name(((struct dm_xvars 
*)dmp->dm_vars.pub_vars)->xtkwin));
-
-    bu_vls_printf(&str, "_init_dm %s %s\n",
-                 bu_vls_addr(&init_proc_vls),
-                 bu_vls_addr(&dmp->dm_pathName));
-
-    if (Tcl_Eval(interp, bu_vls_addr(&str)) == BRLCAD_ERROR) {
-       bu_vls_free(&str);
-       (void)tk_close(dmp);
-
-       return DM_NULL;
-    }
-
-    bu_vls_free(&init_proc_vls);
-    bu_vls_free(&str);
-
-    ((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy =
-       Tk_Display(((struct dm_xvars *)dmp->dm_vars.pub_vars)->top);
-    dpy = ((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy;
-
-    /* make sure there really is a display before proceeding. */
-    if (!dpy) {
-       (void)tk_close(dmp);
-       return DM_NULL;
-    }
-
-    if (dmp->dm_width == 0) {
-       dmp->dm_width =
-           WidthOfScreen(Tk_Screen((
-                                       (struct dm_xvars 
*)dmp->dm_vars.pub_vars)->xtkwin)) - 30;
-       ++make_square;
-    }
-
-    if (dmp->dm_height == 0) {
-       dmp->dm_height =
-           HeightOfScreen(Tk_Screen((
-                                        (struct dm_xvars 
*)dmp->dm_vars.pub_vars)->xtkwin)) - 30;
-       ++make_square;
-    }
-
-    if (make_square > 0) {
-       /* Make window square */
-       if (dmp->dm_height <
-           dmp->dm_width)
-           dmp->dm_width = dmp->dm_height;
-       else
-           dmp->dm_height = dmp->dm_width;
-    }
-
-    Tk_GeometryRequest(((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin,
-                      dmp->dm_width,
-                      dmp->dm_height);
-
-    Tk_MakeWindowExist(((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin);
-    ((struct dm_xvars *)dmp->dm_vars.pub_vars)->win =
-       Tk_WindowId(((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin);
-    dmp->dm_id = ((struct dm_xvars *)dmp->dm_vars.pub_vars)->win;
-
-    ((struct x_vars *)dmp->dm_vars.priv_vars)->pix =
-       Tk_GetPixmap(((struct dm_xvars *)dmp->dm_vars.pub_vars)->dpy,
-                    DefaultRootWindow(((struct dm_xvars 
*)dmp->dm_vars.pub_vars)->dpy),
-                    dmp->dm_width,
-                    dmp->dm_height,
-                    Tk_Depth(((struct dm_xvars 
*)dmp->dm_vars.pub_vars)->xtkwin));
-
-    fg.red = 65535;
-    fg.green = fg.blue = 0;
-
-    ((struct x_vars *)dmp->dm_vars.priv_vars)->fg =
-       Tk_GetColorByValue(((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin,
-                          &fg)->pixel;
-
-    bg.red = bg.green = bg.blue = 3277;
-
-    ((struct x_vars *)dmp->dm_vars.priv_vars)->bg =
-       Tk_GetColorByValue(((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin,
-                          &bg)->pixel;
-
-    gcv.background = ((struct x_vars *)dmp->dm_vars.priv_vars)->bg;
-    gcv.foreground = ((struct x_vars *)dmp->dm_vars.priv_vars)->fg;
-
-    ((struct x_vars *)dmp->dm_vars.priv_vars)->gc =
-       Tk_GetGC(((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin,
-                (GCForeground|GCBackground), &gcv);
-
-    (void)tk_configureWin_guts(dmp, 1);
-
-    /*
-      Tk_SetWindowBackground(((struct dm_xvars 
*)dmp->dm_vars.pub_vars)->xtkwin,
-      ((struct x_vars *)dmp->dm_vars.priv_vars)->bg);
-    */
-    Tk_MapWindow(((struct dm_xvars *)dmp->dm_vars.pub_vars)->xtkwin);
-
-    MAT_IDN(((struct x_vars *)dmp->dm_vars.priv_vars)->mod_mat);
-    MAT_IDN(((struct x_vars *)dmp->dm_vars.priv_vars)->disp_mat);
-
-    ((struct x_vars *)dmp->dm_vars.priv_vars)->xmat = 
-        &(((struct x_vars *)dmp->dm_vars.priv_vars)->mod_mat[0]);
-
-    return dmp;
+    return DM_NULL;
 }
 
-
-#endif /* DM_TK */
-
 /*
  * Local Variables:
  * mode: C

Modified: brlcad/branches/bioh/src/libdm/tests/tcl_img.cpp
===================================================================
--- brlcad/branches/bioh/src/libdm/tests/tcl_img.cpp    2020-05-21 00:32:25 UTC 
(rev 75857)
+++ brlcad/branches/bioh/src/libdm/tests/tcl_img.cpp    2020-05-21 00:44:47 UTC 
(rev 75858)
@@ -146,6 +146,11 @@
     Tcl_MutexLock(&dilock);
     Tcl_MutexLock(&fblock);
 
+    // Render processing now - reset the ready flag
+    Tcl_MutexLock(&threadMutex);
+    idata->dm_render_ready = 0;
+    Tcl_MutexUnlock(&threadMutex);
+
     int width = idata->dm_bwidth;
     int height = idata->dm_bheight;
 
@@ -187,9 +192,6 @@
     fb_data.pixelPtr = idata->fbpixel;
     Tk_PhotoPutBlock(interp, dm_img, &fb_data, 0, 0, idata->fb_width, 
idata->fb_height, TK_PHOTO_COMPOSITE_OVERLAY);
 
-    // Render processed - reset the ready flag
-    idata->dm_render_ready = 0;
-
     Tcl_MutexUnlock(&dilock);
     Tcl_MutexUnlock(&fblock);
 
@@ -399,7 +401,9 @@
     // to start over.
     Tcl_MutexLock(&dilock);
     idata->dm_render_running = 0;
+    Tcl_MutexLock(&threadMutex);
     idata->dm_render_ready = 1;
+    Tcl_MutexUnlock(&threadMutex);
     Tcl_MutexUnlock(&dilock);
 
     // Generate an event for the manager thread to let it know we're done
@@ -432,7 +436,9 @@
     idata->fb_render_running = 1;
 
     // Until we're done, make sure nobody thinks we are ready
+    Tcl_MutexLock(&threadMutex);
     idata->fb_render_ready = 0;
+    Tcl_MutexUnlock(&threadMutex);
 
     // Lock in this width and height - that's what we've got memory for,
     // so that's what the remainder of this rendering pass will use.
@@ -482,7 +488,9 @@
 
     Tcl_MutexLock(&fblock);
     idata->fb_render_running = 0;
+    Tcl_MutexLock(&threadMutex);
     idata->fb_render_ready = 1;
+    Tcl_MutexUnlock(&threadMutex);
     Tcl_MutexUnlock(&fblock);
 
     // Generate an event for the manager thread to let it know we're done, if 
the
@@ -629,7 +637,9 @@
            Tcl_MutexUnlock(&threadMutex);
 
            // Go back to waiting.
+           Tcl_MutexLock(&threadMutex);
            idata->fb_render_ready = 0;
+           Tcl_MutexUnlock(&threadMutex);
            continue;
        }
 

Modified: brlcad/branches/bioh/src/libfb/CMakeLists.txt
===================================================================
--- brlcad/branches/bioh/src/libfb/CMakeLists.txt       2020-05-21 00:32:25 UTC 
(rev 75857)
+++ brlcad/branches/bioh/src/libfb/CMakeLists.txt       2020-05-21 00:44:47 UTC 
(rev 75858)
@@ -48,8 +48,8 @@
 if(BRLCAD_ENABLE_TK)
   set(FBTKDEFS "-DIF_TK")
   set(LINKLIBS ${LINKLIBS} ${TK_LIBRARY})
-  set(fbtk_srcs if_tk.c)
-  set_property(SOURCE if_tk.c APPEND PROPERTY COMPILE_DEFINITIONS 
FB_USE_INTERNAL_API)
+  set(fbtk_srcs if_tk.cpp)
+  set_property(SOURCE if_tk.cpp APPEND PROPERTY COMPILE_DEFINITIONS 
FB_USE_INTERNAL_API)
 endif(BRLCAD_ENABLE_TK)
 if(BRLCAD_ENABLE_QT)
   CHECK_CXX_FLAG(Wno-float-equal)
@@ -124,7 +124,7 @@
   if_ogl.c
   if_osgl.cpp
   if_qt.cpp
-  if_tk.c
+  if_tk.cpp
   if_wgl.c
   fb_private.h
   osg_fb_manipulator.h

Deleted: brlcad/branches/bioh/src/libfb/if_tk.c
===================================================================
--- brlcad/branches/bioh/src/libfb/if_tk.c      2020-05-21 00:32:25 UTC (rev 
75857)
+++ brlcad/branches/bioh/src/libfb/if_tk.c      2020-05-21 00:44:47 UTC (rev 
75858)
@@ -1,655 +0,0 @@
-/*                         I F _ T K . C
- * BRL-CAD
- *
- * Copyright (c) 2007-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 libfb */
-/** @{ */
-/** @file if_tk.c
- *
- * Tk libfb interface.
- *
- */
-/** @} */
-
-#include "common.h"
-
-#ifdef IF_TK
-
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <tcl.h>
-#include <tk.h>
-#include "bio.h"
-#include "bnetwork.h"
-
-#include "bu/color.h"
-#include "bu/str.h"
-#include "bu/exit.h"
-#include "bu/log.h"
-#include "bu/snooze.h"
-
-#include "fb_private.h"
-#include "fb.h"
-
-
-Tcl_Interp *fbinterp;
-Tk_Window fbwin;
-Tk_PhotoHandle fbphoto;
-int p[2] = {0, 0};
-
-/* Note that Tk_PhotoPutBlock claims to have a faster
- * copy method when pixelSize is 4 and alphaOffset is
- * 3 - perhaps output could be massaged to generate this
- * type of information and speed up the process?
- *
- * Might as well use one block and set the three things
- * that actually change in tk_write
- */
-Tk_PhotoImageBlock block = {
-    NULL, /*Pointer to first pixel*/
-    0,    /*Width of block in pixels*/
-    1,    /*Height of block in pixels - always one for a scanline*/
-    0,    /*Address difference between successive lines*/
-    3,    /*Address difference between successive pixels on one scanline*/
-    {
-       RED,
-       GRN,
-       BLU,
-       0   /* alpha */
-    }
-};
-
-
-char *tkwrite_buffer;
-
-
-HIDDEN int
-fb_tk_open(fb *ifp, const char *file, int width, int height)
-{
-    int pid = -1;
-    const char *cmd = "package require Tk";
-    char image_create_cmd[255] = {'\0'};
-    char canvas_create_cmd[255] = {'\0'};
-    char reportcolorcmd[255] = {'\0'};
-    const char canvas_pack_cmd[255] =
-       "pack .fb_tk_canvas -fill both -expand true";
-    const char place_image_cmd[255] =
-       ".fb_tk_canvas create image 0 0 -image fb_tk_photo -anchor nw";
-    const char *wmclosecmd = "wm protocol . WM_DELETE_WINDOW {set CloseWindow 
\"close\"}";
-    const char *bindclosecmd = "bind . <Button-3> {set CloseWindow \"close\"}";
-
-    char *buffer;
-    char *linebuffer;
-
-    FB_CK_FB(ifp);
-    if (file == (char *)NULL)
-       fb_log("fb_open(0x%lx, NULL, %d, %d)\n",
-              (unsigned long)ifp, width, height);
-    else
-       fb_log("fb_open(0x%lx, \"%s\", %d, %d)\n",
-              (unsigned long)ifp, file, width, height);
-
-    /* check for default size */
-    if (width <= 0)
-       width = ifp->if_width;
-    if (height <= 0)
-       height = ifp->if_height;
-
-    /* set debug bit vector */
-    if (file != NULL) {
-       const char *cp;
-       for (cp = file; *cp != '\0' && !isdigit((unsigned char)*cp); cp++)
-           ;
-       sscanf(cp, "%d", &ifp->if_debug);
-    } else {
-       ifp->if_debug = 0;
-    }
-
-    /* Give the user whatever width was asked for */
-    ifp->if_width = width;
-    ifp->if_height = height;
-
-    fbinterp = Tcl_CreateInterp();
-
-    if (Tcl_Init(fbinterp) == TCL_ERROR) {
-       fb_log("Tcl_Init returned error in fb_open.");
-    }
-
-    if (Tcl_Eval(fbinterp, cmd) != TCL_OK) {
-       fb_log("Error returned attempting to start tk in fb_open.");
-    }
-
-    fbwin = Tk_MainWindow(fbinterp);
-
-    Tk_GeometryRequest(fbwin, width, height);
-
-    Tk_MakeWindowExist(fbwin);
-
-    sprintf(image_create_cmd,
-           "image create photo fb_tk_photo -height %d -width %d",
-           width, height);
-
-    if (Tcl_Eval(fbinterp, image_create_cmd) != TCL_OK) {
-       fb_log("Error returned attempting to create image in fb_open.");
-    }
-
-    if ((fbphoto = Tk_FindPhoto(fbinterp, "fb_tk_photo")) == NULL) {
-       fb_log("Image creation unsuccessful in fb_open.");
-    }
-
-    sprintf(canvas_create_cmd,
-           "canvas .fb_tk_canvas -highlightthickness 0 -height %d -width %d", 
width, height);
-
-    sprintf (reportcolorcmd,
-            "bind . <Button-2> {puts \"At image (%%x, [expr %d - %%y]), real 
RGB = ([fb_tk_photo get %%x %%y])\n\"}", height);
-
-    if (Tcl_Eval(fbinterp, canvas_create_cmd) != TCL_OK) {
-       fb_log("Error returned attempting to create canvas in fb_open.");
-    }
-
-    if (Tcl_Eval(fbinterp, canvas_pack_cmd) != TCL_OK) {
-       fb_log("Error returned attempting to pack canvas in fb_open. %s",
-              Tcl_GetStringResult(fbinterp));
-    }
-
-    if (Tcl_Eval(fbinterp, place_image_cmd) != TCL_OK) {
-       fb_log("Error returned attempting to place image in fb_open. %s",
-              Tcl_GetStringResult(fbinterp));
-    }
-
-    /* Set our Tcl variable pertaining to whether a
-     * window closing event has been seen from the
-     * Window manager.  WM_DELETE_WINDOW will be
-     * bound to a command setting this variable to
-     * the string "close", and a vwait watching
-     * for a change to the CloseWindow variable ensures
-     * a "lingering" tk window.
-     */
-    Tcl_SetVar(fbinterp, "CloseWindow", "open", 0);
-    if (Tcl_Eval(fbinterp, wmclosecmd) != TCL_OK) {
-       fb_log("Error binding WM_DELETE_WINDOW.");
-    }
-    if (Tcl_Eval(fbinterp, bindclosecmd) != TCL_OK) {
-       fb_log("Error binding right mouse button.");
-    }
-    if (Tcl_Eval(fbinterp, reportcolorcmd) != TCL_OK) {
-       fb_log("Error binding middle mouse button.");
-    }
-
-    while (Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT));
-
-    /* FIXME: malloc() is necessary here because there are callers
-     * that acquire a BU_SYM_SYSCALL semaphore for libfb calls.
-     * this should be investigated more closely to see if the
-     * semaphore acquires are critical or if they can be pushed
-     * down into libfb proper.  in the meantime, manually call
-     * malloc()/free().
-     */
-    buffer = (char *)malloc(sizeof(uint32_t)*3+ifp->if_width*3);
-    linebuffer = (char *)malloc(ifp->if_width*3);
-    tkwrite_buffer = (char *)malloc(ifp->if_width*3);
-
-    if (pipe(p) == -1) {
-       perror("pipe failed");
-    }
-
-    pid = fork();
-    if (pid < 0) {
-       printf("boo, something bad\n");
-    } else if (pid > 0) {
-       int line = 0;
-       uint32_t lines[3];
-       int i;
-       int y[2];
-       y[0] = 0;
-
-       /* parent */
-       while (y[0] >= 0) {
-           int count;
-
-           /* If the Tk window gets a close event, bail */
-           if (BU_STR_EQUAL(Tcl_GetVar(fbinterp, "CloseWindow", 0), "close")) {
-               free(buffer);
-               free(linebuffer);
-               free(tkwrite_buffer);
-               fclose(stdin);
-               printf("Close Window event\n");
-               Tcl_Eval(fbinterp, "destroy .");
-               bu_exit(0, NULL);
-           }
-
-           /* Unpack inputs from pipe */
-           count = read(p[0], buffer, sizeof(uint32_t)*3+ifp->if_width*3);
-           memcpy(lines, buffer, sizeof(uint32_t)*3);
-           memcpy(linebuffer, buffer+sizeof(uint32_t)*3, ifp->if_width*3);
-           y[0] = ntohl(lines[0]);
-           count = ntohl(lines[1]);
-
-           if (y[0] < 0) {
-               break;
-           }
-
-           line++;
-           block.pixelPtr = (unsigned char *)linebuffer;
-           block.width = count;
-           block.pitch = 3 * ifp->if_width;
-
-#if defined(TK_MAJOR_VERSION) && TK_MAJOR_VERSION >= 8 && 
defined(TK_MINOR_VERSION) && TK_MINOR_VERSION >= 5
-           Tk_PhotoPutBlock(fbinterp, fbphoto, &block, 0, ifp->if_height-y[0], 
count, 1, TK_PHOTO_COMPOSITE_SET);
-#else
-           Tk_PhotoPutBlock(fbinterp, &block, 0, ifp->if_height-y[0], count, 
1, TK_PHOTO_COMPOSITE_SET);
-#endif
-
-           do {
-               i = Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT);
-           } while (i);
-       }
-       /* very bad things will happen if the parent does not terminate here */
-       free(buffer);
-       free(linebuffer);
-       free(tkwrite_buffer);
-       fclose(stdin);
-       Tcl_Eval(fbinterp, "vwait CloseWindow");
-       if (BU_STR_EQUAL(Tcl_GetVar(fbinterp, "CloseWindow", 0), "close")) {
-           printf("Close Window event\n");
-           Tcl_Eval(fbinterp, "destroy .");
-       }
-       bu_exit(0, NULL);
-    } else {
-       /* child */
-       printf("IMA CHILD\n");
-       fflush(stdout);
-    }
-
-    return 0;
-}
-
-HIDDEN struct fb_platform_specific *
-tk_get_fbps(uint32_t UNUSED(magic))
-{
-        return NULL;
-}
-
-
-HIDDEN void
-tk_put_fbps(struct fb_platform_specific *UNUSED(fbps))
-{
-        return;
-}
-
-HIDDEN int
-tk_open_existing(fb *UNUSED(ifp), int UNUSED(width), int UNUSED(height), 
struct fb_platform_specific *UNUSED(fb_p))
-{
-        return 0;
-}
-
-HIDDEN int
-tk_close_existing(fb *UNUSED(ifp))
-{
-        return 0;
-}
-
-HIDDEN int
-tk_configure_window(fb *UNUSED(ifp), int UNUSED(width), int UNUSED(height))
-{
-        return 0;
-}
-
-HIDDEN int
-tk_refresh(fb *UNUSED(ifp), int UNUSED(x), int UNUSED(y), int UNUSED(w), int 
UNUSED(h))
-{
-        return 0;
-}
-
-HIDDEN int
-fb_tk_close(fb *ifp)
-{
-    int y[2];
-    int ret;
-    y[0] = -1;
-    y[1] = 0;
-    printf("Entering fb_tk_close\n");
-    FB_CK_FB(ifp);
-    ret = write(p[1], y, sizeof(y));
-    close(p[1]);
-    printf("Sent write (ret=%d) from fb_tk_close\n", ret);
-    return 0;
-}
-
-
-HIDDEN int
-tk_clear(fb *ifp, unsigned char *pp)
-{
-    FB_CK_FB(ifp);
-    if (pp == 0)
-       fb_log("fb_clear(0x%lx, NULL)\n", (unsigned long)ifp);
-    else
-       fb_log("fb_clear(0x%lx, &[%d %d %d])\n",
-              (unsigned long)ifp,
-              (int)(pp[RED]), (int)(pp[GRN]),
-              (int)(pp[BLU]));
-    return 0;
-}
-
-
-HIDDEN ssize_t
-tk_read(fb *ifp, int x, int y, unsigned char *pixelp, size_t count)
-{
-    FB_CK_FB(ifp);
-    fb_log("fb_read(0x%lx, %4d, %4d, 0x%lx, %ld)\n",
-          (unsigned long)ifp, x, y,
-          (unsigned long)pixelp, (long)count);
-    return (ssize_t)count;
-}
-
-
-HIDDEN ssize_t
-tk_write(fb *ifp, int UNUSED(x), int y, const unsigned char *pixelp, size_t 
count)
-{
-    uint32_t line[3];
-
-    FB_CK_FB(ifp);
-    /* Set local values of Tk_PhotoImageBlock */
-    block.pixelPtr = (unsigned char *)pixelp;
-    block.width = count;
-    block.pitch = 3 * ifp->if_width;
-
-    /* Pack values to be sent to parent */
-    line[0] = htonl(y);
-    line[1] = htonl((long)count);
-    line[2] = 0;
-
-    memcpy(tkwrite_buffer, line, sizeof(uint32_t)*3);
-    memcpy(tkwrite_buffer+sizeof(uint32_t)*3, block.pixelPtr, 3 * 
ifp->if_width);
-
-    /* Send values and data to parent for display */
-    if (write(p[1], tkwrite_buffer, 3 * ifp->if_width + 3*sizeof(uint32_t)) == 
-1) {
-       perror("Unable to write to pipe");
-       bu_snooze(BU_SEC2USEC(1));
-    }
-
-    return (ssize_t)count;
-}
-
-
-HIDDEN int
-tk_rmap(fb *ifp, ColorMap *cmp)
-{
-    FB_CK_FB(ifp);
-    fb_log("fb_rmap(0x%lx, 0x%lx)\n",
-          (unsigned long)ifp, (unsigned long)cmp);
-    return 0;
-}
-
-
-HIDDEN int
-tk_wmap(fb *ifp, const ColorMap *cmp)
-{
-    int i;
-
-    FB_CK_FB(ifp);
-    if (cmp == NULL)
-       fb_log("fb_wmap(0x%lx, NULL)\n",
-              (unsigned long)ifp);
-    else
-       fb_log("fb_wmap(0x%lx, 0x%lx)\n",
-              (unsigned long)ifp, (unsigned long)cmp);
-
-    if (ifp->if_debug & FB_DEBUG_CMAP && cmp != NULL) {
-       for (i = 0; i < 256; i++) {
-           fb_log("%3d: [ 0x%4lx, 0x%4lx, 0x%4lx ]\n",
-                  i,
-                  (unsigned long)cmp->cm_red[i],
-                  (unsigned long)cmp->cm_green[i],
-                  (unsigned long)cmp->cm_blue[i]);
-       }
-    }
-
-    return 0;
-}
-
-
-HIDDEN int
-tk_view(fb *ifp, int xcenter, int ycenter, int xzoom, int yzoom)
-{
-    FB_CK_FB(ifp);
-    fb_log("fb_view(%p, %4d, %4d, %4d, %4d)\n",
-          (void *)ifp, xcenter, ycenter, xzoom, yzoom);
-    fb_sim_view(ifp, xcenter, ycenter, xzoom, yzoom);
-    return 0;
-}
-
-
-HIDDEN int
-tk_getview(fb *ifp, int *xcenter, int *ycenter, int *xzoom, int *yzoom)
-{
-    FB_CK_FB(ifp);
-    fb_log("fb_getview(%p, %p, %p, %p, %p)\n",
-          (void *)ifp, (void *)xcenter, (void *)ycenter, (void *)xzoom, (void 
*)yzoom);
-    fb_sim_getview(ifp, xcenter, ycenter, xzoom, yzoom);
-    fb_log(" <= %d %d %d %d\n",
-          *xcenter, *ycenter, *xzoom, *yzoom);
-    return 0;
-}
-
-
-HIDDEN int
-tk_setcursor(fb *ifp, const unsigned char *bits, int xbits, int ybits, int 
xorig, int yorig)
-{
-    FB_CK_FB(ifp);
-    fb_log("fb_setcursor(%p, %p, %d, %d, %d, %d)\n",
-          (void *)ifp, (void *)bits, xbits, ybits, xorig, yorig);
-    return 0;
-}
-
-
-HIDDEN int
-tk_cursor(fb *ifp, int mode, int x, int y)
-{
-    fb_log("fb_cursor(0x%lx, %d, %4d, %4d)\n",
-          (unsigned long)ifp, mode, x, y);
-    fb_sim_cursor(ifp, mode, x, y);
-    return 0;
-}
-
-
-HIDDEN int
-tk_getcursor(fb *ifp, int *mode, int *x, int *y)
-{
-    FB_CK_FB(ifp);
-    fb_log("fb_getcursor(%p, %p, %p, %p)\n",
-          (void *)ifp, (void *)mode, (void *)x, (void *)y);
-    fb_sim_getcursor(ifp, mode, x, y);
-    fb_log(" <= %d %d %d\n", *mode, *x, *y);
-    return 0;
-}
-
-
-HIDDEN int
-tk_readrect(fb *ifp, int xmin, int ymin, int width, int height, unsigned char 
*pp)
-{
-    FB_CK_FB(ifp);
-    fb_log("fb_readrect(0x%lx, (%4d, %4d), %4d, %4d, 0x%lx)\n",
-          (unsigned long)ifp, xmin, ymin, width, height,
-          (unsigned long)pp);
-    return width*height;
-}
-
-
-HIDDEN int
-tk_writerect(fb *ifp, int xmin, int ymin, int width, int height, const 
unsigned char *pp)
-{
-    FB_CK_FB(ifp);
-    fb_log("fb_writerect(0x%lx, %4d, %4d, %4d, %4d, 0x%lx)\n",
-          (unsigned long)ifp, xmin, ymin, width, height,
-          (unsigned long)pp);
-    return width*height;
-}
-
-
-HIDDEN int
-tk_bwreadrect(fb *ifp, int xmin, int ymin, int width, int height, unsigned 
char *pp)
-{
-    FB_CK_FB(ifp);
-    fb_log("fb_bwreadrect(0x%lx, (%4d, %4d), %4d, %4d, 0x%lx)\n",
-          (unsigned long)ifp, xmin, ymin, width, height,
-          (unsigned long)pp);
-    return width*height;
-}
-
-
-HIDDEN int
-tk_bwwriterect(fb *ifp, int xmin, int ymin, int width, int height, const 
unsigned char *pp)
-{
-    FB_CK_FB(ifp);
-    fb_log("fb_bwwriterect(0x%lx, %4d, %4d, %4d, %4d, 0x%lx)\n",
-          (unsigned long)ifp, xmin, ymin, width, height,
-          (unsigned long)pp);
-    return width*height;
-}
-
-
-HIDDEN int
-tk_poll(fb *ifp)
-{
-    FB_CK_FB(ifp);
-    while (Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT));
-    fb_log("fb_poll(0x%lx)\n", (unsigned long)ifp);
-    return 0;
-}
-
-
-HIDDEN int
-tk_flush(fb *ifp)
-{
-    FB_CK_FB(ifp);
-    fb_log("if_flush(0x%lx)\n", (unsigned long)ifp);
-    return 0;
-}
-
-
-HIDDEN int
-tk_free(fb *ifp)
-{
-    FB_CK_FB(ifp);
-    fb_log("fb_free(0x%lx)\n", (unsigned long)ifp);
-    return 0;
-}
-
-
-/*ARGSUSED*/
-HIDDEN int
-tk_help(fb *ifp)
-{
-    FB_CK_FB(ifp);
-    fb_log("Description: %s\n", tk_interface.if_type);
-    fb_log("Device: %s\n", ifp->if_name);
-    fb_log("Max width/height: %d %d\n",
-          tk_interface.if_max_width,
-          tk_interface.if_max_height);
-    fb_log("Default width/height: %d %d\n",
-          tk_interface.if_width,
-          tk_interface.if_height);
-    fb_log("\
-Usage: /dev/tk[#]\n\
-  where # is a optional bit vector from:\n\
-    1 debug buffered I/O calls\n\
-    2 show colormap entries in rmap/wmap calls\n\
-    4 show actual pixel values in read/write calls\n");
-    /*8 buffered read/write values - ifdef'd out*/
-
-    return 0;
-}
-
-/* This is the ONLY thing that we "export" */
-fb tk_interface = {
-    0,
-    FB_TK_MAGIC,
-    fb_tk_open,
-    tk_open_existing,
-    tk_close_existing,
-    tk_get_fbps,
-    tk_put_fbps,
-    fb_tk_close,
-    tk_clear,
-    tk_read,
-    tk_write,
-    tk_rmap,
-    tk_wmap,
-    tk_view,
-    tk_getview,
-    tk_setcursor,
-    tk_cursor,
-    tk_getcursor,
-    tk_readrect,
-    tk_writerect,
-    tk_bwreadrect,
-    tk_bwwriterect,
-    tk_configure_window,
-    tk_refresh,
-    tk_poll,
-    tk_flush,
-    tk_free,
-    tk_help,
-    "Debugging Interface",
-    FB_XMAXSCREEN,     /* max width */
-    FB_YMAXSCREEN,     /* max height */
-    "/dev/tk",
-    512,               /* current/default width */
-    512,               /* current/default height */
-    -1,                        /* select fd */
-    -1,                        /* file descriptor */
-    1, 1,              /* zoom */
-    256, 256,          /* window center */
-    0, 0, 0,           /* cursor */
-    PIXEL_NULL,                /* page_base */
-    PIXEL_NULL,                /* page_curp */
-    PIXEL_NULL,                /* page_endp */
-    -1,                        /* page_no */
-    0,                 /* page_ref */
-    0L,                        /* page_curpos */
-    0L,                        /* page_pixels */
-    0,                 /* debug */
-    0,                 /* refresh rate */
-    {0}, /* u1 */
-    {0}, /* u2 */
-    {0}, /* u3 */
-    {0}, /* u4 */
-    {0}, /* u5 */
-    {0}  /* u6 */
-};
-
-
-
-#else
-
-/* quell empty-compilation unit warnings */
-static const int unused = 0;
-
-#endif /* IF_TK */
-
-/*
- * Local Variables:
- * mode: C
- * tab-width: 8
- * indent-tabs-mode: t
- * c-file-style: "stroustrup"
- * End:
- * ex: shiftwidth=4 tabstop=8
- */

Copied: brlcad/branches/bioh/src/libfb/if_tk.cpp (from rev 75857, 
brlcad/trunk/src/libfb/if_tk.cpp)
===================================================================
--- brlcad/branches/bioh/src/libfb/if_tk.cpp                            (rev 0)
+++ brlcad/branches/bioh/src/libfb/if_tk.cpp    2020-05-21 00:44:47 UTC (rev 
75858)
@@ -0,0 +1,746 @@
+/*                         I F _ T K . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2007-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 libfb */
+/** @{ */
+/** @file if_tk.c
+ *
+ * Tk libfb interface.
+ *
+ */
+/** @} */
+
+#include "common.h"
+
+#ifdef IF_TK
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <tcl.h>
+#include <tk.h>
+
+
+#include "bio.h"
+#include "bnetwork.h"
+
+#include "bu/color.h"
+#include "bu/malloc.h"
+#include "bu/str.h"
+#include "bu/exit.h"
+#include "bu/log.h"
+#include "bu/snooze.h"
+
+#include "fb_private.h"
+#include "fb.h"
+
+#define TKINFO(ptr) ((struct tk_info *)((ptr)->u6.p))
+#define TKINFOL(ptr) (ptr)->u6.p
+
+struct tk_info {
+    Tcl_Interp *fbinterp;
+    Tk_Window fbwin;
+
+    // The rendering memory used to actually assemble the framebuffer contents.
+    long fb_buff_size;
+    unsigned char *fbpixel;
+
+    Tk_PhotoHandle fbphoto;
+    int draw;
+
+    Tcl_ThreadId parent_id;
+    Tcl_ThreadId fb_id;
+    int ready;
+    int shutdown;
+};
+
+TCL_DECLARE_MUTEX(drawMutex)
+
+TCL_DECLARE_MUTEX(fbthreadMutex)
+// Event container passed to routines triggered by events.
+struct FbEvent {
+    Tcl_Event event;            /* Must be first */
+    fb *ifp;
+};
+
+// Even for events where we don't intend to actually run a proc,
+// we need to tell Tcl it successfully processed them.  For that
+// we define a no-op callback proc.
+static int
+noop_proc(Tcl_Event *UNUSED(evPtr), int UNUSED(mask))
+{
+    // Return one to signify a successful completion of the process execution
+    return 1;
+}
+
+static void
+ImageUpdate(ClientData clientData)
+{
+    fb *ifp = (fb *)clientData;
+    struct tk_info *tki = TKINFO(ifp);
+
+    Tcl_MutexLock(&fbthreadMutex);
+    tki->draw = 0;
+    Tcl_MutexUnlock(&fbthreadMutex);
+
+    Tcl_MutexLock(&drawMutex);
+    Tk_PhotoImageBlock dm_data;
+    Tk_PhotoGetImage(tki->fbphoto, &dm_data);
+    dm_data.pixelPtr = tki->fbpixel;
+    Tk_PhotoPutBlock(tki->fbinterp, tki->fbphoto, &dm_data, 0, 0, 
dm_data.width, dm_data.height, TK_PHOTO_COMPOSITE_SET);
+    Tcl_MutexUnlock(&drawMutex);
+}
+
+static Tcl_ThreadCreateType
+fb_tk_run(ClientData clientData)
+{
+    fb *ifp = (fb *)clientData;
+    struct tk_info *tki = TKINFO(ifp);
+
+    tki->fbinterp = Tcl_CreateInterp();
+
+    if (Tcl_Init(tki->fbinterp) == TCL_ERROR) {
+       return;
+    }
+
+    if (Tcl_Eval(tki->fbinterp, "package require Tk") != TCL_OK) {
+               return;
+    }
+
+    tki->fbwin = Tk_MainWindow(tki->fbinterp);
+
+    Tk_GeometryRequest(tki->fbwin, ifp->if_width, ifp->if_height);
+
+    Tk_MakeWindowExist(tki->fbwin);
+
+    if (Tcl_Eval(tki->fbinterp, "wm resizable . 0 0") != TCL_OK) {
+       return;
+    }
+
+    if (Tcl_Eval(tki->fbinterp, "wm title . \"Frame buffer\"") != TCL_OK) {
+       return;
+    }
+
+    char frame_create_cmd[255] = {'\0'};
+    sprintf(frame_create_cmd, "pack [frame .fb -borderwidth 0 
-highlightthickness 0 -height %d -width %d]", ifp->if_width, ifp->if_height);
+    if (Tcl_Eval(tki->fbinterp, frame_create_cmd) != TCL_OK) {
+       return;
+    }
+
+    char canvas_create_cmd[255] = {'\0'};
+    sprintf(canvas_create_cmd, "pack [canvas .fb.canvas -borderwidth 0 
-highlightthickness 0 -insertborderwidth 0 -selectborderwidth 0 -height %d 
-width %d]", ifp->if_width, ifp->if_height);
+    if (Tcl_Eval(tki->fbinterp, canvas_create_cmd) != TCL_OK) {
+       return;
+    }
+
+    //const char canvas_pack_cmd[255] = "pack .fb_tk_canvas -fill both -expand 
true";
+    char image_create_cmd[255] = {'\0'};
+    sprintf(image_create_cmd, "image create photo .fb.canvas.photo -height %d 
-width %d", ifp->if_width, ifp->if_height);
+    if (Tcl_Eval(tki->fbinterp, image_create_cmd) != TCL_OK) {
+       return;
+    }
+
+    if ((tki->fbphoto = Tk_FindPhoto(tki->fbinterp, ".fb.canvas.photo")) == 
NULL) {
+       return;
+    }
+
+    const char place_image_cmd[255] = ".fb.canvas create image 0 0 -image 
.fb.canvas.photo -anchor nw";
+    if (Tcl_Eval(tki->fbinterp, place_image_cmd) != TCL_OK) {
+       return;
+    }
+
+    char reportcolorcmd[255] = {'\0'};
+    sprintf (reportcolorcmd, "bind . <Button-2> {puts \"At image (%%x, [expr 
%d - %%y]), real RGB = ([.fb.canvas.photo get %%x %%y])\n\"}", ifp->if_height);
+
+    /* Set our Tcl variable pertaining to whether a
+     * window closing event has been seen from the
+     * Window manager.  WM_DELETE_WINDOW will be
+     * bound to a command setting this variable to
+     * the string "close", and a vwait watching
+     * for a change to the CloseWindow variable ensures
+     * a "lingering" tk window.
+     */
+    Tcl_SetVar(tki->fbinterp, "CloseWindow", "open", 0);
+
+    const char *wmclosecmd = "wm protocol . WM_DELETE_WINDOW {set CloseWindow 
\"close\"}";
+    if (Tcl_Eval(tki->fbinterp, wmclosecmd) != TCL_OK) {
+       return;
+       fb_log("Error binding WM_DELETE_WINDOW.");
+    }
+
+    const char *bindclosecmd = "bind . <Button-3> {set CloseWindow \"close\"}";
+    if (Tcl_Eval(tki->fbinterp, bindclosecmd) != TCL_OK) {
+       return;
+    }
+    if (Tcl_Eval(tki->fbinterp, reportcolorcmd) != TCL_OK) {
+       return;
+    }
+
+    // Clear out any events up to this point
+    while (Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT));
+
+    tki->ready = 1;
+
+    while (!tki->shutdown) {
+
+       Tcl_DoOneEvent(0);
+
+       /* If the Tk window gets a close event, wrap up */
+       if (BU_STR_EQUAL(Tcl_GetVar(tki->fbinterp, "CloseWindow", 0), "close")) 
{
+           tki->shutdown = 1;
+           continue;
+       }
+
+       if (tki->draw) {
+           Tk_DoWhenIdle(ImageUpdate, (ClientData) ifp);
+       }
+    }
+
+    Tcl_Eval(tki->fbinterp, "destroy .");
+
+    // Let the parent thread know we're done
+    Tcl_MutexLock(&fbthreadMutex);
+    struct FbEvent *threadEventPtr = (struct FbEvent 
*)ckalloc(sizeof(FbEvent));
+    threadEventPtr->ifp = ifp;
+    threadEventPtr->event.proc = noop_proc;
+    Tcl_ThreadQueueEvent(tki->parent_id, (Tcl_Event *) threadEventPtr, 
TCL_QUEUE_TAIL);
+    Tcl_ThreadAlert(tki->parent_id);
+    Tcl_MutexUnlock(&fbthreadMutex);
+
+    Tcl_DeleteInterp(tki->fbinterp);
+
+    Tcl_ExitThread(TCL_OK);
+    TCL_THREAD_CREATE_RETURN;
+}
+
+
+HIDDEN int
+fb_tk_open(fb *ifp, const char *file, int width, int height)
+{
+    FB_CK_FB(ifp);
+    if (file == (char *)NULL)
+       fb_log("fb_open(0x%lx, NULL, %d, %d)\n",
+              (unsigned long)ifp, width, height);
+    else
+       fb_log("fb_open(0x%lx, \"%s\", %d, %d)\n",
+              (unsigned long)ifp, file, width, height);
+
+    /* check for default size */
+    if (width <= 0)
+       width = ifp->if_width;
+    if (height <= 0)
+       height = ifp->if_height;
+
+    /* set debug bit vector */
+    if (file != NULL) {
+       const char *cp;
+       for (cp = file; *cp != '\0' && !isdigit((unsigned char)*cp); cp++)
+           ;
+       sscanf(cp, "%d", &ifp->if_debug);
+    } else {
+       ifp->if_debug = 0;
+    }
+
+    /* Give the user whatever width was asked for */
+    ifp->if_width = width;
+    ifp->if_height = height;
+
+    /* Set up Tk specific info */
+    if ((TKINFOL(ifp) = (char *)calloc(1, sizeof(struct tk_info))) == NULL) {
+       fb_log("fb_tk_open:  tk_info malloc failed\n");
+       return -1;
+    }
+
+    struct tk_info *tki = TKINFO(ifp);
+    tki->shutdown = 0;
+    tki->ready = 0;
+    tki->draw = 0;
+
+    long b_size = ifp->if_width * ifp->if_height * 4;
+    tki->fbpixel = (unsigned char *)calloc(b_size+1, sizeof(char));
+
+    Tcl_MutexLock(&fbthreadMutex);
+    Tcl_ThreadId fbthreadID;
+    if (Tcl_CreateThread(&fbthreadID, fb_tk_run, (ClientData)ifp, 
TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE) != TCL_OK) {
+       fb_log("can't create fb thread\n");
+       return -1;
+    }
+    tki->fb_id = fbthreadID;
+    Tcl_MutexUnlock(&fbthreadMutex);
+
+#if 0
+    // Let the window finish setting up before open is considered done
+    while (!tki->ready) {
+       Tcl_Sleep(1);
+    }
+#endif
+
+    return 0;
+}
+
+HIDDEN struct fb_platform_specific *
+tk_get_fbps(uint32_t UNUSED(magic))
+{
+        return NULL;
+}
+
+
+HIDDEN void
+tk_put_fbps(struct fb_platform_specific *UNUSED(fbps))
+{
+        return;
+}
+
+HIDDEN int
+tk_open_existing(fb *UNUSED(ifp), int UNUSED(width), int UNUSED(height), 
struct fb_platform_specific *UNUSED(fb_p))
+{
+        return 0;
+}
+
+HIDDEN int
+tk_close_existing(fb *UNUSED(ifp))
+{
+        return 0;
+}
+
+HIDDEN int
+tk_configure_window(fb *UNUSED(ifp), int UNUSED(width), int UNUSED(height))
+{
+        return 0;
+}
+
+HIDDEN int
+tk_refresh(fb *UNUSED(ifp), int UNUSED(x), int UNUSED(y), int UNUSED(w), int 
UNUSED(h))
+{
+        return 0;
+}
+
+HIDDEN int
+fb_tk_close(fb *ifp)
+{
+    FB_CK_FB(ifp);
+    struct tk_info *tki = TKINFO(ifp);
+
+    // Make a local interp so we can get events from the window
+    Tcl_Interp *cinterp = Tcl_CreateInterp();
+
+    // Let the window know who to tell when it's time to shut down
+    tki->parent_id = Tcl_GetCurrentThread();
+
+    while (!tki->shutdown) {
+       Tcl_DoOneEvent(0);
+       if (tki->shutdown) {
+           int tret;
+           Tcl_DeleteInterp(cinterp);
+           Tcl_JoinThread(tki->fb_id, &tret);
+           if (tret != TCL_OK) {
+               printf("shutdown of thread failed\n");
+               return -1;
+           }
+
+           bu_free(tki->fbpixel, "fbpixel");
+           bu_free(tki, "tkinfo");
+           return 0;
+       }
+    }
+
+    // Just in case shutdown got set before fb_tk_close was ever
+    // called, be prepared to clean up outside the loop as well.
+    int tret;
+    Tcl_DeleteInterp(cinterp);
+    Tcl_JoinThread(tki->fb_id, &tret);
+    if (tret != TCL_OK) {
+       printf("shutdown of thread failed\n");
+       return -1;
+    }
+    bu_free(tki->fbpixel, "fbpixel");
+    bu_free(tki, "tkinfo");
+
+    return 0;
+}
+
+
+HIDDEN int
+tk_clear(fb *ifp, unsigned char *pp)
+{
+    FB_CK_FB(ifp);
+    if (pp == 0)
+       fb_log("fb_clear(0x%lx, NULL)\n", (unsigned long)ifp);
+    else
+       fb_log("fb_clear(0x%lx, &[%d %d %d])\n",
+              (unsigned long)ifp,
+              (int)(pp[RED]), (int)(pp[GRN]),
+              (int)(pp[BLU]));
+    return 0;
+}
+
+
+HIDDEN ssize_t
+tk_read(fb *ifp, int x, int y, unsigned char *pixelp, size_t count)
+{
+    FB_CK_FB(ifp);
+    fb_log("fb_read(0x%lx, %4d, %4d, 0x%lx, %ld)\n",
+          (unsigned long)ifp, x, y,
+          (unsigned long)pixelp, (long)count);
+    return (ssize_t)count;
+}
+
+// Given an X,Y coordinate in a TkPhoto image and a desired offset in
+// X and Y, return the index value into the pixelPtr array N such that
+// N is the integer value of the R color at that X,Y coordiante, N+1
+// is the G value, N+2 is the B value and N+3 is the Alpha value.
+// If either desired offset is beyond the width and height boundaries,
+// cap the return at the minimum/maximum allowed value.
+static int
+img_xy_index(int width, int height, int x, int y, int dx, int dy)
+{
+    int nx = ((x + dx) > width)  ? width  : ((x + dx) < 0) ? 0 : x + dx;
+    int ny = ((y + dy) > height) ? height : ((y + dy) < 0) ? 0 : y + dy;
+    return (ny * width * 4) + nx * 4;
+}
+
+HIDDEN ssize_t
+tk_write(fb *ifp, int x, int y, const unsigned char *pixelp, size_t count)
+{
+    FB_CK_FB(ifp);
+
+    struct tk_info *tki = TKINFO(ifp);
+
+#if 0
+    // If the shutdown flag got set and we're still processing, bail
+    // (TODO - is this the right thing to do?  We're rendering to a framebuffer
+    // that's not there anymore, so if we don't do this the process is arguably
+    // a zombie, but maybe it's desirable to keep going in some situations ...)
+    if (tki->shutdown) {
+       bu_exit(0, "Quitting - framebuffer shutdown flag found set during 
tk_write");
+    }
+#endif
+
+    int pindex = img_xy_index(ifp->if_width, ifp->if_height, x, 
ifp->if_height-y-1, 0, 0);
+
+    // Touching the image buffer - lock drawing mutex
+    Tcl_MutexLock(&drawMutex);
+
+    // TkPhoto uses an alpha channel, but at the moment the incoming pix data 
doesn't.
+    // Write pixels accordingly, setting alpha to opaque (for now)
+    for (size_t i = 0; i < count; i++) {
+       tki->fbpixel[pindex+i*4] = pixelp[i*3];
+       tki->fbpixel[pindex+(i*4+1)] = pixelp[i*3+1];
+       tki->fbpixel[pindex+(i*4+2)] = pixelp[i*3+2];
+       tki->fbpixel[pindex+(i*4+3)] = 255;
+    }
+
+    // Lock the drawing thread - we have updated image data, and want to make 
sure
+    // the drawing thread doesn't clear anything in the middle of this block.
+    Tcl_MutexLock(&fbthreadMutex);
+    tki->draw = 1;
+
+    struct FbEvent *threadEventPtr = (struct FbEvent 
*)ckalloc(sizeof(FbEvent));
+    threadEventPtr->ifp = ifp;
+    threadEventPtr->event.proc = noop_proc;
+    Tcl_ThreadQueueEvent(tki->fb_id, (Tcl_Event *) threadEventPtr, 
TCL_QUEUE_TAIL);
+    Tcl_ThreadAlert(tki->fb_id);
+
+    // Flag set, event queued, drawing done - unlock everything
+    Tcl_MutexUnlock(&fbthreadMutex);
+    Tcl_MutexUnlock(&drawMutex);
+
+    return (ssize_t)count;
+}
+
+
+HIDDEN int
+tk_rmap(fb *ifp, ColorMap *cmp)
+{
+    FB_CK_FB(ifp);
+    fb_log("fb_rmap(0x%lx, 0x%lx)\n",
+          (unsigned long)ifp, (unsigned long)cmp);
+    return 0;
+}
+
+
+HIDDEN int
+tk_wmap(fb *ifp, const ColorMap *cmp)
+{
+    int i;
+
+    FB_CK_FB(ifp);
+    if (cmp == NULL)
+       fb_log("fb_wmap(0x%lx, NULL)\n",
+              (unsigned long)ifp);
+    else
+       fb_log("fb_wmap(0x%lx, 0x%lx)\n",
+              (unsigned long)ifp, (unsigned long)cmp);
+
+    if (ifp->if_debug & FB_DEBUG_CMAP && cmp != NULL) {
+       for (i = 0; i < 256; i++) {
+           fb_log("%3d: [ 0x%4lx, 0x%4lx, 0x%4lx ]\n",
+                  i,
+                  (unsigned long)cmp->cm_red[i],
+                  (unsigned long)cmp->cm_green[i],
+                  (unsigned long)cmp->cm_blue[i]);
+       }
+    }
+
+    return 0;
+}
+
+
+HIDDEN int
+tk_view(fb *ifp, int xcenter, int ycenter, int xzoom, int yzoom)
+{
+    FB_CK_FB(ifp);
+    fb_log("fb_view(%p, %4d, %4d, %4d, %4d)\n",
+          (void *)ifp, xcenter, ycenter, xzoom, yzoom);
+    fb_sim_view(ifp, xcenter, ycenter, xzoom, yzoom);
+    return 0;
+}
+
+
+HIDDEN int
+tk_getview(fb *ifp, int *xcenter, int *ycenter, int *xzoom, int *yzoom)
+{
+    FB_CK_FB(ifp);
+    fb_log("fb_getview(%p, %p, %p, %p, %p)\n",
+          (void *)ifp, (void *)xcenter, (void *)ycenter, (void *)xzoom, (void 
*)yzoom);
+    fb_sim_getview(ifp, xcenter, ycenter, xzoom, yzoom);
+    fb_log(" <= %d %d %d %d\n",
+          *xcenter, *ycenter, *xzoom, *yzoom);
+    return 0;
+}
+
+
+HIDDEN int
+tk_setcursor(fb *ifp, const unsigned char *bits, int xbits, int ybits, int 
xorig, int yorig)
+{
+    FB_CK_FB(ifp);
+    fb_log("fb_setcursor(%p, %p, %d, %d, %d, %d)\n",
+          (void *)ifp, (void *)bits, xbits, ybits, xorig, yorig);
+    return 0;
+}
+
+
+HIDDEN int
+tk_cursor(fb *ifp, int mode, int x, int y)
+{
+    fb_log("fb_cursor(0x%lx, %d, %4d, %4d)\n",
+          (unsigned long)ifp, mode, x, y);
+    fb_sim_cursor(ifp, mode, x, y);
+    return 0;
+}
+
+
+HIDDEN int
+tk_getcursor(fb *ifp, int *mode, int *x, int *y)
+{
+    FB_CK_FB(ifp);
+    fb_log("fb_getcursor(%p, %p, %p, %p)\n",
+          (void *)ifp, (void *)mode, (void *)x, (void *)y);
+    fb_sim_getcursor(ifp, mode, x, y);
+    fb_log(" <= %d %d %d\n", *mode, *x, *y);
+    return 0;
+}
+
+
+HIDDEN int
+tk_readrect(fb *ifp, int xmin, int ymin, int width, int height, unsigned char 
*pp)
+{
+    FB_CK_FB(ifp);
+    fb_log("fb_readrect(0x%lx, (%4d, %4d), %4d, %4d, 0x%lx)\n",
+          (unsigned long)ifp, xmin, ymin, width, height,
+          (unsigned long)pp);
+    return width*height;
+}
+
+
+HIDDEN int
+tk_writerect(fb *ifp, int xmin, int ymin, int width, int height, const 
unsigned char *pp)
+{
+    FB_CK_FB(ifp);
+    fb_log("fb_writerect(0x%lx, %4d, %4d, %4d, %4d, 0x%lx)\n",
+          (unsigned long)ifp, xmin, ymin, width, height,
+          (unsigned long)pp);
+    return width*height;
+}
+
+
+HIDDEN int
+tk_bwreadrect(fb *ifp, int xmin, int ymin, int width, int height, unsigned 
char *pp)
+{
+    FB_CK_FB(ifp);
+    fb_log("fb_bwreadrect(0x%lx, (%4d, %4d), %4d, %4d, 0x%lx)\n",
+          (unsigned long)ifp, xmin, ymin, width, height,
+          (unsigned long)pp);
+    return width*height;
+}
+
+
+HIDDEN int
+tk_bwwriterect(fb *ifp, int xmin, int ymin, int width, int height, const 
unsigned char *pp)
+{
+    FB_CK_FB(ifp);
+    fb_log("fb_bwwriterect(0x%lx, %4d, %4d, %4d, %4d, 0x%lx)\n",
+          (unsigned long)ifp, xmin, ymin, width, height,
+          (unsigned long)pp);
+    return width*height;
+}
+
+
+HIDDEN int
+tk_poll(fb *ifp)
+{
+    FB_CK_FB(ifp);
+    while (Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT));
+    fb_log("fb_poll(0x%lx)\n", (unsigned long)ifp);
+    return 0;
+}
+
+
+HIDDEN int
+tk_flush(fb *ifp)
+{
+    FB_CK_FB(ifp);
+    struct tk_info *tki = TKINFO(ifp);
+
+    Tcl_MutexLock(&drawMutex);
+    tki->draw = 1;
+    Tcl_MutexLock(&fbthreadMutex);
+    struct FbEvent *threadEventPtr = (struct FbEvent 
*)ckalloc(sizeof(FbEvent));
+    threadEventPtr->ifp = ifp;
+    threadEventPtr->event.proc = noop_proc;
+    Tcl_ThreadQueueEvent(tki->fb_id, (Tcl_Event *) threadEventPtr, 
TCL_QUEUE_TAIL);
+    Tcl_ThreadAlert(tki->fb_id);
+    Tcl_MutexUnlock(&fbthreadMutex);
+    Tcl_MutexUnlock(&drawMutex);
+

@@ Diff output truncated at 100000 characters. @@
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