You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include "config.h"
#ifdef USE_GTK
#include <string.h>
+#include <signal.h>
#include <stdio.h>
#include "lisp.h"
#include "xterm.h"
#include "blockinput.h"
+#include "syssignal.h"
#include "window.h"
#include "atimer.h"
#include "gtkutil.h"
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)))
{
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;
if (wvbox) gtk_widget_destroy (wvbox);
if (wfixed) gtk_widget_destroy (wfixed);
+ UNBLOCK_INPUT;
return 0;
}
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
/***********************************************************************
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);
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)
{
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);
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 */
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;
}
\f
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);
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)
{
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);
if (xg_timer) xg_stop_timer ();
bar->dragging = Qnil;
}
-
+
return FALSE;
}
"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. */
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);
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);
}
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;
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
{
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));
}
}
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;
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;
}
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);
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);
{
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. */
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
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);
}
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));
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 =
"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 */