Now that we've seen what GroupKit programs look like and how its runtime architecture is set up, we can start building our own conference application. There are a lot of pieces in GroupKit to explain, so what we'll do is develop a relatively sophisticated groupware program over the space of the chapter, starting with a minimalist single-user version and gradually adding features that illustrate GroupKit's programming constructs.
The program we'll build is a brainstorming tool called "Note Organizer." This tool can help a group generate and organize ideas, for example to plan a paper, software project, advertising campaign, etc. As a brainstorming tool, the program will allow users to enter ideas (a few words), each which will be represented as a text item in a Tk canvas widget. To organize the ideas, users will be able to drag them around on the canvas, grouping related ones and so on. Being groupware, everyone in the group will be able to generate and move ideas around at the same time, and see what everyone else is doing. The program will look like the one in Figure XX.
Figure XX. Screen dump of Note Organizer.
Here is how we'll approach building this example. We'll start off by creating a single-user version of the program that allows you to create ideas, but not to move them around. This will run as a normal "wish" script, without using GroupKit at all. We'll then take that program and modify it slightly so that it will run within GroupKit, before putting any code in to "share" the ideas. The next step will be to share ideas, so that when one participant creates an idea on their canvas, it appears on other participants' canvases also. We can then begin to get more sophisticated, by letting users drag ideas around the display, which will introduce some techniques that are useful when building groupware systems. Finally, we'll have the program do appropriate things when people enter and leave the session, and also add some groupware widgets that will help keep track of what people are doing when they are in the session with us. That will complete the application as illustrated in Figure XX. If you'd like to skip ahead and see what the entire program will look like, the complete listing of the final version appears at the end of this chapter.
set notes(x) 20 set notes(y) 20 set notes(notefont) [list helvetica 17] proc buildWindow {} { frame .main canvas .notepad -scrollregion "0 0 800 3000" -yscrollcommand ".scroll set" scrollbar .scroll -command ".notepad yview" frame .controls entry .newidea button .enteridea -text "New Idea" -command addNewIdea pack .main -side top -fill both -expand yes pack .notepad -side left -fill both -expand yes -in .main pack .scroll -side right -fill y -in .main pack .controls -side top -fill x pack .newidea -side left -fill x -expand yes -in .controls pack .enteridea -side left -in .controls } proc addNewIdea {} { set idea [.newidea get] doAddIdea $idea .newidea delete 0 end } proc doAddIdea {idea} { global notes .notepad create text $notes(x) $notes(y) -text $idea -anchor nw \ -font $notes(notefont) incr notes(y) 20 if {$notes(y)>600} { set notes(y) 20 incr notes(x) 100 } } buildWindow
You should be able to run that program just fine under Tk's normal wish. Type ideas in the entry box and press the button to add them to the canvas.
gk::menus addstandard
As before, we'll start our conference application using the Open Registration session manager. But first we have to tell the session manager about our new program. To do this, we need to add a line to the bottom of the GroupKit preferences file, which was created the first time you ran the session manager.
This file is in different places on different platforms:
Note that each user has their own preferences file, so if you're running with several users, each person will have to make this change.
gk::preferences set prog.NoteOrganizer.src "/home/you/noteorg.tcl" # Unix gk::preferences set prog.NoteOrganizer.src "c:\\groupkit\\noteorg.tcl" # Windows gk::preferences set prog.NoteOrganizer.src "Macintosh HD:GroupKit:noteorg.tcl" # Mac
Either quit and restart your session manager, or choose "Re-initialize" from the "File" menu. You should now find an item named "NoteOrganizer" under the Conferences menu. Use it to create the Note Organizer conference as before, and then join the conference from another session manager.
If you run multiple copies, you'll quickly find that if you enter ideas in one copy of the program they don't appear on remote copies. Thats because we haven't actually told the program to display ideas on all screens - GroupKit won't take care of that automatically. You will find though that items in the menubar work fine, such as the "Show Participants" item which provides information on other users in the conference.
doAddIdea $idea
to:
gk::to all doAddIdea $idea
and then re-start the program from the first session manager. After joining the conference from the second session manager, you should find that ideas entered in one copy of the program now appear in the other copy as well. That wasn't so bad!
So at this point, you've seen what is involved in getting a simple groupware program up and running in GroupKit. You've been exposed to GroupKit's session manager, learned how to tell the session manager about your new program, and how to initialize a GroupKit program. Finally, you've seen the "gk::to all" command, which is one of GroupKit's programming constructs that can make it easy to turn a single-user program into a multi-user one.
So what does the "gk::to all" do? That command arranges for the Tcl command following it (i.e. doAddIdea $idea) to be executed not only in the local program (where the idea was typed in), but also in every other copy of the program running in the conference. So, if you had not just two, but three, four or ten people joined in the conference, all of their conference processes would execute that same command. This is illustrated in Figure XX.
Figure XX. The gk_toAll command.
The "gk::to all" command is an example of a Remote Procedure Call (RPC) that GroupKit provides. GroupKit has other RPC's that differ in who the commands get sent to, as shown in the sidebar. RPC's are a fairly straightforward but effective way to turn a single-user program into a multi-user one.
You'll find when you're using RPCs that you often need to "factor" your code, splitting a routine into two parts, as you saw in the "addNewIdea" and "doAddIdea" procs. This separates the code that invokes a routine (usually called from the user interface, and which is executed only by a single user) from the code that actually performs the operation (which is executed by everyone in the conference). Not only is this a useful style to adopt for groupware, but it is good coding practice generally. Factoring your code makes it easier to change your user interface, or invoke the core of your program in entirely new ways such as from a Tcl script.
GroupKit Remote Procedure Calls
GroupKit's Remote Procedure Calls (RPCs) execute a Tcl command in the conference processes of different users in your conference session. They differ in which processes the commands are sent to.
- gk::to all cmd args.
- Execute a Tcl command on all processes in the session, including the local user.
- gk::to others cmd args.
- Execute a Tcl command on all remote processes in the session, but not the process of the local user.
- gk::to user cmd args.
- Execute a Tcl command on only a single conference process, which may be one of the remote users or the local process. The process is identified by its user's unique user number, which can be extracted from the users environment, described shortly.