|
The information below is now out-of-date. There is a much better example of using gtk-server as an editor at this page (6/feb/2012): here I'm a Windows user, and want to use Falcon - but did it have GUI abilities? Yes, there is a GTK binding. I tried this, and found errors in this. Maybe they were my fault, but they could not be resolved via the falcon message board. Anyway, by chance I came across gtk-server, which works by running gtk as a parallel process. Your program sends strings of text to gtk-server, and gets back messages as strings of text. This seems to work with Falcon, after coding a little function to read and send data streams to a process. Below is a trivial text editor for Windows - it is not for serious work, more a proof of concept. To run it, you need falcon of course, and also the gtk-server software, which installs under Windows very simply (I'm not sure about the ease of Linux installing). As a bonus, there is a button which runs ths falcon interpreter on the code you are editing. Screenshot
/*
editor1p0.fal -Windows version - using gtk-server - http://gtk-server.org/
mikeparr at live dot com - Dec 5th 2011
To run this, you need to download and install gtk-server
The site also has docs and examples.
There is a screenshot and more info on this program at:
http://www.mikeparr.info/fade/falcongtk.html
Please note that I am not an expert on GTK or falcon! I present this
as a demo/example only.
(****NOTE: the following info about local config file is not used now)
I added another GTK function, using a local cfg file. To incorporate this:
1. find the gtk-server.cfg file (it comes with the install) and insert the line:
INCLUDE = gtk-server-extra.cfg
(you will see a comment about INCLUDE in the file)
2. In the same folder as this program, create a new file named: gtk-server-extra.cfg
containing this line:
FUNCTION_NAME = gtk_box_set_homogeneous, NONE, NONE, 2, WIDGET, BOOL
If you can't be bothered to do 1 and 2 above, delete the 'set_homogenous' line below - it still runs.
(**** end of local config note)
---------------------------------------------------------------------------- */
load process //for the GTK() function
gtkProcess=Process("gtk-server -stdin") //run gtk-srver in parallel (see gtk-server site)
readFromGTK = gtkProcess.getOutput() //get the streams - see in GTK() function below
writeToGTK = gtkProcess.getInput()
//-----------------------------------------------------------------------------
currentName="" // global
//********** begin to build the gui *******************************************
GTK("gtk_init NULL NULL")
win=GTK("gtk_window_new 0") //main window, and get ptr to it
setTitle(win, currentName)
GTK ("gtk_window_set_position "+win +" 1" )
GTK( "gtk_widget_set_size_request "+win+" 500 300" )
messageDialog=0 //for the pop-up - needs to be global, I think
// make a vertical box
vbox = GTK("gtk_vbox_new 0 0")
//GTK("gtk_box_set_homogeneous "+vbox+" 0") //this gtk command added to local config - but not used now
GTK ("gtk_container_add "+ win +" "+ vbox) //add vbox to win
//-----------------------------------------------------------------------------
//whole menu bar
menuBar = GTK("gtk_menu_bar_new")
//create one menu list
fileMenu = GTK("gtk_menu_new")
file = GTK("gtk_menu_item_new_with_label File") //name at top of menu - not really a menu item!
GTK("gtk_menu_shell_append "+menuBar + " " + file) // add file menu to menubar
GTK("gtk_menu_item_set_submenu " +file+" "+ fileMenu) // add filemenu to file
//add item to a menu list nb I add to fileMenu
openMenu = GTK("gtk_menu_item_new_with_label \"Open Menu item\" ") // menu item!(nb \" if it contains spaces
GTK("gtk_menu_shell_append "+fileMenu + " " + openMenu); // low level actual item!
//add item to a menu list
saveAsMenu = GTK("gtk_menu_item_new_with_label \"Save As Menu item\" ") // menu item!
GTK("gtk_menu_shell_append "+fileMenu + " " + saveAsMenu) //low level actual item!
//add item to a menu list
saveMenu = GTK("gtk_menu_item_new_with_label \"Save Menu item\" ") // menu item!
GTK("gtk_menu_shell_append "+fileMenu + " " + saveMenu) //low level actual item!
//create one menu list
editMenu = GTK("gtk_menu_new")
edit = GTK("gtk_menu_item_new_with_label Edit") //name at top of menu - not a menu item!
GTK("gtk_menu_shell_append "+menuBar + " " + edit)
GTK("gtk_menu_item_set_submenu " +edit+" "+ editMenu)
//add item to a menu list
copyMenu = GTK("gtk_menu_item_new_with_label \"copy Menu item\" ") // menu item!
GTK("gtk_menu_shell_append "+editMenu + " " + copyMenu) // low level actual item!
//-----------hbox of buttons -------------------------------------------------
hbox=GTK( "gtk_hbox_new 0 0")
buttonRun = GTK("gtk_button_new_from_stock \"Run It\"") //or with label is ok
buttonSpare = GTK("gtk_button_new_from_stock new/help")
GTK("gtk_box_pack_start "+hbox+" "+ buttonRun+" 0 0 1") //was 1 1 1
GTK("gtk_box_pack_start "+hbox+" "+ buttonSpare+" 0 0 1")
GTK( "gtk_widget_set_size_request "+buttonRun+" 77 33" ) //needed?
GTK( "gtk_widget_set_size_request "+buttonSpare+" 77 33" )
//------------------textview in a scroller, with associated buffer ------------
buffer=GTK("gtk_text_buffer_new")
myTextview=GTK("gtk_text_view_new_with_buffer "+buffer)
GTK("gtk_text_view_set_wrap_mode "+myTextview+" 2") //WORD_WRAP = enum 2
scrolledWindow=GTK("gtk_scrolled_window_new NULL NULL")
GTK("gtk_container_add " + scrolledWindow+ " "+ myTextview)
// there are several settings for textview, which i am ignoring here
//------------------------------------------------------------------------------
// build the whole screen
GTK("gtk_box_pack_start "+vbox+" "+ menuBar+" 0 0 1"); //add menu to top of vbox
GTK( "gtk_box_pack_start "+vbox +" "+hbox+" 0 0 1") // buttons
GTK( "gtk_box_pack_start "+vbox +" "+scrolledWindow+" 1 1 1") //textview
// 'variables' (objects) for textview buffer
startiter = GTK("gtk_frame_new NULL")
enditer = GTK("gtk_frame_new NULL")
GTK("gtk_widget_show_all "+win) //show the whole thing
//************* end of building GUI ******************************************
//============================================================================
//-------------------------events---------------------------------------------
//maybe not the best way to structure event code, but seems to work for this simple program
//NB does NOT let me call more than 1 event generators in one function
loop
event = GTK("gtk_server_callback WAIT")
if event == buttonRun: doRunMenuClicked()
if event == buttonSpare: spareClicked()
if event == openMenu: doOpenMenuClicked()
if event == saveAsMenu:doSaveAsMenuClicked()
if event == saveMenu:doSaveMenuClicked()
if event == copyMenu:copyClicked()
if event == messageDialog: GTK("gtk_widget_destroy " +messageDialog) //OK or 'closed' clicked
end (event == win)
//here when main window is closed by user
doSaveMenuClicked() // save on exit
GTK("gtk_exit 0" ) //end the program
//-----------------------end events----------------------------------------
//=========================================================================
function doRunMenuClicked()
screen=getScreen(myTextview)
if not((currentName=="") and (screen=="")) //need some text and a file name
writeCurrentFile(screen) //save it
//nb should create bat in same dir as user's program,nd ensure it is workdir for it
userDir=filePath(strReplace(currentName, "\\", "/")) //WINDOWS - but this should have no efect on linux
f=OutputStream(userDir+"/"+"dorun.bat") //but where? -in user's dir (nb no PAUSE needed
f.writeText(@"falcon.exe \"$currentName\"\r\n") //WINDOWS \r
f.flush()
f.close()
myDir=dirCurrent()
dirChange(userDir) //for program i am about to run
system("dorun.bat")
dirChange(myDir) //back to editor
end
end
//----------------------------------------------------------------------------
function doOpenMenuClicked()
global currentName
//file chooser
//nb the C description in gtk docs used constants: GTK_STOCK_CANCEL and OPEN.
// I looked up their defined val, and used that (e.g "gtk-open")
//I look at 4 cases:
screen=getScreen(myTextview) //mtextview not assigned, hence global value used
if(currentName=="") and (screen=="")
opendialog=GTK(@"gtk_file_chooser_dialog_new open-file $win GTK_FILE_CHOOSER_ACTION_OPEN gtk-cancel GTK_RESPONSE_CANCEL gtk-open GTK_RESPONSE_ACCEPT NULL")
response=GTK(@"gtk_dialog_run $opendialog")
//am not setting any chooser options - though I could
if (response== "-3") // GTK_RESPONSE_ACCEPT is -3) nb need "" round -3
currentName = GTK(@"gtk_file_chooser_get_filename $opendialog")
setTitle(win, currentName)
textToScreen(readAllFile(currentName))
end
//other responses could be : close, cancel -4, -6
//nb if cancelled, currentname is unchanged
GTK(@"gtk_widget_destroy $opendialog")
elif (currentName=="") and (screen != "") //text entered, but no name chosen
opendialog=GTK(@"gtk_file_chooser_dialog_new open-file $win GTK_FILE_CHOOSER_ACTION_OPEN gtk-cancel GTK_RESPONSE_CANCEL gtk-open GTK_RESPONSE_ACCEPT NULL")
response=GTK(@"gtk_dialog_run $opendialog")
if (response== "-3")
currentName = GTK(@"gtk_file_chooser_get_filename $opendialog")
setTitle(win, currentName)
textToScreen(readAllFile(currentName))
end
GTK(@"gtk_widget_destroy $opendialog")
elif (currentName != "") and (screen == "") //got a name, but no text
opendialog=GTK(@"gtk_file_chooser_dialog_new open-file $win GTK_FILE_CHOOSER_ACTION_OPEN gtk-cancel GTK_RESPONSE_CANCEL gtk-open GTK_RESPONSE_ACCEPT NULL")
response=GTK(@"gtk_dialog_run $opendialog")
if (response== "-3")
currentName = GTK(@"gtk_file_chooser_get_filename $opendialog")
setTitle(win, currentName)
textToScreen(readAllFile(currentName))
end
GTK(@"gtk_widget_destroy $opendialog")
elif (currentName!="") and (screen != "") //normal case
writeCurrentFile(screen) //save without asking
opendialog=GTK(@"gtk_file_chooser_dialog_new open-file $win GTK_FILE_CHOOSER_ACTION_OPEN gtk-cancel GTK_RESPONSE_CANCEL gtk-open GTK_RESPONSE_ACCEPT NULL")
response=GTK(@"gtk_dialog_run $opendialog")
if (response== "-3")
currentName = GTK(@"gtk_file_chooser_get_filename $opendialog")
setTitle(win, currentName)
textToScreen(readAllFile(currentName))
end
GTK(@"gtk_widget_destroy $opendialog")
else
buildDialog("Error in editor -in Open section")
end
end
//-----------------------------------------------------------------------------
function readAllFile(fName) //return all text in file f //bug
inText=strBuffer(200000)
f=InputStream(strReplace(currentName,"\\","/")) //WINDOWS
f.readText(inText) //must be a way to avoid specifying max size?
f.close()
return inText //strbuff to str value - ok?
end
//---------------------------------------------------------------------------
//------------------------------------------------------------------------------
//format text if needed, and write it to textview
function textToScreen(inText)
//The text passed to gtkserver must be one string, surrounded by "
// I cannot pass a raw eol char, and raw " in the string will screw up the overall
//quoting. Raw eols get replaced by \n, so an existing \n pair in the text gives problems, as
//does the \" pair. So I have to replace them. The following does this. It is a bit crude, and I think regexps would be better!
//It has not been thoroughly tested.
global currentName
inText1=strReplace(inText,"\r\n","\n") //WINDOWS only - remove carriage-returns
//using a 2-step approach to avoid 'double' replacing. First I replace by a magic string
//quote stuff " and \"
inText1=strReplace(inText1, "\\\"", "7BSQ") // do \" before " - longest
inText1=strReplace(inText1, "\"", "3BSQ")
// backslash , double backslash , \b \r \t, backslash n
inText1=strReplace(inText1, "\\\\", "10BACK") // do \\ before \ - longest
inText1=strReplace(inText1, "\\r", "BACKR") // do \r
inText1=strReplace(inText1, "\\b", "BACKB") // do \b
inText1=strReplace(inText1, "\\t", "BACKT") // do \t
inText1=strReplace(inText1, "\\n", "3BACKN") // \n pair
inText1=strReplace(inText1, "\\\n", "XBACKN") // \eol
inText1=strReplace(inText1, "\\", "6BACK") // single \
//so far, there are no special chars -0 eg \ " in text. ---now replace the magic strings
inText1=strReplace(inText1, "6BACK", "\\\\\\" ) // single \ -do first?
//quote stuff " and \"
inText1=strReplace(inText1, "3BSQ", "\\\"") // normal " works-but need to isolate from handling a\", by magic string?
inText1=strReplace(inText1, "7BSQ", "\\\\\\\"") // \" works in isolation
// backslash , double backslash , backslash n
inText1=strReplace(inText1, "10BACK", "\\\\\\\\\\" ) // do \\ before \ - longest
inText1=strReplace(inText1, "BACKR", "\\\\r" ) // \r
inText1=strReplace(inText1, "BACKB", "\\\\b" ) // \b
inText1=strReplace(inText1, "BACKT", "\\\\t" ) // \t
inText1=strReplace(inText1, "3BACKN", "\\\n" ) // \n pair
inText1=strReplace(inText1, "XBACKN", "\\\\\n") // \eol yes
inText1=strReplace(inText1, "\n", "\\n") //replace eol char by 2 chars \ n yes
inText1="\"" + inText1 + "\"" //becuase the whole string is likely to contain spaces
// ("about to show=================: \n"+inText1)
GTK(@"gtk_text_buffer_set_text $buffer $inText1 -1" )
end
//------------------------------------------------------------------------------
function doSaveMenuClicked()
if (currentName=="")
doSaveAsMenuClicked()
else
writeCurrentFile(getScreen(myTextview))
end
end
//-----------------------------------------------------------------------------
function doSaveAsMenuClicked()
//no choices here - always display it
global currentName
//file chooser-save (nb if you want to type in a file name, there is a small button in the chooser
savedialog=GTK(@"gtk_file_chooser_dialog_new save-file $win GTK_FILE_CHOOSER_ACTION_SAVE gtk-cancel GTK_RESPONSE_CANCEL gtk-save GTK_RESPONSE_ACCEPT NULL")
response=GTK(@"gtk_dialog_run $savedialog")
if (response== "-3")
currentName = GTK(@"gtk_file_chooser_get_filename $savedialog")
setTitle(win, currentName)
writeCurrentFile(getScreen(myTextview))
end
//.nb currentName unchanged if chooser cancelled
GTK(@"gtk_widget_destroy $savedialog")
end
//-------------------------------------------------------------------------------
function writeCurrentFile(theText)
f=OutputStream(currentName)
f.writeText(theText)
f.flush()
f.close()
end
//----------------------------------------------------------------------------
function getScreen(aTV) //return the text from a textview, properly formatted for file-writing
//see comments in fileToScreen - but here I need to replace the gtk encoding by actual characters
GTK("gtk_server_enable_c_string_escaping") //so i get all the text as 1 line
buffer=GTK("gtk_text_view_get_buffer "+aTV) //not needed? not sure if it moves
GTK("gtk_text_buffer_get_bounds "+ buffer +" "+ startiter+ " "+ enditer) //they point to the buffer
// GTK("gtk_server_set_c_string_escaping "+"\"\n\"") //cant get it to work for eol - dont use
allText=GTK("gtk_text_buffer_get_text "+buffer +" "+startiter+" "+enditer+" 0") // eol, " are escaped"
GTK("gtk_server_disable_c_string_escaping")
//remove first and last chars (which are ")
allText=allText[1:len(allText)-1]
// \"-y \n-y \\-y " \ (and \ at eol)
allText=strReplace(allText, "\\\\\\n" ,"BSBSEOL") // \ before eol is \\\n
allText=strReplace(allText,"\\\\\\\"" , "BSQT") // pair \" -rep by \\\" in string from gtkserv -yes
allText=strReplace(allText, "\\\\n" ,"BSNL") // pair \n rep by \\n -yes
allText=strReplace(allText,"\\\\\\\\" ,"2BS") // pair \\ rep by \\\\ in string from gtkserv
allText=strReplace(allText,"\\\"" ,"JUSTQT") // singl " rep by pair \" in string from gtkserv -yes
allText=strReplace(allText, "\\\\" ,"JUSTBS") // single \ rep by \\ yes
//done relacing all by magic
//am not doing \b \t \r seems ok!
allText=strReplace(allText,"2BS", "\\\\")
allText=strReplace(allText, "BSBSEOL" ,"\\\\\n")
allText=strReplace(allText,"\\n", "\r\n") //do real eols - yes, here nb WINDOWS
allText=strReplace(allText,"BSQT" ,"\\\"")
allText=strReplace(allText,"BSNL" ,"\\n")
allText=strReplace(allText,"2BS", "\\\\")
allText=strReplace(allText,"JUSTQT", "\"")
allText=strReplace(allText,"JUSTBS", "\\")
return allText
end
//----------------------------------------------------------------------------
function spareClicked()
buildDialog("Spare modal? \n Yes, I am.\n"+
"New file: start typing, do a Save As. \nThe current file is saved when you open/save-as/exit")
end
//-----------------------------------------------------------------------------
function copyClicked()
buildDialog("For copy/paste, use normal control keys, or right mouse button.")
end
//------------------------------------------------------------------------------
function setTitle(win, text)
GTK( "gtk_window_set_title "+ win + " \"Edit - gtk-server(Win): "+strReplace(text, "\\","/")+ "\"" ) //nb \" if holds spaces
end
//------------------------------------------------------------------------------
function buildDialog(msg)
global messageDialog //used in event loop
messageDialog= GTK("gtk_message_dialog_new "+ win+ " 0 0 2 '" + msg +"'"+"''")
GTK(@"gtk_dialog_run $messageDialog")
// GTK("gtk_widget_show_all " + buildDialog("a test----")) //not modal - can show lots at once
// but might need an assoc array for ptrs to several dialogs
end
//------------------------------------------------------------------------------
//see gtk-server page for what this has to do (basically, send a line, read a line)
function GTK(st)
// printl ("sending: "+ st) //for debugging
writeToGTK.write(st)
a=readFromGTK.grabLine()
// printl(" got line: " + a) //for debugging
return a
end
//------------------------------------------------------------------------------
|