tclxosd

What: tclxosd
Where: http://sourceforge.net/projects/tclxosd/ 
       http://www.ignavus.net/software.html 
Description: Tcl bindings for libxosd (On Screen Display)
Updated: 14/02/2009
Contact: See in tclxosd package

AMG: I like the configure script. ;^) It starts out as a shell script then transforms into a Tcl script. Here's an excerpt:

#!/bin/sh
# \
TCL_NAME=tclsh;\
FIND_PATH=`echo -n $PATH | sed 's|:| |g' | tail -n 1`; \
TCL_SHELL=`find $FIND_PATH -name $TCL_NAME -ignore_readdir_race`
#\
echo -n "checking for tclsh... "
# ... *snip* ...\
# give control to tclsh\
exec tclsh "$0" "$@"
puts -nonewline "cheking for libdl... "

kdl: This is my first extension for Tcl, so not be very strict. Configure script is liked me too :), but it is not versatile, I think. Any suggestions are wellcome. I have a question about interface - in version 0.1 of tclxosd we have:

set osd [xosd::create]
xosd::display $osd 0 XOSD_string {text to display}

Would it better to make "osd-command" (as in image) ?:

xosd::create osd1
$osd1 set_align XOSD_left
$osd1 display 0 XOSD_string {text to display}

AMG: It's up to you. Both approaches are widely used in extensions and the Tcl core. I guess it comes down to whether you prefer to put the subject before or after the verb. :^)

However, I do recommend against having xosd::create write the command name into a variable. Instead have it return the command name. Let the caller worry about writing it into a variable with set. You could make it take the name of the command to create, but if you do, please make it an optional argument. If a name is not supplied, have it pick a unique name.

Hey, I have a question. Why do all the "enumerated" options have XOSD_ prefixes? This isn't C; there is no reason to worry about symbolic constants polluting the namespace. I suggest dropping them or making them optional.

kdl: Thank you for observations, Andy. XOSD_ prefixes leaved in extension for compatibility with libxosd syntax, maybe for somebody this more clearly. Perhaps, separation of commands will be good solution:

xosd::set_pos_top $osd
xosd::set_align_center $osd
xosd::display_string $osd $line_number {text to display}
xosd::display_slider $osd $line_number 60

AMG: I've been trying to get it to work on Mac OS X, but I haven't had much luck. First I had to compile and install Tcl 8.6b1. That went alright. I also got xosd installed without a problem; all I needed to do was take xmms_plugin out of SUBDIRS in the makefile. But tclxosd... to get it to compile, I needed to make many changes to the configure script. I removed -ignore_readdir_race from and added | head -n1 to the find invocation, since Tcl 8.4 was already installed in /usr/bin, and now I have two programs called tclsh in my path. I removed all the /sbin/ldconfig-based library checking, since ldconfig isn't available on Mac OS X. And I replaced -shared with -dynamiclib -install_name ~/Library/Tcl/tclxosd/tclxosd.dynlib. Then I modified src/makefile to produce tclxosd.dynlib instead of tclxosd.so, and I edited pkgIndex.tcl to match.

After all that, it segfaults on xosd::create. Actually, as far as I can tell, it segfaults before TclXOSD_create() is called, but after I issue the xosd::create command. Maybe the problem is in Tcl itself. Here's the backtrace from gdb:

% package require tclxosd
Reading symbols for shared libraries .......... done
0.1
% xosd::create 1

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0xef0200ec
0xef0200ec in ?? ()
(gdb) ba
#0  0xef0200ec in ?? ()
Cannot access memory at address 0xef0200ec
Cannot access memory at address 0xef0200ec
Cannot access memory at address 0xef0200ec
Cannot access memory at address 0xef0200ec
Cannot access memory at address 0xef0200ec
#1  0x0a00ebe4 in TclNRRunCallbacks ()
Cannot access memory at address 0xef0200ec
Cannot access memory at address 0xef0200ec
Cannot access memory at address 0xef0200ec
Cannot access memory at address 0xef0200ec
Cannot access memory at address 0xef0200ec
#2  0x0a055820 in TclStackAlloc ()
Cannot access memory at address 0xef0200ec
#3  0x0a00ebe4 in TclNRRunCallbacks ()
#4  0x0a06300c in Tcl_RecordAndEvalObj ()
#5  0x0a0835d0 in Tcl_Main ()
#6  0x00003f90 in ?? ()
#7  0x00003b98 in ?? ()
#8  0x0000389c in ?? ()
(gdb)

I can set a breakpoint on Tclxosd_Init() and it will trigger when I load the library. But if I set a breakpoint on TclXOSD_create(), it never triggers. How odd.

Running osd_cat works just fine, so long as I have an X server running and I use -f to specify a good font.

Hey, I'm a little worried about the way you convert between an xosd* and an integer. This exposes your extension to segfaults and other nasty security issues. It's better to maintain an internal table mapping between tokens and xosd* values. Have a separate instance of this table for each interp. Actually, you were wondering about changing over to a "subject verb" approach, where xosd::create makes a command. Just set the ClientData of the generated command to be the xosd* value or to a struct wrapper thereof. This way Tcl maintains the mapping table for you, and it's automatically interp-local.

If you make that change, consider also changing the commands around to be a bit more "Tclish". Here's an example:

% set osd [xosd::create 3]
xosd1
% $osd lines
3
% $osd onscreen
0
% $osd show
% $osd hide
% $osd position top left
top left
% $osd offset 3 3
3 3
% $osd shadow 2 black
2 black
% $osd outline 1 white
1 white
% $osd color green
green
% $osd timeout 5
5
% $osd text 0 foobar ;# Displays a string on line 0
% $osd percent 1 50  ;# Displays a percentage on line 1
% $osd slider 2 50   ;# Displays a slider on line 2
% $osd wait
% $osd destroy
% # Be sure to also support [rename $osd ""] by setting a deleteProc!

You will need to wrap the xosd* in a struct so that you can keep track of the values you passed to the xosd_set_*() functions for which there are no corresponding xosd_get_*() functions. My example doesn't show it, but I suggest making the arguments optional for most of these subcommands, so that they can be used to query without modifying.

I see that xosd has many undocumented functions that are used by osd_cat. Have a look.

kdl: Wow, Thank you, Andy, for very detailed remarks. I will try to fix this problems and take your advises into consideration. Thanks a lot again.


kdl: New version 0.20 was written. Now syntax looks like above. Configure script was modified, but I think package still not portable (tested only under Linux). Man page appeared in this version. Some examples was added in doc/examples directory.

AMG: Bah, it still dies on my Mac OS X system. But I'm pretty sure the problem is with the way I configured and installed Tcl. It panics with "alloc: invalid block: 0xa1a6b74: 0 0 0", and the (partial) backtrace is:

#0  0x90047dac in kill ()
#1  0x9012d7b4 in abort ()
#2  0x9b44a310 in Tcl_PanicVA ()
#3  0x9b44a32c in Tcl_Panic ()
#4  0x9b457f10 in Ptr2Block ()
#5  0x9b457974 in TclpFree ()
#6  0x9b448a88 in Tcl_InvalidateStringRep ()
#7  0x9b4561cc in Tcl_SetStringObj ()
#8  0x0026d344 in TclXOSD_create ()
#9  0x0a01addc in NRRunObjProc (data=0x21dac, interp=0x10c10, result=0) at /Users/andy/projects/tcl8.6b1/generic/tclBasic.c:4303

Very curious--- I have Tcl compiled with --enable-symbols, and I get good line numbers for all stack frames above #8, but nothing below. What could be going on?

To get it to compile, I had to replace -ltclstub8.6 with -ltcl. Wonder why the stubs library isn't working...

Oh well, the man page looks really nice. :^)