X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/3d930b17852823b8c81c713ca7de77c15f95c4b1..14e1270cdebbb0a3dbb340ae32d69ff4180d5e21:/src/xterm.c diff --git a/src/xterm.c b/src/xterm.c index 25283480c0..512fff35f5 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -1,12 +1,12 @@ /* 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 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, @@ -182,6 +182,10 @@ static Lisp_Object last_window; 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. */ @@ -249,6 +253,7 @@ static unsigned long ignore_next_mouse_click_timeout; /* Where the mouse was last time we reported a mouse event. */ static XRectangle last_mouse_glyph; +static FRAME_PTR last_mouse_glyph_frame; static Lisp_Object last_mouse_press_frame; /* The scroll bar in which the last X motion event occurred. @@ -272,6 +277,10 @@ static Lisp_Object last_mouse_scroll_bar; 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. */ @@ -320,21 +329,8 @@ static int x_alloc_nearest_color_1 P_ ((Display *, Colormap, XColor *)); 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 *)); @@ -366,9 +362,13 @@ static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *, 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. */ @@ -2476,9 +2476,11 @@ x_draw_image_glyph_string (s) { /* 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 { @@ -2543,19 +2545,28 @@ x_draw_stretch_glyph_string (s) { /* 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)) { @@ -2586,8 +2597,20 @@ x_draw_stretch_glyph_string (s) } } 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; } @@ -2674,32 +2697,34 @@ x_draw_glyph_string (s) 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); } } @@ -2711,14 +2736,14 @@ x_draw_glyph_string (s) 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); } } @@ -3463,7 +3488,7 @@ x_find_modifier_meanings (dpyinfo) /* 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; @@ -3591,26 +3616,32 @@ note_mouse_movement (frame, event) 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; last_mouse_scroll_bar = Qnil; note_mouse_highlight (frame, -1, -1); + last_mouse_glyph_frame = 0; return 1; } - note_mouse_highlight (frame, event->x, event->y); /* Has the mouse moved off the glyph it was on at the last sighting? */ - if (event->x < last_mouse_glyph.x + if (frame != last_mouse_glyph_frame + || event->x < last_mouse_glyph.x || event->x >= last_mouse_glyph.x + last_mouse_glyph.width || event->y < last_mouse_glyph.y || event->y >= last_mouse_glyph.y + last_mouse_glyph.height) { frame->mouse_moved = 1; last_mouse_scroll_bar = Qnil; + note_mouse_highlight (frame, event->x, event->y); /* Remember which glyph we're now on. */ remember_mouse_glyph (frame, event->x, event->y, &last_mouse_glyph); + last_mouse_glyph_frame = frame; return 1; } @@ -3713,7 +3744,6 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time) Window win, child; int win_x, win_y; int parent_x = 0, parent_y = 0; - int count; win = root; @@ -3721,7 +3751,7 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time) 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)) @@ -3790,7 +3820,7 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time) 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) @@ -3821,6 +3851,7 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time) the frame are divided into. */ remember_mouse_glyph (f1, win_x, win_y, &last_mouse_glyph); + last_mouse_glyph_frame = f1; *bar_window = Qnil; *part = 0; @@ -4068,6 +4099,9 @@ x_send_scroll_bar_event (window, part, portion, whole) /* 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 @@ -5249,6 +5283,11 @@ x_scroll_bar_expose (bar, event) 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, @@ -5257,7 +5296,12 @@ x_scroll_bar_expose (bar, event) 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 */ @@ -5706,7 +5750,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) 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. */ @@ -5715,7 +5759,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) /* 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 */ @@ -5797,8 +5841,9 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) == 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 */ @@ -5814,6 +5859,8 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) 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; @@ -5832,16 +5879,15 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) #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; @@ -5850,6 +5896,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) 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; @@ -5866,6 +5913,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) 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; @@ -5886,6 +5934,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) 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. */ @@ -5909,6 +5958,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) /* 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; @@ -6067,6 +6117,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) case KeyPress: + last_user_time = event.xkey.time; ignore_next_mouse_click_timeout = 0; #if defined (USE_X_TOOLKIT) || defined (USE_GTK) @@ -6077,7 +6128,11 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) 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; @@ -6237,23 +6292,40 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) } /* Keysyms directly mapped to supported Unicode characters. */ - if ((keysym >= 0x01000100 && keysym <= 0x010033ff) + if ((keysym >= 0x01000000 && keysym <= 0x010033ff) || (keysym >= 0x0100e000 && keysym <= 0x0100ffff)) { - int code, charset_id, c1, c2; - - if (keysym < 0x01002500) - charset_id = charset_mule_unicode_0100_24ff, - code = (keysym & 0xFFFF) - 0x100; - else if (keysym < 0x0100e000) - charset_id = charset_mule_unicode_2500_33ff, - code = (keysym & 0xFFFF) - 0x2500; + int code = keysym & 0xFFFF, charset_id, c1, c2; + + if (code < 0x80) + { + inev.ie.kind = ASCII_KEYSTROKE_EVENT; + inev.ie.code = code; + } + else if (code < 0x100) + { + if (code < 0xA0) + charset_id = CHARSET_8_BIT_CONTROL; + else + charset_id = charset_latin_iso8859_1; + inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.ie.code = MAKE_CHAR (charset_id, code, 0); + } else - charset_id = charset_mule_unicode_e000_ffff, - code = (keysym & 0xFFFF) - 0xe000; - c1 = (code / 96) + 32, c2 = (code % 96) + 32; - inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; - inev.ie.code = MAKE_CHAR (charset_id, c1, c2); + { + if (code < 0x2500) + charset_id = charset_mule_unicode_0100_24ff, + code -= 0x100; + else if (code < 0xE000) + charset_id = charset_mule_unicode_2500_33ff, + code -= 0x2500; + else + charset_id = charset_mule_unicode_e000_ffff, + code -= 0xE000; + c1 = (code / 96) + 32, c2 = (code % 96) + 32; + inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT; + inev.ie.code = MAKE_CHAR (charset_id, c1, c2); + } goto done_keysym; } @@ -6436,6 +6508,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) #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 @@ -6446,6 +6519,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) #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); @@ -6473,6 +6547,12 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) 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: @@ -6480,6 +6560,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) 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); @@ -6500,6 +6581,11 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) 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: @@ -6508,6 +6594,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) case MotionNotify: { + last_user_time = event.xmotion.time; previous_help_echo_string = help_echo_string; help_echo_string = Qnil; @@ -6527,7 +6614,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) { /* Generate SELECT_WINDOW_EVENTs when needed. */ - if (mouse_autoselect_window) + if (!NILP (Vmouse_autoselect_window)) { Lisp_Object window; @@ -6537,7 +6624,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) /* 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)) @@ -6626,11 +6713,8 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) && 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); } @@ -6658,7 +6742,8 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) int tool_bar_p = 0; bzero (&compose_status, sizeof (compose_status)); - bzero (&last_mouse_glyph, sizeof (last_mouse_glyph)); + last_mouse_glyph_frame = 0; + last_user_time = event.xbutton.time; if (dpyinfo->grabbed && last_mouse_frame @@ -6678,15 +6763,16 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) 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; } } @@ -7128,8 +7214,7 @@ x_draw_hollow_cursor (w, row) 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 @@ -7144,7 +7229,7 @@ x_draw_hollow_cursor (w, row) /* 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); } @@ -7357,10 +7442,30 @@ x_bitmap_icon (f, file) /* Create the GNU bitmap and mask if necessary. */ if (FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id < 0) { - FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id - = x_create_bitmap_from_data (f, gnu_bits, - gnu_width, gnu_height); - x_create_bitmap_mask (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id); + int rc = -1; + +#if defined (HAVE_XPM) && defined (HAVE_X_WINDOWS) +#ifdef USE_GTK + if (xg_set_icon_from_xpm_data (f, gnu_xpm_bits)) + return 0; +#else + rc = x_create_bitmap_from_xpm_data (f, gnu_xpm_bits); + if (rc != -1) + FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id = rc; +#endif /* USE_GTK */ +#endif /* defined (HAVE_XPM) && defined (HAVE_X_WINDOWS) */ + + /* If all else fails, use the (black and white) xbm image. */ + if (rc == -1) + { + rc = x_create_bitmap_from_data (f, gnu_xbm_bits, + gnu_xbm_width, gnu_xbm_height); + if (rc == -1) + return 1; + + FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id = rc; + x_create_bitmap_mask (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id); + } } /* The first time we create the GNU bitmap and mask, @@ -7414,12 +7519,21 @@ x_text_icon (f, icon_name) #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. +*/ -static Lisp_Object x_error_message_string; +struct x_error_message_stack { + char string[X_ERROR_MESSAGE_SIZE]; + Display *dpy; + struct x_error_message_stack *prev; +}; +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 @@ -7428,7 +7542,7 @@ x_error_catcher (display, error) XErrorEvent *error; { XGetErrorText (display, error->error_code, - SDATA (x_error_message_string), + x_error_message->string, X_ERROR_MESSAGE_SIZE); } @@ -7438,7 +7552,7 @@ x_error_catcher (display, error) 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. @@ -7446,47 +7560,41 @@ x_error_catcher (display, error) 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 = xmalloc (sizeof (*data)); /* Make sure any errors from previous requests have been dealt with. */ XSync (dpy, False); - record_unwind_protect (x_catch_errors_unwind, - Fcons (make_save_value (dpy, 0), - x_error_message_string)); - - x_error_message_string = make_uninit_string (X_ERROR_MESSAGE_SIZE); - SSET (x_error_message_string, 0, 0); - - return count; + data->dpy = dpy; + data->string[0] = 0; + data->prev = x_error_message; + x_error_message = data; } -/* 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 (old_val) - Lisp_Object old_val; +void +x_uncatch_errors () { - Lisp_Object first = XCAR (old_val); - Display *dpy = XSAVE_VALUE (first)->pointer; + 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); - x_error_message_string = XCDR (old_val); - return Qnil; + tmp = x_error_message; + x_error_message = x_error_message->prev; + xfree (tmp); + UNBLOCK_INPUT; } /* If any X protocol errors have arrived since the last call to @@ -7501,8 +7609,13 @@ x_check_errors (dpy, format) /* Make sure to catch any errors incurred so far. */ XSync (dpy, False); - if (SREF (x_error_message_string, 0)) - error (format, SDATA (x_error_message_string)); + if (x_error_message->string[0]) + { + 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 @@ -7515,7 +7628,7 @@ x_had_errors_p (dpy) /* Make sure to catch any errors incurred so far. */ XSync (dpy, False); - return SREF (x_error_message_string, 0) != 0; + return x_error_message->string[0] != 0; } /* Forget about any errors we have had, since we did x_catch_errors on DPY. */ @@ -7524,20 +7637,24 @@ void x_clear_errors (dpy) Display *dpy; { - SSET (x_error_message_string, 0, 0); + 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 () { - unbind_to (count, Qnil); + while (x_error_message) + x_uncatch_errors (); +} + +/* Nonzero if x_catch_errors has been done and not yet canceled. */ + +int +x_catching_errors () +{ + return x_error_message != 0; } #if 0 @@ -7596,7 +7713,6 @@ x_connection_closed (dpy, error_message) { 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); @@ -7606,7 +7722,7 @@ x_connection_closed (dpy, 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 @@ -7674,7 +7790,7 @@ x_connection_closed (dpy, error_message) if (dpyinfo) x_delete_display (dpyinfo); - x_uncatch_errors (dpy, count); + x_uncatch_errors (); if (x_display_list == 0) { @@ -7696,7 +7812,7 @@ x_connection_closed (dpy, error_message) /* 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. */ @@ -7706,7 +7822,7 @@ x_error_handler (display, error) Display *display; XErrorEvent *error; { - if (! NILP (x_error_message_string)) + if (x_error_message) x_error_catcher (display, error); else x_error_quitter (display, error); @@ -7741,6 +7857,12 @@ x_error_quitter (display, error) { 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. */ @@ -8146,8 +8268,11 @@ x_set_offset (f, xoff, yoff, change_gravity) { 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); @@ -8165,7 +8290,7 @@ x_set_offset (f, xoff, yoff, change_gravity) 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 @@ -8177,17 +8302,222 @@ x_set_offset (f, xoff, yoff, change_gravity) 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)) + { + x_uncatch_errors (); + UNBLOCK_INPUT; + return 0; + } + + if (dpyinfo->net_supported_window != wmcheck_window) { - 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; + /* 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 @@ -8198,6 +8528,9 @@ x_check_fullscreen (f) { 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); @@ -8218,37 +8551,96 @@ x_check_fullscreen (f) } } -/* 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. */ - if (expect_top != f->top_pos || expect_left != f->left_pos) + x_real_positions (f, ¤t_left, ¤t_top); + + 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. */ - f->left_pos = expect_left; - f->top_pos = expect_top; - x_set_offset (f, expect_left, expect_top, 0); + adjusted_left = expected_left + FRAME_X_OUTPUT (f)->move_offset_left; + adjusted_top = expected_top + FRAME_X_OUTPUT (f)->move_offset_top; + + 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. */ - /* Just do this once */ - FRAME_X_OUTPUT (f)->check_expected_move = 0; +static void +x_sync_with_move (f, left, top, fuzzy) + struct frame *f; + int left, top, fuzzy; +{ + int count = 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); } @@ -8440,13 +8832,12 @@ void 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. */ @@ -8470,7 +8861,32 @@ XTframe_raise_lower (f, raise_flag) 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); } @@ -9280,7 +9696,6 @@ x_list_fonts (f, pattern, size, maxnames) = 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) @@ -9320,7 +9735,7 @@ x_list_fonts (f, pattern, size, maxnames) /* At first, put PATTERN in the cache. */ BLOCK_INPUT; - count = x_catch_errors (dpy); + x_catch_errors (dpy); if (try_XLoadQueryFont) { @@ -9401,7 +9816,7 @@ x_list_fonts (f, pattern, size, maxnames) } } - x_uncatch_errors (dpy, count); + x_uncatch_errors (); UNBLOCK_INPUT; if (names) @@ -9492,7 +9907,7 @@ x_list_fonts (f, pattern, size, maxnames) 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)) @@ -9502,7 +9917,7 @@ x_list_fonts (f, pattern, size, maxnames) thisinfo = NULL; x_clear_errors (dpy); } - x_uncatch_errors (dpy, count); + x_uncatch_errors (); UNBLOCK_INPUT; if (thisinfo) @@ -9658,7 +10073,6 @@ x_load_font (f, fontname, size) { 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 @@ -9697,7 +10111,7 @@ x_load_font (f, fontname, size) 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))) { @@ -9706,7 +10120,7 @@ x_load_font (f, fontname, size) 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; @@ -9908,8 +10322,8 @@ x_query_font (f, fontname) 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; } @@ -9972,10 +10386,19 @@ static XrmOptionDescRec emacs_options[] = { {"-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. */ @@ -10053,6 +10476,21 @@ get_bits_and_offset (mask, bits, offset) *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; @@ -10122,18 +10560,14 @@ x_term_init (display_name, xrm_option, resource_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); @@ -10421,6 +10855,15 @@ x_term_init (display_name, xrm_option, resource_name) 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; @@ -10479,7 +10922,6 @@ x_term_init (display_name, xrm_option, resource_name) Display *dpy = dpyinfo->display; XrmValue d, fr, to; Font font; - int count; d.addr = (XPointer)&dpy; d.size = sizeof (Display *); @@ -10487,12 +10929,12 @@ x_term_init (display_name, xrm_option, resource_name) 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 @@ -10532,7 +10974,7 @@ x_term_init (display_name, xrm_option, resource_name) #ifdef HAVE_X_SM /* Only do this for the first display. */ - if (x_initialized == 1) + if (!x_session_initialized++) x_session_initialize (dpyinfo); #endif @@ -10610,12 +11052,16 @@ x_delete_display (dpyinfo) 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); } @@ -10630,13 +11076,39 @@ static void 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 */ @@ -10704,6 +11176,7 @@ x_initialize () 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; @@ -10717,6 +11190,9 @@ x_initialize () 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; @@ -10739,17 +11215,6 @@ x_initialize () 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 @@ -10776,8 +11241,7 @@ x_initialize () void syms_of_xterm () { - staticpro (&x_error_message_string); - x_error_message_string = Qnil; + x_error_message = NULL; staticpro (&x_display_name_list); x_display_name_list = Qnil; @@ -10799,11 +11263,19 @@ syms_of_xterm () 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.