/* 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 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
int x_use_underline_position_properties;
+/* Non-zero means to draw the underline at the same place as the descent line. */
+
+int x_underline_at_descent_line;
+
/* This is a chain of structures for all the X displays currently in
use. */
static Time last_mouse_movement_time;
+/* Time for last user interaction as returned in X events. */
+
+static Time last_user_time;
+
/* Incremented by XTread_socket whenever it really tries to read
events. */
static void x_set_window_size_1 P_ ((struct frame *, int, int, int));
static const XColor *x_color_cells P_ ((Display *, int *));
static void x_update_window_end P_ ((struct window *, int, int));
-void x_delete_display P_ ((struct x_display_info *));
-static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
- unsigned));
+
static int x_io_error_quitter P_ ((Display *));
-int x_catch_errors P_ ((Display *));
-void x_uncatch_errors P_ ((Display *, int));
-void x_lower_frame P_ ((struct frame *));
-void x_scroll_bar_clear P_ ((struct frame *));
-int x_had_errors_p P_ ((Display *));
-void x_wm_set_size_hint P_ ((struct frame *, long, int));
-void x_raise_frame P_ ((struct frame *));
-void x_set_window_size P_ ((struct frame *, int, int, int));
-void x_wm_set_window_state P_ ((struct frame *, int));
-void x_wm_set_icon_pixmap P_ ((struct frame *, int));
-void x_initialize P_ ((void));
static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
static int x_compute_min_glyph_bounds P_ ((struct frame *));
static void x_update_end P_ ((struct frame *));
Lisp_Object *, Lisp_Object *,
unsigned long *));
static void x_check_fullscreen P_ ((struct frame *));
-static void x_check_expected_move P_ ((struct frame *));
+static void x_check_expected_move P_ ((struct frame *, int, int));
+static void x_sync_with_move P_ ((struct frame *, int, int, int));
static int handle_one_xevent P_ ((struct x_display_info *, XEvent *,
int *, struct input_event *));
+/* Don't declare this NO_RETURN because we want no
+ interference with debugging failing X calls. */
+static SIGTYPE x_connection_closed P_ ((Display *, char *));
/* Flush display of frame F, or of all frames if F is null. */
{
/* Fill background with a stipple pattern. */
XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+ XSetTSOrigin (s->display, s->gc, - s->x, - s->y);
XFillRectangle (s->display, pixmap, s->gc,
0, 0, s->background_width, s->height);
XSetFillStyle (s->display, s->gc, FillSolid);
+ XSetTSOrigin (s->display, s->gc, 0, 0);
}
else
{
{
/* If `x-stretch-block-cursor' is nil, don't draw a block cursor
as wide as the stretch glyph. */
- int width = min (FRAME_COLUMN_WIDTH (s->f), s->background_width);
+ int width, background_width = s->background_width;
+ int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
+
+ if (x < left_x)
+ {
+ background_width -= left_x - x;
+ x = left_x;
+ }
+ width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
/* Draw cursor. */
- x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
+ x_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
/* Clear rest using the GC of the original non-cursor face. */
- if (width < s->background_width)
+ if (width < background_width)
{
- int x = s->x + width, y = s->y;
- int w = s->background_width - width, h = s->height;
+ int y = s->y;
+ int w = background_width - width, h = s->height;
XRectangle r;
GC gc;
+ x += width;
if (s->row->mouse_face_p
&& cursor_in_mouse_face_p (s->w))
{
}
}
else if (!s->background_filled_p)
- x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
- s->height);
+ {
+ int background_width = s->background_width;
+ int x = s->x, left_x = window_box_left_offset (s->w, TEXT_AREA);
+
+ /* Don't draw into left margin, fringe or scrollbar area
+ except for header line and mode line. */
+ if (x < left_x && !s->row->mode_line_p)
+ {
+ background_width -= left_x - x;
+ x = left_x;
+ }
+ if (background_width > 0)
+ x_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
+ }
s->background_filled_p = 1;
}
if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
h = 1;
- /* Get the underline position. This is the recommended
- vertical offset in pixels from the baseline to the top of
- the underline. This is a signed value according to the
- specs, and its default is
-
- ROUND ((maximum descent) / 2), with
- ROUND(x) = floor (x + 0.5) */
-
- if (x_use_underline_position_properties
- && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
- y = s->ybase + (long) tem;
- else if (s->face->font)
- y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
- else
- y = s->y + s->height - h;
+ y = s->y + s->height - h;
+ if (!x_underline_at_descent_line)
+ {
+ /* Get the underline position. This is the recommended
+ vertical offset in pixels from the baseline to the top of
+ the underline. This is a signed value according to the
+ specs, and its default is
+
+ ROUND ((maximum descent) / 2), with
+ ROUND(x) = floor (x + 0.5) */
+
+ if (x_use_underline_position_properties
+ && XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &tem))
+ y = s->ybase + (long) tem;
+ else if (s->face->font)
+ y = s->ybase + (s->face->font->max_bounds.descent + 1) / 2;
+ }
if (s->face->underline_defaulted_p)
XFillRectangle (s->display, s->window, s->gc,
- s->x, y, s->width, h);
+ s->x, y, s->background_width, h);
else
{
XGCValues xgcv;
XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
XSetForeground (s->display, s->gc, s->face->underline_color);
XFillRectangle (s->display, s->window, s->gc,
- s->x, y, s->width, h);
+ s->x, y, s->background_width, h);
XSetForeground (s->display, s->gc, xgcv.foreground);
}
}
if (s->face->overline_color_defaulted_p)
XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
- s->width, h);
+ s->background_width, h);
else
{
XGCValues xgcv;
XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
XSetForeground (s->display, s->gc, s->face->overline_color);
XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
- s->width, h);
+ s->background_width, h);
XSetForeground (s->display, s->gc, xgcv.foreground);
}
}
/* Convert between the modifier bits X uses and the modifier bits
Emacs uses. */
-static unsigned int
+unsigned int
x_x_to_emacs_modifiers (dpyinfo, state)
struct x_display_info *dpyinfo;
unsigned int state;
last_mouse_motion_event = *event;
XSETFRAME (last_mouse_motion_frame, frame);
+ if (!FRAME_X_OUTPUT (frame))
+ return 0;
+
if (event->window != FRAME_X_WINDOW (frame))
{
frame->mouse_moved = 1;
Window win, child;
int win_x, win_y;
int parent_x = 0, parent_y = 0;
- int count;
win = root;
structure is changing at the same time this function
is running. So at least we must not crash from them. */
- count = x_catch_errors (FRAME_X_DISPLAY (*fp));
+ x_catch_errors (FRAME_X_DISPLAY (*fp));
if (FRAME_X_DISPLAY_INFO (*fp)->grabbed && last_mouse_frame
&& FRAME_LIVE_P (last_mouse_frame))
if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
f1 = 0;
- x_uncatch_errors (FRAME_X_DISPLAY (*fp), count);
+ x_uncatch_errors ();
/* If not, is it one of our scroll bars? */
if (! f1)
/* Make Xt timeouts work while the scroll bar is active. */
toolkit_scroll_bar_interaction = 1;
+#ifdef USE_X_TOOLKIT
+ x_activate_timeout_atimer ();
+#endif
/* Setting the event mask to zero means that the message will
be sent to the client that created the window, and if that
x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
+ /* Switch to scroll bar foreground color. */
+ if (f->output_data.x->scroll_bar_foreground_pixel != -1)
+ XSetForeground (FRAME_X_DISPLAY (f), gc,
+ f->output_data.x->scroll_bar_foreground_pixel);
+
/* Draw a one-pixel border just inside the edges of the scroll bar. */
XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
XINT (bar->width) - 1 - width_trim - width_trim,
XINT (bar->height) - 1);
- UNBLOCK_INPUT;
+ /* Restore the foreground color of the GC if we changed it above. */
+ if (f->output_data.x->scroll_bar_foreground_pixel != -1)
+ XSetForeground (FRAME_X_DISPLAY (f), gc,
+ f->output_data.x->foreground_pixel);
+
+ UNBLOCK_INPUT;
}
#endif /* not USE_TOOLKIT_SCROLL_BARS */
Display *d = event.xclient.display;
/* Catch and ignore errors, in case window has been
iconified by a window manager such as GWM. */
- int count = x_catch_errors (d);
+ x_catch_errors (d);
XSetInputFocus (d, event.xclient.window,
/* The ICCCM says this is
the only valid choice. */
/* This is needed to detect the error
if there is an error. */
XSync (d, False);
- x_uncatch_errors (d, count);
+ x_uncatch_errors ();
}
/* Not certain about handling scroll bars here */
#endif /* 0 */
== dpyinfo->Xatom_editres)
{
f = x_any_window_to_frame (dpyinfo, event.xclient.window);
- _XEditResCheckMessages (f->output_data.x->widget, NULL,
- &event, NULL);
+ if (f)
+ _XEditResCheckMessages (f->output_data.x->widget, NULL,
+ &event, NULL);
goto done;
}
#endif /* HACK_EDITRES */
images, only, which should have 1 page. */
Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
f = x_window_to_frame (dpyinfo, event.xclient.window);
+ if (!f)
+ goto OTHER;
x_kill_gs_process (pixmap, f);
expose_frame (f, 0, 0, 0, 0);
goto done;
#endif /* USE_TOOLKIT_SCROLL_BARS */
f = x_any_window_to_frame (dpyinfo, event.xclient.window);
-
if (!f)
goto OTHER;
-
if (x_handle_dnd_message (f, &event.xclient, dpyinfo, &inev.ie))
*finish = X_EVENT_DROP;
}
break;
case SelectionNotify:
+ last_user_time = event.xselection.time;
#ifdef USE_X_TOOLKIT
if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
goto OTHER;
break;
case SelectionClear: /* Someone has grabbed ownership. */
+ last_user_time = event.xselectionclear.time;
#ifdef USE_X_TOOLKIT
if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
goto OTHER;
break;
case SelectionRequest: /* Someone wants our selection. */
+ last_user_time = event.xselectionrequest.time;
#ifdef USE_X_TOOLKIT
if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
goto OTHER;
break;
case PropertyNotify:
+ last_user_time = event.xproperty.time;
#if 0 /* This is plain wrong. In the case that we are waiting for a
PropertyNotify used as an ACK in incremental selection
transfer, the property will be on the receiver's window. */
/* Perhaps reparented due to a WM restart. Reset this. */
FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN;
+ FRAME_X_DISPLAY_INFO (f)->net_supported_window = 0;
}
goto OTHER;
case KeyPress:
+ last_user_time = event.xkey.time;
ignore_next_mouse_click_timeout = 0;
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
f = x_any_window_to_frame (dpyinfo, event.xkey.window);
- if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
+ /* If mouse-highlight is an integer, input clears out
+ mouse highlighting. */
+ if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight)
+ && (f == 0
+ || !EQ (f->tool_bar_window, dpyinfo->mouse_face_window)))
{
clear_mouse_face (dpyinfo);
dpyinfo->mouse_face_hidden = 1;
#endif
case KeyRelease:
+ last_user_time = event.xkey.time;
#ifdef HAVE_X_I18N
/* Don't dispatch this event since XtDispatchEvent calls
XFilterEvent, and two calls in a row may freeze the
#endif
case EnterNotify:
+ last_user_time = event.xcrossing.time;
x_detect_focus_change (dpyinfo, &event, &inev.ie);
f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
so update things that depend on mouse position. */
if (f && !f->output_data.x->hourglass_p)
note_mouse_movement (f, &event.xmotion);
+#ifdef USE_GTK
+ /* We may get an EnterNotify on the buttons in the toolbar. In that
+ case we moved out of any highlighted area and need to note this. */
+ if (!f && last_mouse_glyph_frame)
+ note_mouse_movement (last_mouse_glyph_frame, &event);
+#endif
goto OTHER;
case FocusIn:
goto OTHER;
case LeaveNotify:
+ last_user_time = event.xcrossing.time;
x_detect_focus_change (dpyinfo, &event, &inev.ie);
f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
if (any_help_event_p)
do_help = -1;
}
+#ifdef USE_GTK
+ /* See comment in EnterNotify above */
+ else if (last_mouse_glyph_frame)
+ note_mouse_movement (last_mouse_glyph_frame, &event);
+#endif
goto OTHER;
case FocusOut:
case MotionNotify:
{
+ last_user_time = event.xmotion.time;
previous_help_echo_string = help_echo_string;
help_echo_string = Qnil;
{
/* Generate SELECT_WINDOW_EVENTs when needed. */
- if (mouse_autoselect_window)
+ if (!NILP (Vmouse_autoselect_window))
{
Lisp_Object window;
/* Window will be selected only when it is not selected now and
last mouse movement event was not in it. Minibuffer window
- will be selected iff it is active. */
+ will be selected only when it is active. */
if (WINDOWP (window)
&& !EQ (window, last_window)
&& !EQ (window, selected_window))
&& GTK_WIDGET_MAPPED (FRAME_GTK_OUTER_WIDGET (f)))
#endif
{
- /* What we have now is the position of Emacs's own window.
- Convert that to the position of the window manager window. */
x_real_positions (f, &f->left_pos, &f->top_pos);
- x_check_expected_move (f);
if (f->want_fullscreen & FULLSCREEN_WAIT)
f->want_fullscreen &= ~(FULLSCREEN_WAIT|FULLSCREEN_BOTH);
}
bzero (&compose_status, sizeof (compose_status));
last_mouse_glyph_frame = 0;
+ last_user_time = event.xbutton.time;
if (dpyinfo->grabbed
&& last_mouse_frame
int y = event.xbutton.y;
window = window_from_coordinates (f, x, y, 0, 0, 0, 1);
- if (EQ (window, f->tool_bar_window))
+ tool_bar_p = EQ (window, f->tool_bar_window);
+
+ if (tool_bar_p && event.xbutton.button < 4)
{
- if (event.xbutton.type == ButtonPress)
- handle_tool_bar_click (f, x, y, 1, 0);
- else
- handle_tool_bar_click (f, x, y, 0,
- x_x_to_emacs_modifiers (dpyinfo,
+ if (event.xbutton.type == ButtonPress)
+ handle_tool_bar_click (f, x, y, 1, 0);
+ else
+ handle_tool_bar_click (f, x, y, 0,
+ x_x_to_emacs_modifiers (dpyinfo,
event.xbutton.state));
- tool_bar_p = 1;
}
}
return;
/* Compute frame-relative coordinates for phys cursor. */
- x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
- y = get_phys_cursor_geometry (w, row, cursor_glyph, &h);
+ get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
wd = w->phys_cursor_width;
/* The foreground of cursor_gc is typically the same as the normal
/* Set clipping, draw the rectangle, and reset clipping again. */
x_clip_to_row (w, row, TEXT_AREA, gc);
- XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
+ XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h - 1);
XSetClipMask (dpy, gc, None);
}
#define X_ERROR_MESSAGE_SIZE 200
/* If non-nil, this should be a string.
- It means catch X errors and store the error message in this string. */
+ It means catch X errors and store the error message in this string.
+
+ The reason we use a stack is that x_catch_error/x_uncatch_error can
+ be called from a signal handler.
+*/
struct x_error_message_stack {
char string[X_ERROR_MESSAGE_SIZE];
static struct x_error_message_stack *x_error_message;
/* An X error handler which stores the error message in
- x_error_message_string. This is called from x_error_handler if
+ *x_error_message. This is called from x_error_handler if
x_catch_errors is in effect. */
static void
After calling this function, X protocol errors no longer cause
Emacs to exit; instead, they are recorded in the string
- stored in x_error_message_string.
+ stored in *x_error_message.
Calling x_check_errors signals an Emacs error if an X error has
occurred since the last call to x_catch_errors or x_check_errors.
Calling x_uncatch_errors resumes the normal error handling. */
void x_check_errors ();
-static Lisp_Object x_catch_errors_unwind ();
-int
+void
x_catch_errors (dpy)
Display *dpy;
{
- int count = SPECPDL_INDEX ();
- struct x_error_message_stack *data = malloc (sizeof (*data));
- Lisp_Object dummy;
-#ifdef ENABLE_CHECKING
- dummy = make_number ((EMACS_INT)dpy + (EMACS_INT)x_error_message);
-#else
- dummy = Qnil;
-#endif
+ struct x_error_message_stack *data = xmalloc (sizeof (*data));
/* Make sure any errors from previous requests have been dealt with. */
XSync (dpy, False);
data->string[0] = 0;
data->prev = x_error_message;
x_error_message = data;
-
- record_unwind_protect (x_catch_errors_unwind, dummy);
-
- return count;
}
-/* Unbind the binding that we made to check for X errors. */
+/* Undo the last x_catch_errors call.
+ DPY should be the display that was passed to x_catch_errors. */
-static Lisp_Object
-x_catch_errors_unwind (dummy)
- Lisp_Object dummy;
+void
+x_uncatch_errors ()
{
- Display *dpy = x_error_message->dpy;
struct x_error_message_stack *tmp;
+ BLOCK_INPUT;
+
/* The display may have been closed before this function is called.
Check if it is still open before calling XSync. */
- if (x_display_info_for_display (dpy) != 0)
- {
- BLOCK_INPUT;
- XSync (dpy, False);
- UNBLOCK_INPUT;
- }
+ if (x_display_info_for_display (x_error_message->dpy) != 0)
+ XSync (x_error_message->dpy, False);
tmp = x_error_message;
x_error_message = x_error_message->prev;
- free (tmp);
-
- eassert (EQ (dummy,
- make_number ((EMACS_INT)dpy + (EMACS_INT)x_error_message)));
-
- return Qnil;
+ xfree (tmp);
+ UNBLOCK_INPUT;
}
/* If any X protocol errors have arrived since the last call to
XSync (dpy, False);
if (x_error_message->string[0])
- error (format, x_error_message->string);
+ {
+ char string[X_ERROR_MESSAGE_SIZE];
+ bcopy (x_error_message->string, string, X_ERROR_MESSAGE_SIZE);
+ x_uncatch_errors ();
+ error (format, string);
+ }
}
/* Nonzero if we had any X protocol errors
x_error_message->string[0] = 0;
}
-/* Stop catching X protocol errors and let them make Emacs die.
- DPY should be the display that was passed to x_catch_errors.
- COUNT should be the value that was returned by
- the corresponding call to x_catch_errors. */
+/* Close off all unclosed x_catch_errors calls. */
void
-x_uncatch_errors (dpy, count)
- Display *dpy;
- int count;
+x_fully_uncatch_errors ()
+{
+ while (x_error_message)
+ x_uncatch_errors ();
+}
+
+/* Nonzero if x_catch_errors has been done and not yet canceled. */
+
+int
+x_catching_errors ()
{
- unbind_to (count, Qnil);
+ return x_error_message != 0;
}
#if 0
{
struct x_display_info *dpyinfo = x_display_info_for_display (dpy);
Lisp_Object frame, tail;
- int count;
error_msg = (char *) alloca (strlen (error_message) + 1);
strcpy (error_msg, error_message);
below. Otherwise, we might end up with printing ``can't find per
display information'' in the recursive call instead of printing
the original message here. */
- count = x_catch_errors (dpy);
+ x_catch_errors (dpy);
/* We have to close the display to inform Xt that it doesn't
exist anymore. If we don't, Xt will continue to wait for
if (dpyinfo)
x_delete_display (dpyinfo);
- x_uncatch_errors (dpy, count);
+ x_uncatch_errors ();
if (x_display_list == 0)
{
/* We specifically use it before defining it, so that gcc doesn't inline it,
otherwise gdb doesn't know how to properly put a breakpoint on it. */
-static void x_error_quitter (Display *display, XErrorEvent *error);
+static void x_error_quitter P_ ((Display *, XErrorEvent *));
/* This is the first-level handler for X protocol errors.
It calls x_error_quitter or x_error_catcher. */
{
char buf[256], buf1[356];
+ /* Ignore BadName errors. They can happen because of fonts
+ or colors that are not defined. */
+
+ if (error->error_code == BadName)
+ return;
+
/* Note that there is no real way portable across R3/R4 to get the
original error handler. */
{
int modified_top, modified_left;
- if (change_gravity > 0)
+ if (change_gravity != 0)
{
+ FRAME_X_OUTPUT (f)->left_before_move = f->left_pos;
+ FRAME_X_OUTPUT (f)->top_before_move = f->top_pos;
+
f->top_pos = yoff;
f->left_pos = xoff;
f->size_hint_flags &= ~ (XNegative | YNegative);
modified_left = f->left_pos;
modified_top = f->top_pos;
- if (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A)
+ if (change_gravity != 0 && FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A)
{
/* Some WMs (twm, wmaker at least) has an offset that is smaller
than the WM decorations. So we use the calculated offset instead
XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
modified_left, modified_top);
- if (FRAME_VISIBLE_P (f)
- && FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN)
+ x_sync_with_move (f, f->left_pos, f->top_pos,
+ FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
+ ? 1 : 0);
+
+ /* change_gravity is non-zero when this function is called from Lisp to
+ programmatically move a frame. In that case, we call
+ x_check_expected_move to discover if we have a "Type A" or "Type B"
+ window manager, and, for a "Type A" window manager, adjust the position
+ of the frame.
+
+ We call x_check_expected_move if a programmatic move occurred, and
+ either the window manager type (A/B) is unknown or it is Type A but we
+ need to compute the top/left offset adjustment for this frame. */
+
+ if (change_gravity != 0 &&
+ (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
+ || (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
+ && (FRAME_X_OUTPUT (f)->move_offset_left == 0
+ && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
+ x_check_expected_move (f, modified_left, modified_top);
+
+ UNBLOCK_INPUT;
+}
+
+/* Return non-zero if _NET_SUPPORTING_WM_CHECK window exists and _NET_SUPPORTED
+ on the root window for frame F contains ATOMNAME.
+ This is how a WM check shall be done according to the Window Manager
+ Specification/Extended Window Manager Hints at
+ http://freedesktop.org/wiki/Standards_2fwm_2dspec. */
+
+static int
+wm_supports (f, atomname)
+ struct frame *f;
+ const char *atomname;
+{
+ Atom actual_type;
+ unsigned long actual_size, bytes_remaining;
+ int i, rc, actual_format;
+ Atom prop_atom;
+ Window wmcheck_window;
+ struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ Window target_window = dpyinfo->root_window;
+ long max_len = 65536;
+ Display *dpy = FRAME_X_DISPLAY (f);
+ unsigned char *tmp_data = NULL;
+ Atom target_type = XA_WINDOW;
+ Atom want_atom;
+
+ BLOCK_INPUT;
+
+ prop_atom = XInternAtom (dpy, "_NET_SUPPORTING_WM_CHECK", False);
+
+ x_catch_errors (dpy);
+ rc = XGetWindowProperty (dpy, target_window,
+ prop_atom, 0, max_len, False, target_type,
+ &actual_type, &actual_format, &actual_size,
+ &bytes_remaining, &tmp_data);
+
+ if (rc != Success || actual_type != XA_WINDOW || x_had_errors_p (dpy))
+ {
+ if (tmp_data) XFree (tmp_data);
+ x_uncatch_errors ();
+ UNBLOCK_INPUT;
+ return 0;
+ }
+
+ wmcheck_window = *(Window *) tmp_data;
+ XFree (tmp_data);
+
+ /* Check if window exists. */
+ XSelectInput (dpy, wmcheck_window, StructureNotifyMask);
+ x_sync (f);
+ if (x_had_errors_p (dpy))
{
- FRAME_X_OUTPUT (f)->check_expected_move = 1;
- FRAME_X_OUTPUT (f)->expected_top = f->top_pos;
- FRAME_X_OUTPUT (f)->expected_left = f->left_pos;
+ x_uncatch_errors ();
+ UNBLOCK_INPUT;
+ return 0;
}
+ if (dpyinfo->net_supported_window != wmcheck_window)
+ {
+ /* Window changed, reload atoms */
+ if (dpyinfo->net_supported_atoms != NULL)
+ XFree (dpyinfo->net_supported_atoms);
+ dpyinfo->net_supported_atoms = NULL;
+ dpyinfo->nr_net_supported_atoms = 0;
+ dpyinfo->net_supported_window = 0;
+
+ target_type = XA_ATOM;
+ prop_atom = XInternAtom (dpy, "_NET_SUPPORTED", False);
+ tmp_data = NULL;
+ rc = XGetWindowProperty (dpy, target_window,
+ prop_atom, 0, max_len, False, target_type,
+ &actual_type, &actual_format, &actual_size,
+ &bytes_remaining, &tmp_data);
+
+ if (rc != Success || actual_type != XA_ATOM || x_had_errors_p (dpy))
+ {
+ if (tmp_data) XFree (tmp_data);
+ x_uncatch_errors ();
+ UNBLOCK_INPUT;
+ return 0;
+ }
+
+ dpyinfo->net_supported_atoms = (Atom *)tmp_data;
+ dpyinfo->nr_net_supported_atoms = actual_size;
+ dpyinfo->net_supported_window = wmcheck_window;
+ }
+
+ rc = 0;
+ want_atom = XInternAtom (dpy, atomname, False);
+
+ for (i = 0; rc == 0 && i < dpyinfo->nr_net_supported_atoms; ++i)
+ rc = dpyinfo->net_supported_atoms[i] == want_atom;
+
+ x_uncatch_errors ();
UNBLOCK_INPUT;
+
+ return rc;
}
+/* Do fullscreen as specified in extended window manager hints */
+
+static int
+do_ewmh_fullscreen (f)
+ struct frame *f;
+{
+ int have_net_atom = wm_supports (f, "_NET_WM_STATE");
+
+ /* Some window managers don't say they support _NET_WM_STATE, but they do say
+ they support _NET_WM_STATE_FULLSCREEN. Try that also. */
+ if (!have_net_atom)
+ have_net_atom = wm_supports (f, "_NET_WM_STATE_FULLSCREEN");
+
+ if (have_net_atom)
+ {
+ Lisp_Object frame;
+ const char *atom = "_NET_WM_STATE";
+ const char *fs = "_NET_WM_STATE_FULLSCREEN";
+ const char *fw = "_NET_WM_STATE_MAXIMIZED_HORZ";
+ const char *fh = "_NET_WM_STATE_MAXIMIZED_VERT";
+ const char *what = NULL;
+
+ XSETFRAME (frame, f);
+
+ /* If there are _NET_ atoms we assume we have extended window manager
+ hints. */
+ switch (f->want_fullscreen)
+ {
+ case FULLSCREEN_BOTH:
+ what = fs;
+ break;
+ case FULLSCREEN_WIDTH:
+ what = fw;
+ break;
+ case FULLSCREEN_HEIGHT:
+ what = fh;
+ break;
+ }
+
+ if (what != NULL && !wm_supports (f, what)) return 0;
+
+
+ Fx_send_client_event (frame, make_number (0), frame,
+ make_unibyte_string (atom, strlen (atom)),
+ make_number (32),
+ Fcons (make_number (0), /* Remove */
+ Fcons
+ (make_unibyte_string (fs,
+ strlen (fs)),
+ Qnil)));
+ Fx_send_client_event (frame, make_number (0), frame,
+ make_unibyte_string (atom, strlen (atom)),
+ make_number (32),
+ Fcons (make_number (0), /* Remove */
+ Fcons
+ (make_unibyte_string (fh,
+ strlen (fh)),
+ Qnil)));
+ Fx_send_client_event (frame, make_number (0), frame,
+ make_unibyte_string (atom, strlen (atom)),
+ make_number (32),
+ Fcons (make_number (0), /* Remove */
+ Fcons
+ (make_unibyte_string (fw,
+ strlen (fw)),
+ Qnil)));
+ f->want_fullscreen = FULLSCREEN_NONE;
+ if (what != NULL)
+ Fx_send_client_event (frame, make_number (0), frame,
+ make_unibyte_string (atom, strlen (atom)),
+ make_number (32),
+ Fcons (make_number (1), /* Add */
+ Fcons
+ (make_unibyte_string (what,
+ strlen (what)),
+ Qnil)));
+ }
+
+ return have_net_atom;
+}
+
+static void
+XTfullscreen_hook (f)
+ FRAME_PTR f;
+{
+ if (f->async_visible)
+ {
+ BLOCK_INPUT;
+ do_ewmh_fullscreen (f);
+ x_sync (f);
+ UNBLOCK_INPUT;
+ }
+}
+
+
/* Check if we need to resize the frame due to a fullscreen request.
If so needed, resize the frame. */
static void
{
int width, height, ign;
+ if (do_ewmh_fullscreen (f))
+ return;
+
x_real_positions (f, &f->left_pos, &f->top_pos);
x_fullscreen_adjust (f, &width, &height, &ign, &ign);
}
}
-/* If frame parameters are set after the frame is mapped, we need to move
- the window.
- Some window managers moves the window to the right position, some
- moves the outer window manager window to the specified position.
- Here we check that we are in the right spot. If not, make a second
- move, assuming we are dealing with the second kind of window manager. */
+/* This function is called by x_set_offset to determine whether the window
+ manager interfered with the positioning of the frame. Type A window
+ managers position the surrounding window manager decorations a small
+ amount above and left of the user-supplied position. Type B window
+ managers position the surrounding window manager decorations at the
+ user-specified position. If we detect a Type A window manager, we
+ compensate by moving the window right and down by the proper amount. */
+
static void
-x_check_expected_move (f)
+x_check_expected_move (f, expected_left, expected_top)
struct frame *f;
+ int expected_left;
+ int expected_top;
{
- if (FRAME_X_OUTPUT (f)->check_expected_move)
- {
- int expect_top = FRAME_X_OUTPUT (f)->expected_top;
- int expect_left = FRAME_X_OUTPUT (f)->expected_left;
+ int current_left = 0, current_top = 0;
+
+ /* x_real_positions returns the left and top offsets of the outermost
+ window manager window around the frame. */
+
+ x_real_positions (f, ¤t_left, ¤t_top);
- if (expect_top != f->top_pos || expect_left != f->left_pos)
+ if (current_left != expected_left || current_top != expected_top)
{
+ /* It's a "Type A" window manager. */
+
+ int adjusted_left;
+ int adjusted_top;
+
FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_A;
- FRAME_X_OUTPUT (f)->move_offset_left = expect_left - f->left_pos;
- FRAME_X_OUTPUT (f)->move_offset_top = expect_top - f->top_pos;
+ FRAME_X_OUTPUT (f)->move_offset_left = expected_left - current_left;
+ FRAME_X_OUTPUT (f)->move_offset_top = expected_top - current_top;
+
+ /* Now fix the mispositioned frame's location. */
+
+ adjusted_left = expected_left + FRAME_X_OUTPUT (f)->move_offset_left;
+ adjusted_top = expected_top + FRAME_X_OUTPUT (f)->move_offset_top;
- f->left_pos = expect_left;
- f->top_pos = expect_top;
- x_set_offset (f, expect_left, expect_top, 0);
+ XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+ adjusted_left, adjusted_top);
+
+ x_sync_with_move (f, expected_left, expected_top, 0);
}
- else if (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN)
+ else
+ /* It's a "Type B" window manager. We don't have to adjust the
+ frame's position. */
+
FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_B;
+}
+
+
+/* Wait for XGetGeometry to return up-to-date position information for a
+ recently-moved frame. Call this immediately after calling XMoveWindow.
+ If FUZZY is non-zero, then LEFT and TOP are just estimates of where the
+ frame has been moved to, so we use a fuzzy position comparison instead
+ of an exact comparison. */
+
+static void
+x_sync_with_move (f, left, top, fuzzy)
+ struct frame *f;
+ int left, top, fuzzy;
+{
+ int count = 0;
- /* Just do this once */
- FRAME_X_OUTPUT (f)->check_expected_move = 0;
+ while (count++ < 50)
+ {
+ int current_left = 0, current_top = 0;
+
+ /* In theory, this call to XSync only needs to happen once, but in
+ practice, it doesn't seem to work, hence the need for the surrounding
+ loop. */
+
+ XSync (FRAME_X_DISPLAY (f), False);
+ x_real_positions (f, ¤t_left, ¤t_top);
+
+ if (fuzzy)
+ {
+ /* The left fuzz-factor is 10 pixels. The top fuzz-factor is 40
+ pixels. */
+
+ if (abs (current_left - left) <= 10 && abs (current_top - top) <= 40)
+ return;
}
+ else if (current_left == left && current_top == top)
+ return;
+ }
+
+ /* As a last resort, just wait 0.5 seconds and hope that XGetGeometry
+ will then return up-to-date position info. */
+
+ wait_reading_process_output (0, 500000, 0, 0, Qnil, NULL, 0);
}
x_raise_frame (f)
struct frame *f;
{
+ BLOCK_INPUT;
if (f->async_visible)
- {
- BLOCK_INPUT;
- XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
- XFlush (FRAME_X_DISPLAY (f));
- UNBLOCK_INPUT;
- }
+ XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
+
+ XFlush (FRAME_X_DISPLAY (f));
+ UNBLOCK_INPUT;
}
/* Lower frame F. */
int raise_flag;
{
if (raise_flag)
- x_raise_frame (f);
+ {
+ /* The following code is needed for `raise-frame' to work on
+ some versions of metacity; see Window Manager
+ Specification/Extended Window Manager Hints at
+ http://freedesktop.org/wiki/Standards_2fwm_2dspec */
+
+#if 0
+ /* However, on other versions (metacity 2.17.2-1.fc7), it
+ reportedly causes hangs when resizing frames. */
+
+ const char *atom = "_NET_ACTIVE_WINDOW";
+ if (f->async_visible && wm_supports (f, atom))
+ {
+ Lisp_Object frame;
+ XSETFRAME (frame, f);
+ Fx_send_client_event (frame, make_number (0), frame,
+ make_unibyte_string (atom, strlen (atom)),
+ make_number (32),
+ Fcons (make_number (1),
+ Fcons (make_number (last_user_time),
+ Qnil)));
+ }
+ else
+#endif
+ x_raise_frame (f);
+ }
else
x_lower_frame (f);
}
= f ? FRAME_X_DISPLAY_INFO (f) : x_display_list;
Display *dpy = dpyinfo->display;
int try_XLoadQueryFont = 0;
- int count;
int allow_auto_scaled_font = 0;
if (size < 0)
/* At first, put PATTERN in the cache. */
BLOCK_INPUT;
- count = x_catch_errors (dpy);
+ x_catch_errors (dpy);
if (try_XLoadQueryFont)
{
}
}
- x_uncatch_errors (dpy, count);
+ x_uncatch_errors ();
UNBLOCK_INPUT;
if (names)
XFontStruct *thisinfo;
BLOCK_INPUT;
- count = x_catch_errors (dpy);
+ x_catch_errors (dpy);
thisinfo = XLoadQueryFont (dpy,
SDATA (XCAR (tem)));
if (x_had_errors_p (dpy))
thisinfo = NULL;
x_clear_errors (dpy);
}
- x_uncatch_errors (dpy, count);
+ x_uncatch_errors ();
UNBLOCK_INPUT;
if (thisinfo)
{
struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
Lisp_Object font_names;
- int count;
/* Get a list of all the fonts that match this name. Once we
have a list of matching fonts, we compare them against the fonts
fontname = (char *) SDATA (XCAR (font_names));
BLOCK_INPUT;
- count = x_catch_errors (FRAME_X_DISPLAY (f));
+ x_catch_errors (FRAME_X_DISPLAY (f));
font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
if (x_had_errors_p (FRAME_X_DISPLAY (f)))
{
font = NULL;
x_clear_errors (FRAME_X_DISPLAY (f));
}
- x_uncatch_errors (FRAME_X_DISPLAY (f), count);
+ x_uncatch_errors ();
UNBLOCK_INPUT;
if (!font)
return NULL;
for (i = 0; i < dpyinfo->n_fonts; i++)
if (dpyinfo->font_table[i].name
- && (!strcmp (dpyinfo->font_table[i].name, fontname)
- || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
+ && (!xstricmp (dpyinfo->font_table[i].name, fontname)
+ || !xstricmp (dpyinfo->font_table[i].full_name, fontname)))
return (dpyinfo->font_table + i);
return NULL;
}
{"-mc", "*pointerColor", XrmoptionSepArg, (XtPointer) NULL},
{"-cr", "*cursorColor", XrmoptionSepArg, (XtPointer) NULL}
};
+
+/* Whether atimer for Xt timeouts is activated or not. */
+
+static int x_timeout_atimer_activated_flag;
+
#endif /* USE_X_TOOLKIT */
static int x_initialized;
+#ifdef HAVE_X_SM
+static int x_session_initialized;
+#endif
+
#ifdef MULTI_KBOARD
/* Test whether two display-name strings agree up to the dot that separates
the screen number from the server number. */
*bits = nr;
}
+int
+x_display_ok (display)
+ const char * display;
+{
+ int dpy_ok = 1;
+ Display *dpy;
+
+ dpy = XOpenDisplay (display);
+ if (dpy)
+ XCloseDisplay (dpy);
+ else
+ dpy_ok = 0;
+ return dpy_ok;
+}
+
struct x_display_info *
x_term_init (display_name, xrm_option, resource_name)
Lisp_Object display_name;
/* Load our own gtkrc if it exists. */
{
- struct gcpro gcpro1, gcpro2;
char *file = "~/.emacs.d/gtkrc";
Lisp_Object s, abs_file;
- GCPRO2 (s, abs_file);
s = make_string (file, strlen (file));
abs_file = Fexpand_file_name (s, Qnil);
if (! NILP (abs_file) && !NILP (Ffile_readable_p (abs_file)))
gtk_rc_parse (SDATA (abs_file));
-
- UNGCPRO;
}
XSetErrorHandler (x_error_handler);
dpyinfo->cut_buffers_initialized = 0;
+ dpyinfo->x_dnd_atoms_size = 8;
+ dpyinfo->x_dnd_atoms_length = 0;
+ dpyinfo->x_dnd_atoms = xmalloc (sizeof (*dpyinfo->x_dnd_atoms)
+ * dpyinfo->x_dnd_atoms_size);
+
+ dpyinfo->net_supported_atoms = NULL;
+ dpyinfo->nr_net_supported_atoms = 0;
+ dpyinfo->net_supported_window = 0;
+
connection = ConnectionNumber (dpyinfo->display);
dpyinfo->connection = connection;
Display *dpy = dpyinfo->display;
XrmValue d, fr, to;
Font font;
- int count;
d.addr = (XPointer)&dpy;
d.size = sizeof (Display *);
fr.size = sizeof (XtDefaultFont);
to.size = sizeof (Font *);
to.addr = (XPointer)&font;
- count = x_catch_errors (dpy);
+ x_catch_errors (dpy);
if (!XtCallConverter (dpy, XtCvtStringToFont, &d, 1, &fr, &to, NULL))
abort ();
if (x_had_errors_p (dpy) || !XQueryFont (dpy, font))
XrmPutLineResource (&xrdb, "Emacs.dialog.*.font: 9x15");
- x_uncatch_errors (dpy, count);
+ x_uncatch_errors ();
}
#endif
#endif
#ifdef HAVE_X_SM
/* Only do this for the first display. */
- if (x_initialized == 1)
+ if (!x_session_initialized++)
x_session_initialize (dpyinfo);
#endif
xfree (dpyinfo->font_table[i].name);
}
- if (dpyinfo->font_table->font_encoder)
- xfree (dpyinfo->font_table->font_encoder);
-
- xfree (dpyinfo->font_table);
- xfree (dpyinfo->x_id_name);
- xfree (dpyinfo->color_cells);
+ if (dpyinfo->font_table)
+ {
+ if (dpyinfo->font_table->font_encoder)
+ xfree (dpyinfo->font_table->font_encoder);
+ xfree (dpyinfo->font_table);
+ }
+ if (dpyinfo->x_id_name)
+ xfree (dpyinfo->x_id_name);
+ if (dpyinfo->color_cells)
+ xfree (dpyinfo->color_cells);
xfree (dpyinfo);
}
x_process_timeouts (timer)
struct atimer *timer;
{
+ BLOCK_INPUT;
+ x_timeout_atimer_activated_flag = 0;
if (toolkit_scroll_bar_interaction || popup_activated ())
{
- BLOCK_INPUT;
while (XtAppPending (Xt_app_con) & XtIMTimer)
XtAppProcessEvent (Xt_app_con, XtIMTimer);
- UNBLOCK_INPUT;
+ /* Reactivate the atimer for next time. */
+ x_activate_timeout_atimer ();
}
+ UNBLOCK_INPUT;
+}
+
+/* Install an asynchronous timer that processes Xt timeout events
+ every 0.1s as long as either `toolkit_scroll_bar_interaction' or
+ `popup_activated_flag' (in xmenu.c) is set. Make sure to call this
+ function whenever these variables are set. This is necessary
+ because some widget sets use timeouts internally, for example the
+ LessTif menu bar, or the Xaw3d scroll bar. When Xt timeouts aren't
+ processed, these widgets don't behave normally. */
+
+void
+x_activate_timeout_atimer ()
+{
+ BLOCK_INPUT;
+ if (!x_timeout_atimer_activated_flag)
+ {
+ EMACS_TIME interval;
+
+ EMACS_SET_SECS_USECS (interval, 0, 100000);
+ start_atimer (ATIMER_RELATIVE, interval, x_process_timeouts, 0);
+ x_timeout_atimer_activated_flag = 1;
+ }
+ UNBLOCK_INPUT;
}
#endif /* USE_X_TOOLKIT */
condemn_scroll_bars_hook = XTcondemn_scroll_bars;
redeem_scroll_bar_hook = XTredeem_scroll_bar;
judge_scroll_bars_hook = XTjudge_scroll_bars;
+ fullscreen_hook = XTfullscreen_hook;
scroll_region_ok = 1; /* we'll scroll partial frames */
char_ins_del_ok = 1;
last_tool_bar_item = -1;
any_help_event_p = 0;
ignore_next_mouse_click_timeout = 0;
+#ifdef HAVE_X_SM
+ x_session_initialized = 0;
+#endif
#ifdef USE_GTK
current_count = -1;
XtCacheByDisplay, cvt_pixel_dtor);
XtAppSetFallbackResources (Xt_app_con, Xt_default_resources);
-
- /* Install an asynchronous timer that processes Xt timeout events
- every 0.1s. This is necessary because some widget sets use
- timeouts internally, for example the LessTif menu bar, or the
- Xaw3d scroll bar. When Xt timouts aren't processed, these
- widgets don't behave normally. */
- {
- EMACS_TIME interval;
- EMACS_SET_SECS_USECS (interval, 0, 100000);
- start_atimer (ATIMER_CONTINUOUS, interval, x_process_timeouts, 0);
- }
#endif
#ifdef USE_TOOLKIT_SCROLL_BARS
DEFVAR_BOOL ("x-use-underline-position-properties",
&x_use_underline_position_properties,
doc: /* *Non-nil means make use of UNDERLINE_POSITION font properties.
-nil means ignore them. If you encounter fonts with bogus
+A value of nil means ignore them. If you encounter fonts with bogus
UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
to 4.1, set this to nil. */);
x_use_underline_position_properties = 1;
+ DEFVAR_BOOL ("x-underline-at-descent-line",
+ &x_underline_at_descent_line,
+ doc: /* *Non-nil means to draw the underline at the same place as the descent line.
+A value of nil means to draw the underline according to the value of the
+variable `x-use-underline-position-properties', which is usually at the
+baseline level. The default value is nil. */);
+ x_underline_at_descent_line = 0;
+
DEFVAR_BOOL ("x-mouse-click-focus-ignore-position",
&x_mouse_click_focus_ignore_position,
doc: /* Non-nil means that a mouse click to focus a frame does not move point.