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 //------------------------------------------------------------------------------ |