commit 449bc49c768a4733411c7e05186be7efc163cd7c (HEAD, refs/remotes/origin/master) Author: Glenn Morris Date: Tue Apr 11 08:42:54 2017 -0700 Update a package test for hydra * test/lisp/emacs-lisp/package-tests.el (with-package-test): Also bind package-gnupghome-dir, see eg http://hydra.nixos.org/build/51462182 . diff --git a/test/lisp/emacs-lisp/package-tests.el b/test/lisp/emacs-lisp/package-tests.el index 5172b482cb..62fdc751fb 100644 --- a/test/lisp/emacs-lisp/package-tests.el +++ b/test/lisp/emacs-lisp/package-tests.el @@ -117,6 +117,7 @@ (process-environment (cons (format "HOME=%s" package-test-user-dir) process-environment)) (package-user-dir package-test-user-dir) + (package-gnupghome-dir (expand-file-name "gnupg" package-user-dir)) (package-archives `(("gnu" . ,(or ,location package-test-data-dir)))) (default-directory package-test-file-dir) abbreviated-home-dir commit ea6c880aa68bcc8f0e388ecbd8c552392488b38f Author: Martin Rudalics Date: Tue Apr 11 12:37:26 2017 +0200 Frame movement, focus and hook related changes New hook `move-frame-functions'. Run `focus-in-hook' after switching to frame that gets focus. Don't run XMoveWindow for GTK. * lisp/frame.el (handle-move-frame, frame-size-changed-p): New functions. * src/frame.c (do_switch_frame): Simplify code. (Fhandle_switch_frame): Switch frame before running `handle-focus-in'. (Vfocus_in_hook, Vfocus_out_hook): Clarify doc-strings. (Vmove_frame_functions): New hook variable. * src/keyboard.c (kbd_buffer_get_event): Handle MOVE_FRAME_EVENT. Handle SELECT_WINDOW_EVENT separately. (head_table): Add Qmove_frame entry. (syms_of_keyboard): Add Qmove_frame. (keys_of_keyboard): Define key for `move-frame'. * src/termhooks.h (event_kind): Add MOVE_FRAME_EVENT. * src/w32term.c (w32_read_socket): Create MOVE_FRAME_EVENT. * src/window.c (run_window_size_change_functions): Record size of FRAME's minibuffer window too. * src/xterm.c (handle_one_xevent): Create MOVE_FRAME_EVENT. (x_set_offset): For GTK call gtk_widget_move instead of XMoveWindow. diff --git a/lisp/frame.el b/lisp/frame.el index 0a35b715b3..4768b5be00 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -144,6 +144,13 @@ Focus-out events occur when no frame has focus. This function runs the hook `focus-out-hook'." (interactive "e") (run-hooks 'focus-out-hook)) + +(defun handle-move-frame (event) + "Handle a move-frame event. +This function runs the abnormal hook `move-frame-functions'." + (interactive "e") + (let ((frame (posn-window (event-start event)))) + (run-hook-with-args 'move-frame-functions frame))) ;;;; Arrangement of frames at startup @@ -1483,6 +1490,29 @@ keys and their meanings." for frames = (cdr (assq 'frames attributes)) if (memq frame frames) return attributes)) +(defun frame-size-changed-p (&optional frame) + "Return non-nil when the size of FRAME has changed. +More precisely, return non-nil when the inner width or height of +FRAME has changed since `window-size-change-functions' was run +for FRAME." + (let* ((frame (window-normalize-frame frame)) + (root (frame-root-window frame)) + (mini (minibuffer-window frame)) + (mini-height-before-size-change 0) + (mini-height 0)) + ;; FRAME's minibuffer window counts iff it's on FRAME and FRAME is + ;; not a minibuffer-only frame. + (when (and (eq (window-frame mini) frame) (not (eq mini root))) + (setq mini-height-before-size-change + (window-pixel-height-before-size-change mini)) + (setq mini-height (window-pixel-height mini))) + ;; Return non-nil when either the width of the root or the sum of + ;; the heights of root and minibuffer window changed. + (or (/= (window-pixel-width-before-size-change root) + (window-pixel-width root)) + (/= (+ (window-pixel-height-before-size-change root) + mini-height-before-size-change) + (+ (window-pixel-height root) mini-height))))) ;;;; Frame/display capabilities. diff --git a/src/frame.c b/src/frame.c index d873147fc8..5f57d4a0c2 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1107,7 +1107,7 @@ affects all frames on the same terminal device. */) Lisp_Object do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object norecord) { - struct frame *sf = SELECTED_FRAME (); + struct frame *sf = SELECTED_FRAME (), *f; /* If FRAME is a switch-frame event, extract the frame we should switch to. */ @@ -1120,10 +1120,10 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor a switch-frame event to arrive after a frame is no longer live, especially when deleting the initial frame during startup. */ CHECK_FRAME (frame); - if (! FRAME_LIVE_P (XFRAME (frame))) + f = XFRAME (frame); + if (!FRAME_LIVE_P (f)) return Qnil; - - if (sf == XFRAME (frame)) + else if (f == sf) return frame; /* If a frame's focus has been redirected toward the currently @@ -1156,11 +1156,11 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor #else /* ! 0 */ /* Instead, apply it only to the frame we're pointing to. */ #ifdef HAVE_WINDOW_SYSTEM - if (track && FRAME_WINDOW_P (XFRAME (frame))) + if (track && FRAME_WINDOW_P (f)) { Lisp_Object focus, xfocus; - xfocus = x_get_focus_frame (XFRAME (frame)); + xfocus = x_get_focus_frame (f); if (FRAMEP (xfocus)) { focus = FRAME_FOCUS_FRAME (XFRAME (xfocus)); @@ -1168,8 +1168,7 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor /* Redirect frame focus also when FRAME has its minibuffer window on the selected frame (see Bug#24500). */ || (NILP (focus) - && EQ (FRAME_MINIBUF_WINDOW (XFRAME (frame)), - sf->selected_window))) + && EQ (FRAME_MINIBUF_WINDOW (f), sf->selected_window))) Fredirect_frame_focus (xfocus, frame); } } @@ -1179,9 +1178,8 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor if (!for_deletion && FRAME_HAS_MINIBUF_P (sf)) resize_mini_window (XWINDOW (FRAME_MINIBUF_WINDOW (sf)), 1); - if (FRAME_TERMCAP_P (XFRAME (frame)) || FRAME_MSDOS_P (XFRAME (frame))) + if (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f)) { - struct frame *f = XFRAME (frame); struct tty_display_info *tty = FRAME_TTY (f); Lisp_Object top_frame = tty->top_frame; @@ -1209,7 +1207,7 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor if (! FRAME_MINIBUF_ONLY_P (XFRAME (selected_frame))) last_nonminibuf_frame = XFRAME (selected_frame); - Fselect_window (XFRAME (frame)->selected_window, norecord); + Fselect_window (f->selected_window, norecord); /* We want to make sure that the next event generates a frame-switch event to the appropriate frame. This seems kludgy to me, but @@ -1253,12 +1251,15 @@ If EVENT is frame object, handle it as if it were a switch-frame event to that frame. */) (Lisp_Object event) { + Lisp_Object value; + /* Preserve prefix arg that the command loop just cleared. */ kset_prefix_arg (current_kboard, Vcurrent_prefix_arg); run_hook (Qmouse_leave_buffer_hook); /* `switch-frame' implies a focus in. */ + value = do_switch_frame (event, 0, 0, Qnil); call1 (intern ("handle-focus-in"), event); - return do_switch_frame (event, 0, 0, Qnil); + return value; } DEFUN ("selected-frame", Fselected_frame, Sselected_frame, 0, 0, 0, @@ -1709,8 +1710,6 @@ delete_frame (Lisp_Object frame, Lisp_Object force) promise that the terminal of the frame must be valid until we have called the window-system-dependent frame destruction routine. */ - - { struct terminal *terminal; block_input (); @@ -5121,13 +5120,19 @@ The pointer becomes visible again when the mouse is moved. */); Vmake_pointer_invisible = Qt; DEFVAR_LISP ("focus-in-hook", Vfocus_in_hook, - doc: /* Normal hook run when a frame gains input focus. */); + doc: /* Normal hook run when a frame gains input focus. +The frame gaining focus is selected at the time this hook is run. */); Vfocus_in_hook = Qnil; DEFVAR_LISP ("focus-out-hook", Vfocus_out_hook, - doc: /* Normal hook run when a frame loses input focus. */); + doc: /* Normal hook run when all frames lost input focus. */); Vfocus_out_hook = Qnil; + DEFVAR_LISP ("move-frame-functions", Vmove_frame_functions, + doc: /* Functions run after a frame was moved. +The functions are run with one arg, the frame that moved. */); + Vmove_frame_functions = Qnil; + DEFVAR_LISP ("delete-frame-functions", Vdelete_frame_functions, doc: /* Functions run before deleting a frame. The functions are run with one arg, the frame to be deleted. diff --git a/src/keyboard.c b/src/keyboard.c index 2e0a813bb0..3e50142f7c 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4056,6 +4056,14 @@ kbd_buffer_get_event (KBOARD **kbp, kbd_fetch_ptr = event + 1; } #endif +#if defined (HAVE_X11) || defined (HAVE_NTGUI) + else if (event->kind == MOVE_FRAME_EVENT) + { + /* Make an event (move-frame (FRAME)). */ + obj = list2 (Qmove_frame, list1 (event->ie.frame_or_window)); + kbd_fetch_ptr = event + 1; + } +#endif #ifdef HAVE_XWIDGETS else if (event->kind == XWIDGET_EVENT) { @@ -4068,6 +4076,11 @@ kbd_buffer_get_event (KBOARD **kbp, obj = make_lispy_event (&event->ie); kbd_fetch_ptr = event + 1; } + else if (event->kind == SELECT_WINDOW_EVENT) + { + obj = list2 (Qselect_window, list1 (event->ie.frame_or_window)); + kbd_fetch_ptr = event + 1; + } else { /* If this event is on a different frame, return a switch-frame this @@ -10977,6 +10990,7 @@ static const struct event_head head_table[] = { {SYMBOL_INDEX (Qfocus_in), SYMBOL_INDEX (Qfocus_in)}, {SYMBOL_INDEX (Qfocus_out), SYMBOL_INDEX (Qfocus_out)}, + {SYMBOL_INDEX (Qmove_frame), SYMBOL_INDEX (Qmove_frame)}, {SYMBOL_INDEX (Qdelete_frame), SYMBOL_INDEX (Qdelete_frame)}, {SYMBOL_INDEX (Qiconify_frame), SYMBOL_INDEX (Qiconify_frame)}, {SYMBOL_INDEX (Qmake_frame_visible), SYMBOL_INDEX (Qmake_frame_visible)}, @@ -11149,6 +11163,7 @@ syms_of_keyboard (void) DEFSYM (Qswitch_frame, "switch-frame"); DEFSYM (Qfocus_in, "focus-in"); DEFSYM (Qfocus_out, "focus-out"); + DEFSYM (Qmove_frame, "move-frame"); DEFSYM (Qdelete_frame, "delete-frame"); DEFSYM (Qiconify_frame, "iconify-frame"); DEFSYM (Qmake_frame_visible, "make-frame-visible"); @@ -11895,6 +11910,8 @@ keys_of_keyboard (void) "handle-focus-in"); initial_define_lispy_key (Vspecial_event_map, "focus-out", "handle-focus-out"); + initial_define_lispy_key (Vspecial_event_map, "move-frame", + "handle-move-frame"); } /* Mark the pointers in the kboard objects. diff --git a/src/termhooks.h b/src/termhooks.h index 3b1b4959b1..14ec397346 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -202,6 +202,9 @@ enum event_kind FOCUS_OUT_EVENT, + /* Generated when a frame is moved. */ + MOVE_FRAME_EVENT, + /* Generated when mouse moves over window not currently selected. */ SELECT_WINDOW_EVENT, diff --git a/src/w32term.c b/src/w32term.c index 81666f5bc4..31f0b4a2fa 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -5038,7 +5038,11 @@ w32_read_socket (struct terminal *terminal, f = x_window_to_frame (dpyinfo, msg.msg.hwnd); if (f && !FRAME_ICONIFIED_P (f)) - x_real_positions (f, &f->left_pos, &f->top_pos); + { + x_real_positions (f, &f->left_pos, &f->top_pos); + inev.kind = MOVE_FRAME_EVENT; + XSETFRAME (inev.frame_or_window, f); + } check_visibility = 1; break; diff --git a/src/window.c b/src/window.c index 95690443f8..58c0c33cbb 100644 --- a/src/window.c +++ b/src/window.c @@ -3314,6 +3314,9 @@ run_window_size_change_functions (Lisp_Object frame) Lisp_Object functions = Vwindow_size_change_functions; if (FRAME_WINDOW_CONFIGURATION_CHANGED (f) + /* Here we implicitly exclude the possibility that the height of + FRAME and its minibuffer window both change leaving the height + of FRAME's root window alone. */ || window_size_changed (r)) { while (CONSP (functions)) @@ -3324,6 +3327,12 @@ run_window_size_change_functions (Lisp_Object frame) } window_set_before_size_change_sizes (r); + + if (FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f)) + /* Record size of FRAME's minibuffer window too. */ + window_set_before_size_change_sizes + (XWINDOW (FRAME_MINIBUF_WINDOW (f))); + FRAME_WINDOW_CONFIGURATION_CHANGED (f) = false; } } diff --git a/src/xterm.c b/src/xterm.c index 08ccac0700..1d14407aa4 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -8614,7 +8614,22 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (FRAME_GTK_OUTER_WIDGET (f) && gtk_widget_get_mapped (FRAME_GTK_OUTER_WIDGET (f))) #endif - x_real_positions (f, &f->left_pos, &f->top_pos); + { + int old_left = f->left_pos; + int old_top = f->top_pos; + Lisp_Object frame = Qnil; + + XSETFRAME (frame, f); + + x_real_positions (f, &f->left_pos, &f->top_pos); + + if (old_left != f->left_pos || old_top != f->top_pos) + { + inev.ie.kind = MOVE_FRAME_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); + } + } + #ifdef HAVE_X_I18N if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea)) @@ -10088,8 +10103,13 @@ x_set_offset (struct frame *f, register int xoff, register int yoff, int change_ modified_top += FRAME_X_OUTPUT (f)->move_offset_top; } +#ifdef USE_GTK + gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), + modified_left, modified_top); +#else XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), - modified_left, modified_top); + modified_left, modified_top); +#endif x_sync_with_move (f, f->left_pos, f->top_pos, FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN); commit 0eef8e9af7707b7bd01243033b9a48cb74fb8672 Author: Werner LEMBERG Date: Tue Apr 11 13:06:30 2017 +0300 Avoid abort in ftfont.c due to faulty fonts * src/ftfont.c (ftfont_get_metrics): Try loading the font without hinting, before aborting. (Bug#25945) diff --git a/src/ftfont.c b/src/ftfont.c index 6cabddda37..5600bde646 100644 --- a/src/ftfont.c +++ b/src/ftfont.c @@ -1546,7 +1546,8 @@ ftfont_get_metrics (MFLTFont *font, MFLTGlyphString *gstring, { FT_Glyph_Metrics *m; - if (FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_DEFAULT) != 0) + if (FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_DEFAULT) != 0 + && FT_Load_Glyph (ft_face, g->g.code, FT_LOAD_NO_HINTING) != 0) emacs_abort (); m = &ft_face->glyph->metrics; if (flt_font_ft->matrix) commit 695eacc21ea08b7fa080a232eadae881b5295bef Author: Jens Lechtenboerger Date: Tue Apr 11 12:27:37 2017 +0300 Introduce customizable variable 'package-gnupghome-dir' * lisp/emacs-lisp/package.el (package-import-keyring) (package--check-signature-content, package-check-signature): Use new variable package-gnupghome-dir to control which GnuPG homedir to use. * doc/emacs/package.texi: Mention package-gnupghome-dir. * etc/NEWS: Mention package-gnupghome-dir. diff --git a/doc/emacs/package.texi b/doc/emacs/package.texi index d6f88aaec3..ecc955d3ef 100644 --- a/doc/emacs/package.texi +++ b/doc/emacs/package.texi @@ -193,15 +193,22 @@ and use only third parties that you think you can trust! can have in their packages by @dfn{signing} them. They generate a private/public pair of cryptographic keys, and use the private key to create a @dfn{signature file} for each package. With the public key, you -can use the signature files to verify who created the package, and -that it has not been modified. A valid signature is not a cast-iron +can use the signature files to verify the package creator and make sure +the package has not been tampered with. Signature verification uses +@uref{https://www.gnupg.org/, the GnuPG package} via the EasyPG +interface (@pxref{Top,, EasyPG, epa, Emacs EasyPG Assistant Manual}). +A valid signature is not a cast-iron guarantee that a package is not malicious, so you should still exercise caution. Package archives should provide instructions on how you can obtain their public key. One way is to download the key from a server such as @url{http://pgp.mit.edu/}. Use @kbd{M-x package-import-keyring} to import the key into Emacs. -Emacs stores package keys in the @file{gnupg} subdirectory -of @code{package-user-dir}. +Emacs stores package keys in the directory specified by the variable +@code{package-gnupghome-dir}, by default in the @file{gnupg} +subdirectory of @code{package-user-dir}, which causes Emacs to invoke +GnuPG with the option @samp{--homedir} when verifying signatures. +If @code{package-gnupghome-dir} is @code{nil}, GnuPG's option +@samp{--homedir} is omitted. The public key for the GNU package archive is distributed with Emacs, in the @file{etc/package-keyring.gpg}. Emacs uses it automatically. diff --git a/etc/NEWS b/etc/NEWS index b36db07360..3c328ac58a 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -644,6 +644,13 @@ In 'visual-line-mode' it will look for the true beginning of a header while in non-'visual-line-mode' it will move the point to the indented header's value. +** Package + ++++ +*** The new variable 'package-gnupghome-dir' has been added to control +where the GnuPG home directory (used for signature verification) is +located and whether GnuPG's option "--homedir" is used or not. + ** Tramp +++ diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index 769856262b..bef1e8dd59 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -307,6 +307,23 @@ contrast, `package-user-dir' contains packages for personal use." (declare-function epg-find-configuration "epg-config" (protocol &optional no-cache program-alist)) +(defcustom package-gnupghome-dir (expand-file-name "gnupg" package-user-dir) + "Directory containing GnuPG keyring or nil. +This variable specifies the GnuPG home directory used by package. +That directory is passed via the option \"--homedir\" to GnuPG. +If nil, do not use the option \"--homedir\", but stick with GnuPG's +default directory." + :type `(choice + (const + :tag "Default Emacs package management GnuPG home directory" + ,(expand-file-name "gnupg" package-user-dir)) + (const + :tag "Default GnuPG directory (GnuPG option --homedir not used)" + nil) + (directory :tag "A specific GnuPG --homedir")) + :risky t + :version "26.1") + (defcustom package-check-signature (if (and (require 'epg-config) (epg-find-configuration 'OpenPGP)) @@ -1209,9 +1226,9 @@ errors signaled by ERROR-FORM or by BODY). "Check signature CONTENT against STRING. SIG-FILE is the name of the signature file, used when signaling errors." - (let* ((context (epg-make-context 'OpenPGP)) - (homedir (expand-file-name "gnupg" package-user-dir))) - (setf (epg-context-home-directory context) homedir) + (let ((context (epg-make-context 'OpenPGP))) + (when package-gnupghome-dir + (setf (epg-context-home-directory context) package-gnupghome-dir)) (condition-case error (epg-verify-string context content string) (error (package--display-verify-error context sig-file) @@ -1238,7 +1255,7 @@ errors." "Check signature of the current buffer. Download the signature file from LOCATION by appending \".sig\" to FILE. -GnuPG keyring is located under \"gnupg\" in `package-user-dir'. +GnuPG keyring location depends on `package-gnupghome-dir'. STRING is the string to verify, it defaults to `buffer-string'. If ASYNC is non-nil, the download of the signature file is done asynchronously. @@ -1478,11 +1495,11 @@ taken care of by `package-initialize'." "Import keys from FILE." (interactive "fFile: ") (setq file (expand-file-name file)) - (let ((context (epg-make-context 'OpenPGP)) - (homedir (expand-file-name "gnupg" package-user-dir))) - (with-file-modes 448 - (make-directory homedir t)) - (setf (epg-context-home-directory context) homedir) + (let ((context (epg-make-context 'OpenPGP))) + (when package-gnupghome-dir + (with-file-modes 448 + (make-directory package-gnupghome-dir t)) + (setf (epg-context-home-directory context) package-gnupghome-dir)) (message "Importing %s..." (file-name-nondirectory file)) (epg-import-keys-from-file context file) (message "Importing %s...done" (file-name-nondirectory file))))