X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/0a4f23f30e353cbe4c85cef460eca779a2553037..e7427ac187c9d4693ae80c80bfba7c8e3cba80a7:/src/gtkutil.c diff --git a/src/gtkutil.c b/src/gtkutil.c index f5f05709e4..8bd83e4004 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -23,10 +23,12 @@ Boston, MA 02111-1307, USA. */ #ifdef USE_GTK #include +#include #include #include "lisp.h" #include "xterm.h" #include "blockinput.h" +#include "syssignal.h" #include "window.h" #include "atimer.h" #include "gtkutil.h" @@ -554,12 +556,6 @@ xg_resize_outer_widget (f, columns, rows) int columns; int rows; { - gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), - FRAME_PIXEL_WIDTH (f), FRAME_TOTAL_PIXEL_HEIGHT (f)); - - /* base_height is now changed. */ - x_wm_set_size_hint (f, 0, 0); - /* If we are not mapped yet, set geometry once again, as window height now have changed. */ if (! GTK_WIDGET_MAPPED (FRAME_GTK_OUTER_WIDGET (f))) @@ -582,14 +578,14 @@ xg_resize_widgets (f, pixelwidth, pixelheight) { int mbheight = FRAME_MENUBAR_HEIGHT (f); int tbheight = FRAME_TOOLBAR_HEIGHT (f); - int rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, (pixelheight + int rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, (pixelheight - mbheight - tbheight)); int columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth); if (FRAME_GTK_WIDGET (f) - && (columns != FRAME_COLS (f) + && (columns != FRAME_COLS (f) || rows != FRAME_LINES (f) - || pixelwidth != FRAME_PIXEL_WIDTH (f) + || pixelwidth != FRAME_PIXEL_WIDTH (f) || pixelheight != FRAME_PIXEL_HEIGHT (f))) { struct x_output *x = f->output_data.x; @@ -717,6 +713,7 @@ xg_create_frame_widgets (f) if (wvbox) gtk_widget_destroy (wvbox); if (wfixed) gtk_widget_destroy (wfixed); + UNBLOCK_INPUT; return 0; } @@ -754,7 +751,7 @@ xg_create_frame_widgets (f) So we cheat a bit by setting a height that is what it will have later on when tool bar items are added. */ if (FRAME_EXTERNAL_TOOL_BAR (f) && f->n_tool_bar_items == 0) - FRAME_TOOLBAR_HEIGHT (f) = 34; + FRAME_TOOLBAR_HEIGHT (f) = 38; /* We don't want this widget double buffered, because we draw on it @@ -1122,41 +1119,71 @@ create_dialog (wv, select_cb, deactivate_cb) /*********************************************************************** File dialog functions ***********************************************************************/ -enum +/* Function that is called when the file dialog pops down. + W is the dialog widget, RESPONSE is the response code. + USER_DATA is what we passed in to g_signal_connect (pointer to int). */ + +static void +xg_file_response_cb (w, + response, + user_data) + GtkDialog *w; + gint response; + gpointer user_data; { - XG_FILE_NOT_DONE, - XG_FILE_OK, - XG_FILE_CANCEL, - XG_FILE_DESTROYED, -}; + int *ptr = (int *) user_data; + *ptr = response; +} -#ifdef HAVE_GTK_FILE_BOTH -int use_old_gtk_file_dialog; -#endif +/* Destroy the dialog. This makes it pop down. */ + +static Lisp_Object +pop_down_file_dialog (arg) + Lisp_Object arg; +{ + struct Lisp_Save_Value *p = XSAVE_VALUE (arg); + BLOCK_INPUT; + gtk_widget_destroy (GTK_WIDGET (p->pointer)); + UNBLOCK_INPUT; + return Qnil; +} + +typedef char * (*xg_get_file_func) P_ ((GtkWidget *)); #ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW + +/* Return the selected file for file chooser dialog W. + The returned string must be free:d. */ + +static char * +xg_get_file_name_from_chooser (w) + GtkWidget *w; +{ + return gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w)); +} + /* Read a file name from the user using a file chooser dialog. F is the current frame. PROMPT is a prompt to show to the user. May not be NULL. DEFAULT_FILENAME is a default selection to be displayed. May be NULL. If MUSTMATCH_P is non-zero, the returned file name must be an existing - file. + file. *FUNC is set to a function that can be used to retrieve the + selected file name from the returned widget. - Returns a file name or NULL if no file was selected. - The returned string must be freed by the caller. */ + Returns the created widget. */ -static char * -xg_get_file_with_chooser (f, prompt, default_filename, mustmatch_p, only_dir_p) +static GtkWidget * +xg_get_file_with_chooser (f, prompt, default_filename, + mustmatch_p, only_dir_p, func) FRAME_PTR f; char *prompt; char *default_filename; int mustmatch_p, only_dir_p; + xg_get_file_func *func; { GtkWidget *filewin; GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)); - - char *fn = 0; GtkFileChooserAction action = (mustmatch_p ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE); @@ -1170,12 +1197,7 @@ xg_get_file_with_chooser (f, prompt, default_filename, mustmatch_p, only_dir_p) GTK_STOCK_OPEN : GTK_STOCK_OK), GTK_RESPONSE_OK, NULL); - - xg_set_screen (filewin, f); - gtk_widget_set_name (filewin, "emacs-filedialog"); - gtk_window_set_transient_for (GTK_WINDOW (filewin), gwin); - gtk_window_set_destroy_with_parent (GTK_WINDOW (filewin), TRUE); - + gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filewin), TRUE); if (default_filename) { @@ -1183,118 +1205,67 @@ xg_get_file_with_chooser (f, prompt, default_filename, mustmatch_p, only_dir_p) struct gcpro gcpro1; GCPRO1 (file); + file = build_string (default_filename); + /* File chooser does not understand ~/... in the file name. It must be an absolute name starting with /. */ if (default_filename[0] != '/') - { - file = Fexpand_file_name (build_string (default_filename), Qnil); - default_filename = SDATA (file); - } + file = Fexpand_file_name (file, Qnil); - gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filewin), - default_filename); + default_filename = SDATA (file); + if (Ffile_directory_p (file)) + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filewin), + default_filename); + else + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (filewin), + default_filename); UNGCPRO; } - gtk_widget_show (filewin); - - if (gtk_dialog_run (GTK_DIALOG (filewin)) == GTK_RESPONSE_OK) - fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filewin)); - - gtk_widget_destroy (filewin); - - return fn; + *func = xg_get_file_name_from_chooser; + return filewin; } #endif /* HAVE_GTK_FILE_CHOOSER_DIALOG_NEW */ #ifdef HAVE_GTK_FILE_SELECTION_NEW -/* Callback function invoked when the Ok button is pressed in - a file dialog. - W is the file dialog widget, - ARG points to an integer where we record what has happend. */ - -static void -xg_file_sel_ok (w, arg) - GtkWidget *w; - gpointer arg; -{ - *(int*)arg = XG_FILE_OK; -} - -/* Callback function invoked when the Cancel button is pressed in - a file dialog. - W is the file dialog widget, - ARG points to an integer where we record what has happend. */ - -static void -xg_file_sel_cancel (w, arg) - GtkWidget *w; - gpointer arg; -{ - *(int*)arg = XG_FILE_CANCEL; -} -/* Callback function invoked when the file dialog is destroyed (i.e. - popped down). We must keep track of this, because if this - happens, GTK destroys the widget. But if for example, Ok is pressed, - the dialog is popped down, but the dialog widget is not destroyed. - W is the file dialog widget, - ARG points to an integer where we record what has happend. */ +/* Return the selected file for file selector dialog W. + The returned string must be free:d. */ -static void -xg_file_sel_destroy (w, arg) +static char * +xg_get_file_name_from_selector (w) GtkWidget *w; - gpointer arg; { - *(int*)arg = XG_FILE_DESTROYED; + GtkFileSelection *filesel = GTK_FILE_SELECTION (w); + return xstrdup ((char*) gtk_file_selection_get_filename (filesel)); } -/* Read a file name from the user using a file selection dialog. +/* Create a file selection dialog. F is the current frame. PROMPT is a prompt to show to the user. May not be NULL. DEFAULT_FILENAME is a default selection to be displayed. May be NULL. If MUSTMATCH_P is non-zero, the returned file name must be an existing - file. + file. *FUNC is set to a function that can be used to retrieve the + selected file name from the returned widget. - Returns a file name or NULL if no file was selected. - The returned string must be freed by the caller. */ + Returns the created widget. */ -static char * +static GtkWidget * xg_get_file_with_selection (f, prompt, default_filename, - mustmatch_p, only_dir_p) + mustmatch_p, only_dir_p, func) FRAME_PTR f; char *prompt; char *default_filename; int mustmatch_p, only_dir_p; + xg_get_file_func *func; { GtkWidget *filewin; GtkFileSelection *filesel; - int filesel_done = XG_FILE_NOT_DONE; - char *fn = 0; filewin = gtk_file_selection_new (prompt); filesel = GTK_FILE_SELECTION (filewin); - xg_set_screen (filewin, f); - gtk_widget_set_name (filewin, "emacs-filedialog"); - gtk_window_set_transient_for (GTK_WINDOW (filewin), - GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))); - gtk_window_set_destroy_with_parent (GTK_WINDOW (filewin), TRUE); - - g_signal_connect (G_OBJECT (filesel->ok_button), - "clicked", - G_CALLBACK (xg_file_sel_ok), - &filesel_done); - g_signal_connect (G_OBJECT (filesel->cancel_button), - "clicked", - G_CALLBACK (xg_file_sel_cancel), - &filesel_done); - g_signal_connect (G_OBJECT (filesel), - "destroy", - G_CALLBACK (xg_file_sel_destroy), - &filesel_done); - if (default_filename) gtk_file_selection_set_filename (filesel, default_filename); @@ -1305,19 +1276,9 @@ xg_get_file_with_selection (f, prompt, default_filename, gtk_file_selection_hide_fileop_buttons (filesel); } + *func = xg_get_file_name_from_selector; - gtk_widget_show_all (filewin); - - while (filesel_done == XG_FILE_NOT_DONE) - gtk_main_iteration (); - - if (filesel_done == XG_FILE_OK) - fn = xstrdup ((char*) gtk_file_selection_get_filename (filesel)); - - if (filesel_done != XG_FILE_DESTROYED) - gtk_widget_destroy (filewin); - - return fn; + return filewin; } #endif /* HAVE_GTK_FILE_SELECTION_NEW */ @@ -1341,26 +1302,76 @@ xg_get_file_name (f, prompt, default_filename, mustmatch_p, only_dir_p) char *default_filename; int mustmatch_p, only_dir_p; { + GtkWidget *w = 0; + int count = SPECPDL_INDEX (); + char *fn = 0; + int filesel_done = 0; + xg_get_file_func func; + extern int x_use_old_gtk_file_dialog; + +#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN) + /* I really don't know why this is needed, but without this the GLIBC add on + library linuxthreads hangs when the Gnome file chooser backend creates + threads. */ + sigblock (sigmask (__SIGRTMIN)); +#endif /* HAVE_GTK_AND_PTHREAD */ + #ifdef HAVE_GTK_FILE_BOTH - if (use_old_gtk_file_dialog) - return xg_get_file_with_selection (f, prompt, default_filename, - mustmatch_p, only_dir_p); - return xg_get_file_with_chooser (f, prompt, default_filename, - mustmatch_p, only_dir_p); + + if (x_use_old_gtk_file_dialog) + w = xg_get_file_with_selection (f, prompt, default_filename, + mustmatch_p, only_dir_p, &func); + else + w = xg_get_file_with_chooser (f, prompt, default_filename, + mustmatch_p, only_dir_p, &func); #else /* not HAVE_GTK_FILE_BOTH */ -#ifdef HAVE_GTK_FILE_SELECTION_DIALOG_NEW - return xg_get_file_with_selection (f, prompt, default_filename, - mustmatch_p, only_dir_p); +#ifdef HAVE_GTK_FILE_SELECTION_NEW + w = xg_get_file_with_selection (f, prompt, default_filename, + mustmatch_p, only_dir_p, &func); #endif #ifdef HAVE_GTK_FILE_CHOOSER_DIALOG_NEW - return xg_get_file_with_chooser (f, prompt, default_filename, - mustmatch_p, only_dir_p); + w = xg_get_file_with_chooser (f, prompt, default_filename, + mustmatch_p, only_dir_p, &func); #endif #endif /* HAVE_GTK_FILE_BOTH */ - return 0; + + xg_set_screen (w, f); + gtk_widget_set_name (w, "emacs-filedialog"); + gtk_window_set_transient_for (GTK_WINDOW (w), + GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))); + gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE); + gtk_window_set_modal (GTK_WINDOW (w), TRUE); + + g_signal_connect (G_OBJECT (w), + "response", + G_CALLBACK (xg_file_response_cb), + &filesel_done); + + /* Don't destroy the widget if closed by the window manager close button. */ + g_signal_connect (G_OBJECT (w), "delete-event", G_CALLBACK (gtk_true), NULL); + + gtk_widget_show (w); + + record_unwind_protect (pop_down_file_dialog, make_save_value (w, 0)); + while (! filesel_done) + { + x_menu_wait_for_event (0); + gtk_main_iteration (); + } + +#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN) + sigunblock (sigmask (__SIGRTMIN)); +#endif + + if (filesel_done == GTK_RESPONSE_OK) + fn = (*func) (w); + + unbind_to (count, Qnil); + + return fn; } @@ -1889,7 +1900,7 @@ create_menus (data, f, select_cb, deactivate_cb, highlight_cb, if (deactivate_cb) g_signal_connect (G_OBJECT (wmenu), - "deactivate", deactivate_cb, 0); + "selection-done", deactivate_cb, 0); g_signal_connect (G_OBJECT (wmenu), "grab-notify", G_CALLBACK (menu_grab_callback), 0); @@ -1999,6 +2010,7 @@ xg_create_widget (type, name, f, val, GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))); gtk_window_set_destroy_with_parent (GTK_WINDOW (w), TRUE); gtk_widget_set_name (w, "emacs-dialog"); + gtk_window_set_modal (GTK_WINDOW (w), TRUE); } else if (menu_bar_p || pop_up_p) { @@ -2833,7 +2845,7 @@ xg_gtk_scroll_destroy (widget, data) gpointer data; { gpointer p; - int id = (int)data; + int id = (int) (EMACS_INT) data; /* The EMACS_INT cast avoids a warning. */ p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA); if (p) xfree (p); @@ -2864,7 +2876,7 @@ scroll_bar_button_cb (widget, event, user_data) if (xg_timer) xg_stop_timer (); bar->dragging = Qnil; } - + return FALSE; } @@ -2903,10 +2915,11 @@ xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name) "value-changed", scroll_callback, (gpointer) bar); + /* The EMACS_INT cast avoids a warning. */ g_signal_connect (G_OBJECT (wscroll), "destroy", G_CALLBACK (xg_gtk_scroll_destroy), - (gpointer) scroll_id); + (gpointer) (EMACS_INT) scroll_id); /* Connect to button press and button release to detect if any scroll bar has the pointer. */ @@ -2927,7 +2940,7 @@ xg_create_scroll_bar (f, bar, scroll_callback, scroll_bar_name) event box window. */ gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget), webox, -1, -1); gtk_container_add (GTK_CONTAINER (webox), wscroll); - + /* Set the cursor to an arrow. */ xg_set_cursor (webox, FRAME_X_DISPLAY_INFO (f)->xg_cursor); @@ -2986,9 +2999,14 @@ xg_update_scrollbar_pos (f, scrollbar_id, top, left, width, height) GtkWidget *wparent = gtk_widget_get_parent (wscroll); /* Move and resize to new values. */ - gtk_widget_set_size_request (wscroll, width, height); gtk_fixed_move (GTK_FIXED (wfixed), wparent, left, top); - + gtk_widget_set_size_request (wscroll, width, height); + gtk_widget_queue_draw (wparent); + gdk_window_process_all_updates (); + /* GTK does not redraw until the main loop is entered again, but + if there are no X events pending we will not enter it. So we sync + here to get some events. */ + x_sync (f); SET_FRAME_GARBAGED (f); cancel_mouse_face (f); } @@ -3095,7 +3113,8 @@ xg_tool_bar_callback (w, client_data) GtkWidget *w; gpointer client_data; { - int idx = (int)client_data; + /* The EMACS_INT cast avoids a warning. */ + int idx = (int) (EMACS_INT) client_data; FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA); Lisp_Object key, frame; struct input_event event; @@ -3137,10 +3156,11 @@ xg_tool_bar_detach_callback (wbox, w, client_data) if (f) { + FRAME_X_OUTPUT (f)->toolbar_detached = 1; + /* When detaching a tool bar, not everything dissapear. There are a few pixels left that are used to drop the tool bar back into place. */ - int bw = gtk_container_get_border_width (GTK_CONTAINER (wbox)); FRAME_TOOLBAR_HEIGHT (f) = 2; /* The height has changed, resize outer widget and set columns @@ -3168,11 +3188,13 @@ xg_tool_bar_attach_callback (wbox, w, client_data) { GtkRequisition req; + FRAME_X_OUTPUT (f)->toolbar_detached = 0; + gtk_widget_size_request (w, &req); FRAME_TOOLBAR_HEIGHT (f) = req.height; /* The height has changed, resize outer widget and set columns - rows to what we had before detaching the tool bar. */ + rows to what we had before attaching the tool bar. */ xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f)); } } @@ -3192,7 +3214,8 @@ xg_tool_bar_help_callback (w, event, client_data) GdkEventCrossing *event; gpointer client_data; { - int idx = (int)client_data; + /* The EMACS_INT cast avoids a warning. */ + int idx = (int) (EMACS_INT) client_data; FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA); Lisp_Object help, frame; @@ -3247,10 +3270,10 @@ xg_tool_bar_item_expose_callback (w, event, client_data) event->area.x = max (0, event->area.x); event->area.y = max (0, event->area.y); - + event->area.width = max (width, event->area.width); event->area.height = max (height, event->area.height); - + return FALSE; } @@ -3285,6 +3308,8 @@ xg_create_tool_bar (f) x->toolbar_widget = gtk_toolbar_new (); x->handlebox_widget = gtk_handle_box_new (); + x->toolbar_detached = 0; + gtk_container_add (GTK_CONTAINER (x->handlebox_widget), x->toolbar_widget); @@ -3339,12 +3364,37 @@ update_frame_tool_bar (f) GList *icon_list; GList *iter; struct x_output *x = f->output_data.x; + int hmargin, vmargin; if (! FRAME_GTK_WIDGET (f)) return; BLOCK_INPUT; + if (INTEGERP (Vtool_bar_button_margin) + && XINT (Vtool_bar_button_margin) > 0) + { + hmargin = XFASTINT (Vtool_bar_button_margin); + vmargin = XFASTINT (Vtool_bar_button_margin); + } + else if (CONSP (Vtool_bar_button_margin)) + { + if (INTEGERP (XCAR (Vtool_bar_button_margin)) + && XINT (XCAR (Vtool_bar_button_margin)) > 0) + hmargin = XFASTINT (XCAR (Vtool_bar_button_margin)); + + if (INTEGERP (XCDR (Vtool_bar_button_margin)) + && XINT (XCDR (Vtool_bar_button_margin)) > 0) + vmargin = XFASTINT (XCDR (Vtool_bar_button_margin)); + } + + /* The natural size (i.e. when GTK uses 0 as margin) looks best, + so take DEFAULT_TOOL_BAR_BUTTON_MARGIN to mean "default for GTK", + i.e. zero. This means that margins less than + DEFAULT_TOOL_BAR_BUTTON_MARGIN has no effect. */ + hmargin = max (0, hmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN); + vmargin = max (0, vmargin - DEFAULT_TOOL_BAR_BUTTON_MARGIN); + if (! x->toolbar_widget) xg_create_tool_bar (f); @@ -3408,11 +3458,14 @@ update_frame_tool_bar (f) { GtkWidget *w = xg_get_image_for_pixmap (f, img, x->widget, NULL); + gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin); + + /* The EMACS_INT cast avoids a warning. */ gtk_toolbar_append_item (GTK_TOOLBAR (x->toolbar_widget), 0, 0, 0, w, GTK_SIGNAL_FUNC (xg_tool_bar_callback), - (gpointer)i); + (gpointer) (EMACS_INT) i); /* Save the image so we can see if an update is needed when this function is called again. */ @@ -3442,14 +3495,15 @@ update_frame_tool_bar (f) rather than the GtkButton specific signals "enter" and "leave", so we can have only one callback. The event will tell us what kind of event it is. */ + /* The EMACS_INT cast avoids a warning. */ g_signal_connect (G_OBJECT (w), "enter-notify-event", G_CALLBACK (xg_tool_bar_help_callback), - (gpointer)i); + (gpointer) (EMACS_INT) i); g_signal_connect (G_OBJECT (w), "leave-notify-event", G_CALLBACK (xg_tool_bar_help_callback), - (gpointer)i); + (gpointer) (EMACS_INT) i); } } else @@ -3463,6 +3517,8 @@ update_frame_tool_bar (f) XG_TOOL_BAR_IMAGE_DATA); g_list_free (chlist); + gtk_misc_set_padding (GTK_MISC (wimage), hmargin, vmargin); + if (old_img != img->pixmap) (void) xg_get_image_for_pixmap (f, img, x->widget, wimage); @@ -3486,7 +3542,8 @@ update_frame_tool_bar (f) } gtk_widget_size_request (x->toolbar_widget, &new_req); - if (old_req.height != new_req.height) + if (old_req.height != new_req.height + && ! FRAME_X_OUTPUT (f)->toolbar_detached) { FRAME_TOOLBAR_HEIGHT (f) = new_req.height; xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f)); @@ -3532,6 +3589,8 @@ free_frame_tool_bar (f) void xg_initialize () { + GtkBindingSet *binding_set; + xg_ignore_gtk_scrollbar = 0; xg_detached_menus = 0; xg_menu_cb_list.prev = xg_menu_cb_list.next = @@ -3554,6 +3613,17 @@ xg_initialize () "gtk-key-theme-name", "Emacs", EMACS_CLASS); + + /* Make dialogs close on C-g. Since file dialog inherits from + dialog, this works for them also. */ + binding_set = gtk_binding_set_by_class (gtk_type_class (GTK_TYPE_DIALOG)); + gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK, + "close", 0); + + /* Make menus close on C-g. */ + binding_set = gtk_binding_set_by_class (gtk_type_class (GTK_TYPE_MENU_SHELL)); + gtk_binding_entry_add_signal (binding_set, GDK_g, GDK_CONTROL_MASK, + "cancel", 0); } #endif /* USE_GTK */