#!/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"