/* X Communication module for terminals which understand the X protocol.
Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GNU Emacs.
{
int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
- /* Internal border is drawn below the tool bar. */
- if (WINDOWP (f->tool_bar_window)
- && w == XWINDOW (f->tool_bar_window))
- y -= width;
-
BLOCK_INPUT;
x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
0, y, width, height, False);
if (j < i)
{
font->driver->draw (s, j, i, x, y, 0);
+ if (s->face->overstrike)
+ font->driver->draw (s, j, i, x + 1, y, 0);
x += width;
}
xoff = LGLYPH_XOFF (glyph);
yoff = LGLYPH_YOFF (glyph);
wadjust = LGLYPH_WADJUST (glyph);
font->driver->draw (s, i, i + 1, x + xoff, y + yoff, 0);
+ if (s->face->overstrike)
+ font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff, 0);
x += wadjust;
j = i + 1;
width = 0;
}
}
if (j < i)
- font->driver->draw (s, j, i, x, y, 0);
+ {
+ font->driver->draw (s, j, i, x, y, 0);
+ if (s->face->overstrike)
+ font->driver->draw (s, j, i, x + 1, y, 0);
+ }
}
}
colors or something like that, then they should be notified. */
x_scroll_bar_clear (f);
+#if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS)
+ /* Make sure scroll bars are redrawn. As they aren't redrawn by
+ redisplay, do it here. */
+ gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
+#endif
+
XFlush (FRAME_X_DISPLAY (f));
UNBLOCK_INPUT;
BLOCK_INPUT;
{
+#ifdef USE_GTK
+ /* Use Gdk routines to draw. This way, we won't draw over scroll bars
+ when the scroll bars and the edit widget share the same X window. */
+ GdkGCValues vals;
+ GdkGC *gc;
+ vals.foreground.pixel = (FRAME_FOREGROUND_PIXEL (f)
+ ^ FRAME_BACKGROUND_PIXEL (f));
+ vals.function = GDK_XOR;
+ gc = gdk_gc_new_with_values (FRAME_GTK_WIDGET (f)->window,
+ &vals,
+ GDK_GC_FUNCTION
+ | GDK_GC_FOREGROUND);
+#define XFillRectangle(d, win, gc, x, y, w, h) \
+ gdk_draw_rectangle (FRAME_GTK_WIDGET (f)->window, \
+ gc, TRUE, x, y, w, h)
+#else
GC gc;
/* Create a GC that will use the GXxor function to flip foreground
gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
GCFunction | GCForeground, &values);
}
-
+#endif
{
/* Get the height not including a menu bar widget. */
int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
flash_left,
(FRAME_INTERNAL_BORDER_WIDTH (f)
- + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
+ + FRAME_TOP_MARGIN_HEIGHT (f)),
width, flash_height);
XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
flash_left,
(height - flash_height
- FRAME_INTERNAL_BORDER_WIDTH (f)),
width, flash_height);
+
}
else
/* If it is short, flash it all. */
XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
flash_left,
(FRAME_INTERNAL_BORDER_WIDTH (f)
- + FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f)),
+ + FRAME_TOP_MARGIN_HEIGHT (f)),
width, flash_height);
XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
flash_left,
flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
+#ifdef USE_GTK
+ g_object_unref (G_OBJECT (gc));
+#undef XFillRectangle
+#else
XFreeGC (FRAME_X_DISPLAY (f), gc);
+#endif
x_flush (f);
}
}
/* Scroll bar callback for GTK scroll bars. WIDGET is the scroll
bar widget. DATA is a pointer to the scroll_bar structure. */
-static void
-xg_scroll_callback (widget, data)
- GtkRange *widget;
- gpointer data;
+static gboolean
+xg_scroll_callback (GtkRange *range,
+ GtkScrollType scroll,
+ gdouble value,
+ gpointer user_data)
{
- struct scroll_bar *bar = (struct scroll_bar *) data;
- gdouble previous;
+ struct scroll_bar *bar = (struct scroll_bar *) user_data;
gdouble position;
- gdouble *p;
- int diff;
-
int part = -1, whole = 0, portion = 0;
- GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (widget));
+ GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range));
+ FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (range), XG_FRAME_DATA);
+ if (xg_ignore_gtk_scrollbar) return FALSE;
position = gtk_adjustment_get_value (adj);
- p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA);
- if (! p)
- {
- p = (gdouble*) xmalloc (sizeof (gdouble));
- *p = XG_SB_MIN;
- g_object_set_data (G_OBJECT (widget), XG_LAST_SB_DATA, p);
- }
-
- previous = *p;
- *p = position;
-
- if (xg_ignore_gtk_scrollbar) return;
-
- diff = (int) (position - previous);
- if (diff == (int) adj->step_increment)
- {
- part = scroll_bar_down_arrow;
- bar->dragging = Qnil;
- }
- else if (-diff == (int) adj->step_increment)
+ switch (scroll)
{
+ case GTK_SCROLL_JUMP:
+ /* Buttons 1 2 or 3 must be grabbed. */
+ if (FRAME_X_DISPLAY_INFO (f)->grabbed != 0
+ && FRAME_X_DISPLAY_INFO (f)->grabbed < (1 << 4))
+ {
+ part = scroll_bar_handle;
+ whole = adj->upper - adj->page_size;
+ portion = min ((int)position, whole);
+ bar->dragging = make_number ((int)portion);
+ }
+ break;
+ case GTK_SCROLL_STEP_BACKWARD:
part = scroll_bar_up_arrow;
bar->dragging = Qnil;
- }
- else if (diff == (int) adj->page_increment)
- {
- part = scroll_bar_below_handle;
+ break;
+ case GTK_SCROLL_STEP_FORWARD:
+ part = scroll_bar_down_arrow;
bar->dragging = Qnil;
- }
- else if (-diff == (int) adj->page_increment)
- {
+ break;
+ case GTK_SCROLL_PAGE_BACKWARD:
part = scroll_bar_above_handle;
bar->dragging = Qnil;
- }
- else
- {
- part = scroll_bar_handle;
- whole = adj->upper - adj->page_size;
- portion = min ((int)position, whole);
- bar->dragging = make_number ((int)portion);
+ break;
+ case GTK_SCROLL_PAGE_FORWARD:
+ part = scroll_bar_below_handle;
+ bar->dragging = Qnil;
+ break;
}
if (part >= 0)
last_scroll_bar_part = part;
x_send_scroll_bar_event (bar->window, part, portion, whole);
}
+
+ return FALSE;
+}
+
+/* Callback for button release. Sets dragging to Qnil when dragging is done. */
+
+static gboolean
+xg_end_scroll_callback (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ struct scroll_bar *bar = (struct scroll_bar *) user_data;
+ bar->dragging = Qnil;
+ if (WINDOWP (window_being_scrolled))
+ {
+ x_send_scroll_bar_event (window_being_scrolled,
+ scroll_bar_end_scroll, 0, 0);
+ window_being_scrolled = Qnil;
+ }
+
+ return FALSE;
}
+
#else /* not USE_GTK and not USE_MOTIF */
/* Xaw scroll bar callback. Invoked when the thumb is dragged.
BLOCK_INPUT;
xg_create_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
+ G_CALLBACK (xg_end_scroll_callback),
scroll_bar_name);
UNBLOCK_INPUT;
}
{
XEvent *xev = (XEvent *) gxev;
+ BLOCK_INPUT;
if (current_count >= 0)
{
struct x_display_info *dpyinfo;
/* Filter events for the current X input method.
GTK calls XFilterEvent but not for key press and release,
so we do it here. */
- if (xev->type == KeyPress || xev->type == KeyRelease)
- if (dpyinfo && x_filter_event (dpyinfo, xev))
- return GDK_FILTER_REMOVE;
+ if ((xev->type == KeyPress || xev->type == KeyRelease)
+ && dpyinfo
+ && x_filter_event (dpyinfo, xev))
+ {
+ UNBLOCK_INPUT;
+ return GDK_FILTER_REMOVE;
+ }
#endif
if (! dpyinfo)
current_finish = X_EVENT_NORMAL;
else
- {
- current_count +=
- handle_one_xevent (dpyinfo, xev, ¤t_finish,
- current_hold_quit);
- }
+ current_count +=
+ handle_one_xevent (dpyinfo, xev, ¤t_finish,
+ current_hold_quit);
}
else
current_finish = x_dispatch_event (xev, xev->xany.display);
+ UNBLOCK_INPUT;
+
if (current_finish == X_EVENT_GOTO_OUT || current_finish == X_EVENT_DROP)
return GDK_FILTER_REMOVE;
{
x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
x, y, width, height, False);
+#ifdef USE_GTK
+ /* Must queue a redraw, because scroll bars might have been cleared. */
+ if (FRAME_GTK_WIDGET (f))
+ gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
+#endif
}
doing it because it's done in Fx_show_tip, and it leads to
problems because the tip frame has no widget. */
if (NILP (tip_frame) || XFRAME (tip_frame) != f)
- {
- int rows, cols;
-
- /* When the frame is maximized/fullscreen or running under for
- example Xmonad, x_set_window_size will be a no-op.
- In that case, the right thing to do is extend rows/cols to
- the current frame size. We do that first if x_set_window_size
- turns out to not be a no-op (there is no way to know).
- The size will be adjusted again if the frame gets a
- ConfigureNotify event as a result of x_set_window_size. */
- int pixelh = FRAME_PIXEL_HEIGHT (f);
-#ifdef USE_X_TOOLKIT
- /* The menu bar is not part of text lines. The tool bar
- is however. */
- pixelh -= FRAME_MENUBAR_HEIGHT (f);
-#endif
- rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelh);
- /* Update f->scroll_bar_actual_width because it is used in
- FRAME_PIXEL_WIDTH_TO_TEXT_COLS. */
- f->scroll_bar_actual_width
- = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
- cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, FRAME_PIXEL_WIDTH (f));
-
- change_frame_size (f, rows, cols, 0, 1, 0);
- x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
- }
+ x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
}
#ifdef HAVE_X_I18N
{
BLOCK_INPUT;
+ if (NILP (tip_frame) || XFRAME (tip_frame) != f)
+ {
+ int r, c;
+
+ /* When the frame is maximized/fullscreen or running under for
+ example Xmonad, x_set_window_size_1 will be a no-op.
+ In that case, the right thing to do is extend rows/cols to
+ the current frame size. We do that first if x_set_window_size_1
+ turns out to not be a no-op (there is no way to know).
+ The size will be adjusted again if the frame gets a
+ ConfigureNotify event as a result of x_set_window_size. */
+ int pixelh = FRAME_PIXEL_HEIGHT (f);
+#ifdef USE_X_TOOLKIT
+ /* The menu bar is not part of text lines. The tool bar
+ is however. */
+ pixelh -= FRAME_MENUBAR_HEIGHT (f);
+#endif
+ r = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelh);
+ /* Update f->scroll_bar_actual_width because it is used in
+ FRAME_PIXEL_WIDTH_TO_TEXT_COLS. */
+ f->scroll_bar_actual_width
+ = FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f);
+ c = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, FRAME_PIXEL_WIDTH (f));
+ change_frame_size (f, r, c, 0, 1, 0);
+ }
+
#ifdef USE_GTK
if (FRAME_GTK_WIDGET (f))
xg_frame_set_char_size (f, cols, rows);
{
Pixmap icon_pixmap, icon_mask;
-#ifndef USE_X_TOOLKIT
+#if !defined USE_X_TOOLKIT && !defined USE_GTK
Window window = FRAME_OUTER_WINDOW (f);
#endif
return dpy_ok;
}
+#ifdef USE_GTK
+static void
+my_log_handler (log_domain, log_level, message, user_data)
+ const gchar *log_domain;
+ GLogLevelFlags log_level;
+ const gchar *message;
+ gpointer user_data;
+{
+ if (!strstr (message, "g_set_prgname"))
+ fprintf (stderr, "%s-WARNING **: %s\n", log_domain, message);
+}
+#endif
+
/* Open a connection to X display DISPLAY_NAME, and return
the structure that describes the open display.
If we cannot contact the display, return null. */
int argc;
char *argv[NUM_ARGV];
char **argv2 = argv;
- GdkAtom atom;
-
+ guint id;
#ifndef HAVE_GTK_MULTIDISPLAY
if (!EQ (Vinitial_window_system, Qx))
error ("Sorry, you cannot connect to X servers with the GTK toolkit");
XSetLocaleModifiers ("");
+ /* Work around GLib bug that outputs a faulty warning. See
+ https://bugzilla.gnome.org/show_bug.cgi?id=563627. */
+ id = g_log_set_handler ("GLib", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL
+ | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
gtk_init (&argc, &argv2);
+ g_log_remove_handler ("GLib", id);
/* gtk_init does set_locale. We must fix locale after calling it. */
fixup_locale ();
terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
init_kboard (terminal->kboard);
terminal->kboard->Vwindow_system = Qx;
+
+ /* Add the keyboard to the list before running Lisp code (via
+ Qvendor_specific_keysyms below), since these are not traced
+ via terminals but only through all_kboards. */
+ terminal->kboard->next_kboard = all_kboards;
+ all_kboards = terminal->kboard;
+
if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound))
{
char *vendor = ServerVendor (dpy);
- /* Temporarily hide the partially initialized terminal */
+
+ /* Protect terminal from GC before removing it from the
+ list of terminals. */
+ struct gcpro gcpro1;
+ Lisp_Object gcpro_term;
+ XSETTERMINAL (gcpro_term, terminal);
+ GCPRO1 (gcpro_term);
+
+ /* Temporarily hide the partially initialized terminal. */
terminal_list = terminal->next_terminal;
UNBLOCK_INPUT;
terminal->kboard->Vsystem_key_alist
BLOCK_INPUT;
terminal->next_terminal = terminal_list;
terminal_list = terminal;
+ UNGCPRO;
}
- terminal->kboard->next_kboard = all_kboards;
- all_kboards = terminal->kboard;
/* Don't let the initial kboard remain current longer than necessary.
That would cause problems if a file loaded on startup tries to
prompt in the mini-buffer. */
= XInternAtom (dpyinfo->display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
dpyinfo->Xatom_net_wm_state_sticky
= XInternAtom (dpyinfo->display, "_NET_WM_STATE_STICKY", False);
-
+ dpyinfo->Xatom_net_window_type
+ = XInternAtom (dpyinfo->display, "_NET_WM_WINDOW_TYPE", False);
+ dpyinfo->Xatom_net_window_type_tooltip
+ = XInternAtom (dpyinfo->display, "_NET_WM_WINDOW_TYPE_TOOLTIP", False);
+
dpyinfo->cut_buffers_initialized = 0;
dpyinfo->x_dnd_atoms_size = 8;
x_delete_display (dpyinfo)
struct x_display_info *dpyinfo;
{
- int i;
struct terminal *t;
/* Close all frames and delete the generic struct terminal for this
x_delete_terminal (struct terminal *terminal)
{
struct x_display_info *dpyinfo = terminal->display_info.x;
- int i;
/* Protect against recursive calls. delete_frame in
delete_terminal calls us back when it deletes our last frame. */
#endif /* ! USE_GTK */
}
+ /* Mark as dead. */
+ dpyinfo->display = NULL;
x_delete_display (dpyinfo);
UNBLOCK_INPUT;
}