diff options
Diffstat (limited to 'src/xterm.c')
-rw-r--r-- | src/xterm.c | 373 |
1 files changed, 252 insertions, 121 deletions
diff --git a/src/xterm.c b/src/xterm.c index 1e9161c7ab0..e9db4b364fb 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -998,6 +998,7 @@ static const struct x_atom_ref x_atom_refs[] = ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST", Xatom_net_wm_sync_request) ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST_COUNTER", Xatom_net_wm_sync_request_counter) ATOM_REFS_INIT ("_NET_WM_FRAME_DRAWN", Xatom_net_wm_frame_drawn) + ATOM_REFS_INIT ("_NET_WM_FRAME_TIMINGS", Xatom_net_wm_frame_timings) ATOM_REFS_INIT ("_NET_WM_USER_TIME", Xatom_net_wm_user_time) ATOM_REFS_INIT ("_NET_WM_USER_TIME_WINDOW", Xatom_net_wm_user_time_window) ATOM_REFS_INIT ("_NET_CLIENT_LIST_STACKING", Xatom_net_client_list_stacking) @@ -1390,6 +1391,12 @@ static int x_dnd_recursion_depth; initiating Motif drag-and-drop for the first time. */ static Lisp_Object x_dnd_selection_alias_cell; +/* The last known position of the tooltip window. */ +static int x_dnd_last_tooltip_x, x_dnd_last_tooltip_y; + +/* Whether or not those values are actually known yet. */ +static bool x_dnd_last_tooltip_valid; + /* Structure describing a single window that can be the target of drag-and-drop operations. */ struct x_client_list_window @@ -2931,7 +2938,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) Window *toplevels; int format, rc; unsigned long nitems, bytes_after; - unsigned long i; + unsigned long i, real_nitems; unsigned char *data = NULL; int frame_extents[4]; @@ -2995,6 +3002,16 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) toplevels = (Window *) data; + for (i = 0, real_nitems = 0; i < nitems; ++i) + { + /* Some window managers with built in compositors end up putting + tooltips in the client list, which is silly. */ + if (!x_tooltip_window_to_frame (dpyinfo, toplevels[i], NULL)) + toplevels[real_nitems++] = toplevels[i]; + } + + nitems = real_nitems; + #ifdef USE_XCB USE_SAFE_ALLOCA; @@ -5357,12 +5374,16 @@ xi_populate_device_from_info (struct xi_device_t *xi_device, #endif } -/* The code below handles the tracking of scroll valuators on XInput - 2, in order to support scroll wheels that report information more - granular than a screen line. +/* Populate our client-side record of all devices, which includes + basic information about the device and also touchscreen tracking + information and scroll valuators. - On X, when the XInput 2 extension is being utilized, the states of - the mouse wheels in each axis are stored as absolute values inside + Keeping track of scroll valuators is required in order to support + scroll wheels that report information in a fashion more detailed + than a single turn of a "step" in the wheel. + + When the input extension is being utilized, the states of the mouse + wheels on each axis are stored as absolute values inside "valuators" attached to each mouse device. To obtain the delta of the scroll wheel from a motion event (which is used to report that some valuator has changed), it is necessary to iterate over every @@ -5376,20 +5397,13 @@ xi_populate_device_from_info (struct xi_device_t *xi_device, This delta however is still intermediate, to make driver implementations easier. The XInput developers recommend (and most programs use) the following algorithm to convert from scroll unit - deltas to pixel deltas: + deltas to pixel deltas by which the display must actually be + scrolled: pixels_scrolled = pow (window_height, 2.0 / 3.0) * delta; */ -/* Setup valuator tracking for XI2 master devices on - DPYINFO->display. */ - -/* This function's name is a misnomer: these days, it keeps a - client-side record of all devices, which includes basic information - about the device and also touchscreen tracking information, instead - of just scroll valuators. */ - static void -x_init_master_valuators (struct x_display_info *dpyinfo) +x_cache_xi_devices (struct x_display_info *dpyinfo) { int ndevices, actual_devices; XIDeviceInfo *infos; @@ -6582,6 +6596,82 @@ x_set_frame_alpha (struct frame *f) Starting and ending an update ***********************************************************************/ +#if defined HAVE_XSYNC && !defined USE_GTK +/* Tell the compositing manager to postpone updates of F until a frame + has finished drawing. */ + +static void +x_sync_update_begin (struct frame *f) +{ + XSyncValue value, add; + Bool overflow; + + if (FRAME_X_EXTENDED_COUNTER (f) == None) + return; + + value = FRAME_X_COUNTER_VALUE (f); + + /* Since a frame is already in progress, there is no point in + continuing. */ + if (XSyncValueLow32 (value) % 2) + return; + + /* Since Emacs needs a non-urgent redraw, ensure that value % 4 == + 0. */ + if (XSyncValueLow32 (value) % 4 == 2) + XSyncIntToValue (&add, 3); + else + XSyncIntToValue (&add, 1); + + XSyncValueAdd (&FRAME_X_COUNTER_VALUE (f), + value, add, &overflow); + + if (XSyncValueLow32 (FRAME_X_COUNTER_VALUE (f)) % 4 != 1) + emacs_abort (); + + if (overflow) + XSyncIntToValue (&FRAME_X_COUNTER_VALUE (f), 1); + + XSyncSetCounter (FRAME_X_DISPLAY (f), + FRAME_X_EXTENDED_COUNTER (f), + FRAME_X_COUNTER_VALUE (f)); +} + +/* Tell the compositing manager that FRAME has been drawn and can be + updated. */ + +static void +x_sync_update_finish (struct frame *f) +{ + XSyncValue value, add; + Bool overflow; + + if (FRAME_X_EXTENDED_COUNTER (f) == None) + return; + + if (FRAME_X_OUTPUT (f)->ext_sync_end_pending_p) + return; + + value = FRAME_X_COUNTER_VALUE (f); + + if (!(XSyncValueLow32 (value) % 2)) + return; + + XSyncIntToValue (&add, 1); + XSyncValueAdd (&FRAME_X_COUNTER_VALUE (f), + value, add, &overflow); + + if (overflow) + XSyncIntToValue (&FRAME_X_COUNTER_VALUE (f), 0); + + XSyncSetCounter (FRAME_X_DISPLAY (f), + FRAME_X_EXTENDED_COUNTER (f), + FRAME_X_COUNTER_VALUE (f)); + + /* TODO: implement sync fences. */ +} +#endif + /* Start an update of frame F. This function is installed as a hook for update_begin, i.e. it is called when update_begin is called. This function is called prior to calls to gui_update_window_begin for @@ -6591,7 +6681,11 @@ x_set_frame_alpha (struct frame *f) static void x_update_begin (struct frame *f) { +#if defined HAVE_XSYNC && !defined USE_GTK + x_sync_update_begin (f); +#else /* Nothing to do. */ +#endif } /* Draw a vertical window border from (x,y0) to (x,y1) */ @@ -6720,7 +6814,10 @@ x_flip_and_flush (struct frame *f) block_input (); #ifdef HAVE_XDBE if (FRAME_X_NEED_BUFFER_FLIP (f)) - show_back_buffer (f); + { + show_back_buffer (f); + x_sync_update_finish (f); + } #endif x_flush (f); unblock_input (); @@ -6737,17 +6834,17 @@ x_update_end (struct frame *f) #ifdef USE_CAIRO if (!FRAME_X_DOUBLE_BUFFERED_P (f) && FRAME_CR_CONTEXT (f)) - { - block_input (); - cairo_surface_flush (cairo_get_target (FRAME_CR_CONTEXT (f))); - unblock_input (); - } + cairo_surface_flush (cairo_get_target (FRAME_CR_CONTEXT (f))); #endif -#ifndef XFlush - block_input (); - XFlush (FRAME_X_DISPLAY (f)); - unblock_input (); + /* If double buffering is disabled, finish the update here. + Otherwise, finish the update when the back buffer is next + displayed. */ +#if defined HAVE_XSYNC && !defined USE_GTK +#ifdef HAVE_XDBE + if (!FRAME_X_DOUBLE_BUFFERED_P (f)) +#endif + x_sync_update_finish (f); #endif } @@ -6775,6 +6872,11 @@ XTframe_up_to_date (struct frame *f) if (!buffer_flipping_blocked_p () && FRAME_X_NEED_BUFFER_FLIP (f)) show_back_buffer (f); + +#if defined HAVE_XSYNC && !defined USE_GTK + if (FRAME_X_DOUBLE_BUFFERED_P (f)) + x_sync_update_finish (f); +#endif #endif #ifdef HAVE_XSYNC @@ -6791,14 +6893,14 @@ XTframe_up_to_date (struct frame *f) if (FRAME_X_OUTPUT (f)->ext_sync_end_pending_p && FRAME_X_EXTENDED_COUNTER (f) != None) { - current = FRAME_X_OUTPUT (f)->current_extended_counter_value; + current = FRAME_X_COUNTER_VALUE (f); if (XSyncValueLow32 (current) % 2) XSyncIntToValue (&add, 1); else XSyncIntToValue (&add, 2); - XSyncValueAdd (&FRAME_X_OUTPUT (f)->current_extended_counter_value, + XSyncValueAdd (&FRAME_X_COUNTER_VALUE (f), current, add, &overflow_p); if (overflow_p) @@ -6806,7 +6908,7 @@ XTframe_up_to_date (struct frame *f) XSyncSetCounter (FRAME_X_DISPLAY (f), FRAME_X_EXTENDED_COUNTER (f), - FRAME_X_OUTPUT (f)->current_extended_counter_value); + FRAME_X_COUNTER_VALUE (f)); FRAME_X_OUTPUT (f)->ext_sync_end_pending_p = false; } @@ -11066,7 +11168,8 @@ x_tooltip_window_to_frame (struct x_display_info *dpyinfo, GdkWindow *tooltip_window; #endif - *unrelated_tooltip_p = false; + if (unrelated_tooltip_p) + *unrelated_tooltip_p = false; FOR_EACH_FRAME (tail, frame) { @@ -11095,14 +11198,16 @@ x_tooltip_window_to_frame (struct x_display_info *dpyinfo, if (tooltip_window && (gdk_x11_window_get_xid (tooltip_window) == wdesc)) { - *unrelated_tooltip_p = true; + if (unrelated_tooltip_p) + *unrelated_tooltip_p = true; break; } #else if (tooltip_window && (GDK_WINDOW_XID (tooltip_window) == wdesc)) { - *unrelated_tooltip_p = true; + if (unrelated_tooltip_p) + *unrelated_tooltip_p = true; break; } #endif @@ -11670,6 +11775,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, x_dnd_run_unsupported_drop_function = false; x_dnd_use_toplevels = x_wm_supports (f, FRAME_DISPLAY_INFO (f)->Xatom_net_client_list_stacking); + x_dnd_last_tooltip_valid = false; x_dnd_toplevels = NULL; x_dnd_allow_current_frame = allow_current_frame; x_dnd_movement_frame = NULL; @@ -13054,15 +13160,26 @@ static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part, static Lisp_Object window_being_scrolled; -/* Whether this is an Xaw with arrow-scrollbars. This should imply - that movements of 1/20 of the screen size are mapped to up/down. */ +static Time +x_get_last_toolkit_time (struct x_display_info *dpyinfo) +{ +#ifdef USE_X_TOOLKIT + return XtLastTimestampProcessed (dpyinfo->display); +#else + return dpyinfo->last_user_time; +#endif +} #ifndef USE_GTK -/* Id of action hook installed for scroll bars. */ +/* Id of action hook installed for scroll bars and horizontal scroll + bars. */ static XtActionHookId action_hook_id; static XtActionHookId horizontal_action_hook_id; +/* Whether this is an Xaw with arrow-scrollbars. This should imply + that movements of 1/20 of the screen size are mapped to up/down. */ + static Boolean xaw3d_arrow_scroll; /* Whether the drag scrolling maintains the mouse at the top of the @@ -13273,12 +13390,8 @@ x_scroll_bar_to_input_event (const XEvent *event, ievent->kind = SCROLL_BAR_CLICK_EVENT; ievent->frame_or_window = window; ievent->arg = Qnil; -#ifdef USE_GTK - ievent->timestamp = CurrentTime; -#else - ievent->timestamp = - XtLastTimestampProcessed (FRAME_X_DISPLAY (XFRAME (w->frame))); -#endif + ievent->timestamp + = x_get_last_toolkit_time (FRAME_DISPLAY_INFO (XFRAME (w->frame))); ievent->code = 0; ievent->part = ev->data.l[2]; ievent->x = make_fixnum (ev->data.l[3]); @@ -13308,12 +13421,8 @@ x_horizontal_scroll_bar_to_input_event (const XEvent *event, ievent->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT; ievent->frame_or_window = window; ievent->arg = Qnil; -#ifdef USE_GTK - ievent->timestamp = CurrentTime; -#else - ievent->timestamp = - XtLastTimestampProcessed (FRAME_X_DISPLAY (XFRAME (w->frame))); -#endif + ievent->timestamp + = x_get_last_toolkit_time (FRAME_DISPLAY_INFO (XFRAME (w->frame))); ievent->code = 0; ievent->part = ev->data.l[2]; ievent->x = make_fixnum (ev->data.l[3]); @@ -13417,19 +13526,31 @@ xm_scroll_callback (Widget widget, XtPointer client_data, XtPointer call_data) bar widget. DATA is a pointer to the scroll_bar structure. */ static gboolean -xg_scroll_callback (GtkRange *range, - GtkScrollType scroll, - gdouble value, - gpointer user_data) +xg_scroll_callback (GtkRange *range, GtkScrollType scroll, + gdouble value, gpointer user_data) { - int whole = 0, portion = 0; - struct scroll_bar *bar = user_data; - enum scroll_bar_part part = scroll_bar_nowhere; - GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range)); - struct frame *f = g_object_get_data (G_OBJECT (range), XG_FRAME_DATA); + int whole, portion; + struct scroll_bar *bar; + enum scroll_bar_part part; + GtkAdjustment *adj; + struct frame *f; + guint32 time; + struct x_display_info *dpyinfo; if (xg_ignore_gtk_scrollbar) return false; + whole = 0; + portion = 0; + bar = user_data; + part = scroll_bar_nowhere; + adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range)); + f = g_object_get_data (G_OBJECT (range), XG_FRAME_DATA); + time = gtk_get_current_event_time (); + dpyinfo = FRAME_DISPLAY_INFO (f); + + if (time != GDK_CURRENT_TIME) + x_display_set_last_user_time (dpyinfo, time, true); + switch (scroll) { case GTK_SCROLL_JUMP: @@ -13496,8 +13617,11 @@ xg_end_scroll_callback (GtkWidget *widget, GdkEventButton *event, gpointer user_data) { - struct scroll_bar *bar = user_data; + struct scroll_bar *bar; + + bar = user_data; bar->dragging = -1; + if (WINDOWP (window_being_scrolled)) { x_send_scroll_bar_event (window_being_scrolled, @@ -15910,6 +16034,15 @@ x_dnd_update_tooltip_position (int root_x, int root_y) x_dnd_compute_tip_xy (&root_x, &root_y, x_dnd_monitors); + if (x_dnd_last_tooltip_valid + && root_x == x_dnd_last_tooltip_x + && root_y == x_dnd_last_tooltip_y) + return; + + x_dnd_last_tooltip_x = root_x; + x_dnd_last_tooltip_y = root_y; + x_dnd_last_tooltip_valid = true; + XMoveWindow (FRAME_X_DISPLAY (x_dnd_frame), tip_window, root_x, root_y); } @@ -16817,8 +16950,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, } else if (event->xclient.data.l[4] == 1) { - XSyncIntsToValue (&FRAME_X_OUTPUT (f)->current_extended_counter_value, - event->xclient.data.l[2], event->xclient.data.l[3]); + XSyncIntsToValue (&FRAME_X_COUNTER_VALUE (f), + event->xclient.data.l[2], + event->xclient.data.l[3]); FRAME_X_OUTPUT (f)->ext_sync_end_pending_p = true; } @@ -16935,10 +17069,19 @@ handle_one_xevent (struct x_display_info *dpyinfo, goto done; } +#if defined HAVE_XSYNC && !defined USE_GTK + /* These messages are sent by the compositing manager after a + frame is drawn under extended synchronization. */ + if (event->xclient.message_type == dpyinfo->Xatom_net_wm_frame_drawn + || event->xclient.message_type == dpyinfo->Xatom_net_wm_frame_timings) + goto done; +#endif + xft_settings_event (dpyinfo, event); f = any; - if (!f) + /* We don't want to ever leak tooltip frames to Lisp code. */ + if (!f || FRAME_TOOLTIP_P (f)) goto OTHER; /* These values are always used initialized, but GCC doesn't @@ -17711,7 +17854,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, /* `xkey' will be modified, but it's not important to modify `event' itself. */ XKeyEvent xkey = event->xkey; - int i; + #ifdef HAVE_XINPUT2 Time pending_keystroke_time; struct xi_device_t *source; @@ -17761,27 +17904,6 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (modifiers & dpyinfo->meta_mod_mask) memset (&compose_status, 0, sizeof (compose_status)); -#ifdef HAVE_XKB - if (dpyinfo->xkb_desc) - { - XkbDescRec *rec = dpyinfo->xkb_desc; - - if (rec->map->modmap && rec->map->modmap[xkey.keycode]) - goto done_keysym; - } - else -#endif - { - if (dpyinfo->modmap) - { - for (i = 0; i < 8 * dpyinfo->modmap->max_keypermod; i++) - { - if (xkey.keycode == dpyinfo->modmap->modifiermap[i]) - goto done_keysym; - } - } - } - #ifdef HAVE_X_I18N if (FRAME_XIC (f)) { @@ -18258,6 +18380,19 @@ handle_one_xevent (struct x_display_info *dpyinfo, #endif if (f) { + /* Now clear dpyinfo->last_mouse_motion_frame, or + gui_redo_mouse_highlight will end up highlighting the + last known poisition of the mouse if a tooltip frame is + later unmapped. */ + + if (f == dpyinfo->last_mouse_motion_frame) + dpyinfo->last_mouse_motion_frame = NULL; + + /* Something similar applies to + dpyinfo->last_mouse_glyph_frame. */ + if (f == dpyinfo->last_mouse_glyph_frame) + dpyinfo->last_mouse_glyph_frame = NULL; + if (f == hlinfo->mouse_face_mouse_frame) { /* If we move outside the frame, then we're @@ -19004,10 +19139,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, dpyinfo->grabbed |= (1 << event->xbutton.button); dpyinfo->last_mouse_frame = f; - if (f && !tab_bar_p) + + if (f) f->last_tab_bar_item = -1; #if ! defined (USE_GTK) - if (f && !tool_bar_p) + if (f) f->last_tool_bar_item = -1; #endif /* not USE_GTK */ } @@ -19708,8 +19844,22 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!f) f = x_top_window_to_frame (dpyinfo, leave->event); #endif + if (f) { + /* Now clear dpyinfo->last_mouse_motion_frame, or + gui_redo_mouse_highlight will end up highlighting + the last known poisition of the mouse if a + tooltip frame is later unmapped. */ + + if (f == dpyinfo->last_mouse_motion_frame) + dpyinfo->last_mouse_motion_frame = NULL; + + /* Something similar applies to + dpyinfo->last_mouse_glyph_frame. */ + if (f == dpyinfo->last_mouse_glyph_frame) + dpyinfo->last_mouse_glyph_frame = NULL; + if (f == hlinfo->mouse_face_mouse_frame) { /* If we move outside the frame, then we're @@ -19799,9 +19949,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, bar = NULL; - /* See the comment on top of - x_init_master_valuators for more details on how - scroll wheel movement is reported on XInput 2. */ + /* See the comment on top of x_cache_xi_devices + for more details on how scroll wheel movement + is reported on XInput 2. */ delta = x_get_scroll_valuator_delta (dpyinfo, device, i, *values, &val); values++; @@ -20407,10 +20557,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (device) device->grab |= (1 << xev->detail); - if (f && !tab_bar_p) + if (f) f->last_tab_bar_item = -1; #if ! defined (USE_GTK) - if (f && !tool_bar_p) + if (f) f->last_tool_bar_item = -1; #endif /* not USE_GTK */ } @@ -21090,27 +21240,6 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifdef HAVE_XKB if (dpyinfo->xkb_desc) { - XkbDescRec *rec = dpyinfo->xkb_desc; - - if (rec->map->modmap && rec->map->modmap[xev->detail]) - goto xi_done_keysym; - } - else -#endif - { - if (dpyinfo->modmap) - { - for (i = 0; i < 8 * dpyinfo->modmap->max_keypermod; i++) - { - if (xev->detail == dpyinfo->modmap->modifiermap[i]) - goto xi_done_keysym; - } - } - } - -#ifdef HAVE_XKB - if (dpyinfo->xkb_desc) - { uint xkb_state = state; xkb_state &= ~(1 << 13 | 1 << 14); xkb_state |= xev->group.effective << 13; @@ -21663,7 +21792,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (!device) { /* An existing device might have been enabled. */ - x_init_master_valuators (dpyinfo); + x_cache_xi_devices (dpyinfo); /* Now try to find the device again, in case it was just enabled. */ @@ -21795,7 +21924,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (xi_find_touch_point (device, xev->detail)) emacs_abort (); - f = x_any_window_to_frame (dpyinfo, xev->event); + f = x_window_to_frame (dpyinfo, xev->event); #ifdef HAVE_GTK3 menu_bar_p = (f && FRAME_X_OUTPUT (f)->menubar_widget @@ -21893,7 +22022,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, touchpoint->x = xev->event_x; touchpoint->y = xev->event_y; - f = x_any_window_to_frame (dpyinfo, xev->event); + f = x_window_to_frame (dpyinfo, xev->event); if (f && device->direct_p) { @@ -21936,7 +22065,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (unlinked_p) { - f = x_any_window_to_frame (dpyinfo, xev->event); + f = x_window_to_frame (dpyinfo, xev->event); if (f && device->direct_p) { @@ -24291,7 +24420,11 @@ x_set_offset (struct frame *f, int xoff, int yoff, int change_gravity) #endif /* 'x_sync_with_move' is too costly for dragging child frames. */ - if (!FRAME_PARENT_FRAME (f)) + if (!FRAME_PARENT_FRAME (f) + /* If no window manager exists, just calling XSync will be + sufficient to ensure that the window geometry has been + updated. */ + && NILP (Vx_no_window_manager)) { x_sync_with_move (f, f->left_pos, f->top_pos, FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN); @@ -25024,11 +25157,9 @@ x_sync_with_move (struct frame *f, int left, int top, bool fuzzy) 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); + /* There is no need to call XSync (even when no window manager + is present) because x_real_positions already does that + implicitly. */ x_real_positions (f, ¤t_left, ¤t_top); if (fuzzy) @@ -27290,7 +27421,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) if (rc == Success) { dpyinfo->supports_xi2 = true; - x_init_master_valuators (dpyinfo); + x_cache_xi_devices (dpyinfo); } } |