GroupKit User Manual - An Example GroupKit Program

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.

Single-User Version

So lets start out with just a single-user version, and only worry about creating the ideas but not moving them around yet. The code - which is standard Tcl/Tk - is shown below. The program sets up some global variables to keep track of where the ideas are to be placed on the canvas, and the font to use when drawing the ideas. It then creates the canvas to hold the ideas, an entry widget to type in the ideas, and a button used to copy the idea from the entry to the canvas. When pressed, the button calls the addNewIdea proc, which gets the idea out of the entry, calls doAddIdea and clears the entry in preparation for the next idea. The doAddIdea procedure actually puts the idea into the canvas, by creating a text item at the location found in the notes(x) and notes(y) global variables. It then adjusts these variables so as to place the next note below the one just added, starting a new column when it gets far enough down the canvas.
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.

Running the Example in GroupKit

The first thing you should do is add GroupKit's standard menubar, which contains menu items to exit the program, find out what other users are working on the program with you, and display an about box. Add this line before creating the main interface of your program, i.e. just before creating the canvas widget:

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:

When adding the following line to the preferences file, you'll have to change the path from (for example) "/home/you" to be the name of the directory where you put your note organizer script file.

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.

Just One More Thing...

So now lets fix our program so when ideas are entered in one copy of the program they are sent to other users. First, quit both running copies of the program (when you quit the last one it will ask you if you want to delete the conference or keep it around; you should delete it). Now, go back into your program and change the second line in addNewIdea from:

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.


GroupKit User Manual. Last updated March 16, 1998 by Mark Roseman.