Version 1 of 3D Text for Tk in Unix

Updated 2002-06-19 00:24:05

GPS Tue Jun 18, 2002: The following code makes all text in Tk 3D. It only works in Unix, but the concept could be ported to Windows. It passes all ANSI-C tests with gcc 2.95.3. I tested it with OpenBSD 3.0 x86.

You can compile it with: cc -ansi -Wall -W -pedantic -pedantic-errors -I/usr/local/include -I/usr/X11R6/include -L/usr/local/lib -L/usr/X11R6/lib -lX11 -lm -ltcl83 -ltk83 3D_Tk_Text.c

It comes with an example built in that looks like this: http://www.xmission.com/~georgeps/3D_Tk_Text.png

I'd appreciate any comments on this.


  #include <stdio.h>
  #include <stdlib.h>
  #include <dlfcn.h>
  #include <tcl.h>
  #include <tk.h>
  #include <X11/X.h>
  #include <X11/Xlib.h>

  GC lightGC;
  GC darkGC;

  /*Make these typedefs because ANSI forbids assignment between function pointer and `void *' */
  typedef int (*oldXDrawText) (Display *dis, Drawable drawable, GC gc, int x, int y, XTextItem *item, int nItems);
  typedef int (*oldXDrawText16) (Display *dis, Drawable drawable, GC gc, int x, int y, XTextItem16 *item, int nItems);
  typedef int (*oldXDrawString) (Display *dis, Drawable drawable, GC gc, int x, int y, _Xconst char *string, int length);
  typedef int (*oldXDrawString16) (Display *dis, Drawable drawable, GC gc, int x, int y, _Xconst XChar2b *string, int length);

  oldXDrawText oldXDrawTextPtr;
  oldXDrawText16 oldXDrawText16Ptr;
  oldXDrawString oldXDrawStringPtr;
  oldXDrawString16 oldXDrawString16Ptr;

  int XDrawText (Display *dis, Drawable drawable, GC gc, int x, int y, XTextItem *item, int nItems) {
    XCopyGC (dis, gc, GCFont, lightGC);
    XCopyGC (dis, gc, GCFont, darkGC);

    (*oldXDrawTextPtr) (dis, drawable, lightGC, x - 1, y - 1, item, nItems);
    (*oldXDrawTextPtr) (dis, drawable, darkGC, x + 1, y + 1, item, nItems);
    return (*oldXDrawTextPtr) (dis, drawable, lightGC, x, y, item, nItems);
  }

  int XDrawText16 (Display *dis, Drawable drawable, GC gc, int x, int y, XTextItem16 *item, int nItems) {
    XCopyGC (dis, gc, GCFont, lightGC);
    XCopyGC (dis, gc, GCFont, darkGC);

    (*oldXDrawText16Ptr) (dis, drawable, lightGC, x - 1, y - 1, item, nItems);
    (*oldXDrawText16Ptr) (dis, drawable, darkGC, x + 1, y + 1, item, nItems);
    return (*oldXDrawText16Ptr) (dis, drawable, gc, x, y, item, nItems);
  }

  int XDrawString (Display *dis, Drawable drawable, GC gc, int x, int y, _Xconst char *string, int length) {
    XCopyGC (dis, gc, GCFont, lightGC);
    XCopyGC (dis, gc, GCFont, darkGC);

    (*oldXDrawStringPtr) (dis, drawable, lightGC, x - 1, y - 1, string, length);
    (*oldXDrawStringPtr) (dis, drawable, darkGC, x + 1, y + 1, string, length);
    return (*oldXDrawStringPtr) (dis, drawable, gc, x, y, string, length);
  }

  int XDrawString16 (Display *dis, Drawable drawable, GC gc, int x, int y, _Xconst XChar2b *string, int length) {
    XCopyGC (dis, gc, GCFont, lightGC);
    XCopyGC (dis, gc, GCFont, darkGC);

    (*oldXDrawString16Ptr) (dis, drawable, lightGC, x - 1, y - 1, string, length);
    (*oldXDrawString16Ptr) (dis, drawable, darkGC, x + 1, y + 1, string, length);
    return (*oldXDrawString16Ptr) (dis, drawable, gc, x, y, string, length);
  }

  int main (int argc, char *argv[]) {
    Tcl_Interp *interp;
    char evalStr[] = {
      "option add *font -*-lucida-medium-*-*-*-14-*-*-*-*-*-*-*;"
      "option add *Text.background white;"
      "option add *Text.foreground black;"
      "pack [frame .f] -side top -fill x;" 
      "pack [button .f.b -text {Hello World}] -side left;" 
      "pack [entry .f.e] -side left;"
      "pack [label .f.l -text {Sample Text}] -side left;"
      "pack [text .t] -side top -fill both;"
    };
    void *libHandle;

    Tk_Window tkwin;
    Window xWin;
    Display *dis;
    Colormap colormap;
    XColor xLightColor;
    char lightColor[] = "gray90";
    XColor xDarkColor;
    char darkColor[] = "gray30";
    int nScreen;


    Tcl_FindExecutable (argv[0]);
    interp = Tcl_CreateInterp ();

    if (Tcl_Init (interp) != TCL_OK) {
      fprintf (stderr, "Tcl_Init error %s", Tcl_GetStringResult (interp));
      exit (1);
    }

    if (Tk_Init (interp) != TCL_OK) {
      fprintf (stderr, "Tk_Init error %s", Tcl_GetStringResult (interp));
      exit (1);
    }

    tkwin = Tk_MainWindow (interp);
    dis = Tk_Display (tkwin);

    nScreen = DefaultScreen (dis);
    colormap = DefaultColormap (dis, nScreen);

    Tk_MakeWindowExist (tkwin);
    xWin = Tk_WindowId (tkwin);

    lightGC = XCreateGC (dis, xWin, 0, 0);
    darkGC = XCreateGC (dis, xWin, 0, 0);


    XParseColor (dis, colormap, lightColor, &xLightColor);
    XAllocColor (dis, colormap, &xLightColor);
    XSetForeground (dis, lightGC, xLightColor.pixel);

    XParseColor (dis, colormap, darkColor, &xDarkColor);
    XAllocColor (dis, colormap, &xDarkColor);
    XSetForeground (dis, darkGC, xDarkColor.pixel);

    libHandle = dlopen ("/usr/X11R6/lib/libX11.so.6.2", RTLD_LAZY);
    fprintf (stderr, "dlopen %s\n", dlerror ());

    oldXDrawTextPtr = (oldXDrawText) dlsym (libHandle, "_XDrawText");
    fprintf (stderr, "dlsym %s\n", dlerror ());

    oldXDrawText16Ptr = (oldXDrawText16) dlsym (libHandle, "_XDrawText16");
    fprintf (stderr, "dlsym %s\n", dlerror ());

    oldXDrawStringPtr = (oldXDrawString) dlsym (libHandle, "_XDrawString");
    fprintf (stderr, "dlsym %s\n", dlerror ());

    oldXDrawString16Ptr = (oldXDrawString16) dlsym (libHandle, "_XDrawString16");
    fprintf (stderr, "dlsym %s\n", dlerror ());

    if (Tcl_Eval (interp, evalStr) != TCL_OK) {
      fprintf (stderr, "error %s\n", Tcl_GetStringResult (interp));
    }
    Tk_MainLoop ();

    return 0;
  }