#!/bin/ksh
#
# Draw a fractal with the GTK-server and KornShell.
#
# All right, so it is not fast. All right, it is useless.
# So why did I create it? Just to see if it was possible.
# That's all.
#
# On my AMD2000+ machine it takes approx. 7 minutes to
# draw the fractal.
#
# Developed with ksh (AT&T Korn Shell 93) on Slackware Linux.
#
# Codesample. July 25, 2005 - PvE.
#
#------------------------------------------------------- GTK stuff
# Communication function; $1 contains the string to be sent
function GTK
{
print -p $1
read -p RESULT
}
#-------------------------------------------------------
# The core calculation routine was taken from
# http://www.cygnus-software.com/theory/theory.htm
# and translated to KornShell by me.
# With friendly permission of Cygnus-Software.
function Draw_Fractal
{
integer MaxIters=100
integer SIZE=240
integer BLACK=-1
typeset -F LEFT=-2.0 RIGHT=1.0
typeset -F TOP=1.0 BOTTOM=-1.0
typeset -F ZR ZI CR CI RSQUARED ISQUARED
typeset -i INDEX
# Tell drawing is starting
GTK "gdk_color_parse #000000 $COLOR"
GTK "gdk_gc_set_rgb_fg_color $GC $COLOR"
GTK "gdk_draw_layout $PIX $GC 10 240 $START"
GTK "gtk_widget_queue_draw $IMAGE"
GTK "gtk_server_callback update"
# The calculation
integer Y=0
while [[ $Y -lt $SIZE ]]
do
integer X=0
while [[ $X -lt $SIZE ]]
do
ZR=0.0
ZI=0.0
let CR=$LEFT+$X*($RIGHT-1*$LEFT)/$SIZE
let CI=$TOP+$Y*($BOTTOM-$TOP)/$SIZE
let RSQUARED=$ZR*$ZR
let ISQUARED=$ZI*$ZI
integer COUNT=0
while [[ $RSQUARED+$ISQUARED -lt 2.0 && $COUNT -lt $MaxIters ]]
do
let ZI=$ZR*$ZI*2.0
let ZI=$ZI+$CI
let ZR=$RSQUARED-$ISQUARED
let ZR=$ZR+$CR
let RSQUARED=$ZR*$ZR
let ISQUARED=$ZI*$ZI
((COUNT+=1))
done
let SUM=$RSQUARED+$ISQUARED
if [[ $SUM -lt 2.0 ]]
then
if [[ $SUM -lt 1.0 ]]
then
let INDEX=$SUM*16
else
INDEX=15
fi
GTK "gdk_color_parse ${PICOL[$INDEX]} $COLOR"
GTK "gdk_gc_set_rgb_fg_color $GC $COLOR"
GTK "gdk_draw_point $PIX $GC $X $Y"
GTK "gtk_server_callback update"
if [[ $RESULT = $EXIT_BUTTON || $RESULT = $WIN ]]
then
GTK "gtk_exit 0"
exit
fi
fi
((X+=1))
done
GTK "gtk_widget_queue_draw $IMAGE"
GTK "gtk_server_callback update"
((Y+=1))
done
# Wipe wait text
GTK "gdk_color_parse #ffffff $COLOR"
GTK "gdk_gc_set_rgb_fg_color $GC $COLOR"
GTK "gdk_draw_rectangle $PIX $GC 1 10 240 120 25"
# Tell drawing is ready
GTK "gdk_color_parse #000000 $COLOR"
GTK "gdk_gc_set_rgb_fg_color $GC $COLOR"
GTK "gdk_draw_layout $PIX $GC 10 240 $READY"
GTK "gtk_widget_queue_draw $IMAGE"
GTK "gtk_server_callback update"
}
#-------------------------------------------------------
# Setup environment for GTK server
export LC_ALL=C
export LD_LIBRARY_PATH=/usr/X11R6/lib
# Define array with colors - taken from the
# newLisp HTML fractal example
PICOL[0]="#800000"
PICOL[1]="#800080"
PICOL[2]="#8000FF"
PICOL[3]="#808000"
PICOL[4]="#808080"
PICOL[5]="#8080FF"
PICOL[6]="#80FF00"
PICOL[7]="#80FF80"
PICOL[8]="#80FFFF"
PICOL[9]="#FF0000"
PICOL[10]="#FF0080"
PICOL[11]="#FF00FF"
PICOL[12]="#FF8000"
PICOL[13]="#FF8080"
PICOL[14]="#FF80FF"
PICOL[15]="#FFFF00"
# Start GTK-server in STDIN mode
gtk-server stdin |&
# Check GTK version
GTK "gtk_check_version 2 4 0"
if [[ -n $RESULT ]]
then
echo "Your GTK installation is too old!"
echo "GTK version 2.4.0 or higher is required. Exiting..."
GTK "gtk_exit 0"
exit 1
fi
# Window
GTK "gtk_init NULL NULL"
GTK "gtk_window_new 0"
WIN=$RESULT
GTK "gtk_window_set_title $WIN \"KornShell with GTK-server\""
GTK "gtk_widget_set_size_request $WIN 300 300"
GTK "gtk_window_set_position $WIN 1"
GTK "gtk_window_set_resizable $WIN 0"
# Create widget to display image
GTK "gtk_image_new"
IMAGE=$RESULT
# Create eventbox to catch mouseclick
GTK "gtk_event_box_new"
EBOX=$RESULT
GTK "gtk_container_add $EBOX $IMAGE"
# Separator
GTK "gtk_hseparator_new"
SEP=$RESULT
# Action button
GTK "gtk_button_new_with_label Draw!"
ACTION_BUTTON=$RESULT
GTK "gtk_widget_set_size_request $ACTION_BUTTON 75 30"
# Clear button
GTK "gtk_button_new_with_label Clear"
CLEAR_BUTTON=$RESULT
GTK "gtk_widget_set_size_request $CLEAR_BUTTON 75 30"
# Exit button
GTK "gtk_button_new_with_label Exit"
EXIT_BUTTON=$RESULT
GTK "gtk_widget_set_size_request $EXIT_BUTTON 75 30"
# Now arrange widgets on window using boxes
GTK "gtk_hbox_new 0 0"
HBOX=$RESULT
GTK "gtk_box_pack_start $HBOX $CLEAR_BUTTON 0 0 1"
GTK "gtk_box_pack_start $HBOX $ACTION_BUTTON 0 0 1"
GTK "gtk_box_pack_end $HBOX $EXIT_BUTTON 0 0 1"
GTK "gtk_vbox_new 0 0"
VBOX=$RESULT
GTK "gtk_box_pack_start $VBOX $EBOX 0 0 1"
GTK "gtk_box_pack_start $VBOX $SEP 0 0 1"
GTK "gtk_box_pack_end $VBOX $HBOX 0 0 1"
GTK "gtk_container_add $WIN $VBOX"
# Show all widgets
GTK "gtk_widget_show_all $WIN"
# Create the pixmap
GTK "gtk_widget_get_parent_window $IMAGE"
GDKWIN=$RESULT
GTK "gdk_pixmap_new $GDKWIN 300 265 -1"
PIX=$RESULT
GTK "gdk_gc_new $PIX"
GC=$RESULT
GTK "gtk_image_set_from_pixmap $IMAGE $PIX NULL"
# Allocate memory with some random widget for GdkColor
GTK "gtk_frame_new NULL"
COLOR=$RESULT
# Now set foreground and backgroundcolors to WHITE
GTK "gdk_color_parse #ffffff $COLOR"
GTK "gdk_gc_set_rgb_bg_color $GC $COLOR"
GTK "gdk_gc_set_rgb_fg_color $GC $COLOR"
# Clear the complete pixmap with WHITE
GTK "gdk_draw_rectangle $PIX $GC 1 0 0 300 265"
# Set color to BLACK
GTK "gdk_color_parse #000000 $COLOR"
GTK "gdk_gc_set_rgb_fg_color $GC $COLOR"
# Put some text on the canvas
GTK "gtk_widget_create_pango_layout $IMAGE \"Draw a fractal with Korn!\""
LAYOUT=$RESULT
GTK "gdk_draw_layout $PIX $GC 130 240 $LAYOUT"
# Define start and finishing text
GTK "gtk_widget_create_pango_layout $IMAGE \"Please wait...\""
START=$RESULT
GTK "gtk_widget_create_pango_layout $IMAGE \"Drawing ready.\""
READY=$RESULT
# Update the IMAGE widget with the pixmap
GTK "gtk_widget_queue_draw $IMAGE"
# Mainloop
while [[ $RESULT != $WIN && $RESULT != $EXIT_BUTTON ]]
do
# Get event
GTK "gtk_server_callback wait"
# Check events
case $RESULT in
# If action button is pressed
$ACTION_BUTTON)
Draw_Fractal;;
# If clear button is pressed
$CLEAR_BUTTON)
GTK "gdk_color_parse #ffffff $COLOR"
GTK "gdk_gc_set_rgb_fg_color $GC $COLOR"
GTK "gdk_draw_rectangle $PIX $GC 1 0 0 450 265"
GTK "gdk_color_parse #000000 $COLOR"
GTK "gdk_gc_set_rgb_fg_color $GC $COLOR"
GTK "gdk_draw_layout $PIX $GC 130 240 $LAYOUT"
GTK "gtk_widget_queue_draw $IMAGE";;
esac
done
# Exit GTK
GTK "gtk_exit 0"