Here’s a summary of what should happen with development on a branch that is intended to later be merged to the trunk. Suppose the branch is called “mine”.
1) tag the repository (trunk) to create a branch point tag:
cvs tag mine-base
2) branch
cvs tag -b -r mine-base mine
What step #1 does is to keep track of where the “mine” branch started
from. The "-r mine-base” in step #2 says to create the branch starting
from the tag “mine-base”. It is important to do this because you need
to be able to know where each file is rooted (i.e., what version in the
trunk it is derived from).
Usually, it is a good idea to periodically merge changes which have taken
place on the trunk to the branch. This will reduce the amount of work when
the work on the branch is ready to go back to the trunk.
# go to where the trunk is checked out and update it
cd /to/my/trunk/sources cvs update -PdA
# create a temporary tag in case someone commits stuff while you’re
# in the middle of this procedure. This keeps you from losing anything.
cvs tag merge-mine
# go to your branch source tree
cd /to/my/branch/sources cvs update -Pd
# the following says to apply the changes that have taken place on
# the trunk between the version tagged with “mine-base” and “merge-mine”
# to your branch source tree
cvs update -j mine-base -j merge-mine -dP
# if all goes well, you’ll have no conflicts. It is not uncommon
# for there to be some cases where you have to resolve conflicts by
# hand. In this case the affected files will have a special comment
# showing what your file on the branch had and what the file tagged as
# merge-mine had. You, as the programmer, have to figure out what is
# correct. Once this is all done, proceed.
# checkin with a message like “sync with trunk” or
# “pull up revs #### from the trunk” (if you were pulling up
# a specific change).
cvs ci
# Now we move the branch point tag to the temporary merge tag
# This is because we have changed what rev each file in the branch
# is based on in the trunk. This is known as re-rooting.
cvs tag -F -r merge-mine mine-base
# now we don’t need the temporary merge tag anymore so remove it
cvs tag -d merge-mine
When it is time to merge changes that have taken place on a branch back
to the trunk (usually marking the end of that branch), first do a final
trunk → branch merge as mentioned above. Then do a branch → trunk merge.
Now for a branch to trunk merge you’d do
cd /to/my/trunk/sources cvs update -PdA cvs update -j mine-base -j mine -dP
# resolve conflicts
cvs ci cvs tag -F mine-base
This takes any changes between “mine-base” and “mine” and tries to apply
it to the trunk. If it all goes cleanly, you just check it in otherwise you
have to resolve conflicts. Then you move the branch point tag because the trunk
now reflects the lastest in the branch.
The above was contributed by Dan McMahill
Any volunteer for writing some notes?
There’s a nice document from the gnome guys called Gnome HIG. There are several suggestions on how to design dialogs and how they should behave.
The dialog design is mostly a matter of taste:
Misc:
A modal dialog is required whenever the main application provides data for the dialog.
Example: The dialog is called with a selection list and the dialog only should operate on this selection.
A modal dialog is OK too, if the dialog is only called very seldom. The file open dialog could be nonmodal because it does not require any input from the application.
A modal dialog is not OK if there is a lot of user interaction with the dialog. The component selection is a good example.
A dialog can be put on different places in on the screen. A list of possible places can be found in the GtkReference
The current dialogs are placed either on the mouse position (GTK_WIN_POS_MOUSE) or at no preset position (GTK_WIN_POS_NONE). The Gnome HID does not say anything about that topic.
The default setting is GTK_WIN_POS_NONE for GtkWindow see GtkWindow. The default for GtkDialog is GTK_WIN_POS_CENTER_ON_PARENT ( taken from the GtkDialog source).
Most of the dialogs are placed in front of their parent window using the transient_for property (see. GtkReference). This property should be set for all modal dialogs.
For nonmodal dialogs the setting of transient_for property is not obvious. While in gschem for example the coord dialog should stay above the parent window, the log window does not need to stay in front of it.
Note: There is an older mechanism that keeps the the dialogs in front of gschem. If the raise-dialog-boxes-on-expose variable is set to enable in one of gschem’s configuration files, it may cause problems with some window managers. If dialogs are flickering at 100% CPU load, then disable that setting.
; raise-dialog-boxes-on-expose string ; ; Controls if dialog boxes are raised whenever an expose event happens ; Default is enabled ; ;(raise-dialog-boxes-on-expose "enabled") (raise-dialog-boxes-on-expose "disabled")
Button order at the bottom of the dialog depends on which operating system the user is using. GTK handles this automatically (require version > 2.6.0) , but requires the developers set the alternative button order. For more information, check the GTK documentation here.
The alternative button order is set with just one call to a GTK function:
#if GTK_CHECK_VERSION (2,6,0) /* Set the alternative button order (ok, cancel, help) for other systems */ gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog), GTK_RESPONSE_OK, GTK_RESPONSE_NO, GTK_RESPONSE_CANCEL, GTK_RESPONSE_HELP, -1); #endif
This should be done for every new dialog created, before running it.
This template is not intented to compile, but you can easily copy the code block that you need.
void dialog (TOPLEVEL *w_current) { GtkWidget *vbox, *label, *alignment, *table; GtkWidget *dialog; /* only create the dialog if it is not there yet. This usually is a widget pointer in the w_current structure: dialog = w_current->tewindow */ if (!dialog) { dialog = gtk_dialog_new_with_buttons(_("Dialog title"), /* the parent window or NULL */ GTK_WINDOW(w_current->main_window), /* dialog properties */ GTK_DIALOG_MODAL, /* 0 for nonmodal dialogs */ /* dialog buttons and response signals */ GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); #if GTK_CHECK_VERSION (2,6,0) /* Set the alternative button order (ok, cancel, help) for other systems */ gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog), GTK_RESPONSE_OK, GTK_RESPONSE_NO, GTK_RESPONSE_CANCEL, GTK_RESPONSE_HELP, -1); #endif /* set default response signal. This is usually triggered by the "Return" key */ gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT); /* set the function for handling the button responses and dialog close for nonmodal dialogs you can use dialog_run() too.*/ gtk_signal_connect(GTK_OBJECT(dialog), "response", GTK_SIGNAL_FUNC(dialog_response), w_current); /* where to place the dialog: GTK_WIN_POS_MOUSE or GTK_WIN_POS_NONE */ gtk_window_position(GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE); /* set the border spacing and the vbox spacing of the dialog */ vbox = GTK_DIALOG(dialog)->vbox; gtk_container_set_border_width(GTK_CONTAINER(dialog),DIALOG_BORDER_SPACING); gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING); /* create a label (with markup) and pack it into the dialog box */ label = gtk_label_new(_("<b>Section label</b>")); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_misc_set_alignment(GTK_MISC(label),0,0); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); /* create a alignment container with the DIALOG_INDENTATION on the left */ alignment = gtk_alignment_new(0,0,1,1); gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, DIALOG_INDENTATION, 0); gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0); /* a table can store several entries. It is stored in the aligment container. Note: the vertical and horizontal cell spacings */ table = gtk_table_new (3, 2, FALSE); gtk_table_set_row_spacings(GTK_TABLE(table), DIALOG_V_SPACING); gtk_table_set_col_spacings(GTK_TABLE(table), DIALOG_H_SPACING); gtk_container_add(GTK_CONTAINER(alignment), table); /* a simple text label in one table cell with left alignment. Note: the GTK_FILL in the third line is required */ label = gtk_label_new(_("Text:")); gtk_misc_set_alignment(GTK_MISC(label),0,0); gtk_table_attach(GTK_TABLE(table), label, 0,1,0,1, GTK_FILL,0,0,0); /* a simple text entry completes the option row */ textentry = gtk_entry_new_with_max_length (10); gtk_table_attach_defaults(GTK_TABLE(table), textentry, 1,2,0,1); gtk_entry_set_activates_default(GTK_ENTRY(textentry), TRUE); /* ..... more table rows with options, or new sections */ /* create references to all widgets that you need later */ GLADE_HOOKUP_OBJECT(dialog, sizeentry,"textentry"); /* show all widgets recursivly */ gtk_widget_show_all(dialog); } else { /* Dialog is already there. Present it to the user. This is only required if you have a nonmodal dialog */ gtk_window_present(GTK_WINDOW(dialog)); } /* always set the current values to the dialog If you're placing that part at the end of the dialog function you can easily create dialogs that can be called, even if they are already open */ textentry = g_object_get_data(G_OBJECT(dialog), "textentry"); gtk_entry_set_text(GTK_ENTRY(textentry), string); /* select the text region that the user usually likes to overwrite */ gtk_entry_select_region(GTK_ENTRY(textentry), 0, strlen(string)); }
The response function for such a dialog may look like this:
void dialog_response(GtkWidget *widget, gint response, TOPLEVEL *w_current) { switch (response) { case GTK_RESPONSE_ACCEPT: /* apply the dialog settings: just insert your code here if it is short call an extra apply function if the required code is long */ break; case GTK_RESPONSE_REJECT: case GTK_RESPONSE_DELETE_EVENT: /* for modal dialogs just do nothing, for nonmodal dialogs, destroy the dialog and clean up */ break; default: /* catch wrong signals signals (paranoid error checking ;-)) */ printf("dialog_response(): strange signal %d\n", response); } /* for nonmodal dialogs just do nothing, for modal dialogs, always destroy the dialog and clean up */ }
Here’s a list of things that could be improved: