/* Functions for creating and updating GTK widgets.
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GNU Emacs.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
-#include "config.h"
+#include <config.h>
#ifdef USE_GTK
#include <string.h>
#include "coding.h"
#include <gdk/gdkkeysyms.h>
+#ifdef HAVE_XFT
+#include <X11/Xft/Xft.h>
+#endif
#define FRAME_TOTAL_PIXEL_HEIGHT(f) \
(FRAME_PIXEL_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f))
#ifdef HAVE_GTK_MULTIDISPLAY
-/* Gtk does not work well without any display open. Emacs may close
- all its displays. In that case, keep a display around just for
- the purpose of having one. */
+/* Keep track of the default display, or NULL if there is none. Emacs
+ may close all its displays. */
static GdkDisplay *gdpy_def;
-
/* Return the GdkDisplay that corresponds to the X display DPY. */
static GdkDisplay *
GdkDisplay *gdpy;
gdpy = gdk_display_open (display_name);
- *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
+ if (!gdpy_def)
+ gdk_display_manager_set_default_display (gdk_display_manager_get (),
+ gdpy);
+ *dpy = gdpy ? GDK_DISPLAY_XDISPLAY (gdpy) : NULL;
return gdpy != NULL;
#else /* not HAVE_GTK_MULTIDISPLAY */
#ifdef HAVE_GTK_MULTIDISPLAY
GdkDisplay *gdpy = gdk_x11_lookup_xdisplay (dpy);
- /* If this is the default display, we must change it before calling
- dispose, otherwise it will crash on some Gtk+ versions. */
+ /* If this is the default display, try to change it before closing.
+ If there is no other display to use, gdpy_def is set to NULL, and
+ the next call to xg_display_open resets the default display. */
if (gdk_display_get_default () == gdpy)
{
struct x_display_info *dpyinfo;
- Display *new_dpy = 0;
- GdkDisplay *gdpy_new;
+ GdkDisplay *gdpy_new = NULL;
/* Find another display. */
for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
if (dpyinfo->display != dpy)
{
- new_dpy = dpyinfo->display;
+ gdpy_new = gdk_x11_lookup_xdisplay (dpyinfo->display);
+ gdk_display_manager_set_default_display (gdk_display_manager_get (),
+ gdpy_new);
break;
}
-
- if (new_dpy)
- gdpy_new = gdk_x11_lookup_xdisplay (new_dpy);
- else
- {
- if (!gdpy_def)
- gdpy_def = gdk_display_open (gdk_display_get_name (gdpy));
- gdpy_new = gdpy_def;
- }
-
- gdk_display_manager_set_default_display (gdk_display_manager_get (),
- gdpy_new);
+ gdpy_def = gdpy_new;
}
- /* GTK 2.2-2.8 has a bug that makes gdk_display_close crash (bug
- http://bugzilla.gnome.org/show_bug.cgi?id=85715). This way
- we can continue running, but there will be memory leaks. */
-
#if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 10
+ /* GTK 2.2-2.8 has a bug that makes gdk_display_close crash (bug
+ http://bugzilla.gnome.org/show_bug.cgi?id=85715). This way we
+ can continue running, but there will be memory leaks. */
g_object_run_dispose (G_OBJECT (gdpy));
#else
/* This seems to be fixed in GTK 2.10. */
{
/* When the number of already allocated cells is too big,
We free it. */
- free (wv);
+ xfree (wv);
malloc_cpt--;
}
else
FRAME_PIXEL_WIDTH (f) = pixelwidth;
FRAME_PIXEL_HEIGHT (f) = pixelheight;
- if (rows != FRAME_LINES (f) || columns != FRAME_COLS (f)
- || (f->new_text_lines != 0 && f->new_text_lines != rows)
- || (f->new_text_cols != 0 && f->new_text_cols != columns))
- {
- change_frame_size (f, rows, columns, 0, 1, 0);
- SET_FRAME_GARBAGED (f);
- cancel_mouse_face (f);
- }
+ change_frame_size (f, rows, columns, 0, 1, 0);
+ SET_FRAME_GARBAGED (f);
+ cancel_mouse_face (f);
}
}
gtk_widget_modify_style (wfixed, style);
/* GTK does not set any border, and they look bad with GTK. */
+ /* That they look bad is no excuse for imposing this here. --Stef
+ It should be done by providing the proper default in Fx_create_Frame.
f->border_width = 0;
- f->internal_border_width = 0;
+ f->internal_border_width = 0; */
UNBLOCK_INPUT;
long flags;
int user_position;
{
- if (FRAME_GTK_OUTER_WIDGET (f))
- {
- /* Must use GTK routines here, otherwise GTK resets the size hints
- to its own defaults. */
- GdkGeometry size_hints;
- gint hint_flags = 0;
- int base_width, base_height;
- int min_rows = 0, min_cols = 0;
- int win_gravity = f->win_gravity;
-
- if (flags)
- {
- memset (&size_hints, 0, sizeof (size_hints));
- f->output_data.x->size_hints = size_hints;
- f->output_data.x->hint_flags = hint_flags;
- }
- else
- flags = f->size_hint_flags;
-
- size_hints = f->output_data.x->size_hints;
- hint_flags = f->output_data.x->hint_flags;
-
- hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE;
- size_hints.width_inc = FRAME_COLUMN_WIDTH (f);
- size_hints.height_inc = FRAME_LINE_HEIGHT (f);
-
- hint_flags |= GDK_HINT_BASE_SIZE;
- base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
- base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0)
- + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
-
- check_frame_size (f, &min_rows, &min_cols);
-
- size_hints.base_width = base_width;
- size_hints.base_height = base_height;
- size_hints.min_width = base_width + min_cols * size_hints.width_inc;
- size_hints.min_height = base_height + min_rows * size_hints.height_inc;
-
-
- /* These currently have a one to one mapping with the X values, but I
- don't think we should rely on that. */
- hint_flags |= GDK_HINT_WIN_GRAVITY;
- size_hints.win_gravity = 0;
- if (win_gravity == NorthWestGravity)
- size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
- else if (win_gravity == NorthGravity)
- size_hints.win_gravity = GDK_GRAVITY_NORTH;
- else if (win_gravity == NorthEastGravity)
- size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
- else if (win_gravity == WestGravity)
- size_hints.win_gravity = GDK_GRAVITY_WEST;
- else if (win_gravity == CenterGravity)
- size_hints.win_gravity = GDK_GRAVITY_CENTER;
- else if (win_gravity == EastGravity)
- size_hints.win_gravity = GDK_GRAVITY_EAST;
- else if (win_gravity == SouthWestGravity)
- size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
- else if (win_gravity == SouthGravity)
- size_hints.win_gravity = GDK_GRAVITY_SOUTH;
- else if (win_gravity == SouthEastGravity)
- size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
- else if (win_gravity == StaticGravity)
- size_hints.win_gravity = GDK_GRAVITY_STATIC;
-
- if (flags & PPosition) hint_flags |= GDK_HINT_POS;
- if (flags & USPosition) hint_flags |= GDK_HINT_USER_POS;
- if (flags & USSize) hint_flags |= GDK_HINT_USER_SIZE;
-
- if (user_position)
- {
- hint_flags &= ~GDK_HINT_POS;
- hint_flags |= GDK_HINT_USER_POS;
- }
+ /* Don't set size hints during initialization; that apparently leads
+ to a race condition. See the thread at
+ http://lists.gnu.org/archive/html/emacs-devel/2008-10/msg00033.html */
+ if (NILP (Vafter_init_time) || !FRAME_GTK_OUTER_WIDGET (f))
+ return;
- if (hint_flags != f->output_data.x->hint_flags
- || memcmp (&size_hints,
- &f->output_data.x->size_hints,
- sizeof (size_hints)) != 0)
- {
- BLOCK_INPUT;
+ /* Must use GTK routines here, otherwise GTK resets the size hints
+ to its own defaults. */
+ GdkGeometry size_hints;
+ gint hint_flags = 0;
+ int base_width, base_height;
+ int min_rows = 0, min_cols = 0;
+ int win_gravity = f->win_gravity;
- gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
- NULL,
- &size_hints,
- hint_flags);
+ if (flags)
+ {
+ memset (&size_hints, 0, sizeof (size_hints));
+ f->output_data.x->size_hints = size_hints;
+ f->output_data.x->hint_flags = hint_flags;
+ }
+ else
+ flags = f->size_hint_flags;
- f->output_data.x->size_hints = size_hints;
- f->output_data.x->hint_flags = hint_flags;
- UNBLOCK_INPUT;
- }
- }
+ size_hints = f->output_data.x->size_hints;
+ hint_flags = f->output_data.x->hint_flags;
+
+ hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE;
+ size_hints.width_inc = FRAME_COLUMN_WIDTH (f);
+ size_hints.height_inc = FRAME_LINE_HEIGHT (f);
+
+ hint_flags |= GDK_HINT_BASE_SIZE;
+ base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0);
+ base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0)
+ + FRAME_MENUBAR_HEIGHT (f) + FRAME_TOOLBAR_HEIGHT (f);
+
+ check_frame_size (f, &min_rows, &min_cols);
+
+ size_hints.base_width = base_width;
+ size_hints.base_height = base_height;
+ size_hints.min_width = base_width + min_cols * size_hints.width_inc;
+ size_hints.min_height = base_height + min_rows * size_hints.height_inc;
+
+ /* These currently have a one to one mapping with the X values, but I
+ don't think we should rely on that. */
+ hint_flags |= GDK_HINT_WIN_GRAVITY;
+ size_hints.win_gravity = 0;
+ if (win_gravity == NorthWestGravity)
+ size_hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
+ else if (win_gravity == NorthGravity)
+ size_hints.win_gravity = GDK_GRAVITY_NORTH;
+ else if (win_gravity == NorthEastGravity)
+ size_hints.win_gravity = GDK_GRAVITY_NORTH_EAST;
+ else if (win_gravity == WestGravity)
+ size_hints.win_gravity = GDK_GRAVITY_WEST;
+ else if (win_gravity == CenterGravity)
+ size_hints.win_gravity = GDK_GRAVITY_CENTER;
+ else if (win_gravity == EastGravity)
+ size_hints.win_gravity = GDK_GRAVITY_EAST;
+ else if (win_gravity == SouthWestGravity)
+ size_hints.win_gravity = GDK_GRAVITY_SOUTH_WEST;
+ else if (win_gravity == SouthGravity)
+ size_hints.win_gravity = GDK_GRAVITY_SOUTH;
+ else if (win_gravity == SouthEastGravity)
+ size_hints.win_gravity = GDK_GRAVITY_SOUTH_EAST;
+ else if (win_gravity == StaticGravity)
+ size_hints.win_gravity = GDK_GRAVITY_STATIC;
+
+ if (flags & PPosition) hint_flags |= GDK_HINT_POS;
+ if (flags & USPosition) hint_flags |= GDK_HINT_USER_POS;
+ if (flags & USSize) hint_flags |= GDK_HINT_USER_SIZE;
+
+ if (user_position)
+ {
+ hint_flags &= ~GDK_HINT_POS;
+ hint_flags |= GDK_HINT_USER_POS;
+ }
+
+ if (hint_flags != f->output_data.x->hint_flags
+ || memcmp (&size_hints,
+ &f->output_data.x->size_hints,
+ sizeof (size_hints)) != 0)
+ {
+ BLOCK_INPUT;
+ gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+ NULL, &size_hints, hint_flags);
+ f->output_data.x->size_hints = size_hints;
+ f->output_data.x->hint_flags = hint_flags;
+ UNBLOCK_INPUT;
+ }
}
/* Change background color of a frame.
- Since GTK uses the background colour to clear the window, we must
+ Since GTK uses the background color to clear the window, we must
keep the GTK and X colors in sync.
F is the frame to change,
BG is the pixel value to change to. */
}
-/* Function that is called when the file dialog pops down.
+/* Function that is called when the file or font dialogs pop 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,
+xg_dialog_response_cb (w,
response,
user_data)
GtkDialog *w;
/* Destroy the dialog. This makes it pop down. */
static Lisp_Object
-pop_down_file_dialog (arg)
+pop_down_dialog (arg)
Lisp_Object arg;
{
struct Lisp_Save_Value *p = XSAVE_VALUE (arg);
g_signal_connect (G_OBJECT (w),
"response",
- G_CALLBACK (xg_file_response_cb),
+ G_CALLBACK (xg_dialog_response_cb),
&filesel_done);
/* Don't destroy the widget if closed by the window manager close button. */
gtk_widget_show (w);
- record_unwind_protect (pop_down_file_dialog, make_save_value (w, 0));
+ record_unwind_protect (pop_down_dialog, make_save_value (w, 0));
while (! filesel_done)
{
x_menu_wait_for_event (0);
return fn;
}
+#ifdef HAVE_FREETYPE
+/* Pop up a GTK font selector and return the name of the font the user
+ selects, as a C string. The returned font name follows GTK's own
+ format:
+
+ `FAMILY [VALUE1 VALUE2] SIZE'
+
+ This can be parsed using font_parse_fcname in font.c.
+ DEFAULT_NAME, if non-zero, is the default font name. */
+
+char *
+xg_get_font_name (f, default_name)
+ FRAME_PTR f;
+ char *default_name;
+{
+ GtkWidget *w = 0;
+ int count = SPECPDL_INDEX ();
+ char *fontname = NULL;
+ int done = 0;
+
+#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
+ sigblock (sigmask (__SIGRTMIN));
+#endif /* HAVE_GTK_AND_PTHREAD */
+
+ w = gtk_font_selection_dialog_new ("Pick a font");
+ if (default_name)
+ gtk_font_selection_dialog_set_font_name (GTK_FONT_SELECTION_DIALOG (w),
+ default_name);
+
+ xg_set_screen (w, f);
+ gtk_widget_set_name (w, "emacs-fontdialog");
+ 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_dialog_response_cb), &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_dialog, make_save_value (w, 0));
+ while (!done)
+ {
+ x_menu_wait_for_event (0);
+ gtk_main_iteration ();
+ }
+
+#if defined (HAVE_GTK_AND_PTHREAD) && defined (__SIGRTMIN)
+ sigunblock (sigmask (__SIGRTMIN));
+#endif
+
+ if (done == GTK_RESPONSE_OK)
+ fontname = gtk_font_selection_dialog_get_font_name
+ ((GtkFontSelectionDialog *) w);
+
+ unbind_to (count, Qnil);
+
+ return fontname;
+}
+#endif /* HAVE_FREETYPE */
+
+
\f
/***********************************************************************
Menu functions.
***********************************************************************/
-/* The name of menu items that can be used for citomization. Since GTK
+/* The name of menu items that can be used for customization. Since GTK
RC files are very crude and primitive, we have to set this on all
- menu item names so a user can easily cutomize menu items. */
+ menu item names so a user can easily customize menu items. */
#define MENU_ITEM_NAME "emacs-menuitem"
return w;
}
-/* Callback called when keyboard traversal (started by x-menu-bar-open) ends.
- WMENU is the menu for which traversal has been done. DATA points to the
- frame for WMENU. We must release grabs, some bad interaction between GTK
- and Emacs makes the menus keep the grabs. */
-
-static void
-menu_nav_ended (wmenu, data)
- GtkMenuShell *wmenu;
- gpointer data;
-{
- FRAME_PTR f = (FRAME_PTR) data;
-
- if (FRAME_X_OUTPUT (f)->menubar_widget)
- {
- GtkMenuShell *w = GTK_MENU_SHELL (FRAME_X_OUTPUT (f)->menubar_widget);
- Display *dpy = FRAME_X_DISPLAY (f);
-
- BLOCK_INPUT;
- gtk_menu_shell_deactivate (w);
- gtk_menu_shell_deselect (w);
-
- XUngrabKeyboard (dpy, CurrentTime);
- XUngrabPointer (dpy, CurrentTime);
- UNBLOCK_INPUT;
- }
-}
-
-
static GtkWidget *create_menus P_ ((widget_value *, FRAME_PTR, GCallback,
GCallback, GCallback, int, int, int,
GtkWidget *, xg_menu_cb_data *, char *));
}
else wmenu = gtk_menu_bar_new ();
- /* Fix up grabs after keyboard traversal ends. */
- g_signal_connect (G_OBJECT (wmenu),
- "selection-done",
- G_CALLBACK (menu_nav_ended),
- f);
-
/* Put cl_data on the top menu for easier access. */
cl_data = make_cl_data (cl_data, f, highlight_cb);
g_object_set_data (G_OBJECT (wmenu), XG_FRAME_DATA, (gpointer)cl_data);
static void
xg_update_menubar (menubar, f, list, iter, pos, val,
- select_cb, highlight_cb, cl_data)
+ select_cb, deactivate_cb, highlight_cb, cl_data)
GtkWidget *menubar;
FRAME_PTR f;
GList **list;
int pos;
widget_value *val;
GCallback select_cb;
+ GCallback deactivate_cb;
GCallback highlight_cb;
xg_menu_cb_data *cl_data;
{
else if (! iter && val)
{
/* Item(s) added. Add all new items in one call. */
- create_menus (val, f, select_cb, 0, highlight_cb,
+ create_menus (val, f, select_cb, deactivate_cb, highlight_cb,
0, 1, 0, menubar, cl_data, 0);
/* All updated. */
/* Create a possibly empty submenu for menu bar items, since some
themes don't highlight items correctly without it. */
GtkWidget *submenu = create_menus (NULL, f,
- select_cb, NULL, highlight_cb,
+ select_cb, deactivate_cb,
+ highlight_cb,
0, 0, 0, 0, cl_data, 0);
gtk_widget_set_name (w, MENU_ITEM_NAME);
gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), w, pos);
/* Update the rest of the menu bar. */
xg_update_menubar (menubar, f, list, iter, pos, val,
- select_cb, highlight_cb, cl_data);
+ select_cb, deactivate_cb, highlight_cb, cl_data);
}
/* Update the menu item W so it corresponds to VAL.
XG_FRAME_DATA);
xg_update_menubar (menubar, f, &list, list, 0, val->contents,
- select_cb, highlight_cb, cl_data);
+ select_cb, deactivate_cb, highlight_cb, cl_data);
if (deep_p)
{
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);
+ xfree (p);
xg_remove_widget_from_map (id);
}
GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
XG_TOOL_BAR_PROXY_BUTTON));
xg_tool_bar_callback (wbutton, client_data);
+ FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (wbutton),
+ XG_FRAME_DATA);
+ /* Put focus back to the frame after we have clicked on a detached
+ tool bar button. */
+ Lisp_Object frame;
+ XSETFRAME (frame, f);
+ Fx_focus_frame (frame);
}
/* This callback is called when a tool item should create a proxy item,
int icon_size = 0;
struct image *img = NULL;
Lisp_Object image;
- Lisp_Object stock;
+ Lisp_Object stock = Qnil;
GtkStockItem stock_item;
char *stock_name = NULL;
char *icon_name = NULL;