pcb 4.1.1
An interactive printed circuit board layout editor.

gui-top-window.c

Go to the documentation of this file.
00001 
00067 /* #define DEBUG_MENUS */
00068 
00069 #ifdef HAVE_CONFIG_H
00070 #include "config.h"
00071 #endif
00072 
00073 #include <unistd.h>
00074 
00075 #include "ghid-layer-selector.h"
00076 #include "ghid-route-style-selector.h"
00077 #include "gtkhid.h"
00078 #include "gui.h"
00079 #include "hid.h"
00080 #include "../hidint.h"
00081 #include "hid/common/hid_resource.h"
00082 
00083 #include "action.h"
00084 #include "autoplace.h"
00085 #include "autoroute.h"
00086 #include "buffer.h"
00087 #include "change.h"
00088 #include "copy.h"
00089 #include "create.h"
00090 #include "crosshair.h"
00091 #include "draw.h"
00092 #include "error.h"
00093 #include "file.h"
00094 #include "find.h"
00095 #include "gpcb-menu.h"
00096 #include "insert.h"
00097 #include "line.h"
00098 #include "mymem.h"
00099 #include "misc.h"
00100 #include "move.h"
00101 #include "pcb-printf.h"
00102 #include "polygon.h"
00103 #include "rats.h"
00104 #include "remove.h"
00105 #include "report.h"
00106 #include "resource.h"
00107 #include "rotate.h"
00108 #include "rubberband.h"
00109 #include "search.h"
00110 #include "select.h"
00111 #include "set.h"
00112 #include "undo.h"
00113 #include "vendor.h"
00114 #include "free_atexit.h"
00115 
00116 #include "gui-icons-mode-buttons.data"
00117 #include "gui-icons-misc.data"
00118 #include "gui-trackball.h"
00119 
00120 #ifdef HAVE_LIBDMALLOC
00121 #include <dmalloc.h>
00122 #endif
00123 
00124 static bool ignore_layer_update;
00125 
00126 static GtkWidget *ghid_load_menus (void);
00127 
00128 GhidGui _ghidgui, *ghidgui = NULL;
00129 
00130 GHidPort ghid_port, *gport;
00131 
00132 static gchar *bg_image_file;
00133 
00134 static struct { GtkAction *action; const Resource *node; }
00135   ghid_hotkey_actions[256];
00136 #define N_HOTKEY_ACTIONS \
00137         (sizeof (ghid_hotkey_actions) / sizeof (ghid_hotkey_actions[0]))
00138 
00139 
00143 void
00144 menu_toggle_update_cb (GtkAction *act, const char *tflag, const char *aflag)
00145 {
00146   if (tflag != NULL)
00147     {
00148       int v = hid_get_flag (tflag);
00149       gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (act), !!v);
00150     }
00151   if (aflag != NULL)
00152     {
00153       int v = hid_get_flag (aflag);
00154       gtk_action_set_sensitive (act, !!v);
00155     }
00156 }
00157 
00161 void
00162 ghid_update_toggle_flags ()
00163 {
00164   ghid_main_menu_update_toggle_state (GHID_MAIN_MENU (ghidgui->menu_bar),
00165                                       menu_toggle_update_cb);
00166 }
00167 
00168 static void
00169 h_adjustment_changed_cb (GtkAdjustment * adj, GhidGui * g)
00170 {
00171   if (g->adjustment_changed_holdoff)
00172     return;
00173 
00174   ghid_port_ranges_changed ();
00175 }
00176 
00177 static void
00178 v_adjustment_changed_cb (GtkAdjustment * adj, GhidGui * g)
00179 {
00180   if (g->adjustment_changed_holdoff)
00181     return;
00182 
00183   ghid_port_ranges_changed ();
00184 }
00185 
00186   /* Save size of top window changes so PCB can restart at its size at exit.
00187    */
00188 static gint
00189 top_window_configure_event_cb (GtkWidget * widget, GdkEventConfigure * ev,
00190                                GHidPort * port)
00191 {
00192   GtkAllocation allocation;
00193   gboolean new_w, new_h;
00194 
00195   gtk_widget_get_allocation (widget, &allocation);
00196 
00197   new_w = (ghidgui->top_window_width != allocation.width);
00198   new_h = (ghidgui->top_window_height != allocation.height);
00199 
00200   ghidgui->top_window_width = allocation.width;
00201   ghidgui->top_window_height = allocation.height;
00202 
00203   if (new_w || new_h)
00204     ghidgui->config_modified = TRUE;
00205 
00206   return FALSE;
00207 }
00208 
00209 static void
00210 info_bar_response_cb (GtkInfoBar *info_bar,
00211                       gint        response_id,
00212                       GhidGui    *_gui)
00213 {
00214   gtk_widget_destroy (_gui->info_bar);
00215   _gui->info_bar = NULL;
00216 
00217   if (response_id == GTK_RESPONSE_ACCEPT)
00218     RevertPCB ();
00219 }
00220 
00221 static void
00222 close_file_modified_externally_prompt (void)
00223 {
00224   if (ghidgui->info_bar != NULL)
00225     gtk_widget_destroy (ghidgui->info_bar);
00226   ghidgui->info_bar = NULL;
00227 }
00228 
00229 static void
00230 show_file_modified_externally_prompt (void)
00231 {
00232   GtkWidget *button;
00233   GtkWidget *button_image;
00234   GtkWidget *icon;
00235   GtkWidget *label;
00236   GtkWidget *content_area;
00237   char *file_path_utf8;
00238   char *secondary_text;
00239   char *markup;
00240 
00241   close_file_modified_externally_prompt ();
00242 
00243   ghidgui->info_bar = gtk_info_bar_new ();
00244 
00245   button = gtk_info_bar_add_button (GTK_INFO_BAR (ghidgui->info_bar),
00246                                     _("Reload"),
00247                                     GTK_RESPONSE_ACCEPT);
00248   button_image = gtk_image_new_from_stock (GTK_STOCK_REFRESH,
00249                                            GTK_ICON_SIZE_BUTTON);
00250   gtk_button_set_image (GTK_BUTTON (button), button_image);
00251 
00252   gtk_info_bar_add_button (GTK_INFO_BAR (ghidgui->info_bar),
00253                            GTK_STOCK_CANCEL,
00254                            GTK_RESPONSE_CANCEL);
00255   gtk_info_bar_set_message_type (GTK_INFO_BAR (ghidgui->info_bar),
00256                                  GTK_MESSAGE_WARNING);
00257   gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle),
00258                       ghidgui->info_bar, FALSE, FALSE, 0);
00259   gtk_box_reorder_child (GTK_BOX (ghidgui->vbox_middle), ghidgui->info_bar, 0);
00260 
00261 
00262   g_signal_connect (ghidgui->info_bar, "response",
00263                     G_CALLBACK (info_bar_response_cb), ghidgui);
00264 
00265   file_path_utf8 = g_filename_to_utf8 (PCB->Filename, -1, NULL, NULL, NULL);
00266 
00267   secondary_text = PCB->Changed ? _("Do you want to drop your changes and reload the file?") :
00268                                   _("Do you want to reload the file?");
00269 
00270   markup =  g_markup_printf_escaped (_("<b>The file %s has changed on disk</b>\n\n%s"),
00271                                      file_path_utf8, secondary_text);
00272   g_free (file_path_utf8);
00273 
00274   content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (ghidgui->info_bar));
00275 
00276   icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
00277                                    GTK_ICON_SIZE_DIALOG);
00278   gtk_box_pack_start (GTK_BOX (content_area),
00279                       icon, FALSE, FALSE, 0);
00280 
00281   label = gtk_label_new ("");
00282   gtk_box_pack_start (GTK_BOX (content_area),
00283                       label, TRUE, TRUE, 6);
00284 
00285   gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
00286   gtk_label_set_markup (GTK_LABEL (label), markup);
00287   g_free (markup);
00288 
00289   gtk_misc_set_alignment (GTK_MISC (label), 0., 0.5);
00290 
00291   gtk_widget_show_all (ghidgui->info_bar);
00292 }
00293 
00294 static bool
00295 check_externally_modified (void)
00296 {
00297   GFile *file;
00298   GFileInfo *info;
00299   GTimeVal timeval;
00300 
00301   /* Treat zero time as a flag to indicate we've not got an mtime yet */
00302   if (PCB->Filename == NULL ||
00303       (ghidgui->our_mtime.tv_sec == 0 &&
00304        ghidgui->our_mtime.tv_usec == 0))
00305     return false;
00306 
00307   file = g_file_new_for_path (PCB->Filename);
00308   info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED,
00309                             G_FILE_QUERY_INFO_NONE, NULL, NULL);
00310   g_object_unref (file);
00311 
00312   if (info == NULL ||
00313       !g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
00314     return false;
00315 
00316   g_file_info_get_modification_time (info, &timeval); //&ghidgui->last_seen_mtime);
00317   g_object_unref (info);
00318 
00319   /* Ignore when the file on disk is the same age as when we last looked */
00320   if (timeval.tv_sec == ghidgui->last_seen_mtime.tv_sec &&
00321       timeval.tv_usec == ghidgui->last_seen_mtime.tv_usec)
00322     return false;
00323 
00324   ghidgui->last_seen_mtime = timeval;
00325 
00326   return (ghidgui->last_seen_mtime.tv_sec > ghidgui->our_mtime.tv_sec) ||
00327          (ghidgui->last_seen_mtime.tv_sec == ghidgui->our_mtime.tv_sec &&
00328          ghidgui->last_seen_mtime.tv_usec > ghidgui->our_mtime.tv_usec);
00329 }
00330 
00331 static gboolean
00332 top_window_enter_cb (GtkWidget *widget, GdkEvent  *event, GHidPort *port)
00333 {
00334   if (check_externally_modified ())
00335     show_file_modified_externally_prompt ();
00336 
00337   return FALSE;
00338 }
00339 
00355 static void
00356 ghid_menu_cb (GtkAction *action, const Resource *node)
00357 {
00358   int i;
00359 
00360   if (action == NULL || node == NULL) 
00361     return;
00362 
00363   for (i = 1; i < node->c; i++)
00364     if (resource_type (node->v[i]) == 10)
00365       {
00366 #ifdef DEBUG_MENUS
00367         printf ("    %s\n", node->v[i].value);
00368 #endif
00369         hid_parse_actions (node->v[i].value);
00370       }
00371 
00372   /* Sync gui widgets with pcb state */
00373   ghid_update_toggle_flags ();
00374   ghid_mode_buttons_update ();
00375 
00376   /* Sync gui status display with pcb state */
00377   AdjustAttachedObjects ();
00378   ghid_invalidate_all ();
00379   ghid_window_set_name_label (PCB->Name);
00380   ghid_set_status_line_label ();
00381 }
00382 
00387 void ghid_hotkey_cb (int which)
00388 {
00389   if (ghid_hotkey_actions[which].action != NULL)
00390     ghid_menu_cb (ghid_hotkey_actions[which].action,
00391                   (gpointer) ghid_hotkey_actions[which].node);
00392 }
00393 
00394 static void
00395 update_board_mtime_from_disk (void)
00396 {
00397   GFile *file;
00398   GFileInfo *info;
00399 
00400   ghidgui->our_mtime.tv_sec = 0;
00401   ghidgui->our_mtime.tv_usec = 0;
00402   ghidgui->last_seen_mtime = ghidgui->our_mtime;
00403 
00404   if (PCB->Filename == NULL)
00405     return;
00406 
00407   file = g_file_new_for_path (PCB->Filename);
00408   info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED,
00409                             G_FILE_QUERY_INFO_NONE, NULL, NULL);
00410   g_object_unref (file);
00411 
00412   if (info == NULL ||
00413       !g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
00414     return;
00415 
00416   g_file_info_get_modification_time (info, &ghidgui->our_mtime);
00417   g_object_unref (info);
00418 
00419   ghidgui->last_seen_mtime = ghidgui->our_mtime;
00420 }
00421 
00426 void
00427 ghid_sync_with_new_layout (void)
00428 {
00429   pcb_use_route_style (&PCB->RouteStyle[0]);
00430   ghid_route_style_selector_select_style
00431     (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector),
00432      &PCB->RouteStyle[0]);
00433 
00434   ghid_config_handle_units_changed ();
00435 
00436   ghid_window_set_name_label (PCB->Name);
00437   ghid_set_status_line_label ();
00438   close_file_modified_externally_prompt ();
00439   update_board_mtime_from_disk ();
00440 }
00441 
00442 void
00443 ghid_notify_save_pcb (const char *filename, bool done)
00444 {
00445   /* Do nothing if it is not the active PCB file that is being saved.
00446    */
00447   if (PCB->Filename == NULL || strcmp (filename, PCB->Filename) != 0)
00448     return;
00449 
00450   if (done)
00451     update_board_mtime_from_disk ();
00452 }
00453 
00454 void
00455 ghid_notify_filename_changed (void)
00456 {
00457   /* Pick up the mtime of the new PCB file */
00458   update_board_mtime_from_disk ();
00459 }
00460 
00468 void
00469 layer_process (gchar **color_string, char **text, int *set, int i)
00470 {
00471   int tmp;
00472   char *tmps;
00473   gchar *tmpc;
00474 
00475   /* cheap hack to let users pass in NULL for either text or set if
00476    * they don't care about the result
00477    */
00478    
00479   if (color_string == NULL)
00480     color_string = &tmpc;
00481 
00482   if (text == NULL)
00483     text = &tmps;
00484 
00485   if (set == NULL)
00486     set = &tmp;
00487   
00488   switch (i)
00489     {
00490     case LAYER_BUTTON_SILK:
00491       *color_string = Settings.ElementColor;
00492       if (Settings.ShowBottomSide)
00493          *text = (char *)UNKNOWN (PCB->Data->Layer[bottom_silk_layer].Name);
00494       else
00495          *text = (char *)UNKNOWN (PCB->Data->Layer[top_silk_layer].Name);
00496       *set = PCB->ElementOn;
00497       break;
00498     case LAYER_BUTTON_RATS:
00499       *color_string = Settings.RatColor;
00500       *text = _( "rat lines");
00501       *set = PCB->RatOn;
00502       break;
00503     case LAYER_BUTTON_PINS:
00504       *color_string = Settings.PinColor;
00505       *text = _( "pins/pads");
00506       *set = PCB->PinOn;
00507       break;
00508     case LAYER_BUTTON_VIAS:
00509       *color_string = Settings.ViaColor;
00510       *text = _( "vias");
00511       *set = PCB->ViaOn;
00512       break;
00513     case LAYER_BUTTON_FARSIDE:
00514       *color_string = Settings.InvisibleObjectsColor;
00515       *text = _( "far side");
00516       *set = PCB->InvisibleObjectsOn;
00517       break;
00518     case LAYER_BUTTON_MASK:
00519       *color_string = Settings.MaskColor;
00520       *text = _( "solder mask");
00521       *set = TEST_FLAG (SHOWMASKFLAG, PCB);
00522       break;
00523     default:            /* layers */
00524       *color_string = Settings.LayerColor[i];
00525       *text = (char *)UNKNOWN (PCB->Data->Layer[i].Name);
00526       *set = PCB->Data->Layer[i].On;
00527       break;
00528     }
00529 }
00530 
00534 static void
00535 layer_selector_select_callback (GHidLayerSelector *ls, int layer, gpointer d)
00536 {
00537   ignore_layer_update = true;
00538   /* Select Layer */
00539   PCB->SilkActive = (layer == LAYER_BUTTON_SILK);
00540   PCB->RatDraw  = (layer == LAYER_BUTTON_RATS);
00541   if (layer == LAYER_BUTTON_SILK)
00542     {
00543       PCB->ElementOn = true;
00544       hid_action ("LayersChanged");
00545     }
00546   else if (layer == LAYER_BUTTON_RATS)
00547     {
00548       PCB->RatOn = true;
00549       hid_action ("LayersChanged");
00550     }
00551   else if (layer < max_copper_layer)
00552     ChangeGroupVisibility (layer, TRUE, true);
00553 
00554   ignore_layer_update = false;
00555 
00556   ghid_invalidate_all ();
00557 }
00558 
00562 static void
00563 layer_selector_rename_callback (GHidLayerSelector *ls,
00564                                 int layer_id,
00565                                 char *new_name,
00566                                 void *userdata)
00567 {
00568   LayerType *layer = LAYER_PTR (layer_id);
00569 
00570   /* Check for a legal layer name - for now, allow anything non-empty */
00571   if (new_name[0] == '\0')
00572     return;
00573 
00574   /* Don't bother if the name is identical to the current one */
00575   if (strcmp (layer->Name, new_name) == 0)
00576     return;
00577 
00578   free (layer->Name);
00579   layer->Name = strdup (new_name);
00580   ghid_layer_buttons_update ();
00581   if (!PCB->Changed)
00582     {
00583       SetChangedFlag (true);
00584       ghid_window_set_name_label (PCB->Name);
00585     }
00586 }
00587 
00591 static void
00592 layer_selector_toggle_callback (GHidLayerSelector *ls, int layer, gpointer d)
00593 {
00594   gboolean redraw = FALSE;
00595   gboolean active;
00596   layer_process (NULL, NULL, &active, layer);
00597 
00598   active = !active;
00599   ignore_layer_update = true;
00600   switch (layer)
00601     {
00602     case LAYER_BUTTON_SILK:
00603       PCB->ElementOn = active;
00604       PCB->Data->SILKLAYER.On = PCB->ElementOn;
00605       PCB->Data->BACKSILKLAYER.On = PCB->ElementOn;
00606       redraw = 1;
00607       break;
00608     case LAYER_BUTTON_RATS:
00609       PCB->RatOn = active;
00610       redraw = 1;
00611       break;
00612     case LAYER_BUTTON_PINS:
00613       PCB->PinOn = active;
00614       redraw |= (PCB->Data->ElementN != 0);
00615       break;
00616     case LAYER_BUTTON_VIAS:
00617       PCB->ViaOn = active;
00618       redraw |= (PCB->Data->ViaN != 0);
00619       break;
00620     case LAYER_BUTTON_FARSIDE:
00621       PCB->InvisibleObjectsOn = active;
00622       PCB->Data->BACKSILKLAYER.On = (active && PCB->ElementOn);
00623       redraw = TRUE;
00624       break;
00625     case LAYER_BUTTON_MASK:
00626       if (active)
00627         SET_FLAG (SHOWMASKFLAG, PCB);
00628       else
00629         CLEAR_FLAG (SHOWMASKFLAG, PCB);
00630       redraw = TRUE;
00631       break;
00632     default:
00633       /* Flip the visibility */
00634       ChangeGroupVisibility (layer, active, false);
00635       redraw = TRUE;
00636       break;
00637     }
00638 
00639   /* Select the next visible layer. (If there is none, this will
00640    * select the currently-selected layer, triggering the selection
00641    * callback, which will turn the visibility on.) This way we
00642    * will never have an invisible layer selected.
00643    */
00644   if (!active)
00645     ghid_layer_selector_select_next_visible (ls);
00646 
00647   ignore_layer_update = false;
00648 
00649   if (redraw)
00650     ghid_invalidate_all();
00651 }
00652 
00656 void
00657 ghid_install_accel_groups (GtkWindow *window, GhidGui *gui)
00658 {
00659   gtk_window_add_accel_group
00660     (window, ghid_main_menu_get_accel_group
00661                (GHID_MAIN_MENU (gui->menu_bar)));
00662   gtk_window_add_accel_group
00663     (window, ghid_layer_selector_get_accel_group
00664                (GHID_LAYER_SELECTOR (gui->layer_selector)));
00665   gtk_window_add_accel_group
00666     (window, ghid_route_style_selector_get_accel_group
00667                (GHID_ROUTE_STYLE_SELECTOR (gui->route_style_selector)));
00668 }
00669 
00673 void
00674 ghid_remove_accel_groups (GtkWindow *window, GhidGui *gui)
00675 {
00676   gtk_window_remove_accel_group
00677     (window, ghid_main_menu_get_accel_group
00678                (GHID_MAIN_MENU (gui->menu_bar)));
00679   gtk_window_remove_accel_group
00680     (window, ghid_layer_selector_get_accel_group
00681                (GHID_LAYER_SELECTOR (gui->layer_selector)));
00682   gtk_window_remove_accel_group
00683     (window, ghid_route_style_selector_get_accel_group
00684                (GHID_ROUTE_STYLE_SELECTOR (gui->route_style_selector)));
00685 }
00686 
00691 void
00692 ghid_window_set_name_label (gchar * name)
00693 {
00694   gchar *str;
00695   gchar *filename;
00696 
00697   /* FIXME -- should this happen?  It does... */
00698   /* This happens if we're calling an exporter from the command line */
00699   if (ghidgui == NULL)
00700     return;
00701 
00702   dup_string (&(ghidgui->name_label_string), name);
00703   if (!ghidgui->name_label_string || !*ghidgui->name_label_string)
00704     ghidgui->name_label_string = g_strdup (_("Unnamed"));
00705 
00706   if (!PCB->Filename  || !*PCB->Filename)
00707     filename = g_strdup(_("Unsaved.pcb"));
00708   else
00709     filename = g_strdup(PCB->Filename);
00710 
00711   str = g_strdup_printf ("%s%s (%s) - PCB", PCB->Changed ? "*": "",
00712                          ghidgui->name_label_string, filename);
00713   gtk_window_set_title (GTK_WINDOW (gport->top_window), str);
00714   g_free (str);
00715   g_free (filename);
00716 }
00717 
00718 static void
00719 grid_units_button_cb (GtkWidget * widget, gpointer data)
00720 {
00721   /* Button only toggles between mm and mil */
00722   if (Settings.grid_unit == get_unit_struct ("mm"))
00723     hid_actionl ("SetUnits", "mil", NULL);
00724   else
00725     hid_actionl ("SetUnits", "mm", NULL);
00726 }
00727 
00733 static void
00734 absolute_label_size_req_cb (GtkWidget * widget, 
00735                             GtkRequisition *req, gpointer data)
00736 {
00737   
00738   static gint w = 0;
00739   if (req->width > w)
00740     w = req->width;
00741   else
00742     req->width = w;
00743 }
00744 
00745 static void
00746 relative_label_size_req_cb (GtkWidget * widget, 
00747                             GtkRequisition *req, gpointer data)
00748 {
00749   
00750   static gint w = 0;
00751   if (req->width > w)
00752     w = req->width;
00753   else
00754     req->width = w;
00755 }
00756 
00757 static void
00758 make_cursor_position_labels (GtkWidget * hbox, GHidPort * port)
00759 {
00760   GtkWidget *frame, *label;
00761 
00762   /* The grid units button next to the cursor position labels.
00763    */
00764   ghidgui->grid_units_button = gtk_button_new ();
00765   label = gtk_label_new ("");
00766   gtk_label_set_markup (GTK_LABEL (label),
00767                         Settings.grid_unit->in_suffix);
00768   ghidgui->grid_units_label = label;
00769   gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
00770   gtk_container_add (GTK_CONTAINER (ghidgui->grid_units_button), label);
00771   gtk_box_pack_end (GTK_BOX (hbox), ghidgui->grid_units_button, FALSE, TRUE, 0);
00772   g_signal_connect (ghidgui->grid_units_button, "clicked",
00773                     G_CALLBACK (grid_units_button_cb), NULL);
00774 
00775   /* The absolute cursor position label
00776    */
00777   frame = gtk_frame_new (NULL);
00778   gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
00779   gtk_container_set_border_width (GTK_CONTAINER (frame), 0);
00780   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
00781 
00782   label = gtk_label_new ("");
00783   gtk_container_add (GTK_CONTAINER (frame), label);
00784   ghidgui->cursor_position_absolute_label = label;
00785   g_signal_connect (G_OBJECT (label), "size-request",
00786                     G_CALLBACK (absolute_label_size_req_cb), NULL);
00787 
00788 
00789   /* The relative cursor position label
00790    */
00791   frame = gtk_frame_new (NULL);
00792   gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
00793   gtk_container_set_border_width (GTK_CONTAINER (frame), 0);
00794   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
00795   label = gtk_label_new (" __.__  __.__ ");
00796   gtk_container_add (GTK_CONTAINER (frame), label);
00797   ghidgui->cursor_position_relative_label = label;
00798   g_signal_connect (G_OBJECT (label), "size-request",
00799                     G_CALLBACK (relative_label_size_req_cb), NULL);
00800 
00801 }
00802 
00806 static void
00807 make_virtual_layer_buttons (GtkWidget *layer_selector)
00808 {
00809   GHidLayerSelector *layersel = GHID_LAYER_SELECTOR (layer_selector);
00810   gchar *text;
00811   gchar *color_string;
00812   gboolean active;
00813  
00814   layer_process (&color_string, &text, &active, LAYER_BUTTON_SILK);
00815   ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_SILK,
00816                                  text, color_string, active, TRUE, FALSE);
00817   layer_process (&color_string, &text, &active, LAYER_BUTTON_RATS);
00818   ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_RATS,
00819                                  text, color_string, active, TRUE, FALSE);
00820   layer_process (&color_string, &text, &active, LAYER_BUTTON_PINS);
00821   ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_PINS,
00822                                  text, color_string, active, FALSE, FALSE);
00823   layer_process (&color_string, &text, &active, LAYER_BUTTON_VIAS);
00824   ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_VIAS,
00825                                  text, color_string, active, FALSE, FALSE);
00826   layer_process (&color_string, &text, &active, LAYER_BUTTON_FARSIDE);
00827   ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_FARSIDE,
00828                                  text, color_string, active, FALSE, FALSE);
00829   layer_process (&color_string, &text, &active, LAYER_BUTTON_MASK);
00830   ghid_layer_selector_add_layer (layersel, LAYER_BUTTON_MASK,
00831                                  text, color_string, active, FALSE, FALSE);
00832 }
00833 
00837 const gchar *
00838 get_layer_color (gint layer)
00839 {
00840   gchar *rv;
00841   layer_process (&rv, NULL, NULL, layer);
00842   return rv;
00843 }
00844 
00848 void
00849 ghid_layer_buttons_color_update (void)
00850 {
00851   ghid_layer_selector_update_colors
00852     (GHID_LAYER_SELECTOR (ghidgui->layer_selector), get_layer_color);
00853   pcb_colors_from_settings (PCB);
00854 }
00855  
00859 static void
00860 make_layer_buttons (GtkWidget *layersel)
00861 {
00862   gint i;
00863   gchar *text;
00864   gchar *color_string;
00865   gboolean active = TRUE;
00866 
00867   for (i = 0; i < max_copper_layer; ++i)
00868     {
00869       layer_process (&color_string, &text, &active, i);
00870       ghid_layer_selector_add_layer (GHID_LAYER_SELECTOR (layersel), i,
00871                                      text, color_string, active, TRUE, TRUE);
00872     }
00873 }
00874 
00875 
00879 gboolean
00880 get_layer_delete (gint layer)
00881 {
00882   return layer >= max_copper_layer;
00883 }
00884 
00891 void
00892 ghid_layer_buttons_update (void)
00893 {
00894   gint layer;
00895 
00896   if (ignore_layer_update)
00897     return;
00898  
00899   ghid_layer_selector_delete_layers
00900     (GHID_LAYER_SELECTOR (ghidgui->layer_selector),
00901      get_layer_delete);
00902   make_layer_buttons (ghidgui->layer_selector);
00903   make_virtual_layer_buttons (ghidgui->layer_selector);
00904   ghid_main_menu_install_layer_selector
00905       (GHID_MAIN_MENU (ghidgui->menu_bar),
00906        GHID_LAYER_SELECTOR (ghidgui->layer_selector));
00907 
00908   /* Sync selected layer with PCB's state */
00909   if (PCB->RatDraw)
00910     layer = LAYER_BUTTON_RATS;
00911   else if (PCB->SilkActive)
00912     layer = LAYER_BUTTON_SILK;
00913   else
00914     layer = LayerStack[0];
00915 
00916   ghid_layer_selector_select_layer
00917     (GHID_LAYER_SELECTOR (ghidgui->layer_selector), layer);
00918 }
00919 
00923 static void
00924 route_styles_edited_cb (GHidRouteStyleSelector *rss, gboolean save,
00925                         gpointer data)
00926 {
00927   if (save)
00928     {
00929       g_free (Settings.Routes);
00930       Settings.Routes = make_route_string (PCB->RouteStyle, NUM_STYLES);
00931       ghidgui->config_modified = TRUE;
00932       ghid_config_files_write ();
00933     }
00934   ghid_main_menu_install_route_style_selector
00935       (GHID_MAIN_MENU (ghidgui->menu_bar),
00936        GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
00937 }
00938 
00942 static void
00943 route_style_changed_cb (GHidRouteStyleSelector *rss, RouteStyleType *rst,
00944                         gpointer data)
00945 {
00946   pcb_use_route_style (rst);
00947   ghid_set_status_line_label();
00948 }
00949 
00953 void
00954 make_route_style_buttons (GHidRouteStyleSelector *rss)
00955 {
00956   int i;
00957   for (i = 0; i < NUM_STYLES; ++i)
00958     ghid_route_style_selector_add_route_style (rss, &PCB->RouteStyle[i]);
00959   g_signal_connect (G_OBJECT (rss), "select_style",
00960                     G_CALLBACK (route_style_changed_cb), NULL);
00961   g_signal_connect (G_OBJECT (rss), "style_edited",
00962                     G_CALLBACK (route_styles_edited_cb), NULL);
00963   ghid_main_menu_install_route_style_selector
00964       (GHID_MAIN_MENU (ghidgui->menu_bar),
00965        GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
00966 }
00967 
00971 typedef struct
00972 {
00973   GtkWidget *button;
00974   GtkWidget *toolbar_button;
00975   guint button_cb_id;
00976   guint toolbar_button_cb_id;
00977   gchar *name;
00978   gint mode;
00979   gchar **xpm;
00980   gchar *tooltip;
00981 }
00982 ModeButton;
00983 
00984 
00985 static ModeButton mode_buttons[] = {
00986   {NULL, NULL, 0, 0, N_("via"), VIA_MODE, via,
00987     N_("create vias with <select mouse button>")},
00988   {NULL, NULL, 0, 0, N_("line"), LINE_MODE, line,
00989     N_("create a line segment, toggle draw modes with '/' or '.'")},
00990   {NULL, NULL, 0, 0, N_("arc"), ARC_MODE, arc,
00991     N_("create an arc segment")},
00992   {NULL, NULL, 0, 0, N_("text"), TEXT_MODE, text,
00993     N_("create a text")},
00994   {NULL, NULL, 0, 0, N_("rectangle"), RECTANGLE_MODE, rect,
00995     N_("create a filled rectangle")},
00996   {NULL, NULL, 0, 0, N_("polygon"), POLYGON_MODE, poly,
00997     N_("create a polygon, <shift>-P for closing the polygon")},
00998   {NULL, NULL, 0, 0, N_("polygonhole"), POLYGONHOLE_MODE, polyhole,
00999     N_("create a hole into an existing polygon")},
01000   {NULL, NULL, 0, 0, N_("buffer"), PASTEBUFFER_MODE, buf,
01001     N_("paste the selection from buffer into the layout")},
01002   {NULL, NULL, 0, 0, N_("remove"), REMOVE_MODE, del,
01003     N_("remove objects under the cursor")},
01004   {NULL, NULL, 0, 0, N_("rotate"), ROTATE_MODE, rot,
01005     N_("rotate a selection or object CCW, hold the <shift> key to rotate CW")},
01006   {NULL, NULL, 0, 0, N_("insertPoint"), INSERTPOINT_MODE, ins,
01007     N_("add points into existing lines and polygons")},
01008   {NULL, NULL, 0, 0, N_("thermal"), THERMAL_MODE, thrm,
01009     N_("create thermals with <select mouse button>, toggle thermal style with <Shift> <select mouse button>")},
01010   {NULL, NULL, 0, 0, N_("select"), ARROW_MODE, sel,
01011     N_("select, deselect or move objects or selections")},
01012   {NULL, NULL, 0, 0, N_("lock"), LOCK_MODE, lock,
01013     N_("lock or unlock an object")}
01014 };
01015 
01016 static gint n_mode_buttons = G_N_ELEMENTS (mode_buttons);
01017 
01018 static void
01019 do_set_mode (int mode)
01020 {
01021   SetMode (mode);
01022   ghid_mode_cursor (mode);
01023   ghidgui->settings_mode = mode;
01024 }
01025 
01026 static void
01027 mode_toolbar_button_toggled_cb (GtkToggleButton *button, ModeButton * mb)
01028 {
01029   gboolean active = gtk_toggle_button_get_active (button);
01030 
01031   if (mb->button != NULL)
01032     {
01033       g_signal_handler_block (mb->button, mb->button_cb_id);
01034       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->button), active);
01035       g_signal_handler_unblock (mb->button, mb->button_cb_id);
01036     }
01037 
01038   if (active)
01039     do_set_mode (mb->mode);
01040 }
01041 
01042 static void
01043 mode_button_toggled_cb (GtkWidget * widget, ModeButton * mb)
01044 {
01045   gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
01046 
01047   if (mb->toolbar_button != NULL)
01048     {
01049       g_signal_handler_block (mb->toolbar_button, mb->toolbar_button_cb_id);
01050       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->toolbar_button), active);
01051       g_signal_handler_unblock (mb->toolbar_button, mb->toolbar_button_cb_id);
01052     }
01053 
01054   if (active)
01055     do_set_mode (mb->mode);
01056 }
01057 
01058 void
01059 ghid_mode_buttons_update (void)
01060 {
01061   ModeButton *mb;
01062   gint i;
01063 
01064   for (i = 0; i < n_mode_buttons; ++i)
01065     {
01066       mb = &mode_buttons[i];
01067       if (Settings.Mode == mb->mode)
01068         {
01069           g_signal_handler_block (mb->button, mb->button_cb_id);
01070           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->button), TRUE);
01071           g_signal_handler_unblock (mb->button, mb->button_cb_id);
01072 
01073           g_signal_handler_block (mb->toolbar_button, mb->toolbar_button_cb_id);
01074           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->toolbar_button), TRUE);
01075           g_signal_handler_unblock (mb->toolbar_button, mb->toolbar_button_cb_id);
01076           break;
01077         }
01078     }
01079 }
01080 
01081 void
01082 ghid_pack_mode_buttons (void)
01083 {
01084   if (ghidgui->compact_vertical)
01085     {
01086       gtk_widget_hide (ghidgui->mode_buttons_frame);
01087       gtk_widget_show_all (ghidgui->mode_toolbar);
01088     }
01089   else
01090     {
01091       gtk_widget_hide (ghidgui->mode_toolbar);
01092       gtk_widget_show_all (ghidgui->mode_buttons_frame);
01093     }
01094 }
01095 
01096 static void
01097 make_mode_buttons_and_toolbar (GtkWidget **mode_frame,
01098                                GtkWidget **mode_toolbar)
01099 {
01100   GtkToolItem *tool_item;
01101   GtkWidget *vbox, *hbox = NULL;
01102   GtkWidget *image;
01103   GdkPixbuf *pixbuf;
01104   GSList *group = NULL;
01105   GSList *toolbar_group = NULL;
01106   ModeButton *mb;
01107   int i;
01108 
01109   *mode_toolbar = gtk_toolbar_new ();
01110 
01111   *mode_frame = gtk_frame_new (NULL);
01112   vbox = gtk_vbox_new (FALSE, 0);
01113   gtk_container_add (GTK_CONTAINER (*mode_frame), vbox);
01114 
01115   for (i = 0; i < n_mode_buttons; ++i)
01116     {
01117       mb = &mode_buttons[i];
01118 
01119       /* Create tool button for mode frame */
01120       mb->button = gtk_radio_button_new (group);
01121       gtk_widget_set_tooltip_text (mb->button, _(mb->tooltip));
01122       gtk_widget_set_name (mb->button, (mb->name));
01123       group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (mb->button));
01124       gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (mb->button), FALSE);
01125 
01126       /* Create tool button for toolbar */
01127       mb->toolbar_button = gtk_radio_button_new (toolbar_group);
01128       gtk_widget_set_tooltip_text (mb->toolbar_button, _(mb->tooltip));
01129       gtk_widget_set_name (mb->toolbar_button, (mb->name));
01130       toolbar_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (mb->toolbar_button));
01131       gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (mb->toolbar_button), FALSE);
01132 
01133       /* Pack mode-frame button into the frame */
01134       if ((i % ghidgui->n_mode_button_columns) == 0)
01135         {
01136           hbox = gtk_hbox_new (FALSE, 0);
01137           gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
01138         }
01139       gtk_box_pack_start (GTK_BOX (hbox), mb->button, FALSE, FALSE, 0);
01140 
01141       /* Create a container for the toolbar button and add that */
01142       tool_item = gtk_tool_item_new ();
01143       gtk_container_add (GTK_CONTAINER (tool_item), mb->toolbar_button);
01144       gtk_toolbar_insert (GTK_TOOLBAR (*mode_toolbar), tool_item, -1);
01145 
01146       /* Load the image for the button, create GtkImage widgets for both
01147        * the grid button and the toolbar button, then pack into the buttons
01148        */
01149       pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **) mb->xpm);
01150       image = gtk_image_new_from_pixbuf (pixbuf);
01151       gtk_container_add (GTK_CONTAINER (mb->button), image);
01152       image = gtk_image_new_from_pixbuf (pixbuf);
01153       gtk_container_add (GTK_CONTAINER (mb->toolbar_button), image);
01154       g_object_unref (pixbuf);
01155 
01156       if (strcmp (mb->name, "select") == 0)
01157         {
01158           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->button), TRUE);
01159           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mb->toolbar_button), TRUE);
01160         }
01161 
01162       mb->button_cb_id =
01163         g_signal_connect (mb->button, "toggled",
01164                           G_CALLBACK (mode_button_toggled_cb), mb);
01165       mb->toolbar_button_cb_id =
01166         g_signal_connect (mb->toolbar_button, "toggled",
01167                           G_CALLBACK (mode_toolbar_button_toggled_cb), mb);
01168     }
01169 }
01170 
01171 
01172 /*
01173  * ---------------------------------------------------------------
01174  * Top window
01175  * ---------------------------------------------------------------
01176  */
01177 
01178 static gint
01179 delete_chart_cb (GtkWidget * widget, GdkEvent * event, GHidPort * port)
01180 {
01181   ghid_config_files_write ();
01182   hid_action ("Quit");
01183 
01184   /*
01185    * Return TRUE to keep our app running.  A FALSE here would let the
01186    * delete signal continue on and kill our program.
01187    */
01188   return TRUE;
01189 }
01190 
01191 static void
01192 destroy_chart_cb (GtkWidget * widget, GHidPort * port)
01193 {
01194   ghid_shutdown_renderer (port);
01195   gtk_main_quit ();
01196 }
01197 
01198 static void
01199 get_widget_styles (GtkStyle **menu_bar_style,
01200                    GtkStyle **tool_button_style,
01201                    GtkStyle **tool_button_label_style)
01202 {
01203   GtkWidget *tool_button;
01204   GtkWidget *tool_button_label;
01205   GtkToolItem *tool_item;
01206 
01207   /* Build a tool item to extract the theme's styling for a toolbar button with text */
01208   tool_item = gtk_tool_item_new ();
01209   gtk_toolbar_insert (GTK_TOOLBAR (ghidgui->mode_toolbar), tool_item, 0);
01210   tool_button = gtk_button_new ();
01211   gtk_container_add (GTK_CONTAINER (tool_item), tool_button);
01212   tool_button_label = gtk_label_new ("");
01213   gtk_container_add (GTK_CONTAINER (tool_button), tool_button_label);
01214 
01215   /* Grab the various styles we need */
01216   gtk_widget_ensure_style (ghidgui->menu_bar);
01217   *menu_bar_style = gtk_widget_get_style (ghidgui->menu_bar);
01218 
01219   gtk_widget_ensure_style (tool_button);
01220   *tool_button_style = gtk_widget_get_style (tool_button);
01221 
01222   gtk_widget_ensure_style (tool_button_label);
01223   *tool_button_label_style = gtk_widget_get_style (tool_button_label);
01224 
01225   gtk_widget_destroy (GTK_WIDGET (tool_item));
01226 }
01227 
01228 static void
01229 do_fix_topbar_theming (void)
01230 {
01231   GtkWidget *rel_pos_frame;
01232   GtkWidget *abs_pos_frame;
01233   GtkStyle *menu_bar_style;
01234   GtkStyle *tool_button_style;
01235   GtkStyle *tool_button_label_style;
01236 
01237   get_widget_styles (&menu_bar_style,
01238                      &tool_button_style,
01239                      &tool_button_label_style);
01240 
01241   /* Style the top bar background as if it were all a menu bar */
01242   gtk_widget_set_style (ghidgui->top_bar_background, menu_bar_style);
01243 
01244   /* Style the cursor position labels using the menu bar style as well.
01245    * If this turns out to cause problems with certain gtk themes, we may
01246    * need to grab the GtkStyle associated with an actual menu item to
01247    * get a text color to render with.
01248    */
01249   gtk_widget_set_style (ghidgui->cursor_position_relative_label, menu_bar_style);
01250   gtk_widget_set_style (ghidgui->cursor_position_absolute_label, menu_bar_style);
01251 
01252   /* Style the units button as if it were a toolbar button - hopefully
01253    * this isn't too ugly sitting on a background themed as a menu bar.
01254    * It is unlikely any theme defines colours for a GtkButton sitting on
01255    * a menu bar.
01256    */
01257   rel_pos_frame = gtk_widget_get_parent (ghidgui->cursor_position_relative_label);
01258   abs_pos_frame = gtk_widget_get_parent (ghidgui->cursor_position_absolute_label);
01259   gtk_widget_set_style (rel_pos_frame, menu_bar_style);
01260   gtk_widget_set_style (abs_pos_frame, menu_bar_style);
01261   gtk_widget_set_style (ghidgui->grid_units_button, tool_button_style);
01262   gtk_widget_set_style (ghidgui->grid_units_label, tool_button_label_style);
01263 }
01264 
01273 static void
01274 fix_topbar_theming (void)
01275 {
01276   GtkSettings *settings;
01277 
01278   do_fix_topbar_theming ();
01279 
01280   settings = gtk_widget_get_settings (ghidgui->top_bar_background);
01281   g_signal_connect (settings, "notify::gtk-theme-name",
01282                     G_CALLBACK (do_fix_topbar_theming), NULL);
01283   g_signal_connect (settings, "notify::gtk-font-name",
01284                     G_CALLBACK (do_fix_topbar_theming), NULL);
01285 }
01286 
01292 static void
01293 ghid_build_pcb_top_window (void)
01294 {
01295   GtkWidget *window;
01296   GtkWidget *vbox_main, *hbox_middle, *hbox;
01297   GtkWidget *vbox, *frame;
01298   GtkWidget *label;
01299   /* FIXME: IFDEF HACK */
01300 #ifdef ENABLE_GL
01301   GtkWidget *trackball;
01302 #endif
01303   GHidPort *port = &ghid_port;
01304   GtkWidget *scrolled;
01305 
01306   window = gport->top_window;
01307 
01308   vbox_main = gtk_vbox_new (FALSE, 0);
01309   gtk_container_add (GTK_CONTAINER (window), vbox_main);
01310 
01311   /* -- Top control bar */
01312   ghidgui->top_bar_background = gtk_event_box_new ();
01313   gtk_box_pack_start (GTK_BOX (vbox_main),
01314                       ghidgui->top_bar_background, FALSE, FALSE, 0);
01315 
01316   ghidgui->top_hbox = gtk_hbox_new (FALSE, 0);
01317   gtk_container_add (GTK_CONTAINER (ghidgui->top_bar_background),
01318                      ghidgui->top_hbox);
01319 
01320   /*
01321    * menu_hbox will be made insensitive when the gui needs
01322    * a modal button GetLocation button press.
01323    */
01324   ghidgui->menu_hbox = gtk_hbox_new (FALSE, 0);
01325   gtk_box_pack_start (GTK_BOX (ghidgui->top_hbox), ghidgui->menu_hbox,
01326                       FALSE, FALSE, 0);
01327 
01328   ghidgui->menubar_toolbar_vbox = gtk_vbox_new (FALSE, 0);
01329   gtk_box_pack_start (GTK_BOX (ghidgui->menu_hbox),
01330                       ghidgui->menubar_toolbar_vbox, FALSE, FALSE, 0);
01331 
01332   /* Build layer menus */
01333   ghidgui->layer_selector = ghid_layer_selector_new ();
01334   make_layer_buttons (ghidgui->layer_selector);
01335   make_virtual_layer_buttons (ghidgui->layer_selector);
01336   g_signal_connect (G_OBJECT (ghidgui->layer_selector), "select-layer",
01337                     G_CALLBACK (layer_selector_select_callback),
01338                     NULL);
01339   g_signal_connect (G_OBJECT (ghidgui->layer_selector), "toggle-layer",
01340                     G_CALLBACK (layer_selector_toggle_callback),
01341                     NULL);
01342   g_signal_connect (G_OBJECT (ghidgui->layer_selector), "rename-layer",
01343                     G_CALLBACK (layer_selector_rename_callback),
01344                     NULL);
01345   /* Build main menu */
01346   ghidgui->menu_bar = ghid_load_menus ();
01347   gtk_box_pack_start (GTK_BOX (ghidgui->menubar_toolbar_vbox),
01348                       ghidgui->menu_bar, FALSE, FALSE, 0);
01349 
01350   make_mode_buttons_and_toolbar (&ghidgui->mode_buttons_frame,
01351                                  &ghidgui->mode_toolbar);
01352   gtk_box_pack_start (GTK_BOX (ghidgui->menubar_toolbar_vbox),
01353                       ghidgui->mode_toolbar, FALSE, FALSE, 0);
01354 
01355 
01356   ghidgui->position_hbox = gtk_hbox_new (FALSE, 0);
01357   gtk_box_pack_end (GTK_BOX(ghidgui->top_hbox),
01358                     ghidgui->position_hbox, TRUE, TRUE, 0);
01359 
01360   make_cursor_position_labels (ghidgui->position_hbox, port);
01361 
01362   hbox_middle = gtk_hbox_new (FALSE, 0);
01363   gtk_box_pack_start (GTK_BOX (vbox_main), hbox_middle, TRUE, TRUE, 0);
01364 
01365   fix_topbar_theming (); /* Must be called after toolbar is created */
01366 
01367   /* -- Left control bar */
01368   /*
01369    * This box will be made insensitive when the gui needs
01370    * a modal button GetLocation button press.
01371    */
01372   ghidgui->left_toolbar = gtk_vbox_new (FALSE, 0);
01373   gtk_box_pack_start (GTK_BOX (hbox_middle),
01374                       ghidgui->left_toolbar, FALSE, FALSE, 0);
01375 
01376   vbox = ghid_scrolled_vbox (ghidgui->left_toolbar, &scrolled,
01377                              GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
01378   gtk_box_pack_start (GTK_BOX(vbox), ghidgui->layer_selector,
01379                       FALSE, FALSE, 0);
01380 
01381   /* FIXME: IFDEF HACK */
01382 #ifdef ENABLE_GL
01383   trackball = ghid_trackball_new ();
01384   g_signal_connect (trackball, "rotation-changed",
01385                     G_CALLBACK (ghid_port_rotate), NULL);
01386   g_signal_connect (trackball, "view-2d-changed",
01387                     G_CALLBACK (ghid_view_2d), NULL);
01388   gtk_box_pack_start (GTK_BOX(ghidgui->left_toolbar),
01389                       trackball, FALSE, FALSE, 0);
01390 #endif
01391 
01392   /* ghidgui->mode_buttons_frame was created above in the call to
01393    * make_mode_buttons_and_toolbar (...);
01394    */
01395   gtk_box_pack_start (GTK_BOX (ghidgui->left_toolbar),
01396                       ghidgui->mode_buttons_frame, FALSE, FALSE, 0);
01397 
01398   frame = gtk_frame_new(NULL);
01399   gtk_box_pack_end (GTK_BOX (ghidgui->left_toolbar), frame, FALSE, FALSE, 0);
01400   vbox = gtk_vbox_new(FALSE, 0);
01401   gtk_container_add(GTK_CONTAINER(frame), vbox);
01402   hbox = gtk_hbox_new(FALSE, 0);
01403   gtk_box_pack_start(GTK_BOX (vbox), hbox, FALSE, FALSE, 1);
01404   ghidgui->route_style_selector = ghid_route_style_selector_new ();
01405   make_route_style_buttons
01406     (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
01407   gtk_box_pack_start(GTK_BOX(hbox), ghidgui->route_style_selector,
01408                      FALSE, FALSE, 0);
01409 
01410   ghidgui->vbox_middle = gtk_vbox_new (FALSE, 0);
01411   gtk_box_pack_start (GTK_BOX (hbox_middle),
01412                       ghidgui->vbox_middle, TRUE, TRUE, 0);
01413 
01414   hbox = gtk_hbox_new (FALSE, 0);
01415   gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle), hbox, TRUE, TRUE, 0);
01416 
01417   /* -- The PCB layout output drawing area */
01418 
01419   gport->drawing_area = gtk_drawing_area_new ();
01420   ghid_init_drawing_widget (gport->drawing_area, gport);
01421 
01422   gtk_widget_add_events (gport->drawing_area, GDK_EXPOSURE_MASK
01423                          | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
01424                          | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK
01425                          | GDK_KEY_RELEASE_MASK | GDK_KEY_PRESS_MASK
01426                          | GDK_FOCUS_CHANGE_MASK | GDK_POINTER_MOTION_MASK
01427                          | GDK_POINTER_MOTION_HINT_MASK);
01428 
01429   /*
01430    * This is required to get the drawing_area key-press-event.  Also the
01431    * enter and button press callbacks grab focus to be sure we have it
01432    * when in the drawing_area.
01433    */
01434   gtk_widget_set_can_focus (gport->drawing_area, TRUE);
01435 
01436   gtk_box_pack_start (GTK_BOX (hbox), gport->drawing_area, TRUE, TRUE, 0);
01437 
01438   ghidgui->v_adjustment = gtk_adjustment_new (0.0, 0.0, 100.0,
01439                                               10.0, 10.0, 10.0);
01440   ghidgui->v_range =
01441     gtk_vscrollbar_new (GTK_ADJUSTMENT (ghidgui->v_adjustment));
01442 
01443   gtk_box_pack_start (GTK_BOX (hbox), ghidgui->v_range, FALSE, FALSE, 0);
01444 
01445   g_signal_connect (G_OBJECT (ghidgui->v_adjustment), "value_changed",
01446                     G_CALLBACK (v_adjustment_changed_cb), ghidgui);
01447 
01448   ghidgui->h_adjustment = gtk_adjustment_new (0.0, 0.0, 100.0,
01449                                               10.0, 10.0, 10.0);
01450   ghidgui->h_range =
01451     gtk_hscrollbar_new (GTK_ADJUSTMENT (ghidgui->h_adjustment));
01452   gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle),
01453                       ghidgui->h_range, FALSE, FALSE, 0);
01454 
01455   g_signal_connect (G_OBJECT (ghidgui->h_adjustment), "value_changed",
01456                     G_CALLBACK (h_adjustment_changed_cb), ghidgui);
01457 
01458   /* -- The bottom status line label */
01459   ghidgui->status_line_hbox = gtk_hbox_new (FALSE, 0);
01460   gtk_box_pack_start (GTK_BOX (ghidgui->vbox_middle),
01461                       ghidgui->status_line_hbox, FALSE, FALSE, 0);
01462 
01463   label = gtk_label_new ("");
01464   gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
01465   gtk_box_pack_start (GTK_BOX (ghidgui->status_line_hbox), label, FALSE,
01466                       FALSE, 0);
01467   ghidgui->status_line_label = label;
01468 
01469   /* Depending on user setting, the command_combo_box may get packed into
01470      |  the status_line_hbox, but it will happen on demand the first time
01471      |  the user does a command entry.
01472    */
01473 
01474   g_signal_connect (G_OBJECT (gport->drawing_area), "realize",
01475                     G_CALLBACK (ghid_port_drawing_realize_cb),
01476                     port);
01477   g_signal_connect (G_OBJECT (gport->drawing_area), "expose_event",
01478                     G_CALLBACK (ghid_drawing_area_expose_cb),
01479                     port);
01480   g_signal_connect (G_OBJECT (gport->top_window), "configure_event",
01481                     G_CALLBACK (top_window_configure_event_cb), port);
01482   g_signal_connect (gport->top_window, "enter-notify-event",
01483                     G_CALLBACK (top_window_enter_cb), port);
01484   g_signal_connect (G_OBJECT (gport->drawing_area), "configure_event",
01485                     G_CALLBACK (ghid_port_drawing_area_configure_event_cb),
01486                     port);
01487 
01488 
01489   /* Mouse and key events will need to be intercepted when PCB needs a
01490      |  location from the user.
01491    */
01492 
01493   ghid_interface_input_signals_connect ();
01494 
01495   g_signal_connect (G_OBJECT (gport->drawing_area), "enter_notify_event",
01496                     G_CALLBACK (ghid_port_window_enter_cb), port);
01497   g_signal_connect (G_OBJECT (gport->drawing_area), "leave_notify_event",
01498                     G_CALLBACK (ghid_port_window_leave_cb), port);
01499   g_signal_connect (G_OBJECT (gport->drawing_area), "motion_notify_event",
01500                     G_CALLBACK (ghid_port_window_motion_cb), port);
01501 
01502 
01503 
01504   g_signal_connect (G_OBJECT (window), "delete_event",
01505                     G_CALLBACK (delete_chart_cb), port);
01506   g_signal_connect (G_OBJECT (window), "destroy",
01507                     G_CALLBACK (destroy_chart_cb), port);
01508 
01509   ghidgui->creating = FALSE;
01510 
01511   gtk_widget_show_all (gport->top_window);
01512   ghid_pack_mode_buttons ();
01513   gdk_window_set_back_pixmap (gtk_widget_get_window (gport->drawing_area),
01514                               NULL, FALSE);
01515 
01516   port->tooltip_update_timeout_id = 0;
01517 }
01518 
01519 
01520   /* Connect and disconnect just the signals a g_main_loop() will need.
01521      |  Cursor and motion events still need to be handled by the top level
01522      |  loop, so don't connect/reconnect these.
01523      |  A g_main_loop will be running when PCB wants the user to select a
01524      |  location or if command entry is needed in the status line hbox.
01525      |  During these times normal button/key presses are intercepted, either
01526      |  by new signal handlers or the command_combo_box entry.
01527    */
01528 static gulong button_press_handler;
01529 static gulong button_release_handler;
01530 static gulong scroll_event_handler;
01531 static gulong key_press_handler;
01532 static gulong key_release_handler;
01533 
01544 void
01545 ghid_interface_input_signals_connect (void)
01546 {
01547   button_press_handler =
01548     g_signal_connect (G_OBJECT (gport->drawing_area), "button_press_event",
01549                       G_CALLBACK (ghid_port_button_press_cb), NULL);
01550 
01551   button_release_handler =
01552     g_signal_connect (G_OBJECT (gport->drawing_area), "button_release_event",
01553                       G_CALLBACK (ghid_port_button_release_cb), NULL);
01554 
01555   scroll_event_handler =
01556     g_signal_connect (G_OBJECT (gport->drawing_area), "scroll_event",
01557                     G_CALLBACK (ghid_port_window_mouse_scroll_cb), NULL);
01558 
01559   key_press_handler =
01560     g_signal_connect (G_OBJECT (gport->drawing_area), "key_press_event",
01561                       G_CALLBACK (ghid_port_key_press_cb), NULL);
01562 
01563   key_release_handler =
01564     g_signal_connect (G_OBJECT (gport->drawing_area), "key_release_event",
01565                       G_CALLBACK (ghid_port_key_release_cb), NULL);
01566 }
01567 
01578 void
01579 ghid_interface_input_signals_disconnect (void)
01580 {
01581   if (button_press_handler)
01582     g_signal_handler_disconnect (gport->drawing_area, button_press_handler);
01583 
01584   if (button_release_handler)
01585     g_signal_handler_disconnect (gport->drawing_area, button_release_handler);
01586 
01587   if (scroll_event_handler)
01588     g_signal_handler_disconnect (gport->drawing_area, scroll_event_handler);
01589 
01590   if (key_press_handler)
01591     g_signal_handler_disconnect (gport->drawing_area, key_press_handler);
01592 
01593   if (key_release_handler)
01594     g_signal_handler_disconnect (gport->drawing_area, key_release_handler);
01595 
01596   button_press_handler = 0;
01597   button_release_handler = 0;
01598   scroll_event_handler = 0;
01599   key_press_handler = 0;
01600   key_release_handler = 0;
01601 }
01602 
01603 
01609 void
01610 ghid_interface_set_sensitive (gboolean sensitive)
01611 {
01612   gtk_widget_set_sensitive (ghidgui->left_toolbar, sensitive);
01613   gtk_widget_set_sensitive (ghidgui->menu_hbox, sensitive);
01614 }
01615 
01616 
01620 static void
01621 ghid_init_icons (GHidPort * port)
01622 {
01623   GdkWindow *window = gtk_widget_get_window (gport->top_window);
01624 
01625   XC_clock_source = gdk_bitmap_create_from_data (window,
01626                                                  (char *) rotateIcon_bits,
01627                                                  rotateIcon_width,
01628                                                  rotateIcon_height);
01629   XC_clock_mask =
01630     gdk_bitmap_create_from_data (window, (char *) rotateMask_bits,
01631                                  rotateMask_width, rotateMask_height);
01632 
01633   XC_hand_source = gdk_bitmap_create_from_data (window,
01634                                                 (char *) handIcon_bits,
01635                                                 handIcon_width,
01636                                                 handIcon_height);
01637   XC_hand_mask =
01638     gdk_bitmap_create_from_data (window, (char *) handMask_bits,
01639                                  handMask_width, handMask_height);
01640 
01641   XC_lock_source = gdk_bitmap_create_from_data (window,
01642                                                 (char *) lockIcon_bits,
01643                                                 lockIcon_width,
01644                                                 lockIcon_height);
01645   XC_lock_mask =
01646     gdk_bitmap_create_from_data (window, (char *) lockMask_bits,
01647                                  lockMask_width, lockMask_height);
01648 }
01649 
01650 void
01651 ghid_create_pcb_widgets (void)
01652 {
01653   GHidPort *port = &ghid_port;
01654   GError        *err = NULL;
01655 
01656   if (bg_image_file)
01657     ghidgui->bg_pixbuf = gdk_pixbuf_new_from_file(bg_image_file, &err);
01658   if (err)
01659     {
01660     g_error("%s", err->message);
01661     g_error_free(err);
01662     }
01663   ghid_build_pcb_top_window ();
01664   ghid_install_accel_groups (GTK_WINDOW (port->top_window), ghidgui);
01665   ghid_update_toggle_flags ();
01666 
01667   ghid_init_icons (port);
01668   SetMode (ARROW_MODE);
01669   ghid_mode_buttons_update ();
01670 }
01671 
01672 static gboolean
01673 ghid_listener_cb (GIOChannel *source,
01674                   GIOCondition condition,
01675                   gpointer data)
01676 {
01677   GIOStatus status;
01678   gchar *str;
01679   gsize len;
01680   gsize term;
01681   GError *err = NULL;
01682 
01683 
01684   if (condition & G_IO_HUP)
01685     {
01686       gui->log (_("Read end of pipe died!\n"));
01687       return FALSE;
01688     }
01689 
01690   if (condition == G_IO_IN)
01691     {
01692       status = g_io_channel_read_line (source, &str, &len, &term, &err);
01693       switch (status)
01694         {
01695         case G_IO_STATUS_NORMAL:
01696           hid_parse_actions (str);
01697           g_free (str);
01698           break;
01699 
01700         case G_IO_STATUS_ERROR:
01701           gui->log (_("ERROR status from g_io_channel_read_line\n"));
01702           return FALSE;
01703           break;
01704 
01705         case G_IO_STATUS_EOF:
01706           gui->log (_("Input pipe returned EOF.  The --listen option is \n"
01707                     "probably not running anymore in this session.\n"));
01708           return FALSE;
01709           break;
01710 
01711         case G_IO_STATUS_AGAIN:
01712           gui->log (_("AGAIN status from g_io_channel_read_line\n"));
01713           return FALSE;
01714           break;
01715 
01716         default:
01717           fprintf (stderr, _("ERROR:  unhandled case in ghid_listener_cb\n"));
01718           return FALSE;
01719           break;
01720         }
01721 
01722     }
01723   else
01724     fprintf (stderr, _("Unknown condition in ghid_listener_cb\n"));
01725   
01726   return TRUE;
01727 }
01728 
01729 static void
01730 ghid_create_listener (void)
01731 {
01732   GIOChannel *channel;
01733   int fd = fileno (stdin);
01734 
01735   channel = g_io_channel_unix_new (fd);
01736   g_io_add_watch (channel, G_IO_IN, ghid_listener_cb, NULL);
01737 }
01738 
01739 
01740 /* ------------------------------------------------------------ */
01741 
01742 static int stdin_listen = 0;
01743 static char *pcbmenu_path = "gpcb-menu.res";
01744 
01745 HID_Attribute ghid_attribute_list[] = {
01746 
01747 /* %start-doc options "21 GTK+ GUI Options"
01748 @ftable @code
01749 @item --listen
01750 Listen for actions on stdin.
01751 @end ftable
01752 %end-doc
01753 */
01754   {"listen", N_("Listen for actions on stdin"),
01755    HID_Boolean, 0, 0, {0, 0, 0}, 0, &stdin_listen},
01756 #define HA_listen 0
01757 
01758 /* %start-doc options "21 GTK+ GUI Options"
01759 @ftable @code
01760 @item --bg-image <string>
01761 File name of an image to put into the background of the GUI canvas. The image must
01762 be a color PPM image, in binary (not ASCII) format. It can be any size, and will be
01763 automatically scaled to fit the canvas.
01764 @end ftable
01765 %end-doc
01766 */
01767   {"bg-image", N_("Background Image"),
01768    HID_String, 0, 0, {0, 0, 0}, 0, &bg_image_file},
01769 #define HA_bg_image 1
01770 
01771 /* %start-doc options "21 GTK+ GUI Options"
01772 @ftable @code
01773 @item --pcb-menu <string>
01774 Location of the @file{gpcb-menu.res} file which defines the menu for the GTK+ GUI.
01775 @end ftable
01776 %end-doc
01777 */
01778 {"pcb-menu", N_("Location of gpcb-menu.res file"),
01779    HID_String, 0, 0, {0, PCBLIBDIR "/gpcb-menu.res", 0}, 0, &pcbmenu_path}
01780 #define HA_pcbmenu 2
01781 };
01782 
01783 REGISTER_ATTRIBUTES (ghid_attribute_list)
01784 
01785 HID_Attribute *
01786 ghid_get_export_options (int *n_ret)
01787 {
01788   *n_ret = sizeof (ghid_attribute_list) / sizeof (HID_Attribute);
01789   return ghid_attribute_list;
01790 }
01791 
01796 void
01797 ghid_parse_arguments (int *argc, char ***argv)
01798 {
01799   GtkWidget *window;
01800   gint i;
01801   GdkPixbuf *icon;
01802 
01803   /* on windows we need to figure out the installation directory */
01804 #ifdef WIN32
01805   char * tmps;
01806   char * libdir;
01807   tmps = g_win32_get_package_installation_directory_of_module (NULL);
01808 #define REST_OF_PATH G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S PACKAGE  G_DIR_SEPARATOR_S "newlib"
01809   libdir = (char *) malloc(strlen(tmps) +
01810                           strlen(REST_OF_PATH) +
01811                           1);
01812   sprintf(libdir, "%s%s", tmps, REST_OF_PATH);
01813   free(tmps);
01814   
01815   Settings.LibraryTree = libdir;
01816 
01817 #undef REST_OF_PATH
01818 
01819 #endif 
01820 
01821 #if defined (DEBUG)
01822   for (i = 0; i < *argc; i++)
01823     {
01824       printf ("ghid_parse_arguments():  *argv[%d] = \"%s\"\n", i, (*argv)[i]);
01825     }
01826 #endif
01827 
01828   /* Threads aren't used in PCB, but this call would go here.
01829    */
01830   /* g_thread_init (NULL); */
01831 
01832   /*
01833    * Prevent gtk_init() and gtk_init_check() from automatically calling
01834    * setlocale (LC_ALL, "") which would undo LC_NUMERIC handling in main().
01835    */
01836   gtk_disable_setlocale ();
01837 
01838   gtk_init (argc, argv);
01839 
01840   gport = &ghid_port;
01841   gport->view.coord_per_px = 300.0;
01842   pixel_slop = 300;
01843 
01844   ghid_init_renderer (argc, argv, gport);
01845 
01846   ghid_config_files_read (argc, argv);
01847 
01848   Settings.AutoPlace = 0;
01849   for (i = 0; i < *argc; i++)
01850     {
01851       if (strcmp ((*argv)[i], "-auto-place") == 0)
01852         Settings.AutoPlace = 1;
01853     }
01854 
01855   bindtextdomain (PACKAGE, LOCALEDIR);
01856   textdomain (PACKAGE);
01857   bind_textdomain_codeset (PACKAGE, "UTF-8");
01858 
01859   icon = gdk_pixbuf_new_from_xpm_data ((const gchar **) icon_bits);
01860   gtk_window_set_default_icon (icon);
01861 
01862   window = gport->top_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
01863   gtk_window_set_title (GTK_WINDOW (window), "PCB");
01864   gtk_window_resize (GTK_WINDOW(window),
01865                      ghidgui->top_window_width, ghidgui->top_window_height);
01866 
01867   if (Settings.AutoPlace)
01868     gtk_window_move (GTK_WINDOW (window), 10, 10);
01869 
01870   gtk_widget_show_all (gport->top_window);
01871   ghidgui->creating = TRUE;
01872 }
01873 
01874 void
01875 ghid_do_export (HID_Attr_Val * options)
01876 {
01877   ghid_create_pcb_widgets ();
01878 
01879   /* These are needed to make sure the @layerpick and @layerview menus
01880    * are properly initialized and synchronized with the current PCB.
01881    */
01882   ghid_layer_buttons_update ();
01883   ghid_main_menu_install_route_style_selector
01884       (GHID_MAIN_MENU (ghidgui->menu_bar),
01885        GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
01886 
01887   if (stdin_listen)
01888     ghid_create_listener ();
01889 
01890   ghid_notify_gui_is_up ();
01891 
01892   gtk_main ();
01893   ghid_config_files_write ();
01894 
01895 }
01896 
01900 static gboolean
01901 get_layer_visible_cb (int id)
01902 {
01903   int visible;
01904   layer_process (NULL, NULL, &visible, id);
01905   return visible;
01906 }
01907 
01908 gint
01909 LayersChanged (int argc, char **argv, Coord x, Coord y)
01910 {
01911   if (!ghidgui || !ghidgui->menu_bar)
01912     return 0;
01913 
01914   ghid_config_groups_changed();
01915   ghid_layer_buttons_update ();
01916   ghid_layer_selector_show_layers
01917     (GHID_LAYER_SELECTOR (ghidgui->layer_selector), get_layer_visible_cb);
01918 
01924   pcb_colors_from_settings (PCB);
01925   return 0;
01926 }
01927 
01928 static const char toggleview_syntax[] =
01929     N_("ToggleView(1..MAXLAYER)\n"
01930        "ToggleView(layername)\n"
01931        "ToggleView(Silk|Rats|Pins|Vias|Mask|BackSide)");
01932 
01933 static const char toggleview_help[] =
01934     N_("Toggle the visibility of the specified layer or layer group.");
01935 
01936 /* %start-doc actions ToggleView
01937 
01938 If you pass an integer, that layer is specified by index (the first
01939 layer is @code{1}, etc).  If you pass a layer name, that layer is
01940 specified by name.  When a layer is specified, the visibility of the
01941 layer group containing that layer is toggled.
01942 
01943 If you pass a special layer name, the visibility of those components
01944 (silk, rats, etc) is toggled.  Note that if you have a layer named
01945 the same as a special layer, the layer is chosen over the special layer.
01946 
01947 %end-doc */
01948 
01949 static int
01950 ToggleView (int argc, char **argv, Coord x, Coord y)
01951 {
01952   int i, l;
01953 
01954 #ifdef DEBUG_MENUS
01955   puts ("Starting ToggleView().");
01956 #endif
01957 
01958   if (argc == 0)
01959     {
01960       AFAIL (toggleview);
01961     }
01962   if (isdigit ((int) argv[0][0]))
01963     {
01964       l = atoi (argv[0]) - 1;
01965     }
01966   else if (strcmp (argv[0], "Silk") == 0)
01967     l = LAYER_BUTTON_SILK;
01968   else if (strcmp (argv[0], "Rats") == 0)
01969     l = LAYER_BUTTON_RATS;
01970   else if (strcmp (argv[0], "Pins") == 0)
01971     l = LAYER_BUTTON_PINS;
01972   else if (strcmp (argv[0], "Vias") == 0)
01973     l = LAYER_BUTTON_VIAS;
01974   else if (strcmp (argv[0], "Mask") == 0)
01975     l = LAYER_BUTTON_MASK;
01976   else if (strcmp (argv[0], "BackSide") == 0)
01977     l = LAYER_BUTTON_FARSIDE;
01978   else
01979     {
01980       l = -1;
01981       for (i = 0; i < max_copper_layer + SILK_LAYER; i++)
01982         if (strcmp (argv[0], PCB->Data->Layer[i].Name) == 0)
01983           {
01984             l = i;
01985             break;
01986           }
01987       if (l == -1)
01988         {
01989           AFAIL (toggleview);
01990         }
01991 
01992     }
01993 
01994   /* Now that we've figured out which toggle button ought to control
01995    * this layer, simply hit the button and let the pre-existing code deal
01996    */
01997   ghid_layer_selector_toggle_layer
01998     (GHID_LAYER_SELECTOR (ghidgui->layer_selector), l);
01999   return 0;
02000 }
02001 
02002 static const char selectlayer_syntax[] =
02003     N_("SelectLayer(1..MAXLAYER|Silk|Rats)");
02004 
02005 static const char selectlayer_help[] =
02006     N_("Select which layer is the current layer.");
02007 
02008 /* %start-doc actions SelectLayer
02009 
02010 The specified layer becomes the currently active layer.  It is made
02011 visible if it is not already visible
02012 
02013 %end-doc */
02014 
02015 static int
02016 SelectLayer (int argc, char **argv, Coord x, Coord y)
02017 {
02018   int i;
02019   int newl = -1;
02020   if (argc == 0)
02021     AFAIL (selectlayer);
02022 
02023   for (i = 0; i < max_copper_layer; ++i)
02024     if (strcasecmp (argv[0], PCB->Data->Layer[i].Name) == 0)
02025       newl = i;
02026 
02027   if (strcasecmp (argv[0], "silk") == 0)
02028     newl = LAYER_BUTTON_SILK;
02029   else if (strcasecmp (argv[0], "rats") == 0)
02030     newl = LAYER_BUTTON_RATS;
02031   else if (newl == -1)
02032     newl = atoi (argv[0]) - 1;
02033 
02034 #ifdef DEBUG_MENUS
02035   printf ("SelectLayer():  newl = %d\n", newl);
02036 #endif
02037 
02038   /* Now that we've figured out which radio button ought to select
02039    * this layer, simply hit the button and let the pre-existing code deal
02040    */
02041   ghid_layer_selector_select_layer
02042     (GHID_LAYER_SELECTOR (ghidgui->layer_selector), newl);
02043 
02044   return 0;
02045 }
02046 
02047 
02048 HID_Action gtk_topwindow_action_list[] = {
02049   {"LayersChanged", 0, LayersChanged,
02050    layerschanged_help, layerschanged_syntax},
02051   {"SelectLayer", 0, SelectLayer,
02052    selectlayer_help, selectlayer_syntax},
02053   {"ToggleView", 0, ToggleView,
02054    toggleview_help, toggleview_syntax}
02055 };
02056 
02057 REGISTER_ACTIONS (gtk_topwindow_action_list)
02058 
02059 
02069 static void
02070 ghid_check_special_key (const char *accel, GtkAction *action,
02071                         const Resource *node)
02072 {
02073   size_t len;
02074   unsigned int mods;
02075   unsigned int ind;
02076 
02077   if (action == NULL || accel == NULL || *accel == '\0')
02078     return ;
02079 
02080 #ifdef DEBUG_MENUS
02081   printf ("%s(\"%s\", \"%s\")\n", __FUNCTION__, accel, name);
02082 #endif
02083 
02084   mods = 0;
02085   if (strstr (accel, "<alt>") )
02086     {
02087       mods |= GHID_KEY_ALT;
02088     }
02089   if (strstr (accel, "<ctrl>") )
02090     {
02091       mods |= GHID_KEY_CONTROL;
02092     }
02093   if (strstr (accel, "<shift>") )
02094     {
02095       mods |= GHID_KEY_SHIFT;
02096     }
02097 
02098   
02099   len = strlen (accel);
02100   
02101 #define  CHECK_KEY(a) ((len >= strlen (a)) && (strcmp (accel + len - strlen (a), (a)) == 0))
02102 
02103   ind = 0;
02104   if ( CHECK_KEY ("Tab") )
02105     {
02106       ind = mods | GHID_KEY_TAB;
02107     }
02108   else if ( CHECK_KEY ("Up") )
02109     {
02110       ind = mods | GHID_KEY_UP;
02111     }
02112   else if ( CHECK_KEY ("Down") )
02113     {
02114       ind = mods | GHID_KEY_DOWN;
02115     }
02116   else if ( CHECK_KEY ("Left") )
02117     {
02118       ind = mods | GHID_KEY_LEFT;
02119     }
02120   else if ( CHECK_KEY ("Right") )
02121     {
02122       ind = mods | GHID_KEY_RIGHT;
02123     }
02124 
02125   if (ind > 0) 
02126     {
02127       if (ind >= N_HOTKEY_ACTIONS)
02128         {
02129           fprintf (stderr, _("ERROR:  overflow of the ghid_hotkey_actions array.  Index = %d\n"
02130                    "Please report this.\n"), ind);
02131           exit (1);
02132         }
02133 
02134       ghid_hotkey_actions[ind].action = action;
02135       ghid_hotkey_actions[ind].node = node;
02136 #ifdef DEBUG_MENUS
02137       printf ("Adding \"special\" hotkey to ghid_hotkey_actions[%u] :"
02138               " %s (%s)\n", ind, accel, name);
02139 #endif
02140     }
02141 }
02142 
02146 char *
02147 get_menu_filename (void)
02148 {
02149   char *rv = NULL;
02150   char *home_pcbmenu = NULL;
02151 
02152   /* homedir is set by the core */
02153   if (homedir)
02154     {
02155       Message (_("Note:  home directory is \"%s\"\n"), homedir);
02156       home_pcbmenu = Concat (homedir, PCB_DIR_SEPARATOR_S, ".pcb",
02157                              PCB_DIR_SEPARATOR_S, "gpcb-menu.res", NULL);
02158     }
02159   else
02160     Message (_("Warning:  could not determine home directory\n"));
02161 
02162   if (access ("gpcb-menu.res", R_OK) == 0)
02163     rv = strdup ("gpcb-menu.res");
02164   else if (home_pcbmenu != NULL && (access (home_pcbmenu, R_OK) == 0) )
02165     rv = home_pcbmenu;
02166   else if (access (pcbmenu_path, R_OK) == 0)
02167     rv = strdup (pcbmenu_path);
02168 
02169   return rv;
02170 }
02171 
02172 static GtkWidget *
02173 ghid_load_menus (void)
02174 {
02175   char *filename;
02176   const Resource *r = 0, *bir;
02177   const Resource *mr;
02178   GtkWidget *menu_bar = NULL;
02179   int i;
02180 
02181   for (i = 0; i < N_HOTKEY_ACTIONS; i++)
02182     {
02183       ghid_hotkey_actions[i].action = NULL;
02184       ghid_hotkey_actions[i].node = NULL;
02185     }
02186  
02187   bir = resource_parse (0, gpcb_menu_default);
02188   if (!bir)
02189     {
02190       fprintf (stderr, _("Error: internal menu resource didn't parse\n"));
02191       exit(1);
02192     }
02193 
02194   filename = get_menu_filename ();
02195   if (filename)
02196     {
02197       Message (_("Loading menus from %s\n"), filename);
02198       r = resource_parse (filename, 0);
02199     }
02200 
02201   if (!r)
02202     {
02203       Message (_("Using default menus\n"));
02204       r = bir;
02205     }
02206   free (filename);
02207 
02208   mr = resource_subres (r, "MainMenu");
02209   if (!mr)
02210     mr = resource_subres (bir, "MainMenu");
02211     
02212   if (mr)
02213     {
02214       menu_bar = ghid_main_menu_new (G_CALLBACK (ghid_menu_cb),
02215                                      ghid_check_special_key);
02216       ghid_main_menu_add_resource (GHID_MAIN_MENU (menu_bar), mr);
02217     }
02218 
02219   mr = resource_subres (r, "PopupMenus");
02220   if (!mr)
02221     mr = resource_subres (bir, "PopupMenus");
02222 
02223   if (mr)
02224     {
02225       int i;
02226       for (i = 0; i < mr->c; i++)
02227         if (resource_type (mr->v[i]) == 101)
02228           /* This is a named resource which defines a popup menu */
02229           ghid_main_menu_add_popup_resource (GHID_MAIN_MENU (menu_bar),
02230                                              mr->v[i].name, mr->v[i].subres);
02231     }
02232 
02233 #ifdef DEBUG_MENUS
02234    puts ("Finished loading menus.");
02235 #endif
02236 
02237     mr = resource_subres (r, "Mouse");
02238     if (!mr)
02239       mr = resource_subres (bir, "Mouse");
02240     if (mr)
02241       load_mouse_resource (mr);
02242 
02243   return menu_bar;
02244 }
02245 
02246 /* ------------------------------------------------------------ */
02247 
02248 static const char adjuststyle_syntax[] =
02249     N_("AdjustStyle()\n");
02250 
02251 static const char adjuststyle_help[] =
02252     N_("Open the window which allows editing of the route styles.");
02253 
02254 /* %start-doc actions AdjustStyle
02255 
02256 Opens the window which allows editing of the route styles.
02257 
02258 %end-doc */
02259 
02260 static int
02261 AdjustStyle(int argc, char **argv, Coord x, Coord y)
02262 {
02263   ghid_route_style_selector_edit_dialog
02264     (GHID_ROUTE_STYLE_SELECTOR (ghidgui->route_style_selector));
02265 
02266   return 0;
02267 }
02268 
02269 /* ------------------------------------------------------------ */
02270 
02271 static const char editlayergroups_syntax[] =
02272     N_("EditLayerGroups()\n");
02273 
02274 static const char editlayergroups_help[] =
02275     N_("Open the preferences window which allows editing of the layer groups.");
02276 
02277 /* %start-doc actions EditLayerGroups
02278 
02279 Opens the preferences window which is where the layer groups
02280 are edited.  This action is primarily provides to provide menu
02281 resource compatibility with the lesstif HID.
02282 
02283 %end-doc */
02284 
02285 static int
02286 EditLayerGroups(int argc, char **argv, Coord x, Coord y)
02287 {
02288   
02289   if (argc != 0)
02290     AFAIL (editlayergroups);
02291 
02292   hid_actionl ("DoWindows", "Preferences", NULL);
02293 
02294   return 0;
02295 }
02296 
02297 /* ------------------------------------------------------------ */
02298 
02299 HID_Action ghid_menu_action_list[] = {
02300   {"AdjustStyle", 0, AdjustStyle, adjuststyle_help, adjuststyle_syntax},
02301   {"EditLayerGroups", 0, EditLayerGroups, editlayergroups_help, editlayergroups_syntax}
02302 };
02303 
02304 REGISTER_ACTIONS (ghid_menu_action_list)
02305