X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/c4f592c47f236d2493b86760d11fb38ffd3275d6..b12f6e85a068462962d1bf012260e2b55aabd4e7:/src/xterm.c diff --git a/src/xterm.c b/src/xterm.c index 2e8fca7915..0e56b04c1b 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -6,7 +6,7 @@ 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, @@ -54,7 +54,6 @@ Boston, MA 02110-1301, USA. */ #include #endif /* ! defined (BSD_SYSTEM) */ -#include "systty.h" #include "systime.h" #ifndef INCLUDED_FCNTL @@ -322,6 +321,10 @@ static Lisp_Object Qalt, Qhyper, Qmeta, Qsuper, Qmodifier_value; static Lisp_Object Qvendor_specific_keysyms; static Lisp_Object Qlatin_1; +/* Used in x_flush. */ + +extern Lisp_Object Vinhibit_redisplay; + extern XrmDatabase x_load_resources P_ ((Display *, char *, char *, char *)); extern int x_bitmap_mask P_ ((FRAME_PTR, int)); @@ -331,13 +334,15 @@ static const XColor *x_color_cells P_ ((Display *, int *)); static void x_update_window_end P_ ((struct window *, int, int)); static int x_io_error_quitter P_ ((Display *)); +static struct terminal *x_create_terminal P_ ((struct x_display_info *)); +void x_delete_terminal P_ ((struct terminal *)); 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 *)); static void XTframe_up_to_date P_ ((struct frame *)); -static void XTset_terminal_modes P_ ((void)); -static void XTreset_terminal_modes P_ ((void)); -static void x_clear_frame P_ ((void)); +static void XTset_terminal_modes P_ ((struct terminal *)); +static void XTreset_terminal_modes P_ ((struct terminal *)); +static void x_clear_frame P_ ((struct frame *)); static void frame_highlight P_ ((struct frame *)); static void frame_unhighlight P_ ((struct frame *)); static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *)); @@ -377,12 +382,18 @@ static void x_flush (f) struct frame *f; { + /* Don't call XFlush when it is not safe to redisplay; the X + connection may be broken. */ + if (!NILP (Vinhibit_redisplay)) + return; + BLOCK_INPUT; if (f == NULL) { Lisp_Object rest, frame; FOR_EACH_FRAME (rest, frame) - x_flush (XFRAME (frame)); + if (FRAME_X_P (XFRAME (frame))) + x_flush (XFRAME (frame)); } else if (FRAME_X_P (f)) XFlush (FRAME_X_DISPLAY (f)); @@ -720,8 +731,10 @@ x_draw_fringe_bitmap (w, row, p) else x_clip_to_row (w, row, -1, gc); - if (p->bx >= 0 && !p->overlay_p) + if (!p->overlay_p) { + int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny; + /* In case the same realized face is used for fringes and for something displayed in the text (e.g. face `region' on mono-displays, the fill style may have been changed to @@ -731,8 +744,55 @@ x_draw_fringe_bitmap (w, row, p) else XSetForeground (display, face->gc, face->background); - XFillRectangle (display, window, face->gc, - p->bx, p->by, p->nx, p->ny); +#ifdef USE_TOOLKIT_SCROLL_BARS + /* If the fringe is adjacent to the left (right) scroll bar of a + leftmost (rightmost, respectively) window, then extend its + background to the gap between the fringe and the bar. */ + if ((WINDOW_LEFTMOST_P (w) + && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)) + || (WINDOW_RIGHTMOST_P (w) + && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))) + { + int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w); + + if (sb_width > 0) + { + int left = WINDOW_SCROLL_BAR_AREA_X (w); + int width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w) + * FRAME_COLUMN_WIDTH (f)); + + if (bx < 0) + { + /* Bitmap fills the fringe. */ + if (left + width == p->x) + bx = left + sb_width; + else if (p->x + p->wd == left) + bx = left; + if (bx >= 0) + { + int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); + + nx = width - sb_width; + by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, + row->y)); + ny = row->visible_height; + } + } + else + { + if (left + width == bx) + { + bx = left + sb_width; + nx += width - sb_width; + } + else if (bx + nx == left) + nx += width - sb_width; + } + } + } +#endif + if (bx >= 0 && nx > 0) + XFillRectangle (display, window, face->gc, bx, by, nx, ny); if (!face->stipple) XSetForeground (display, face->gc, face->foreground); @@ -794,7 +854,7 @@ x_draw_fringe_bitmap (w, row, p) rarely happens). */ static void -XTset_terminal_modes () +XTset_terminal_modes (struct terminal *terminal) { } @@ -802,7 +862,7 @@ XTset_terminal_modes () the X-windows go away, and suspending requires no action. */ static void -XTreset_terminal_modes () +XTreset_terminal_modes (struct terminal *terminal) { } @@ -1415,7 +1475,8 @@ x_frame_of_widget (widget) for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail)) if (GC_FRAMEP (XCAR (tail)) && (f = XFRAME (XCAR (tail)), - (f->output_data.nothing != 1 + (FRAME_X_P (f) + && f->output_data.nothing != 1 && FRAME_X_DISPLAY_INFO (f) == dpyinfo)) && f->output_data.x->widget == widget) return f; @@ -2476,9 +2537,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 { @@ -2792,7 +2855,8 @@ x_shift_glyphs_for_insert (f, x, y, width, height, shift_by) for X frames. */ static void -x_delete_glyphs (n) +x_delete_glyphs (f, n) + struct frame *f; register int n; { abort (); @@ -2815,19 +2879,11 @@ x_clear_area (dpy, window, x, y, width, height, exposures) } -/* Clear entire frame. If updating_frame is non-null, clear that - frame. Otherwise clear the selected frame. */ +/* Clear an entire frame. */ static void -x_clear_frame () +x_clear_frame (struct frame *f) { - struct frame *f; - - if (updating_frame) - f = updating_frame; - else - f = SELECTED_FRAME (); - /* Clearing the frame will erase any cursor, so mark them all as no longer visible. */ mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f))); @@ -2906,8 +2962,8 @@ XTflash (f) XGCValues values; values.function = GXxor; - values.foreground = (f->output_data.x->foreground_pixel - ^ f->output_data.x->background_pixel); + values.foreground = (FRAME_FOREGROUND_PIXEL (f) + ^ FRAME_BACKGROUND_PIXEL (f)); gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), GCFunction | GCForeground, &values); @@ -3073,7 +3129,8 @@ XTset_terminal_window (n) lines or deleting -N lines at vertical position VPOS. */ static void -x_ins_del_lines (vpos, n) +x_ins_del_lines (f, vpos, n) + struct frame *f; int vpos, n; { abort (); @@ -3710,7 +3767,8 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time) /* Clear the mouse-moved flag for every frame on this display. */ FOR_EACH_FRAME (tail, frame) - if (FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp)) + if (FRAME_X_P (XFRAME (frame)) + && FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp)) XFRAME (frame)->mouse_moved = 0; last_mouse_scroll_bar = Qnil; @@ -3899,6 +3957,9 @@ x_window_to_scroll_bar (display, window_id) if (! GC_FRAMEP (frame)) abort (); + if (! FRAME_X_P (XFRAME (frame))) + continue; + /* Scan this frame's scroll bar list for a scroll bar with the right window ID. */ condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame)); @@ -3933,11 +3994,14 @@ x_window_to_menu_bar (window) XGCTYPE (tail) == Lisp_Cons; tail = XCDR (tail)) { - Lisp_Object frame = XCAR (tail); - Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget; + if (FRAME_X_P (XFRAME (XCAR (tail)))) + { + Lisp_Object frame = XCAR (tail); + Widget menu_bar = XFRAME (frame)->output_data.x->menubar_widget; - if (menu_bar && xlwmenu_window_p (menu_bar, window)) - return menu_bar; + if (menu_bar && xlwmenu_window_p (menu_bar, window)) + return menu_bar; + } } return NULL; @@ -4745,7 +4809,7 @@ x_scroll_bar_create (w, top, left, width, height) a.background_pixel = f->output_data.x->scroll_bar_background_pixel; if (a.background_pixel == -1) - a.background_pixel = f->output_data.x->background_pixel; + a.background_pixel = FRAME_BACKGROUND_PIXEL (f); a.event_mask = (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | PointerMotionHintMask @@ -4787,6 +4851,9 @@ x_scroll_bar_create (w, top, left, width, height) XSETINT (bar->start, 0); XSETINT (bar->end, 0); bar->dragging = Qnil; +#ifdef USE_TOOLKIT_SCROLL_BARS + bar->fringe_extended_p = Qnil; +#endif /* Add bar to its frame's list of scroll bars. */ bar->next = FRAME_SCROLL_BARS (f); @@ -4919,7 +4986,7 @@ x_scroll_bar_set_handle (bar, start, end, rebuild) /* 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); + FRAME_FOREGROUND_PIXEL (f)); /* Draw the empty space below the handle. Note that we can't clear zero-height areas; that means "clear to end of window." */ @@ -4979,6 +5046,9 @@ XTset_vertical_scroll_bar (w, portion, whole, position) struct scroll_bar *bar; int top, height, left, sb_left, width, sb_width; int window_y, window_height; +#ifdef USE_TOOLKIT_SCROLL_BARS + int fringe_extended_p; +#endif /* Get window dimensions. */ window_box (w, -1, 0, &window_y, 0, &window_height); @@ -4999,15 +5069,9 @@ XTset_vertical_scroll_bar (w, portion, whole, position) /* Compute the left edge of the scroll bar. */ #ifdef USE_TOOLKIT_SCROLL_BARS if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)) - sb_left = (left + - (WINDOW_RIGHTMOST_P (w) - ? width - sb_width - (width - sb_width) / 2 - : 0)); + sb_left = left + (WINDOW_RIGHTMOST_P (w) ? width - sb_width : 0); else - sb_left = (left + - (WINDOW_LEFTMOST_P (w) - ? (width - sb_width) / 2 - : width - sb_width)); + sb_left = left + (WINDOW_LEFTMOST_P (w) ? 0 : width - sb_width); #else if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)) sb_left = left + width - sb_width; @@ -5015,14 +5079,33 @@ XTset_vertical_scroll_bar (w, portion, whole, position) sb_left = left; #endif +#ifdef USE_TOOLKIT_SCROLL_BARS + if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)) + fringe_extended_p = (WINDOW_LEFTMOST_P (w) + && WINDOW_LEFT_FRINGE_WIDTH (w) + && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) + || WINDOW_LEFT_MARGIN_COLS (w) == 0)); + else + fringe_extended_p = (WINDOW_RIGHTMOST_P (w) + && WINDOW_RIGHT_FRINGE_WIDTH (w) + && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) + || WINDOW_RIGHT_MARGIN_COLS (w) == 0)); +#endif + /* Does the scroll bar exist yet? */ if (NILP (w->vertical_scroll_bar)) { if (width > 0 && height > 0) { BLOCK_INPUT; - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - left, top, width, height, False); +#ifdef USE_TOOLKIT_SCROLL_BARS + if (fringe_extended_p) + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + sb_left, top, sb_width, height, False); + else +#endif + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + left, top, width, height, False); UNBLOCK_INPUT; } @@ -5049,13 +5132,19 @@ XTset_vertical_scroll_bar (w, portion, whole, position) #ifdef USE_TOOLKIT_SCROLL_BARS /* Move/size the scroll bar widget. */ - if (mask) + if (mask || !NILP (bar->fringe_extended_p) != fringe_extended_p) { /* Since toolkit scroll bars are smaller than the space reserved for them on the frame, we have to clear "under" them. */ if (width > 0 && height > 0) - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - left, top, width, height, False); + { + if (fringe_extended_p) + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + sb_left, top, sb_width, height, False); + else + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + left, top, width, height, False); + } #ifdef USE_GTK xg_update_scrollbar_pos (f, SCROLL_BAR_X_WINDOW (bar), @@ -5130,6 +5219,8 @@ XTset_vertical_scroll_bar (w, portion, whole, position) } #ifdef USE_TOOLKIT_SCROLL_BARS + bar->fringe_extended_p = fringe_extended_p ? Qt : Qnil; + x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole); #else /* not USE_TOOLKIT_SCROLL_BARS */ /* Set the scroll bar's current state, unless we're currently being @@ -5297,7 +5388,7 @@ x_scroll_bar_expose (bar, event) /* 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); + FRAME_FOREGROUND_PIXEL (f)); UNBLOCK_INPUT; @@ -5697,7 +5788,7 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) int count = 0; int do_help = 0; int nbytes = 0; - struct frame *f; + struct frame *f = NULL; struct coding_system coding; XEvent event = *eventp; @@ -6273,19 +6364,19 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) bzero (&compose_status, sizeof (compose_status)); orig_keysym = keysym; - /* Common for all keysym input events. */ - XSETFRAME (inev.ie.frame_or_window, f); - inev.ie.modifiers - = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), modifiers); - inev.ie.timestamp = event.xkey.time; - - /* First deal with keysyms which have defined - translations to characters. */ - if (keysym >= 32 && keysym < 128) - /* Avoid explicitly decoding each ASCII character. */ - { - inev.ie.kind = ASCII_KEYSTROKE_EVENT; - inev.ie.code = keysym; + /* Common for all keysym input events. */ + XSETFRAME (inev.ie.frame_or_window, f); + inev.ie.modifiers + = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), modifiers); + inev.ie.timestamp = event.xkey.time; + + /* First deal with keysyms which have defined + translations to characters. */ + if (keysym >= 32 && keysym < 128) + /* Avoid explicitly decoding each ASCII character. */ + { + inev.ie.kind = ASCII_KEYSTROKE_EVENT; + inev.ie.code = keysym; goto done_keysym; } @@ -6330,18 +6421,18 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) /* Now non-ASCII. */ if (HASH_TABLE_P (Vx_keysym_table) && (NATNUMP (c = Fgethash (make_number (keysym), - Vx_keysym_table, - Qnil)))) - { - inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c)) - ? ASCII_KEYSTROKE_EVENT - : MULTIBYTE_CHAR_KEYSTROKE_EVENT); - inev.ie.code = XFASTINT (c); - goto done_keysym; - } - - /* Random non-modifier sorts of keysyms. */ - if (((keysym >= XK_BackSpace && keysym <= XK_Escape) + Vx_keysym_table, + Qnil)))) + { + inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c)) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.ie.code = XFASTINT (c); + goto done_keysym; + } + + /* Random non-modifier sorts of keysyms. */ + if (((keysym >= XK_BackSpace && keysym <= XK_Escape) || keysym == XK_Delete #ifdef XK_ISO_Left_Tab || (keysym >= XK_ISO_Left_Tab @@ -6622,7 +6713,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)) @@ -6775,27 +6866,23 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) } if (!tool_bar_p) - if (!dpyinfo->x_focus_frame - || f == dpyinfo->x_focus_frame) - { #if defined (USE_X_TOOLKIT) || defined (USE_GTK) - if (! popup_activated ()) + if (! popup_activated ()) #endif - { - if (ignore_next_mouse_click_timeout) - { - if (event.type == ButtonPress - && (int)(event.xbutton.time - ignore_next_mouse_click_timeout) > 0) - { - ignore_next_mouse_click_timeout = 0; - construct_mouse_click (&inev.ie, &event.xbutton, f); - } - if (event.type == ButtonRelease) - ignore_next_mouse_click_timeout = 0; - } - else - construct_mouse_click (&inev.ie, &event.xbutton, f); - } + { + if (ignore_next_mouse_click_timeout) + { + if (event.type == ButtonPress + && (int)(event.xbutton.time - ignore_next_mouse_click_timeout) > 0) + { + ignore_next_mouse_click_timeout = 0; + construct_mouse_click (&inev.ie, &event.xbutton, f); + } + if (event.type == ButtonRelease) + ignore_next_mouse_click_timeout = 0; + } + else + construct_mouse_click (&inev.ie, &event.xbutton, f); } } else @@ -6989,8 +7076,8 @@ x_dispatch_event (event, display) EXPECTED is nonzero if the caller knows input is available. */ static int -XTread_socket (sd, expected, hold_quit) - register int sd; +XTread_socket (terminal, expected, hold_quit) + struct terminal *terminal; int expected; struct input_event *hold_quit; { @@ -7013,6 +7100,31 @@ XTread_socket (sd, expected, hold_quit) ++handling_signal; +#ifdef HAVE_X_SM + /* Only check session manager input for the primary display. */ + if (terminal->id == 1 && x_session_have_connection ()) + { + struct input_event inev; + BLOCK_INPUT; + /* We don't need to EVENT_INIT (inev) here, as + x_session_check_input copies an entire input_event. */ + if (x_session_check_input (&inev)) + { + kbd_buffer_store_event_hold (&inev, hold_quit); + count++; + } + UNBLOCK_INPUT; + } +#endif + + /* For debugging, this gives a way to fake an I/O error. */ + if (terminal->display_info.x == XTread_socket_fake_io_error) + { + XTread_socket_fake_io_error = 0; + x_io_error_quitter (dpyinfo->display); + } + +#if 0 /* This loop is a noop now. */ /* Find the display we are supposed to read input for. It's the one communicating on descriptor SD. */ for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) @@ -7043,52 +7155,31 @@ XTread_socket (sd, expected, hold_quit) #endif /* HAVE_SELECT */ #endif /* SIGIO */ #endif - - /* For debugging, this gives a way to fake an I/O error. */ - if (dpyinfo == XTread_socket_fake_io_error) - { - XTread_socket_fake_io_error = 0; - x_io_error_quitter (dpyinfo->display); - } - -#ifdef HAVE_X_SM - { - struct input_event inev; - BLOCK_INPUT; - /* We don't need to EVENT_INIT (inev) here, as - x_session_check_input copies an entire input_event. */ - if (x_session_check_input (&inev)) - { - kbd_buffer_store_event_hold (&inev, hold_quit); - count++; - } - UNBLOCK_INPUT; - } + } #endif #ifndef USE_GTK - while (XPending (dpyinfo->display)) - { - int finish; + while (XPending (terminal->display_info.x->display)) + { + int finish; - XNextEvent (dpyinfo->display, &event); + XNextEvent (terminal->display_info.x->display, &event); #ifdef HAVE_X_I18N - /* Filter events for the current X input method. */ - if (x_filter_event (dpyinfo, &event)) - break; + /* Filter events for the current X input method. */ + if (x_filter_event (terminal->display_info.x, &event)) + break; #endif - event_found = 1; + event_found = 1; - count += handle_one_xevent (dpyinfo, &event, &finish, hold_quit); + count += handle_one_xevent (terminal->display_info.x, + &event, &finish, hold_quit); - if (finish == X_EVENT_GOTO_OUT) - goto out; - } -#endif /* not USE_GTK */ + if (finish == X_EVENT_GOTO_OUT) + goto out; } -#ifdef USE_GTK +#else /* USE_GTK */ /* For GTK we must use the GTK event loop. But XEvents gets passed to our filter function above, and then to the big event switch. @@ -7399,8 +7490,7 @@ x_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, activ } #ifndef XFlush - if (updating_frame != f) - XFlush (FRAME_X_DISPLAY (f)); + XFlush (FRAME_X_DISPLAY (f)); #endif } @@ -7638,6 +7728,8 @@ x_clear_errors (dpy) x_error_message->string[0] = 0; } +#if 0 /* See comment in unwind_to_catch why calling this is a bad + * idea. --lorentey */ /* Close off all unclosed x_catch_errors calls. */ void @@ -7646,6 +7738,7 @@ x_fully_uncatch_errors () while (x_error_message) x_uncatch_errors (); } +#endif /* Nonzero if x_catch_errors has been done and not yet canceled. */ @@ -7711,6 +7804,7 @@ x_connection_closed (dpy, error_message) { struct x_display_info *dpyinfo = x_display_info_for_display (dpy); Lisp_Object frame, tail; + int index = SPECPDL_INDEX (); error_msg = (char *) alloca (strlen (error_message) + 1); strcpy (error_msg, error_message); @@ -7722,6 +7816,44 @@ x_connection_closed (dpy, error_message) the original message here. */ x_catch_errors (dpy); + /* Inhibit redisplay while frames are being deleted. */ + specbind (Qinhibit_redisplay, Qt); + + if (dpyinfo) + { + /* Protect display from being closed when we delete the last + frame on it. */ + dpyinfo->reference_count++; + dpyinfo->terminal->reference_count++; + } + + /* First delete frames whose mini-buffers are on frames + that are on the dead display. */ + FOR_EACH_FRAME (tail, frame) + { + Lisp_Object minibuf_frame; + minibuf_frame + = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame)))); + if (FRAME_X_P (XFRAME (frame)) + && FRAME_X_P (XFRAME (minibuf_frame)) + && ! EQ (frame, minibuf_frame) + && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo) + Fdelete_frame (frame, Qt); + } + + /* Now delete all remaining frames on the dead display. + We are now sure none of these is used as the mini-buffer + for another frame that we need to delete. */ + FOR_EACH_FRAME (tail, frame) + if (FRAME_X_P (XFRAME (frame)) + && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo) + { + /* Set this to t so that Fdelete_frame won't get confused + trying to find a replacement. */ + FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt; + Fdelete_frame (frame, Qt); + } + /* 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 events from the display. As a consequence, a sequence of @@ -7754,43 +7886,23 @@ x_connection_closed (dpy, error_message) xg_display_close (dpyinfo->display); #endif - /* Indicate that this display is dead. */ if (dpyinfo) - dpyinfo->display = 0; - - /* First delete frames whose mini-buffers are on frames - that are on the dead display. */ - FOR_EACH_FRAME (tail, frame) { - Lisp_Object minibuf_frame; - minibuf_frame - = WINDOW_FRAME (XWINDOW (FRAME_MINIBUF_WINDOW (XFRAME (frame)))); - if (FRAME_X_P (XFRAME (frame)) - && FRAME_X_P (XFRAME (minibuf_frame)) - && ! EQ (frame, minibuf_frame) - && FRAME_X_DISPLAY_INFO (XFRAME (minibuf_frame)) == dpyinfo) - Fdelete_frame (frame, Qt); - } + /* Indicate that this display is dead. */ + dpyinfo->display = 0; - /* Now delete all remaining frames on the dead display. - We are now sure none of these is used as the mini-buffer - for another frame that we need to delete. */ - FOR_EACH_FRAME (tail, frame) - if (FRAME_X_P (XFRAME (frame)) - && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo) - { - /* Set this to t so that Fdelete_frame won't get confused - trying to find a replacement. */ - FRAME_KBOARD (XFRAME (frame))->Vdefault_minibuffer_frame = Qt; - Fdelete_frame (frame, Qt); - } + dpyinfo->reference_count--; + dpyinfo->terminal->reference_count--; + if (dpyinfo->reference_count != 0) + /* We have just closed all frames on this display. */ + abort (); - if (dpyinfo) - x_delete_display (dpyinfo); + x_delete_display (dpyinfo); + } x_uncatch_errors (); - if (x_display_list == 0) + if (terminal_list == 0) { fprintf (stderr, "%s\n", error_msg); shut_down_emacs (0, 0, Qnil); @@ -7804,6 +7916,7 @@ x_connection_closed (dpy, error_message) sigunblock (sigmask (SIGALRM)); TOTALLY_UNBLOCK_INPUT; + unbind_to (index, Qnil); clear_waiting_for_input (); error ("%s", error_msg); } @@ -8014,7 +8127,7 @@ xim_destroy_callback (xim, client_data, call_data) FOR_EACH_FRAME (tail, frame) { struct frame *f = XFRAME (frame); - if (FRAME_X_DISPLAY_INFO (f) == dpyinfo) + if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo) { FRAME_XIC (f) = NULL; xic_free_xfontset (f); @@ -8113,7 +8226,8 @@ xim_instantiate_callback (display, client_data, call_data) { struct frame *f = XFRAME (frame); - if (FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo) + if (FRAME_X_P (f) + && FRAME_X_DISPLAY_INFO (f) == xim_inst->dpyinfo) if (FRAME_XIC (f) == NULL) { create_frame_xic (f); @@ -9328,8 +9442,8 @@ x_free_frame_resources (f) XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); #endif /* !USE_X_TOOLKIT */ - unload_color (f, f->output_data.x->foreground_pixel); - unload_color (f, f->output_data.x->background_pixel); + unload_color (f, FRAME_FOREGROUND_PIXEL (f)); + unload_color (f, FRAME_BACKGROUND_PIXEL (f)); unload_color (f, f->output_data.x->cursor_pixel); unload_color (f, f->output_data.x->cursor_foreground_pixel); unload_color (f, f->output_data.x->border_pixel); @@ -10495,6 +10609,7 @@ x_term_init (display_name, xrm_option, resource_name) { int connection; Display *dpy; + struct terminal *terminal; struct x_display_info *dpyinfo; XrmDatabase xrdb; @@ -10514,14 +10629,21 @@ x_term_init (display_name, xrm_option, resource_name) char **argv2 = argv; GdkAtom atom; +#ifndef HAVE_GTK_MULTIDISPLAY + if (!EQ (Vinitial_window_system, intern ("x"))) + error ("Sorry, you cannot connect to X servers with the GTK toolkit"); +#endif + if (x_initialized++ > 1) { +#ifdef HAVE_GTK_MULTIDISPLAY /* Opening another display. If xg_display_open returns less than zero, we are probably on GTK 2.0, which can only handle one display. GTK 2.2 or later can handle more than one. */ if (xg_display_open (SDATA (display_name), &dpy) < 0) +#endif error ("Sorry, this version of GTK can only handle one display"); - } + } else { for (argc = 0; argc < NUM_ARGV; ++argc) @@ -10625,6 +10747,8 @@ x_term_init (display_name, xrm_option, resource_name) dpyinfo = (struct x_display_info *) xmalloc (sizeof (struct x_display_info)); bzero (dpyinfo, sizeof *dpyinfo); + terminal = x_create_terminal (dpyinfo); + #ifdef MULTI_KBOARD { struct x_display_info *share; @@ -10636,30 +10760,30 @@ x_term_init (display_name, xrm_option, resource_name) SDATA (display_name))) break; if (share) - dpyinfo->kboard = share->kboard; + terminal->kboard = share->terminal->kboard; else { - dpyinfo->kboard = (KBOARD *) xmalloc (sizeof (KBOARD)); - init_kboard (dpyinfo->kboard); + terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD)); + init_kboard (terminal->kboard); if (!EQ (XSYMBOL (Qvendor_specific_keysyms)->function, Qunbound)) { char *vendor = ServerVendor (dpy); UNBLOCK_INPUT; - dpyinfo->kboard->Vsystem_key_alist + terminal->kboard->Vsystem_key_alist = call1 (Qvendor_specific_keysyms, vendor ? build_string (vendor) : empty_unibyte_string); BLOCK_INPUT; } - dpyinfo->kboard->next_kboard = all_kboards; - all_kboards = dpyinfo->kboard; + 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. */ if (current_kboard == initial_kboard) - current_kboard = dpyinfo->kboard; + current_kboard = terminal->kboard; } - dpyinfo->kboard->reference_count++; + terminal->kboard->reference_count++; } #endif @@ -10674,6 +10798,11 @@ x_term_init (display_name, xrm_option, resource_name) dpyinfo->display = dpy; + /* Set the name of the terminal. */ + terminal->name = (char *) xmalloc (SBYTES (display_name) + 1); + strncpy (terminal->name, SDATA (display_name), SBYTES (display_name)); + terminal->name[SBYTES (display_name)] = 0; + #if 0 XSetAfterFunction (x_current_display, x_trace_wire); #endif /* ! 0 */ @@ -10969,8 +11098,10 @@ x_term_init (display_name, xrm_option, resource_name) } #ifdef HAVE_X_SM - /* Only do this for the first display. */ - if (!x_session_initialized++) + /* Only do this for the very first display in the Emacs session. + Ignore X session management when Emacs was first started on a + tty. */ + if (terminal->id == 1) x_session_initialize (dpyinfo); #endif @@ -10979,7 +11110,7 @@ x_term_init (display_name, xrm_option, resource_name) return dpyinfo; } -/* Get rid of display DPYINFO, assuming all frames are already gone, +/* Get rid of display DPYINFO, deleting all frames on it, and without sending any more commands to the X server. */ void @@ -10987,6 +11118,20 @@ 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 display. */ + for (t = terminal_list; t; t = t->next_terminal) + if (t->type == output_x_window && t->display_info.x == dpyinfo) + { + /* Close X session management when we close its display. */ + if (t->id == 1 && x_session_have_connection ()) + x_session_close(); + + delete_terminal (t); + break; + } delete_keyboard_wait_descriptor (dpyinfo->connection); @@ -11030,10 +11175,6 @@ x_delete_display (dpyinfo) XrmDestroyDatabase (dpyinfo->xrdb); #endif #endif -#ifdef MULTI_KBOARD - if (--dpyinfo->kboard->reference_count == 0) - delete_kboard (dpyinfo->kboard); -#endif #ifdef HAVE_X_I18N if (dpyinfo->xim) xim_close_dpy (dpyinfo); @@ -11115,71 +11256,129 @@ x_activate_timeout_atimer () extern frame_parm_handler x_frame_parm_handlers[]; static struct redisplay_interface x_redisplay_interface = -{ - x_frame_parm_handlers, - x_produce_glyphs, - x_write_glyphs, - x_insert_glyphs, - x_clear_end_of_line, - x_scroll_run, - x_after_update_window_line, - x_update_window_begin, - x_update_window_end, - x_cursor_to, - x_flush, + { + x_frame_parm_handlers, + x_produce_glyphs, + x_write_glyphs, + x_insert_glyphs, + x_clear_end_of_line, + x_scroll_run, + x_after_update_window_line, + x_update_window_begin, + x_update_window_end, + x_cursor_to, + x_flush, #ifdef XFlush - x_flush, + x_flush, #else - 0, /* flush_display_optional */ -#endif - x_clear_window_mouse_face, - x_get_glyph_overhangs, - x_fix_overlapping_area, - x_draw_fringe_bitmap, - 0, /* define_fringe_bitmap */ - 0, /* destroy_fringe_bitmap */ - x_per_char_metric, - x_encode_char, - x_compute_glyph_string_overhangs, - x_draw_glyph_string, - x_define_frame_cursor, - x_clear_frame_area, - x_draw_window_cursor, - x_draw_vertical_window_border, - x_shift_glyphs_for_insert -}; + 0, /* flush_display_optional */ +#endif + x_clear_window_mouse_face, + x_get_glyph_overhangs, + x_fix_overlapping_area, + x_draw_fringe_bitmap, + 0, /* define_fringe_bitmap */ + 0, /* destroy_fringe_bitmap */ + x_per_char_metric, + x_encode_char, + x_compute_glyph_string_overhangs, + x_draw_glyph_string, + x_define_frame_cursor, + x_clear_frame_area, + x_draw_window_cursor, + x_draw_vertical_window_border, + x_shift_glyphs_for_insert + }; + + +/* This function is called when the last frame on a display is deleted. */ +void +x_delete_terminal (struct terminal *terminal) +{ + struct x_display_info *dpyinfo = terminal->display_info.x; + int i; + + /* Protect against recursive calls. Fdelete_frame in + delete_terminal calls us back when it deletes our last frame. */ + if (terminal->deleted) + return; + + BLOCK_INPUT; + /* Free the fonts in the font table. */ + for (i = 0; i < dpyinfo->n_fonts; i++) + if (dpyinfo->font_table[i].name) + { + XFreeFont (dpyinfo->display, dpyinfo->font_table[i].font); + } + + x_destroy_all_bitmaps (dpyinfo); + XSetCloseDownMode (dpyinfo->display, DestroyAll); + +#ifdef USE_GTK + xg_display_close (dpyinfo->display); +#else +#ifdef USE_X_TOOLKIT + XtCloseDisplay (dpyinfo->display); +#else + XCloseDisplay (dpyinfo->display); +#endif +#endif /* ! USE_GTK */ + + x_delete_display (dpyinfo); + UNBLOCK_INPUT; +} + + +static struct terminal * +x_create_terminal (struct x_display_info *dpyinfo) +{ + struct terminal *terminal; + + terminal = create_terminal (); + + terminal->type = output_x_window; + terminal->display_info.x = dpyinfo; + dpyinfo->terminal = terminal; + + /* kboard is initialized in x_term_init. */ + + terminal->clear_frame_hook = x_clear_frame; + terminal->ins_del_lines_hook = x_ins_del_lines; + terminal->delete_glyphs_hook = x_delete_glyphs; + terminal->ring_bell_hook = XTring_bell; + terminal->reset_terminal_modes_hook = XTreset_terminal_modes; + terminal->set_terminal_modes_hook = XTset_terminal_modes; + terminal->update_begin_hook = x_update_begin; + terminal->update_end_hook = x_update_end; + terminal->set_terminal_window_hook = XTset_terminal_window; + terminal->read_socket_hook = XTread_socket; + terminal->frame_up_to_date_hook = XTframe_up_to_date; + terminal->mouse_position_hook = XTmouse_position; + terminal->frame_rehighlight_hook = XTframe_rehighlight; + terminal->frame_raise_lower_hook = XTframe_raise_lower; + terminal->fullscreen_hook = XTfullscreen_hook; + terminal->set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar; + terminal->condemn_scroll_bars_hook = XTcondemn_scroll_bars; + terminal->redeem_scroll_bar_hook = XTredeem_scroll_bar; + terminal->judge_scroll_bars_hook = XTjudge_scroll_bars; + + terminal->delete_frame_hook = x_destroy_window; + terminal->delete_terminal_hook = x_delete_terminal; + + terminal->rif = &x_redisplay_interface; + terminal->scroll_region_ok = 1; /* We'll scroll partial frames. */ + terminal->char_ins_del_ok = 1; + terminal->line_ins_del_ok = 1; /* We'll just blt 'em. */ + terminal->fast_clear_end_of_line = 1; /* X does this well. */ + terminal->memory_below_frame = 0; /* We don't remember what scrolls + off the bottom. */ + + return terminal; +} void x_initialize () { - rif = &x_redisplay_interface; - - clear_frame_hook = x_clear_frame; - ins_del_lines_hook = x_ins_del_lines; - delete_glyphs_hook = x_delete_glyphs; - ring_bell_hook = XTring_bell; - reset_terminal_modes_hook = XTreset_terminal_modes; - set_terminal_modes_hook = XTset_terminal_modes; - update_begin_hook = x_update_begin; - update_end_hook = x_update_end; - set_terminal_window_hook = XTset_terminal_window; - read_socket_hook = XTread_socket; - frame_up_to_date_hook = XTframe_up_to_date; - mouse_position_hook = XTmouse_position; - frame_rehighlight_hook = XTframe_rehighlight; - frame_raise_lower_hook = XTframe_raise_lower; - set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar; - 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; - line_ins_del_ok = 1; /* we'll just blt 'em */ - fast_clear_end_of_line = 1; /* X does this well */ - memory_below_frame = 0; /* we don't remember what scrolls - off the bottom */ baud_rate = 19200; x_noop_count = 0; @@ -11195,7 +11394,7 @@ x_initialize () #endif /* Try to use interrupt input; if we can't, then start polling. */ - Fset_input_mode (Qt, Qnil, Qt, Qnil); + Fset_input_interrupt_mode (Qt); #ifdef USE_X_TOOLKIT XtToolkitInitialize (); @@ -11226,9 +11425,11 @@ x_initialize () XSetIOErrorHandler (x_io_error_quitter); /* Disable Window Change signals; they are handled by X events. */ +#if 0 /* Don't. We may want to open tty frames later. */ #ifdef SIGWINCH signal (SIGWINCH, SIG_DFL); #endif /* SIGWINCH */ +#endif signal (SIGPIPE, x_connection_signal); }