diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index 9a396f57ef0..ccb97528418 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi @@ -2085,6 +2085,27 @@ portable code, use the variables @code{mouse-wheel-up-event} and @code{mouse-wheel-down-event} defined in @file{mwheel.el} to determine what event types to expect for the mouse wheel. +@cindex @code{pinch} event +@item (pinch @var{position} @var{dx} @var{dy} @var{scale} @var{angle}) +This kind of event is generated by the user performing a ``pinch'' +gesture with two fingers on a touchpad. @var{position} is a mouse +position list (@pxref{Click Events}) detailing the position of the +mouse cursor when the event occured, @var{dx} is the distance between +the horizontal positions of the fingers since the last event in the +same sequence, @var{dy} is the vertical movement of the fingers since +the last event in the same sequence, @var{scale} is the division of +the current distance between the fingers and the distance at the start +of the sequence, and @var{angle} is the delta in degrees between the +angles of the fingers in this event and the fingers in the last event +of the same sequence. + +All arguments after @var{position} are floating point numbers. + +This event is usually sent as part of a sequence, which begins with +the user placing two fingers on the touchpad and ends with the user +removing those fingers. @var{dx}, @var{dy}, and @var{angle} will be +@code{0.0} in the first event sent after a sequence begins. + @cindex @code{drag-n-drop} event @item (drag-n-drop @var{position} @var{files}) This kind of event is generated when a group of files is diff --git a/etc/NEWS b/etc/NEWS index 39fbd8f6b77..aea6a46c1d3 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -312,6 +312,9 @@ effectively dragged. Customize this option to limit the number of entries in the menu "Edit->Paste from Kill Menu". The default is 60. +--- +** Performing a pinch gesture on a touchpad now increases the text scale. + ** show-paren-mode +++ @@ -885,6 +888,11 @@ This allows setting a minimum display width for a region of text. This event is sent whenever the user's finger moves off the mouse wheel on some mice, or when the user's finger moves off the touchpad. ++++ +** New event type 'pinch'. +This event is sent when a user peforms a two-finger pinch gesture on a +touchpad. + ** Keymaps and key definitions +++ diff --git a/etc/PROBLEMS b/etc/PROBLEMS index 230313d2247..07ae98885d5 100644 --- a/etc/PROBLEMS +++ b/etc/PROBLEMS @@ -1681,6 +1681,18 @@ This happens on the proprietary X server ASTEC-X when the number of monitors is changed after the server has started. A workaround is to restart the X server after the monitor configuration has been changed. +*** Touchpad gestures don't work and emit warning messages. + +When pinching or swiping on your touchpad, you might see a warning +message that looks like: + + XInputWireToCookie: Unknown generic event. type 28 + +This happens when your XInput headers support XInput 2.4, but the +actual version of libXi installed does not. The solution is to +upgrade your libXi binaries to libXi 1.8.0 or later, to correspond +with your XInput headers. + * Runtime problems on character terminals *** With X forwarding, mouse highlighting can make Emacs slow. diff --git a/lisp/face-remap.el b/lisp/face-remap.el index 50302b9682c..8507f7e8e36 100644 --- a/lisp/face-remap.el +++ b/lisp/face-remap.el @@ -390,6 +390,30 @@ a top-level keymap, `text-scale-increase' or (lambda () (interactive) (text-scale-adjust (abs inc)))))) map))))) ;; ) +(defvar-local text-scale--pinch-start-scale 0 + "The text scale at the start of a pinch sequence.") + +;;;###autoload (define-key global-map [pinch] 'text-scale-pinch) +;;;###autoload +(defun text-scale-pinch (event) + "Adjust the height of the default face by the scale in EVENT." + (interactive "e") + (let ((window (posn-window (nth 1 event))) + (scale (nth 4 event)) + (dx (nth 2 event)) + (dy (nth 3 event)) + (angle (nth 5 event))) + (with-selected-window window + (when (and (zerop dx) + (zerop dy) + (zerop angle) + (equal scale 1.0)) + (setq text-scale--pinch-start-scale + (if text-scale-mode text-scale-mode-amount 0))) + (text-scale-set + (+ text-scale--pinch-start-scale + (round (log scale text-scale-mode-step))))))) + ;; ---------------------------------------------------------------- ;; buffer-face-mode diff --git a/src/keyboard.c b/src/keyboard.c index 821a1b576be..54538114065 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4466,6 +4466,7 @@ static Lisp_Object func_key_syms; static Lisp_Object mouse_syms; static Lisp_Object wheel_syms; static Lisp_Object drag_n_drop_syms; +static Lisp_Object pinch_syms; /* This is a list of keysym codes for special "accent" characters. It parallels lispy_accent_keys. */ @@ -6032,6 +6033,22 @@ make_lispy_event (struct input_event *event) Fcons (id, position)); } + case PINCH_EVENT: + { + Lisp_Object x, y, position; + struct frame *f = XFRAME (event->frame_or_window); + + x = event->x; + y = event->y; + + position = make_lispy_position (f, x, y, event->timestamp); + + return Fcons (modify_event_symbol (0, event->modifiers, Qpinch, + Qnil, (const char *[]) {"pinch"}, + &pinch_syms, 1), + Fcons (position, event->arg)); + } + case TOUCHSCREEN_UPDATE_EVENT: { Lisp_Object x, y, id, position, tem, it, evt; @@ -11970,6 +11987,9 @@ syms_of_keyboard (void) drag_n_drop_syms = Qnil; staticpro (&drag_n_drop_syms); + pinch_syms = Qnil; + staticpro (&pinch_syms); + unread_switch_frame = Qnil; staticpro (&unread_switch_frame); @@ -12309,6 +12329,7 @@ See also `pre-command-hook'. */); DEFSYM (Qtouchscreen_begin, "touchscreen-begin"); DEFSYM (Qtouchscreen_end, "touchscreen-end"); DEFSYM (Qtouchscreen_update, "touchscreen-update"); + DEFSYM (Qpinch, "pinch"); Fset (Qecho_area_clear_hook, Qnil); DEFVAR_LISP ("lucid-menu-bar-dirty-flag", Vlucid_menu_bar_dirty_flag, diff --git a/src/termhooks.h b/src/termhooks.h index 9f22187b841..1c89a4d306f 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -293,6 +293,21 @@ enum event_kind , TOUCHSCREEN_UPDATE_EVENT , TOUCHSCREEN_BEGIN_EVENT , TOUCHSCREEN_END_EVENT + + /* In a PINCH_EVENT, X and Y are the position of the pointer + relative to the top-left corner of the frame, and arg is a list + of (DX DY SCALE ANGLE), in which: + + - DX and DY are the difference between the positions of the + fingers comprising the current gesture and the last such + gesture in the same sequence. + - SCALE is the division of the current distance between the + fingers and the distance at the start of the gesture. + - DELTA-ANGLE is the delta between the angle of the current + event and the last event in the same sequence, in degrees. A + positive delta represents a change clockwise, and a negative + delta represents a change counter-clockwise. */ + , PINCH_EVENT }; /* Bit width of an enum event_kind tag at the start of structs and unions. */ diff --git a/src/xfns.c b/src/xfns.c index 126e837b43c..2b134716bd7 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -2961,6 +2961,14 @@ setup_xi_event_mask (struct frame *f) XISetMask (m, XI_TouchBegin); XISetMask (m, XI_TouchUpdate); XISetMask (m, XI_TouchEnd); +#ifdef XI_GesturePinchBegin + if (FRAME_DISPLAY_INFO (f)->xi2_version >= 4) + { + XISetMask (m, XI_GesturePinchBegin); + XISetMask (m, XI_GesturePinchUpdate); + XISetMask (m, XI_GesturePinchEnd); + } +#endif } #endif XISelectEvents (FRAME_X_DISPLAY (f), diff --git a/src/xterm.c b/src/xterm.c index 6be7e2e9f95..12c14e5e4f1 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -11044,6 +11044,39 @@ handle_one_xevent (struct x_display_info *dpyinfo, goto XI_OTHER; } +#endif +#ifdef XI_GesturePinchBegin + case XI_GesturePinchBegin: + case XI_GesturePinchUpdate: + { + XIGesturePinchEvent *pev = (XIGesturePinchEvent *) xi_event; + struct xi_device_t *device = xi_device_from_id (dpyinfo, pev->deviceid); + + if (!device || !device->master_p) + goto XI_OTHER; + + any = x_any_window_to_frame (dpyinfo, pev->event); + if (any) + { + inev.ie.kind = PINCH_EVENT; + inev.ie.modifiers = x_x_to_emacs_modifiers (FRAME_DISPLAY_INFO (any), + pev->mods.effective); + XSETINT (inev.ie.x, lrint (pev->event_x)); + XSETINT (inev.ie.y, lrint (pev->event_y)); + XSETFRAME (inev.ie.frame_or_window, any); + inev.ie.arg = list4 (make_float (pev->delta_x), + make_float (pev->delta_y), + make_float (pev->scale), + make_float (pev->delta_angle)); + } + /* Once again GTK seems to crash when confronted by + events it doesn't understand. */ + *finish = X_EVENT_DROP; + goto XI_OTHER; + } + case XI_GesturePinchEnd: + *finish = X_EVENT_DROP; + goto XI_OTHER; #endif default: goto XI_OTHER;