#!/bin/zsh # # Draw a fractal with the GTK-server and ZShell. # # On my AMD2000+ machine it takes approx. 3 minutes to # draw the fractal. Twice as fast as KornShell. # # Developed with zsh 4.2.0 on Slackware Linux. # # Codesample. July 26, 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 ((CR=$LEFT+$X*($RIGHT-1*$LEFT)/$SIZE)) ((CI=$TOP+$Y*($BOTTOM-$TOP)/$SIZE)) ((RSQUARED=$ZR*$ZR)) ((ISQUARED=$ZI*$ZI)) integer COUNT=0 while [[ $RSQUARED+$ISQUARED -lt 2.0 && $COUNT -lt $MaxIters ]] do ((ZI=$ZR*$ZI*2.0)) ((ZI=$ZI+$CI)) ((ZR=$RSQUARED-$ISQUARED)) ((ZR=$ZR+$CR)) ((RSQUARED=$ZR*$ZR)) ((ISQUARED=$ZI*$ZI)) ((COUNT+=1)) done ((SUM=$RSQUARED+$ISQUARED)) if [[ $SUM -lt 2.0 ]] then if [[ $SUM -lt 1.0 ]] then ((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 110 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 coproc 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 \"ZShell 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 ZShell!\"" LAYOUT=$RESULT GTK "gdk_draw_layout $PIX $GC 120 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 280 240 $LAYOUT" GTK "gtk_widget_queue_draw $IMAGE";; esac done # Exit GTK GTK "gtk_exit 0"