;; fns.c
(use-dialog-box menu boolean "21.1")
(use-file-dialog menu boolean "22.1")
- (focus-follows-mouse frames boolean "20.3")
+ (focus-follows-mouse
+ frames (choice
+ (const :tag "Off (nil)" :value nil)
+ (const :tag "On (t)" :value t)
+ (const :tag "Auto-raise" :value auto-raise)) "26.1")
;; fontset.c
;; FIXME nil is the initial value, fontset.el setqs it.
(vertical-centering-font-regexp display
(defun handle-delete-frame (event)
"Handle delete-frame events from the X server."
(interactive "e")
- (let ((frame (posn-window (event-start event)))
- (i 0)
- (tail (frame-list)))
- (while tail
- (and (frame-visible-p (car tail))
- (not (eq (car tail) frame))
- (setq i (1+ i)))
- (setq tail (cdr tail)))
- (if (> i 0)
+ (let* ((frame (posn-window (event-start event))))
+ (if (catch 'other-frame
+ (dolist (frame-1 (frame-list))
+ ;; A valid "other" frame is visible, owns its minibuffer
+ ;; window, has its `delete-before' parameter unset and is
+ ;; not a child frame.
+ (when (and (not (eq frame-1 frame))
+ (frame-visible-p frame-1)
+ (window-live-p (minibuffer-window frame-1))
+ (eq (window-frame (minibuffer-window frame-1)) frame-1)
+ (not (frame-parent frame-1))
+ (not (frame-parameter frame-1 'delete-before)))
+ (throw 'other-frame t))))
(delete-frame frame t)
;; Gildea@x.org says it is ok to ask questions before terminating.
(save-buffers-kill-emacs))))
This command selects the frame ARG steps away in that order.
A negative ARG moves in the opposite order.
-To make this command work properly, you must tell Emacs
-how the system (or the window manager) generally handles
-focus-switching between windows. If moving the mouse onto a window
-selects it (gives it focus), set `focus-follows-mouse' to t.
-Otherwise, that variable should be nil."
+To make this command work properly, you must tell Emacs how the
+system (or the window manager) generally handles focus-switching
+between windows. If moving the mouse onto a window selects
+it (gives it focus), set `focus-follows-mouse' to t. Otherwise,
+that variable should be nil."
(interactive "p")
- (let ((frame (selected-frame)))
+ (let ((sframe (selected-frame))
+ (frame (selected-frame)))
(while (> arg 0)
(setq frame (next-frame frame))
- (while (not (eq (frame-visible-p frame) t))
+ (while (and (not (eq frame sframe))
+ (not (eq (frame-visible-p frame) t)))
(setq frame (next-frame frame)))
(setq arg (1- arg)))
(while (< arg 0)
(setq frame (previous-frame frame))
- (while (not (eq (frame-visible-p frame) t))
+ (while (and (not (eq frame sframe))
+ (not (eq (frame-visible-p frame) t)))
(setq frame (previous-frame frame)))
(setq arg (1+ arg)))
(select-frame-set-input-focus frame)))
'(outer-position 0 . 0)
(cons 'outer-size (cons (frame-width frame) (frame-height frame)))
'(external-border-size 0 . 0)
+ '(outer-border-width . 0)
'(title-bar-size 0 . 0)
'(menu-bar-external . nil)
(let ((menu-bar-lines (frame-parameter frame 'menu-bar-lines)))
for frames = (cdr (assq 'frames attributes))
if (memq frame frames) return attributes))
+(declare-function x-frame-list-z-order "xfns.c" (&optional display))
+(declare-function w32-frame-list-z-order "w32fns.c" (&optional display))
+
+(defun frame-list-z-order (&optional display)
+ "Return list of Emacs' frames, in Z (stacking) order.
+The optional argument DISPLAY specifies which display to poll.
+DISPLAY should be either a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display.
+
+Frames are listed from topmost (first) to bottommost (last). As
+a special case, if DISPLAY is non-nil and specifies a live frame,
+return the child frames of that frame in Z (stacking) order.
+
+Return nil if DISPLAY contains no Emacs frame."
+ (let ((frame-type (framep-on-display display)))
+ (cond
+ ((eq frame-type 'x)
+ (x-frame-list-z-order display))
+ ((eq frame-type 'w32)
+ (w32-frame-list-z-order display)))))
+
+(declare-function x-frame-restack "xfns.c" (frame1 frame2 &optional above))
+(declare-function w32-frame-restack "w32fns.c" (frame1 frame2 &optional above))
+
+(defun frame-restack (frame1 frame2 &optional above)
+ "Restack FRAME1 below FRAME2.
+This implies that if both frames are visible and the display
+areas of these frames overlap, FRAME2 will (partially) obscure
+FRAME1. If the optional third argument ABOVE is non-nil, restack
+FRAME1 above FRAME2. This means that if both frames are visible
+and the display areas of these frames overlap, FRAME1 will
+\(partially) obscure FRAME2.
+
+This may be thought of as an atomic action performed in two
+steps: The first step removes FRAME1's window-system window from
+the display. The second step reinserts FRAME1's window
+below (above if ABOVE is true) that of FRAME2. Hence the
+position of FRAME2 in its display's Z (stacking) order relative
+to all other frames excluding FRAME1 remains unaltered.
+
+Some window managers may refuse to restack windows. "
+ (if (and (frame-live-p frame1)
+ (frame-live-p frame2)
+ (equal (frame-parameter frame1 'display)
+ (frame-parameter frame2 'display)))
+ (let ((frame-type (framep-on-display frame1)))
+ (cond
+ ((eq frame-type 'x)
+ (x-frame-restack frame1 frame2 above))
+ ((eq frame-type 'w32)
+ (w32-frame-restack frame1 frame2 above))))
+ (error "Cannot restack frames")))
+
(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
where the value is a cons with car `+', not numeric.
SPEC is a frame geometry spec: (left . VALUE) or (top . VALUE).
If VALUE is a number, then it is converted to a cons value, perhaps
- relative to the opposite frame edge from that in the original spec.
+relative to the opposite frame edge from that in the original spec.
FRAME defaults to the selected frame.
Examples (measures in pixels) -
(defun delete-other-frames (&optional frame)
"Delete all frames on FRAME's terminal, except FRAME.
If FRAME uses another frame's minibuffer, the minibuffer frame is
-left untouched. FRAME must be a live frame and defaults to the
-selected one."
+left untouched. Do not delete any of FRAME's child frames. If
+FRAME is a child frame, delete its siblings only. FRAME must be
+a live frame and defaults to the selected one."
(interactive)
(setq frame (window-normalize-frame frame))
(let ((minibuffer-frame (window-frame (minibuffer-window frame)))
(this (next-frame frame t))
+ (parent (frame-parent frame))
next)
;; In a first round consider minibuffer-less frames only.
(while (not (eq this frame))
(setq next (next-frame this t))
- (unless (eq (window-frame (minibuffer-window this)) this)
+ (unless (or (eq (window-frame (minibuffer-window this)) this)
+ ;; When FRAME is a child frame, delete its siblings
+ ;; only.
+ (and parent (not (eq (frame-parent this) parent)))
+ ;; Do not delete a child frame of FRAME.
+ (eq (frame-parent this) frame))
(delete-frame this))
(setq this next))
;; In a second round consider all remaining frames.
(setq this (next-frame frame t))
(while (not (eq this frame))
(setq next (next-frame this t))
- (unless (eq this minibuffer-frame)
+ (unless (or (eq this minibuffer-frame)
+ ;; When FRAME is a child frame, delete its siblings
+ ;; only.
+ (and parent (not (eq (frame-parent this) parent)))
+ ;; Do not delete a child frame of FRAME.
+ (eq (frame-parent this) frame))
(delete-frame this))
(setq this next))))
(buffer-list . :never)
(buffer-predicate . :never)
(buried-buffer-list . :never)
+ (delete-before . :never)
(font . frameset-filter-shelve-param)
(foreground-color . frameset-filter-sanitize-color)
(fullscreen . frameset-filter-shelve-param)
(GUI:width . frameset-filter-unshelve-param)
(height . frameset-filter-shelve-param)
(outer-window-id . :never)
+ (parent-frame . :never)
(parent-id . :never)
+ (mouse-wheel-frame . :never)
(tty . frameset-filter-tty-to-GUI)
(tty-type . frameset-filter-tty-to-GUI)
(width . frameset-filter-shelve-param)
\f
;; Saving framesets
-(defun frameset--record-minibuffer-relationships (frame-list)
- "Process FRAME-LIST and record minibuffer relationships.
-FRAME-LIST is a list of frames. Internal use only."
+(defun frameset--record-relationships (frame-list)
+ "Process FRAME-LIST and record relationships.
+FRAME-LIST is a list of frames.
+
+The relationships recorded for each frame are
+
+- `minibuffer' via `frameset--mini'
+- `delete-before' via `frameset--delete-before'
+- `parent-frame' via `frameset--parent-frame'
+- `mouse-wheel-frame' via `frameset--mouse-wheel-frame'
+
+Internal use only."
;; Record frames with their own minibuffer
(dolist (frame (minibuffer-frame-list))
(when (memq frame frame-list)
(set-frame-parameter frame
'frameset--mini
(cons t (eq frame default-minibuffer-frame)))))
- ;; Now link minibufferless frames with their minibuffer frames
+ ;; Now link minibufferless frames with their minibuffer frames and
+ ;; store `parent-frame', `delete-before' and `mouse-wheel-frame'
+ ;; relationships in a similar way.
(dolist (frame frame-list)
- (unless (frame-parameter frame 'frameset--mini)
- (frameset--set-id frame)
- (let ((mb-frame (window-frame (minibuffer-window frame))))
- ;; For minibufferless frames, frameset--mini is a cons
- ;; (nil . FRAME-ID), where FRAME-ID is the frameset--id of
- ;; the frame containing its minibuffer window.
- ;; FRAME-ID can be set to nil, if FRAME-LIST doesn't contain
- ;; the minibuffer frame of a minibufferless frame; we allow
- ;; it without trying to second-guess the user.
- (set-frame-parameter frame
- 'frameset--mini
- (cons nil
- (and mb-frame
- (frameset-frame-id mb-frame))))))))
+ (let ((parent-frame (frame-parent frame))
+ (delete-before (frame-parameter frame 'delete-before))
+ (mouse-wheel-frame (frame-parameter frame 'mouse-wheel-frame))
+ (nomini (not (frame-parameter frame 'frameset--mini))))
+ (when (or nomini parent-frame delete-before mouse-wheel-frame)
+ (when nomini
+ (frameset--set-id frame))
+ (when parent-frame
+ (set-frame-parameter
+ frame 'frameset--parent-frame (frameset-frame-id parent-frame)))
+ (when delete-before
+ (set-frame-parameter
+ frame 'frameset--delete-before (frameset-frame-id delete-before)))
+ (when mouse-wheel-frame
+ (set-frame-parameter
+ frame 'frameset--mouse-wheel-frame
+ (frameset-frame-id mouse-wheel-frame)))
+ (when nomini
+ (let ((mb-frame (window-frame (minibuffer-window frame))))
+ ;; For minibufferless frames, frameset--mini is a cons
+ ;; (nil . FRAME-ID), where FRAME-ID is the frameset--id of
+ ;; the frame containing its minibuffer window.
+ ;; FRAME-ID can be set to nil, if FRAME-LIST doesn't contain
+ ;; the minibuffer frame of a minibufferless frame; we allow
+ ;; it without trying to second-guess the user.
+ (set-frame-parameter
+ frame
+ 'frameset--mini
+ (cons nil
+ (and mb-frame
+ (frameset-frame-id mb-frame))))))))))
;;;###autoload
(cl-defun frameset-save (frame-list
(cl-delete-if-not predicate list)
list)))
fs)
- (frameset--record-minibuffer-relationships frames)
+ (frameset--record-relationships frames)
(setq fs (frameset--make
:app app
:name name
(frameset--initial-params filtered-cfg))))
(puthash frame :created frameset--action-map))
+ ;; Try to assign parent-frame right here - it will improve things
+ ;; for minibuffer-less child frames.
+ (let* ((frame-id (frame-parameter frame 'frameset--parent-frame))
+ (parent-frame
+ (and frame-id (frameset-frame-with-id frame-id))))
+ (when (frame-live-p parent-frame)
+ (set-frame-parameter frame 'parent-frame parent-frame)))
+
(modify-frame-parameters frame
(if (eq (frame-parameter frame 'fullscreen) fullscreen)
;; Workaround for bug#14949
(error
(delay-warning 'frameset (error-message-string err) :error))))))
+ ;; Setting the parent frame after the frame has been created is a
+ ;; pain because one can see the frame move on the screen. Ideally,
+ ;; we would restore minibuffer equipped child frames after their
+ ;; respective parents have been made but this might interfere with
+ ;; the reordering of minibuffer frames. Left to the experts ...
+ (dolist (frame (frame-list))
+ (let* ((frame-id (frame-parameter frame 'frameset--parent-frame))
+ (parent-frame
+ (and frame-id (frameset-frame-with-id frame-id))))
+ (when (and (not (eq (frame-parameter frame 'parent-frame) parent-frame))
+ (frame-live-p parent-frame))
+ (set-frame-parameter frame 'parent-frame parent-frame)))
+ (let* ((frame-id (frame-parameter frame 'frameset--delete-before))
+ (delete-before
+ (and frame-id (frameset-frame-with-id frame-id))))
+ (when (frame-live-p delete-before)
+ (set-frame-parameter frame 'delete-before delete-before)))
+ (let* ((frame-id (frame-parameter frame 'frameset--mouse-wheel-frame))
+ (mouse-wheel-frame
+ (and frame-id (frameset-frame-with-id frame-id))))
+ (when (frame-live-p mouse-wheel-frame)
+ (set-frame-parameter frame 'mouse-wheel-frame mouse-wheel-frame))))
+
;; In case we try to delete the initial frame, we want to make sure that
;; other frames are already visible (discussed in thread for bug#14841).
(sit-for 0 t)
This should be bound only to mouse buttons 4 and 5 on non-Windows
systems."
(interactive (list last-input-event))
- (let* ((curwin (if mouse-wheel-follow-mouse
- (prog1
- (selected-window)
- (select-window (mwheel-event-window event)))))
- (buffer (window-buffer curwin))
- (opoint (with-current-buffer buffer
- (when (eq (car-safe transient-mark-mode) 'only)
- (point))))
+ (let* ((selected-window (selected-window))
+ (scroll-window
+ (or (catch 'found
+ (let* ((window (if mouse-wheel-follow-mouse
+ (mwheel-event-window event)
+ (selected-window)))
+ (frame (when (window-live-p window)
+ (frame-parameter
+ (window-frame window) 'mouse-wheel-frame))))
+ (when (frame-live-p frame)
+ (let* ((pos (mouse-absolute-pixel-position))
+ (pos-x (car pos))
+ (pos-y (cdr pos)))
+ (walk-window-tree
+ (lambda (window-1)
+ (let ((edges (window-edges window-1 nil t t)))
+ (when (and (<= (nth 0 edges) pos-x)
+ (<= pos-x (nth 2 edges))
+ (<= (nth 1 edges) pos-y)
+ (<= pos-y (nth 3 edges)))
+ (throw 'found window-1))))
+ frame nil t)))))
+ (mwheel-event-window event)))
+ (old-point
+ (and (eq scroll-window selected-window)
+ (eq (car-safe transient-mark-mode) 'only)
+ (window-point)))
(mods
(delq 'click (delq 'double (delq 'triple (event-modifiers event)))))
(amt (assoc mods mouse-wheel-scroll-amount)))
;; Make sure we do indeed scroll to the end of the buffer.
(end-of-buffer (while t (funcall mwheel-scroll-up-function)))))
(t (error "Bad binding in mwheel-scroll"))))
- (if curwin (select-window curwin)))
- ;; If there is a temporarily active region, deactivate it if
- ;; scrolling moves point.
- (when opoint
- (with-current-buffer buffer
- (when (/= opoint (point))
- ;; Call `deactivate-mark' at the original position, so that
- ;; the original region is saved to the X selection.
- (let ((newpoint (point)))
- (goto-char opoint)
- (deactivate-mark)
- (goto-char newpoint))))))
+ (if (eq scroll-window selected-window)
+ ;; If there is a temporarily active region, deactivate it if
+ ;; scrolling moved point.
+ (when (and old-point (/= old-point (window-point)))
+ ;; Call `deactivate-mark' at the original position, so that
+ ;; the original region is saved to the X selection.
+ (let ((new-point (window-point)))
+ (goto-char old-point)
+ (deactivate-mark)
+ (goto-char new-point)))
+ (select-window selected-window t))))
+
(when (and mouse-wheel-click-event mouse-wheel-inhibit-click-time)
(if mwheel-inhibit-click-event-timer
(cancel-timer mwheel-inhibit-click-event-timer)
(window-normalize-window window) horizontal ignore pixelwise))
(defun window--min-size-ignore-p (window ignore)
- "Return non-nil if IGNORE says to ignore height restrictions for WINDOW."
+ "Return non-nil if IGNORE says to ignore size restrictions for WINDOW."
(if (window-valid-p ignore)
(eq window ignore)
(not (memq ignore '(nil preserved)))))
If the mouse position has stabilized in a non-selected window, select
that window. The minibuffer window is selected only if the minibuffer
is active. This function is run by `mouse-autoselect-window-timer'."
- (ignore-errors
- (let* ((mouse-position (mouse-position))
- (window
- (ignore-errors
- (window-at (cadr mouse-position) (cddr mouse-position)
- (car mouse-position)))))
- (cond
+ (let* ((mouse-position (mouse-position))
+ (mouse-x (and (numberp (cadr mouse-position))
+ (cadr mouse-position)))
+ (mouse-y (and (numberp (cddr mouse-position))
+ (cddr mouse-position)))
+ (frame (and mouse-x mouse-y (car mouse-position)))
+ (window (and frame (window-at mouse-x mouse-y frame))))
+ (cond
((or (and (fboundp 'menu-or-popup-active-p) (menu-or-popup-active-p))
(and window
(let ((coords (coordinates-in-window-p
;; text region of WINDOW: Suspend autoselection temporarily.
(mouse-autoselect-window-start mouse-position nil t))
((or (eq mouse-autoselect-window-state 'suspend)
- ;; When the mouse is at its first recorded position, restart
- ;; delayed autoselection. This works around a scenario with
- ;; two two-window frames with identical dimensions: select the
- ;; first window of the first frame, switch to the second
- ;; frame, move the mouse to its second window, minimize the
- ;; second frame. Now the second window of the first frame
- ;; gets selected although the mouse never really "moved" into
- ;; that window.
- (and (numberp mouse-autoselect-window)
- (equal (mouse-position) mouse-autoselect-window-position-1)))
- ;; Delayed autoselection was temporarily suspended, reenable it.
- (mouse-autoselect-window-start mouse-position))
- ((and window (not (eq window (selected-window)))
- (or (not (numberp mouse-autoselect-window))
- (and (>= mouse-autoselect-window 0)
- ;; If `mouse-autoselect-window' is non-negative,
- ;; select window if it's the same as before.
- (eq window mouse-autoselect-window-window))
- ;; Otherwise select window iff the mouse is at the same
- ;; position as before. Observe that the first test
- ;; after starting autoselection usually fails since the
- ;; value of `mouse-autoselect-window-position' recorded
- ;; there is the position where the mouse has entered the
- ;; new window and not necessarily where the mouse has
- ;; stopped moving.
- (equal mouse-position mouse-autoselect-window-position))
- ;; The minibuffer is a candidate window if it's active.
- (or (not (window-minibuffer-p window))
- (eq window (active-minibuffer-window))))
- ;; Mouse position has stabilized in non-selected window: Cancel
- ;; delayed autoselection and try to select that window.
- (mouse-autoselect-window-cancel t)
- ;; Select window where mouse appears unless the selected window is the
- ;; minibuffer. Use `unread-command-events' in order to execute pre-
- ;; and post-command hooks and trigger idle timers. To avoid delaying
- ;; autoselection again, set `mouse-autoselect-window-state'."
- (unless (window-minibuffer-p)
- (setq mouse-autoselect-window-state 'select)
- (setq unread-command-events
- (cons (list 'select-window (list window))
- unread-command-events))))
- ((or (and window (eq window (selected-window)))
- (not (numberp mouse-autoselect-window))
- (equal mouse-position mouse-autoselect-window-position))
- ;; Mouse position has either stabilized in the selected window or at
- ;; `mouse-autoselect-window-position': Cancel delayed autoselection.
- (mouse-autoselect-window-cancel t))
- (t
- ;; Mouse position has not stabilized yet, resume delayed
- ;; autoselection.
- (mouse-autoselect-window-start mouse-position window))))))
+ ;; When the mouse is at its first recorded position, restart
+ ;; delayed autoselection. This works around a scenario with
+ ;; two two-window frames with identical dimensions: select the
+ ;; first window of the first frame, switch to the second
+ ;; frame, move the mouse to its second window, minimize the
+ ;; second frame. Now the second window of the first frame
+ ;; gets selected although the mouse never really "moved" into
+ ;; that window.
+ (and (numberp mouse-autoselect-window)
+ (equal (mouse-position) mouse-autoselect-window-position-1)))
+ ;; Delayed autoselection was temporarily suspended, reenable it.
+ (mouse-autoselect-window-start mouse-position))
+ ((and window
+ (or (not (numberp mouse-autoselect-window))
+ (and (>= mouse-autoselect-window 0)
+ ;; If `mouse-autoselect-window' is non-negative,
+ ;; select window if it's the same as before.
+ (eq window mouse-autoselect-window-window))
+ ;; Otherwise select window iff the mouse is at the same
+ ;; position as before. Observe that the first test
+ ;; after starting autoselection usually fails since the
+ ;; value of `mouse-autoselect-window-position' recorded
+ ;; there is the position where the mouse has entered the
+ ;; new window and not necessarily where the mouse has
+ ;; stopped moving.
+ (equal mouse-position mouse-autoselect-window-position))
+ ;; The minibuffer is a candidate window if it's active.
+ (or (not (window-minibuffer-p window))
+ (eq window (active-minibuffer-window))))
+ ;; Mouse position has stabilized in non-selected window: Cancel
+ ;; delayed autoselection and try to select that window.
+ (mouse-autoselect-window-cancel t)
+ ;; Use `unread-command-events' in order to execute pre- and
+ ;; post-command hooks and trigger idle timers. To avoid delaying
+ ;; autoselection again, set `mouse-autoselect-window-state'."
+ (setq mouse-autoselect-window-state 'select)
+ (setq unread-command-events
+ (cons (list 'select-window (list window))
+ unread-command-events)))
+ ((or (not (numberp mouse-autoselect-window))
+ (equal mouse-position mouse-autoselect-window-position))
+ ;; Mouse position has stabilized at
+ ;; `mouse-autoselect-window-position': Cancel delayed
+ ;; autoselection.
+ (mouse-autoselect-window-cancel t))
+ (window
+ ;; Mouse position has not stabilized yet, resume delayed
+ ;; autoselection.
+ (mouse-autoselect-window-start mouse-position window)))))
(defun handle-select-window (event)
"Handle select-window events."
(interactive "^e")
- (let ((window (posn-window (event-start event))))
+ (let* ((window (posn-window (event-start event)))
+ (frame (and (window-live-p window) (window-frame window)))
+ (old-frame (selected-frame)))
(unless (or (not (window-live-p window))
- ;; Don't switch if we're currently in the minibuffer.
- ;; This tries to work around problems where the
- ;; minibuffer gets unselected unexpectedly, and where
- ;; you then have to move your mouse all the way down to
- ;; the minibuffer to select it.
- (window-minibuffer-p)
- ;; Don't switch to minibuffer window unless it's active.
- (and (window-minibuffer-p window)
- (not (minibuffer-window-active-p window)))
;; Don't switch when autoselection shall be delayed.
(and (numberp mouse-autoselect-window)
(not (eq mouse-autoselect-window-state 'select))
(mouse-autoselect-window-start position window)
;; Executing a command cancels delayed autoselection.
(add-hook
- 'pre-command-hook 'mouse-autoselect-window-cancel))))
- (when mouse-autoselect-window
- ;; Reset state of delayed autoselection.
- (setq mouse-autoselect-window-state nil)
- ;; Run `mouse-leave-buffer-hook' when autoselecting window.
- (run-hooks 'mouse-leave-buffer-hook))
+ 'pre-command-hook 'mouse-autoselect-window-cancel)))
+ ;; Don't switch to a `no-accept-focus' frame unless it's
+ ;; already selected.
+ (and (not (eq frame (selected-frame)))
+ (frame-parameter frame 'no-accept-focus))
+ ;; Don't switch to minibuffer window unless it's active.
+ (and (window-minibuffer-p window)
+ (not (minibuffer-window-active-p window))))
+ ;; Reset state of delayed autoselection.
+ (setq mouse-autoselect-window-state nil)
+ ;; Run `mouse-leave-buffer-hook' when autoselecting window.
+ (run-hooks 'mouse-leave-buffer-hook)
;; Clear echo area.
(message nil)
- (select-window window))))
+ ;; Select the window before giving the frame focus since otherwise
+ ;; we might get two windows with an active cursor.
+ (select-window window)
+ (cond
+ ((or (not (memq (window-system frame) '(x w32 ns)))
+ (not focus-follows-mouse)
+ ;; Focus FRAME if it's either a child frame or an ancestor
+ ;; of the frame switched from.
+ (and (not (frame-parameter frame 'parent-frame))
+ (not (frame-ancestor-p frame old-frame)))))
+ ((eq focus-follows-mouse 'auto-raise)
+ ;; Focus and auto-raise frame.
+ (x-focus-frame frame)
+ ;; This doesn't seem to work when we move from a normal frame
+ ;; right into the child frame of another frame - we should raise
+ ;; that child frame's ancestor frame first ...
+ (raise-frame frame))
+ (t
+ ;; Just focus frame.
+ (x-focus-frame frame))))))
(defun truncated-partial-width-window-p (&optional window)
"Return non-nil if lines in WINDOW are specifically truncated due to its width.
return make_number (0);
}
+/**
+ * frame_windows_min_size:
+ *
+ * Return the minimum number of lines (columns if HORIZONTAL is non-nil)
+ * of FRAME. If PIXELWISE is non-nil, return the minimum height (width)
+ * in pixels.
+ *
+ * This value is calculated by the function `frame-windows-min-size' in
+ * window.el unless the `min-height' (`min-width' if HORIZONTAL is
+ * non-nil) parameter of FRAME is non-nil thus explicitly specifying the
+ * value to be returned. In that latter case IGNORE is ignored.
+ *
+ * If `frame-windows-min-size' is called, it will make sure that the
+ * return value accomodates all windows of FRAME respecting the values
+ * of `window-min-height' (`window-min-width' if HORIZONTAL is non-nil).
+ * With IGNORE non-nil the values of these variables are ignored.
+ *
+ * In either case never return a value less than 1.
+ */
static int
frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal,
Lisp_Object ignore, Lisp_Object pixelwise)
{
- return XINT (call4 (Qframe_windows_min_size, frame, horizontal,
+ struct frame *f = XFRAME (frame);
+ Lisp_Object par_size;
+
+ if ((!NILP (horizontal)
+ && NUMBERP (par_size = get_frame_param (f, Qmin_width)))
+ || (NILP (horizontal)
+ && NUMBERP (par_size = get_frame_param (f, Qmin_height))))
+ {
+ int min_size = XINT (par_size);
+
+ /* Don't allow phantom frames. */
+ if (min_size < 1)
+ min_size = 1;
+
+ return (NILP (pixelwise)
+ ? min_size
+ : min_size * (NILP (horizontal)
+ ? FRAME_LINE_HEIGHT (f)
+ : FRAME_COLUMN_WIDTH (f)));
+ }
+ else
+ return XINT (call4 (Qframe_windows_min_size, frame, horizontal,
ignore, pixelwise));
}
f->vertical_scroll_bar_type = vertical_scroll_bar_none;
f->horizontal_scroll_bars = false;
f->want_fullscreen = FULLSCREEN_NONE;
+#if ! defined (HAVE_NS)
+ f->undecorated = false;
+#ifndef HAVE_NTGUI
+ f->override_redirect = false;
+#endif
+ f->skip_taskbar = false;
+ f->no_focus_on_map = false;
+ f->no_accept_focus = false;
+ f->z_group = z_group_none;
+#endif
#if ! defined (USE_GTK) && ! defined (HAVE_NS)
f->last_tool_bar_item = -1;
#endif
(select-window (frame-root-window (new-frame))) doesn't end up
with your typing being interpreted in the new frame instead of
the one you're actually typing in. */
- internal_last_event_frame = Qnil;
+#ifdef HAVE_WINDOW_SYSTEM
+ if (!frame_ancestor_p (f, sf))
+#endif
+ internal_last_event_frame = Qnil;
return frame;
}
return frames;
}
+DEFUN ("frame-parent", Fframe_parent, Sframe_parent,
+ 0, 1, 0,
+ doc: /* Return the parent frame of FRAME.
+The parent frame of FRAME is the Emacs frame whose window-system window
+is the parent window of FRAME's window-system window. When such a frame
+exists, FRAME is considered a child frame of that frame.
+
+Return nil if FRAME has no parent frame. This means that FRAME's
+window-system window is either a "top-level" window (a window whose
+parent window is the window-system's root window) or an embedded window
+\(a window whose parent window is owned by some other application). */)
+ (Lisp_Object frame)
+{
+ struct frame *f = decode_live_frame (frame);
+ struct frame *p = FRAME_PARENT_FRAME (f);
+ Lisp_Object parent;
+
+ /* Can't return f->parent_frame directly since it might not be defined
+ for this platform. */
+ if (p)
+ {
+ XSETFRAME (parent, p);
+
+ return parent;
+ }
+ else
+ return Qnil;
+}
+
+#ifdef HAVE_WINDOW_SYSTEM
+bool
+frame_ancestor_p (struct frame *af, struct frame *df)
+{
+ struct frame *pf = FRAME_PARENT_FRAME (df);
+
+ while (pf)
+ {
+ if (pf == af)
+ return true;
+ else
+ pf = FRAME_PARENT_FRAME (pf);
+ }
+
+ return false;
+}
+#endif
+
+DEFUN ("frame-ancestor-p", Fframe_ancestor_p, Sframe_ancestor_p,
+ 2, 2, 0,
+ doc: /* Return non-nil if ANCESTOR is an ancestor of DESCENDANT.
+ANCESTOR is an ancestor of DESCENDANT when it is either DESCENDANT's
+parent frame or it is an ancestor of DESCENDANT's parent frame. Both,
+ANCESTOR and DESCENDANT must be live frames and default to the selected
+frame. */)
+ (Lisp_Object ancestor, Lisp_Object descendant)
+{
+#ifdef HAVE_WINDOW_SYSTEM
+ struct frame *af = decode_live_frame (ancestor);
+ struct frame *df = decode_live_frame (descendant);
+
+ return frame_ancestor_p (af, df) ? Qt : Qnil;
+#else
+ return Qnil;
+#endif
+ }
+
/* Return CANDIDATE if it can be used as 'other-than-FRAME' frame on the
same tty (for tty frames) or among frames which uses FRAME's keyboard.
If MINIBUF is nil, do not consider minibuffer-only candidate.
|| (FRAME_TERMCAP_P (c) && FRAME_TERMCAP_P (f)
&& FRAME_TTY (c) == FRAME_TTY (f)))
{
- if (NILP (minibuf))
+ if (!NILP (get_frame_param (c, Qno_other_frame)))
+ return Qnil;
+ else if (NILP (minibuf))
{
if (!FRAME_MINIBUF_ONLY_P (c))
return candidate;
return frame;
}
\f
-/* Return 1 if it is ok to delete frame F;
- 0 if all frames aside from F are invisible.
- (Exception: if F is the terminal frame, and we are using X, return 1.) */
+/**
+ * other_frames:
+ *
+ * Return true if there exists at least one visible or iconified frame
+ * but F. Return false otherwise.
+ *
+ * Always return false when all remaining frames are either tooltip or
+ * child frames or frames with a non-nil `delete-before' parameter. If
+ * INVISIBLE is false, also return false when the minibuffer window of
+ * all remaining frames is on F.
+
+ * If F is the terminal frame and we are using X, return true if at
+ * least one X frame exists. */
+static bool
+other_frames (struct frame *f, bool invisible)
+{
+ Lisp_Object frames, frame, frame1;
+ struct frame *f1;
+ Lisp_Object minibuffer_window = FRAME_MINIBUF_WINDOW (f);
-static int
-other_visible_frames (struct frame *f)
-{
- Lisp_Object frames, this;
+ XSETFRAME (frame, f);
+ if (WINDOWP (minibuffer_window)
+ && !EQ (frame, WINDOW_FRAME (XWINDOW (minibuffer_window))))
+ minibuffer_window = Qnil;
- FOR_EACH_FRAME (frames, this)
+ FOR_EACH_FRAME (frames, frame1)
{
- if (f == XFRAME (this))
- continue;
-
- /* Verify that we can still talk to the frame's X window,
- and note any recent change in visibility. */
+ f1 = XFRAME (frame1);
+ if (f != f1)
+ {
+ /* Verify that we can still talk to the frame's X window, and
+ note any recent change in visibility. */
#ifdef HAVE_X_WINDOWS
- if (FRAME_WINDOW_P (XFRAME (this)))
- x_sync (XFRAME (this));
+ if (FRAME_WINDOW_P (f1))
+ x_sync (f1);
#endif
-
- if (FRAME_VISIBLE_P (XFRAME (this))
- || FRAME_ICONIFIED_P (XFRAME (this))
- /* Allow deleting the terminal frame when at least one X
- frame exists. */
- || (FRAME_WINDOW_P (XFRAME (this)) && !FRAME_WINDOW_P (f)))
- return 1;
+ if (NILP (Fframe_parameter (frame1, Qtooltip))
+ /* Tooltips and child frames don't count. */
+ && !FRAME_PARENT_FRAME (f1)
+ /* Frames with a non-nil `delete-before' parameter don't
+ count - either they depend on us or they depend on a
+ frame that we will have to find right here. */
+ && NILP (get_frame_param (f1, Qdelete_before))
+ /* Frames whose minibuffer window is on F don't count
+ unless INVISIBLE is set - in that case F is either made
+ invisible and may be autoraised from such a frame or
+ the FORCE argument of delete_frame was non-nil. */
+ && (invisible || NILP (minibuffer_window)
+ || !EQ (FRAME_MINIBUF_WINDOW (f1), minibuffer_window))
+ /* At least one visible/iconified frame must remain. */
+ && (FRAME_VISIBLE_P (f1) || FRAME_ICONIFIED_P (f1)
+ /* Allow deleting the terminal frame when at least one
+ X frame exists. */
+ || (FRAME_WINDOW_P (f1) && !FRAME_WINDOW_P (f))))
+ return true;
+ }
}
- return 0;
+
+ return false;
}
/* Make sure that minibuf_window doesn't refer to FRAME's minibuffer
}
-/* Delete FRAME. When FORCE equals Qnoelisp, delete FRAME
- unconditionally. x_connection_closed and delete_terminal use
- this. Any other value of FORCE implements the semantics
- described for Fdelete_frame. */
+/**
+ * delete_frame:
+ *
+ * Delete FRAME. When FORCE equals Qnoelisp, delete FRAME
+ * unconditionally. x_connection_closed and delete_terminal use this.
+ * Any other value of FORCE implements the semantics described for
+ * Fdelete_frame. */
Lisp_Object
delete_frame (Lisp_Object frame, Lisp_Object force)
{
struct frame *f = decode_any_frame (frame);
struct frame *sf;
struct kboard *kb;
-
+ Lisp_Object frames, frame1;
int minibuffer_selected, is_tooltip_frame;
+ bool nochild = !FRAME_PARENT_FRAME (f);
- if (! FRAME_LIVE_P (f))
+ if (!FRAME_LIVE_P (f))
return Qnil;
-
- if (NILP (force) && !other_visible_frames (f))
- error ("Attempt to delete the sole visible or iconified frame");
-
- /* x_connection_closed must have set FORCE to `noelisp' in order
- to delete the last frame, if it is gone. */
- if (NILP (XCDR (Vframe_list)) && !EQ (force, Qnoelisp))
- error ("Attempt to delete the only frame");
+ else if (!EQ (force, Qnoelisp) && !other_frames (f, !NILP (force)))
+ {
+ if (NILP (force))
+ error ("Attempt to delete the sole visible or iconified frame");
+ else
+ error ("Attempt to delete the only frame");
+ }
XSETFRAME (frame, f);
+ /* Softly delete all frames with this frame as their parent frame or
+ as their `delete-before' frame parameter value. */
+ FOR_EACH_FRAME (frames, frame1)
+ if (FRAME_PARENT_FRAME (XFRAME (frame1)) == f
+ /* Process `delete-before' parameter iff FRAME is not a child
+ frame. This avoids that we enter an infinite chain of mixed
+ dependencies. */
+ || (nochild
+ && EQ (get_frame_param (XFRAME (frame1), Qdelete_before), frame)))
+ delete_frame (frame1, Qnil);
+
/* Does this frame have a minibuffer, and is it the surrogate
minibuffer for any other frame? */
if (FRAME_HAS_MINIBUF_P (f))
{
- Lisp_Object frames, this;
-
- FOR_EACH_FRAME (frames, this)
+ FOR_EACH_FRAME (frames, frame1)
{
Lisp_Object fminiw;
- if (EQ (this, frame))
+ if (EQ (frame1, frame))
continue;
- fminiw = FRAME_MINIBUF_WINDOW (XFRAME (this));
+ fminiw = FRAME_MINIBUF_WINDOW (XFRAME (frame1));
if (WINDOWP (fminiw) && EQ (frame, WINDOW_FRAME (XWINDOW (fminiw))))
{
/* If we MUST delete this frame, delete the other first.
But do this only if FORCE equals `noelisp'. */
if (EQ (force, Qnoelisp))
- delete_frame (this, Qnoelisp);
+ delete_frame (frame1, Qnoelisp);
else
error ("Attempt to delete a surrogate minibuffer frame");
}
safe_call2 (Qrun_hook_with_args, Qdelete_frame_functions, frame);
}
- /* The hook may sometimes (indirectly) cause the frame to be deleted. */
- if (! FRAME_LIVE_P (f))
+ /* delete_frame_functions may have deleted any frame, including this
+ one. */
+ if (!FRAME_LIVE_P (f))
return Qnil;
+ else if (!EQ (force, Qnoelisp) && !other_frames (f, !NILP (force)))
+ {
+ if (NILP (force))
+ error ("Attempt to delete the sole visible or iconified frame");
+ else
+ error ("Attempt to delete the only frame");
+ }
/* At this point, we are committed to deleting the frame.
There is no more chance for errors to prevent it. */
-
minibuffer_selected = EQ (minibuf_window, selected_window);
sf = SELECTED_FRAME ();
/* Don't let the frame remain selected. */
if (f == sf)
{
Lisp_Object tail;
- Lisp_Object frame1 = Qnil;
/* Look for another visible frame on the same terminal.
Do not call next_frame here because it may loop forever.
another one. */
if (f == last_nonminibuf_frame)
{
- Lisp_Object frames, this;
-
last_nonminibuf_frame = 0;
- FOR_EACH_FRAME (frames, this)
+ FOR_EACH_FRAME (frames, frame1)
{
- f = XFRAME (this);
- if (!FRAME_MINIBUF_ONLY_P (f))
+ struct frame *f1 = XFRAME (frame1);
+
+ if (!FRAME_MINIBUF_ONLY_P (f1))
{
- last_nonminibuf_frame = f;
+ last_nonminibuf_frame = f1;
break;
}
}
single-kboard state if we're in it for this kboard. */
if (kb != NULL)
{
- Lisp_Object frames, this;
/* Some frame we found on the same kboard, or nil if there are none. */
Lisp_Object frame_on_same_kboard = Qnil;
- FOR_EACH_FRAME (frames, this)
- if (kb == FRAME_KBOARD (XFRAME (this)))
- frame_on_same_kboard = this;
+ FOR_EACH_FRAME (frames, frame1)
+ if (kb == FRAME_KBOARD (XFRAME (frame1)))
+ frame_on_same_kboard = frame1;
if (NILP (frame_on_same_kboard))
not_single_kboard_state (kb);
frames with other windows. */
if (kb != NULL && EQ (frame, KVAR (kb, Vdefault_minibuffer_frame)))
{
- Lisp_Object frames, this;
-
/* The last frame we saw with a minibuffer, minibuffer-only or not. */
Lisp_Object frame_with_minibuf = Qnil;
/* Some frame we found on the same kboard, or nil if there are none. */
Lisp_Object frame_on_same_kboard = Qnil;
- FOR_EACH_FRAME (frames, this)
+ FOR_EACH_FRAME (frames, frame1)
{
- struct frame *f1 = XFRAME (this);
+ struct frame *f1 = XFRAME (frame1);
/* Consider only frames on the same kboard
and only those with minibuffers. */
if (kb == FRAME_KBOARD (f1)
&& FRAME_HAS_MINIBUF_P (f1))
{
- frame_with_minibuf = this;
+ frame_with_minibuf = frame1;
if (FRAME_MINIBUF_ONLY_P (f1))
break;
}
if (kb == FRAME_KBOARD (f1))
- frame_on_same_kboard = this;
+ frame_on_same_kboard = frame1;
}
if (!NILP (frame_on_same_kboard))
{
struct frame *f = decode_live_frame (frame);
- if (NILP (force) && !other_visible_frames (f))
+ if (NILP (force) && !other_frames (f, true))
error ("Attempt to make invisible the sole visible or iconified frame");
/* Don't allow minibuf_window to remain on an invisible frame. */
}
}
+ /* Check these parameters for circular dependeny. This does not check
+ for interdependencies between these properties. Hence you can
+ still create circular dependencies with different properties, for
+ example a chain of frames F1->F2->...Fn such that F1 is an ancestor
+ frame of Fn and thus cannot be deleted before Fn and a second chain
+ Fn->Fn-1->...F1 such that Fn cannot be deleted before F1. */
+ else if (EQ (prop, Qparent_frame) || EQ (prop, Qdelete_before))
+ {
+ Lisp_Object oldval = Fcdr (Fassq (prop, f->param_alist));
+
+ if (!EQ (oldval, val) && !NILP (val))
+ {
+ Lisp_Object frame;
+ Lisp_Object frame1 = val;
+
+ if (!FRAMEP (frame1) || !FRAME_LIVE_P (XFRAME (frame1)))
+ error ("Invalid `%s' frame parameter",
+ SSDATA (SYMBOL_NAME (prop)));
+
+ XSETFRAME (frame, f);
+
+ while (FRAMEP (frame1) && FRAME_LIVE_P (XFRAME (frame1)))
+ if (EQ (frame1, frame))
+ error ("Circular specification of `%s' frame parameter",
+ SSDATA (SYMBOL_NAME (prop)));
+ else
+ frame1 = get_frame_param (XFRAME (frame1), prop);
+ }
+ }
+
/* The buffer-list parameters are stored in a special place and not
in the alist. All buffers must be live. */
- if (EQ (prop, Qbuffer_list))
+ else if (EQ (prop, Qbuffer_list))
{
Lisp_Object list = Qnil;
for (; CONSP (val); val = XCDR (val))
fset_buffer_list (f, Fnreverse (list));
return;
}
- if (EQ (prop, Qburied_buffer_list))
+ else if (EQ (prop, Qburied_buffer_list))
{
Lisp_Object list = Qnil;
for (; CONSP (val); val = XCDR (val))
{"sticky", SYMBOL_INDEX (Qsticky)},
{"tool-bar-position", SYMBOL_INDEX (Qtool_bar_position)},
{"inhibit-double-buffering", SYMBOL_INDEX (Qinhibit_double_buffering)},
+ {"undecorated", SYMBOL_INDEX (Qundecorated)},
+ {"parent-frame", SYMBOL_INDEX (Qparent_frame)},
+ {"skip-taskbar", SYMBOL_INDEX (Qskip_taskbar)},
+ {"no-focus-on-map", SYMBOL_INDEX (Qno_focus_on_map)},
+ {"no-accept-focus", SYMBOL_INDEX (Qno_accept_focus)},
+ {"z-group", SYMBOL_INDEX (Qz_group)},
+ {"override-redirect", SYMBOL_INDEX (Qoverride_redirect)},
};
#ifdef HAVE_WINDOW_SYSTEM
DEFSYM (Qheight, "height");
DEFSYM (Qicon, "icon");
DEFSYM (Qminibuffer, "minibuffer");
+ DEFSYM (Qundecorated, "undecorated");
+ DEFSYM (Qparent_frame, "parent-frame");
+ DEFSYM (Qskip_taskbar, "skip-taskbar");
+ DEFSYM (Qno_focus_on_map, "no-focus-on-map");
+ DEFSYM (Qno_accept_focus, "no-accept-focus");
+ DEFSYM (Qz_group, "z-group");
+ DEFSYM (Qoverride_redirect, "override-redirect");
+ DEFSYM (Qdelete_before, "delete-before");
DEFSYM (Qmodeline, "modeline");
DEFSYM (Qonly, "only");
DEFSYM (Qnone, "none");
DEFSYM (Qauto_raise, "auto-raise");
DEFSYM (Qborder_color, "border-color");
DEFSYM (Qborder_width, "border-width");
+ DEFSYM (Qouter_border_width, "outer-border-width");
DEFSYM (Qbottom_divider_width, "bottom-divider-width");
DEFSYM (Qcursor_color, "cursor-color");
DEFSYM (Qcursor_type, "cursor-type");
DEFSYM (Qvisibility, "visibility");
DEFSYM (Qwait_for_wm, "wait-for-wm");
DEFSYM (Qinhibit_double_buffering, "inhibit-double-buffering");
+ DEFSYM (Qno_other_frame, "no-other-frame");
+ DEFSYM (Qbelow, "below");
+ DEFSYM (Qabove_suspended, "above-suspended");
+ DEFSYM (Qmin_width, "min-width");
+ DEFSYM (Qmin_height, "min-height");
+ DEFSYM (Qmouse_wheel_frame, "mouse-wheel-frame");
{
int i;
This variable is local to the current terminal and cannot be buffer-local. */);
- DEFVAR_BOOL ("focus-follows-mouse", focus_follows_mouse,
+ DEFVAR_LISP ("focus-follows-mouse", focus_follows_mouse,
doc: /* Non-nil if window system changes focus when you move the mouse.
You should set this variable to tell Emacs how your window manager
handles focus, since there is no way in general for Emacs to find out
-automatically. See also `mouse-autoselect-window'. */);
- focus_follows_mouse = 0;
+automatically.
+
+There are three meaningful values:
+
+- The default nil should be used when your window manager follows a
+ "click-to-focus" policy where you have to click the mouse inside of a
+ frame in order for that frame to get focus.
+
+- The value t should be used when your window manager has the focus
+ automatically follow the position of the mouse pointer but a window
+ that gains focus is not raised automatically.
+
+- The value `auto-raise' should be used when your window manager has the
+ focus automatically follow the position of the mouse pointer and a
+ window that gains focus is raised automatically.
+
+If this option is non-nil, Emacs moves the mouse pointer to the frame
+selected by `select-frame-set-input-focus'. This function is used by a
+number of commands like, for example, `other-frame' and `pop-to-buffer'.
+If this option is nil and your focus follows mouse window manager does
+not autonomously move the mouse pointer to the newly selected frame, the
+previously selected window manager window might get reselected instead
+immediately.
+
+The distinction between the values t and `auto-raise' is not needed for
+"normal" frames because the window manager takes care of raising them.
+Setting this to `auto-raise' will, however, override the standard
+behavior of a window manager that does not automatically raise the frame
+that gets focus. Setting this to `auto-raise' is also necessary to
+automatically raise child frames which are usually left alone by the
+window manager.
+
+Note that this option does not distinguish "sloppy" focus (where the
+frame that previously had focus retains focus as long as the mouse
+pointer does not move into another window manager window) from "strict"
+focus (where a frame immediately loses focus when it's left by the mouse
+pointer).
+
+In order to extend a "focus follows mouse" policy to individual Emacs
+windows, customize the variable `mouse-autoselect-window'. */);
+ focus_follows_mouse = Qnil;
DEFVAR_BOOL ("frame-resize-pixelwise", frame_resize_pixelwise,
doc: /* Non-nil means resize frames pixelwise.
defsubr (&Sselect_frame);
defsubr (&Sselected_frame);
defsubr (&Sframe_list);
+ defsubr (&Sframe_parent);
+ defsubr (&Sframe_ancestor_p);
defsubr (&Snext_frame);
defsubr (&Sprevious_frame);
defsubr (&Slast_nonminibuf_frame);
#endif
};
+enum z_group
+{
+ z_group_none,
+ z_group_above,
+ z_group_below,
+ z_group_above_suspended,
+};
#endif /* HAVE_WINDOW_SYSTEM */
/* The structure representing a frame. */
Usually it is nil. */
Lisp_Object title;
+#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS)
+ /* This frame's parent frame, if it has one. */
+ Lisp_Object parent_frame;
+#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */
+
/* The frame which should receive keystrokes that occur in this
frame, or nil if they should go to the frame itself. This is
usually nil, but if the frame is minibufferless, we can use this
bool_bf horizontal_scroll_bars : 1;
#endif /* HAVE_WINDOW_SYSTEM */
+#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS)
+ /* True if this is an undecorated frame. */
+ bool_bf undecorated : 1;
+
+#ifndef HAVE_NTGUI
+ /* True if this is an override_redirect frame. */
+ bool_bf override_redirect : 1;
+#endif
+
+ /* Nonzero if this frame's icon should not appear on its display's taskbar. */
+ bool_bf skip_taskbar : 1;
+
+ /* Nonzero if this frame's window F's X window does not want to
+ receive input focus when it is mapped. */
+ bool_bf no_focus_on_map : 1;
+
+ /* Nonzero if this frame's window does not want to receive input focus
+ via mouse clicks or by moving the mouse into it. */
+ bool_bf no_accept_focus : 1;
+
+ /* The z-group this frame's window belongs to. */
+ ENUM_BF (z_group) z_group : 2;
+#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */
+
/* Whether new_height and new_width shall be interpreted
in pixels. */
bool_bf new_pixelwise : 1;
{
f->face_alist = val;
}
+#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS)
+INLINE void
+fset_parent_frame (struct frame *f, Lisp_Object val)
+{
+ f->parent_frame = val;
+}
+#endif
INLINE void
fset_focus_frame (struct frame *f, Lisp_Object val)
{
#define FRAME_FOCUS_FRAME(f) f->focus_frame
#ifdef HAVE_WINDOW_SYSTEM
-
/* This frame slot says whether scroll bars are currently enabled for frame F,
and which side they are on. */
#define FRAME_VERTICAL_SCROLL_BAR_TYPE(f) ((f)->vertical_scroll_bar_type)
((f)->vertical_scroll_bar_type == vertical_scroll_bar_left)
#define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) \
((f)->vertical_scroll_bar_type == vertical_scroll_bar_right)
-
#else /* not HAVE_WINDOW_SYSTEM */
-
/* If there is no window system, there are no scroll bars. */
#define FRAME_VERTICAL_SCROLL_BAR_TYPE(f) ((void) f, vertical_scroll_bar_none)
#define FRAME_HAS_VERTICAL_SCROLL_BARS(f) ((void) f, 0)
#define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT(f) ((void) f, 0)
#define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) ((void) f, 0)
-
#endif /* HAVE_WINDOW_SYSTEM */
+#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS)
+#define FRAME_UNDECORATED(f) ((f)->undecorated)
+#ifdef HAVE_NTGUI
+#define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0)
+#else
+#define FRAME_OVERRIDE_REDIRECT(f) ((f)->override_redirect)
+#endif
+#define FRAME_PARENT_FRAME(f) \
+ (NILP ((f)->parent_frame) \
+ ? NULL \
+ : XFRAME ((f)->parent_frame))
+#define FRAME_SKIP_TASKBAR(f) ((f)->skip_taskbar)
+#define FRAME_NO_FOCUS_ON_MAP(f) ((f)->no_focus_on_map)
+#define FRAME_NO_ACCEPT_FOCUS(f) ((f)->no_accept_focus)
+#define FRAME_Z_GROUP(f) ((f)->z_group)
+#define FRAME_Z_GROUP_NONE(f) ((f)->z_group == z_group_none)
+#define FRAME_Z_GROUP_ABOVE(f) ((f)->z_group == z_group_above)
+#define FRAME_Z_GROUP_ABOVE_SUSPENDED(f) \
+ ((f)->z_group == z_group_above_suspended)
+#define FRAME_Z_GROUP_BELOW(f) ((f)->z_group == z_group_below)
+#else /* not HAVE_WINDOW_SYSTEM or HAVE_NS */
+#define FRAME_UNDECORATED(f) ((void) f, 0)
+#define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0)
+#define FRAME_PARENT_FRAME(f) ((void) f, NULL)
+#define FRAME_SKIP_TASKBAR(f) ((void) f, 0)
+#define FRAME_NO_FOCUS_ON_MAP(f) ((void) f, 0)
+#define FRAME_NO_ACCEPT_FOCUS(f) ((void) f, 0)
+#define FRAME_Z_GROUP(f) ((void) f, z_group_none)
+#define FRAME_Z_GROUP_NONE(f) ((void) f, true)
+#define FRAME_Z_GROUP_ABOVE(f) ((void) f, false)
+#define FRAME_Z_GROUP_BELOW(f) ((void) f, false)
+#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */
+
/* Whether horizontal scroll bars are currently enabled for frame F. */
#if USE_HORIZONTAL_SCROLL_BARS
#define FRAME_HAS_HORIZONTAL_SCROLL_BARS(f) \
loop will set FRAME_VAR, a Lisp_Object, to each frame in
Vframe_list in succession and execute the statement. LIST_VAR
should be a Lisp_Object too; it is used to iterate through the
- Vframe_list.
+ Vframe_list. Note that this macro walks over child frames and
+ the tooltip frame as well.
This macro is a holdover from a time when multiple frames weren't always
supported. An alternate definition of the macro would expand to
return frame_dimension (f->internal_border_width);
}
-/* Pixel-size of window border lines */
+/* Pixel-size of window divider lines */
INLINE int
FRAME_RIGHT_DIVIDER_WIDTH (struct frame *f)
{
extern void x_real_positions (struct frame *, int *, int *);
extern void free_frame_menubar (struct frame *);
extern void x_free_frame_resources (struct frame *);
+extern bool frame_ancestor_p (struct frame *af, struct frame *df);
#if defined HAVE_X_WINDOWS
extern void x_wm_set_icon_position (struct frame *, int, int);
else if (! NILP (f->name))
title = SSDATA (ENCODE_UTF_8 (f->name));
- if (title) gtk_window_set_title (GTK_WINDOW (wtop), title);
+ if (title)
+ gtk_window_set_title (GTK_WINDOW (wtop), title);
+
+ if (FRAME_UNDECORATED (f))
+ {
+ gtk_window_set_decorated (GTK_WINDOW (wtop), FALSE);
+ store_frame_param (f, Qundecorated, Qt);
+ }
FRAME_GTK_OUTER_WIDGET (f) = wtop;
FRAME_GTK_WIDGET (f) = wfixed;
gtk_window_set_resizable (GTK_WINDOW (wtop), TRUE);
#endif
+ if (FRAME_OVERRIDE_REDIRECT (f))
+ {
+ GdkWindow *gwin = gtk_widget_get_window (wtop);
+
+ if (gwin)
+ gdk_window_set_override_redirect (gwin, TRUE);
+ }
+
#ifdef USE_GTK_TOOLTIP
/* Steal a tool tip window we can move ourselves. */
f->output_data.x->ttip_widget = 0;
/* Don't set size hints during initialization; that apparently leads
to a race condition. See the thread at
http://lists.gnu.org/archive/html/emacs-devel/2008-10/msg00033.html */
- if (NILP (Vafter_init_time) || !FRAME_GTK_OUTER_WIDGET (f))
+ if (NILP (Vafter_init_time)
+ || !FRAME_GTK_OUTER_WIDGET (f)
+ || FRAME_PARENT_FRAME (f))
return;
XSETFRAME (frame, f);
}
}
+/* Change the frame's decoration (title bar + resize borders). This
+ might not work with all window managers. */
+void
+xg_set_undecorated (struct frame *f, Lisp_Object undecorated)
+{
+ if (FRAME_GTK_WIDGET (f))
+ {
+ block_input ();
+ gtk_window_set_decorated (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+ NILP (undecorated) ? TRUE : FALSE);
+ unblock_input ();
+ }
+}
+
+
+/* Restack F1 below F2, above if ABOVE_FLAG is true. This might not
+ work with all window managers. */
+void
+xg_frame_restack (struct frame *f1, struct frame *f2, bool above_flag)
+{
+ block_input ();
+ if (FRAME_GTK_OUTER_WIDGET (f1) && FRAME_GTK_OUTER_WIDGET (f2))
+ {
+ GdkWindow *gwin1 = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f1));
+ GdkWindow *gwin2 = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f2));
+ Lisp_Object frame1, frame2;
+
+ XSETFRAME (frame1, f1);
+ XSETFRAME (frame2, f2);
+
+ gdk_window_restack (gwin1, gwin2, above_flag);
+ x_sync (f1);
+ }
+ unblock_input ();
+}
+
+
+/* Don't show frame in taskbar, don't ALT-TAB to it. */
+void
+xg_set_skip_taskbar (struct frame *f, Lisp_Object skip_taskbar)
+{
+ block_input ();
+ if (FRAME_GTK_WIDGET (f))
+ gdk_window_set_skip_taskbar_hint
+ (gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f)),
+ NILP (skip_taskbar) ? FALSE : TRUE);
+ unblock_input ();
+}
+
+
+/* Don't give frame focus. */
+void
+xg_set_no_focus_on_map (struct frame *f, Lisp_Object no_focus_on_map)
+{
+ block_input ();
+ if (FRAME_GTK_WIDGET (f))
+ {
+ GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
+ gboolean gno_focus_on_map = NILP (no_focus_on_map) ? TRUE : FALSE;
+
+ gtk_window_set_focus_on_map (gwin, gno_focus_on_map);
+ }
+ unblock_input ();
+}
+
+
+void
+xg_set_no_accept_focus (struct frame *f, Lisp_Object no_accept_focus)
+{
+ block_input ();
+ if (FRAME_GTK_WIDGET (f))
+ {
+ GtkWindow *gwin = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
+ gboolean gno_accept_focus = NILP (no_accept_focus) ? TRUE : FALSE;
+
+ gtk_window_set_accept_focus (gwin, gno_accept_focus);
+ }
+ unblock_input ();
+}
+
+void
+xg_set_override_redirect (struct frame *f, Lisp_Object override_redirect)
+{
+ block_input ();
+
+ if (FRAME_GTK_OUTER_WIDGET (f))
+ {
+ GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
+
+ gdk_window_set_override_redirect (gwin, NILP (override_redirect) ? FALSE : TRUE);
+ }
+
+ unblock_input ();
+}
/* Set the frame icon to ICON_PIXMAP/MASK. This must be done with GTK
functions so GTK does not overwrite the icon. */
GtkWidget *wparent = gtk_widget_get_parent (wscroll);
gint msl;
int scale = xg_get_gdk_scale ();
+ bool hidden;
top /= scale;
left /= scale;
the height is less than the min size. */
gtk_widget_hide (wparent);
gtk_widget_hide (wscroll);
+ hidden = true;
}
else
{
x_clear_area (f, oldx, oldy, oldw, oldh);
}
+ if (!hidden)
+ {
+ GtkWidget *scrollbar = xg_get_widget_from_map (scrollbar_id);
+ GtkWidget *webox = gtk_widget_get_parent (scrollbar);
+
+ /* Don't obscure any child frames. */
+ XLowerWindow (FRAME_X_DISPLAY (f), GTK_WIDGET_TO_X_WIN (webox));
+ }
+
/* GTK does not redraw until the main loop is entered again, but
if there are no X events pending we will not enter it. So we sync
here to get some events. */
if there are no X events pending we will not enter it. So we sync
here to get some events. */
+ {
+ GtkWidget *scrollbar =
+ xg_get_widget_from_map (scrollbar_id);
+ GtkWidget *webox = gtk_widget_get_parent (scrollbar);
+
+ /* Don't obscure any child frames. */
+ XLowerWindow (FRAME_X_DISPLAY (f), GTK_WIDGET_TO_X_WIN (webox));
+ }
+
x_sync (f);
SET_FRAME_GARBAGED (f);
cancel_mouse_face (f);
Pixmap icon_pixmap,
Pixmap icon_mask);
+extern void xg_set_undecorated (struct frame *f, Lisp_Object undecorated);
+extern void xg_frame_restack (struct frame *f1, struct frame *f2, bool above);
+extern void xg_set_skip_taskbar (struct frame *f, Lisp_Object skip_taskbar);
+extern void xg_set_no_focus_on_map (struct frame *f, Lisp_Object no_focus_on_map);
+extern void xg_set_no_accept_focus (struct frame *f, Lisp_Object no_accept_focus);
+extern void xg_set_override_redirect (struct frame *f, Lisp_Object override_redirect);
+
extern bool xg_prepare_tooltip (struct frame *f,
Lisp_Object string,
int *width,
0, /* x_set_sticky */
0, /* x_set_tool_bar_position */
0, /* x_set_inhibit_double_buffering */
+ 0, /* x_set_undecorated */
+ 0, /* x_set_parent_frame */
+ 0, /* x_set_skip_taskbar */
+ 0, /* x_set_no_focus_on_map */
+ 0, /* x_set_no_accept_focus */
+ 0, /* x_set_z_group */
+ 0, /* x_set_override_redirect */
};
init_frame_faces (f);
/* Read comment about this code in corresponding place in xfns.c. */
+ tem = x_get_arg (dpyinfo, parms, Qmin_width, NULL, NULL, RES_TYPE_NUMBER);
+ if (NUMBERP (tem))
+ store_frame_param (f, Qmin_width, tem);
+ tem = x_get_arg (dpyinfo, parms, Qmin_height, NULL, NULL, RES_TYPE_NUMBER);
+ if (NUMBERP (tem))
+ store_frame_param (f, Qmin_height, tem);
adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1,
Qx_create_frame_1);
if (WINDOWP (window)
&& !EQ (window, last_mouse_window)
&& !EQ (window, selected_window)
- && (focus_follows_mouse
+ && (!NILP (focus_follows_mouse)
|| (EQ (XWINDOW (window)->frame,
XWINDOW (selected_window)->frame))))
{
# define WTS_SESSION_LOCK 0x7
#endif
+#ifndef WS_EX_NOACTIVATE
+#define WS_EX_NOACTIVATE 0x08000000L
+#endif
+
/* Keyboard hook state data. */
static struct
{
void
x_real_positions (struct frame *f, int *xptr, int *yptr)
{
- POINT pt;
RECT rect;
/* Get the bounds of the WM window. */
GetWindowRect (FRAME_W32_WINDOW (f), &rect);
- pt.x = 0;
- pt.y = 0;
+ if (FRAME_PARENT_FRAME (f))
+ {
+ /* For a child window we have to get its coordinates wrt its
+ parent. */
+ HWND parent_hwnd = FRAME_W32_WINDOW (FRAME_PARENT_FRAME (f));
- /* Convert (0, 0) in the client area to screen co-ordinates. */
- ClientToScreen (FRAME_W32_WINDOW (f), &pt);
+ if (parent_hwnd)
+ MapWindowPoints (HWND_DESKTOP, parent_hwnd, (LPPOINT) &rect, 2);
+ }
*xptr = rect.left;
*yptr = rect.top;
most of the commands try to apply themselves to the minibuffer
frame itself, and get an error because you can't switch buffers
in or split the minibuffer window. */
- if (FRAME_MINIBUF_ONLY_P (f))
+ if (FRAME_MINIBUF_ONLY_P (f) || FRAME_PARENT_FRAME (f))
return;
if (INTEGERP (value))
FRAME_CONFIG_SCROLL_BAR_LINES (f)
= (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + unit - 1) / unit;
}
+
+/**
+ * x_set_undecorated:
+ *
+ * Set frame F's `undecorated' parameter. If non-nil, F's window-system
+ * window is drawn without decorations, title, minimize/maximize boxes
+ * and external borders. This usually means that the window cannot be
+ * dragged, resized, iconified, maximized or deleted with the mouse. If
+ * nil, draw the frame with all the elements listed above unless these
+ * have been suspended via window manager settings.
+ *
+ * Some window managers may not honor this parameter.
+ */
+static void
+x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ HWND hwnd = FRAME_W32_WINDOW (f);
+ DWORD dwStyle = GetWindowLong (hwnd, GWL_STYLE);
+ Lisp_Object border_width = Fcdr (Fassq (Qborder_width, f->param_alist));
+
+ block_input ();
+ if (!NILP (new_value) && !FRAME_UNDECORATED (f))
+ {
+ dwStyle = ((dwStyle & ~WS_THICKFRAME & ~WS_CAPTION)
+ | ((NUMBERP (border_width) && (XINT (border_width) > 0))
+ ? WS_BORDER : false));
+ SetWindowLong (hwnd, GWL_STYLE, dwStyle);
+ SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE
+ | SWP_FRAMECHANGED);
+ FRAME_UNDECORATED (f) = true;
+ }
+ else if (NILP (new_value) && FRAME_UNDECORATED (f))
+ {
+ SetWindowLong (hwnd, GWL_STYLE, dwStyle | WS_THICKFRAME | WS_CAPTION
+ | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU);
+ SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE
+ | SWP_FRAMECHANGED);
+ FRAME_UNDECORATED (f) = false;
+ }
+ unblock_input ();
+}
+
+/**
+ * x_set_parent_frame:
+ *
+ * Set frame F's `parent-frame' parameter. If non-nil, make F a child
+ * frame of the frame specified by that parameter. Technically, this
+ * makes F's window-system window a child window of the parent frame's
+ * window-system window. If nil, make F's window-system window a
+ * top-level window--a child of its display's root window.
+ *
+ * A child frame is clipped at the native edges of its parent frame.
+ * Its `left' and `top' parameters specify positions relative to the
+ * top-left corner of its parent frame's native rectangle. Usually,
+ * moving a parent frame moves all its child frames too, keeping their
+ * position relative to the parent unaltered. When a parent frame is
+ * iconified or made invisible, its child frames are made invisible.
+ * When a parent frame is deleted, its child frames are deleted too.
+ *
+ * A visible child frame always appears on top of its parent frame thus
+ * obscuring parts of it. When a frame has more than one child frame,
+ * their stacking order is specified just as that of non-child frames
+ * relative to their display.
+ *
+ * Whether a child frame has a menu or tool bar may be window-system or
+ * window manager dependent. It's advisable to disable both via the
+ * frame parameter settings.
+ *
+ * Some window managers may not honor this parameter.
+ */
+static void
+x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ struct frame *p = NULL;
+
+ if (!NILP (new_value)
+ && (!FRAMEP (new_value)
+ || !FRAME_LIVE_P (p = XFRAME (new_value))
+ || !FRAME_W32_P (p)))
+ {
+ store_frame_param (f, Qparent_frame, old_value);
+ error ("Invalid specification of `parent-frame'");
+ }
+
+ if (p != FRAME_PARENT_FRAME (f))
+ {
+ HWND hwnd = FRAME_W32_WINDOW (f);
+ HWND hwnd_parent = p ? FRAME_W32_WINDOW (p) : NULL;
+ HWND hwnd_value;
+
+ block_input ();
+ hwnd_value = SetParent (hwnd, hwnd_parent);
+ unblock_input ();
+
+ if (hwnd_value)
+ fset_parent_frame (f, new_value);
+ else
+ {
+ store_frame_param (f, Qparent_frame, old_value);
+ error ("Reparenting frame failed");
+ }
+ }
+}
+
+/**
+ * x_set_skip_taskbar:
+ *
+ * Set frame F's `skip-taskbar' parameter. If non-nil, this should
+ * remove F's icon from the taskbar associated with the display of F's
+ * window-system window and inhibit switching to F's window via
+ * <Alt>-<TAB>. On Windows iconifying F will "roll in" its window at
+ * the bottom of the desktop. If nil, lift these restrictions.
+ *
+ * Some window managers may not honor this parameter.
+ */
+static void
+x_set_skip_taskbar (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ if (!EQ (new_value, old_value))
+ {
+ HWND hwnd = FRAME_W32_WINDOW (f);
+ DWORD exStyle = GetWindowLong (hwnd, GWL_EXSTYLE);
+
+ block_input ();
+ /* Temporarily hide the window while changing its WS_EX_NOACTIVATE
+ setting. */
+ ShowWindow (hwnd, SW_HIDE);
+ if (!NILP (new_value))
+ SetWindowLong (hwnd, GWL_EXSTYLE, exStyle | WS_EX_NOACTIVATE);
+ else
+ SetWindowLong (hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_NOACTIVATE);
+ ShowWindow (hwnd, SW_SHOWNOACTIVATE);
+ unblock_input ();
+
+ FRAME_SKIP_TASKBAR (f) = !NILP (new_value);
+ }
+}
+
+/**
+ * x_set_no_focus_on_map:
+ *
+ * Set frame F's `no-focus-on-map' parameter which, if non-nil, means
+ * that F's window-system window does not want to receive input focus
+ * when it is mapped. (A frame's window is mapped when the frame is
+ * displayed for the first time and when the frame changes its state
+ * from `iconified' or `invisible' to `visible'.)
+ *
+ * Some window managers may not honor this parameter.
+ */
+static void
+x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ if (!EQ (new_value, old_value))
+ FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
+}
+
+/**
+ * x_set_no_accept_focus:
+ *
+ * Set frame F's `no-accept-focus' parameter which, if non-nil, hints
+ * that F's window-system window does not want to receive input focus
+ * via mouse clicks or by moving the mouse into it.
+ *
+ * If non-nil, this may have the unwanted side-effect that a user cannot
+ * scroll a non-selected frame with the mouse.
+ *
+ * Some window managers may not honor this parameter.
+ */
+static void
+x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ if (!EQ (new_value, old_value))
+ FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
+}
+
+/**
+ * x_set_z_group:
+ *
+ * Set frame F's `z-group' parameter. If `above', F's window-system
+ * window is displayed above all windows that do not have the `above'
+ * property set. If nil, F's window is shown below all windows that
+ * have the `above' property set and above all windows that have the
+ * `below' property set. If `below', F's window is displayed below all
+ * windows that do not have the `below' property set.
+ *
+ * Some window managers may not honor this parameter. The value `below'
+ * is not supported on Windows.
+ */
+static void
+x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ HWND hwnd = FRAME_W32_WINDOW (f);
+
+ if (NILP (new_value))
+ {
+ block_input ();
+ SetWindowPos (hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE
+ | SWP_NOOWNERZORDER);
+ unblock_input ();
+ FRAME_Z_GROUP (f) = z_group_none;
+ }
+ else if (EQ (new_value, Qabove))
+ {
+ block_input ();
+ SetWindowPos (hwnd, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE
+ | SWP_NOOWNERZORDER);
+ unblock_input ();
+ FRAME_Z_GROUP (f) = z_group_above;
+ }
+ else if (EQ (new_value, Qabove_suspended))
+ {
+ block_input ();
+ SetWindowPos (hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE
+ | SWP_NOOWNERZORDER);
+ unblock_input ();
+ FRAME_Z_GROUP (f) = z_group_above_suspended;
+ }
+ else if (EQ (new_value, Qbelow))
+ error ("Value `below' for z-group is not supported on Windows");
+ else
+ error ("Invalid z-group specification");
+}
\f
/* Subroutines for creating a frame. */
static HWND
w32_createvscrollbar (struct frame *f, struct scroll_bar * bar)
{
- return CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
+ return CreateWindow ("SCROLLBAR", "",
+ /* Clip siblings so we don't draw over child
+ frames. Apparently this is not always
+ sufficient so we also try to make bar windows
+ bottommost. */
+ SBS_VERT | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
/* Position and size of scroll bar. */
bar->left, bar->top, bar->width, bar->height,
FRAME_W32_WINDOW (f), NULL, hinst, NULL);
static HWND
w32_createhscrollbar (struct frame *f, struct scroll_bar * bar)
{
- return CreateWindow ("SCROLLBAR", "", SBS_HORZ | WS_CHILD | WS_VISIBLE,
+ return CreateWindow ("SCROLLBAR", "",
+ /* Clip siblings so we don't draw over child
+ frames. Apparently this is not always
+ sufficient so we also try to make bar windows
+ bottommost. */
+ SBS_HORZ | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
/* Position and size of scroll bar. */
bar->left, bar->top, bar->width, bar->height,
FRAME_W32_WINDOW (f), NULL, hinst, NULL);
static void
w32_createwindow (struct frame *f, int *coords)
{
- HWND hwnd;
+ HWND hwnd = NULL, parent_hwnd = NULL;
RECT rect;
- int top;
- int left;
+ DWORD dwStyle;
+ int top, left;
+ Lisp_Object border_width = Fcdr (Fassq (Qborder_width, f->param_alist));
+
+ if (FRAME_PARENT_FRAME (f) && FRAME_W32_P (FRAME_PARENT_FRAME (f)))
+ {
+ parent_hwnd = FRAME_W32_WINDOW (FRAME_PARENT_FRAME (f));
+ f->output_data.w32->dwStyle = WS_CHILD | WS_CLIPSIBLINGS;
+
+ if (FRAME_UNDECORATED (f))
+ {
+ /* If we want a thin border, specify it here. */
+ if (NUMBERP (border_width) && (XINT (border_width) > 0))
+ f->output_data.w32->dwStyle =
+ f->output_data.w32->dwStyle | WS_BORDER;
+ }
+ else
+ /* To decorate a child frame, list all needed elements. */
+ f->output_data.w32->dwStyle =
+ f->output_data.w32->dwStyle | WS_THICKFRAME | WS_CAPTION
+ | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU;
+ }
+ else if (FRAME_UNDECORATED (f))
+ {
+ /* All attempts to start with ~WS_OVERLAPPEDWINDOW or overlapped
+ with all other style elements negated failed here. */
+ f->output_data.w32->dwStyle = WS_POPUP;
+
+ /* If we want a thin border, specify it here. */
+ if (NUMBERP (border_width) && (XINT (border_width) > 0))
+ f->output_data.w32->dwStyle =
+ f->output_data.w32->dwStyle | WS_BORDER;
+ }
+ else
+ f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
+
+ /* Always clip children. */
+ f->output_data.w32->dwStyle = f->output_data.w32->dwStyle | WS_CLIPCHILDREN;
rect.left = rect.top = 0;
rect.right = FRAME_PIXEL_WIDTH (f);
rect.bottom = FRAME_PIXEL_HEIGHT (f);
AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
- FRAME_EXTERNAL_MENU_BAR (f));
+ FRAME_EXTERNAL_MENU_BAR (f) && !parent_hwnd);
/* Do first time app init */
-
w32_init_class (hinst);
if (f->size_hint_flags & USPosition || f->size_hint_flags & PPosition)
}
FRAME_W32_WINDOW (f) = hwnd
- = CreateWindow (EMACS_CLASS,
- f->namebuf,
- f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
- left, top,
- rect.right - rect.left, rect.bottom - rect.top,
- NULL,
- NULL,
- hinst,
- NULL);
+ = CreateWindow (EMACS_CLASS, f->namebuf, f->output_data.w32->dwStyle,
+ left, top, rect.right - rect.left, rect.bottom - rect.top,
+ parent_hwnd, NULL, hinst, NULL);
if (hwnd)
{
+ if (FRAME_SKIP_TASKBAR (f))
+ SetWindowLong (hwnd, GWL_EXSTYLE,
+ GetWindowLong (hwnd, GWL_EXSTYLE) | WS_EX_NOACTIVATE);
+
SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f));
SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f));
SetWindowLong (hwnd, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f));
/* Update frame positions. */
GetWindowRect (hwnd, &rect);
+
+ if (parent_hwnd)
+ /* For a child window we have to get its coordinates wrt its
+ parent. */
+ MapWindowPoints (HWND_DESKTOP, parent_hwnd, (LPPOINT) &rect, 2);
+
f->left_pos = rect.left;
f->top_pos = rect.top;
}
}
}
+ if (f && (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN
+ || msg == WM_MBUTTONDOWN ||msg == WM_XBUTTONDOWN)
+ && !FRAME_NO_ACCEPT_FOCUS (f))
+ /* When clicking into a child frame or when clicking into a
+ parent frame with the child frame selected and
+ `no-accept-focus' is not set, select the clicked frame. */
+ {
+ struct frame *p = FRAME_PARENT_FRAME (XFRAME (selected_frame));
+
+ if (FRAME_PARENT_FRAME (f) || f == p)
+ {
+ SetFocus (hwnd);
+ SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ }
+ }
+
wmsg.dwModifiers = w32_get_modifiers ();
my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
signal_user_input ();
if (w32_pass_multimedia_buttons_to_system)
goto dflt;
/* Otherwise, pass to lisp, the same way we do with mousehwheel. */
+
+ /* FIXME!!! This is never reached so what's the purpose? If the
+ non-zero return remark below is right we're doing it wrong all
+ the time. */
case WM_MOUSEHWHEEL:
wmsg.dwModifiers = w32_get_modifiers ();
my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
}
return 0;
-#if 0
+ case WM_MOUSEACTIVATE:
+ /* WM_MOUSEACTIVATE is the only way on Windows to implement the
+ `no-accept-focus' frame parameter. This means that one can't
+ use the mouse to scroll a window on a non-selected frame. */
+
/* Still not right - can't distinguish between clicks in the
client area of the frame from clicks forwarded from the scroll
bars - may have to hook WM_NCHITTEST to remember the mouse
- position and then check if it is in the client area ourselves. */
- case WM_MOUSEACTIVATE:
+ position and then check if it is in the client area
+ ourselves. */
+
/* Discard the mouse click that activates a frame, allowing the
user to click anywhere without changing point (or worse!).
Don't eat mouse clicks on scrollbars though!! */
- if (LOWORD (lParam) == HTCLIENT )
- return MA_ACTIVATEANDEAT;
+
+ if ((f = x_window_to_frame (dpyinfo, hwnd))
+ && FRAME_NO_ACCEPT_FOCUS (f)
+ /* Ignore child frames, they don't accept focus anyway. */
+ && !FRAME_PARENT_FRAME (f))
+ {
+ Lisp_Object frame;
+
+ XSETFRAME (frame, f);
+ if (!EQ (selected_frame, frame))
+ /* Don't discard the message, GTK doesn't either. */
+ return MA_NOACTIVATE; /* ANDEAT; */
+ }
goto dflt;
-#endif
case WM_MOUSELEAVE:
/* No longer tracking mouse. */
AttachThreadInput (GetCurrentThreadId (),
foreground_thread, FALSE);
+ /* SetFocus to give/remove focus to/from a child window. */
+ if (msg == WM_EMACS_SETFOREGROUND)
+ SetFocus ((HWND) wParam);
+
return retval;
}
unblock_input ();
- if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
+ if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f)
+ && !FRAME_PARENT_FRAME (f))
initialize_frame_menubar (f);
if (FRAME_W32_WINDOW (f) == 0)
ptrdiff_t count = SPECPDL_INDEX ();
Lisp_Object display;
struct w32_display_info *dpyinfo = NULL;
- Lisp_Object parent;
+ Lisp_Object parent, parent_frame;
struct kboard *kb;
int x_width = 0, x_height = 0;
Vx_resource_name = name;
/* See if parent window is specified. */
- parent = x_get_arg (dpyinfo, parameters, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
+ parent = x_get_arg (dpyinfo, parameters, Qparent_id, NULL, NULL,
+ RES_TYPE_NUMBER);
if (EQ (parent, Qunbound))
parent = Qnil;
- if (! NILP (parent))
+ else if (!NILP (parent))
CHECK_NUMBER (parent);
/* make_frame_without_minibuffer can run Lisp code and garbage collect. */
XSETFRAME (frame, f);
+ parent_frame = x_get_arg (dpyinfo, parameters, Qparent_frame, NULL, NULL,
+ RES_TYPE_SYMBOL);
+ /* Apply `parent-frame' parameter only when no `parent-id' was
+ specified. */
+ if (!NILP (parent_frame)
+ && (!NILP (parent)
+ || !FRAMEP (parent_frame)
+ || !FRAME_LIVE_P (XFRAME (parent_frame))
+ || !FRAME_W32_P (XFRAME (parent_frame))))
+ parent_frame = Qnil;
+
+ fset_parent_frame (f, parent_frame);
+ store_frame_param (f, Qparent_frame, parent_frame);
+
+ tem = x_get_arg (dpyinfo, parameters, Qundecorated, NULL, NULL,
+ RES_TYPE_BOOLEAN);
+ FRAME_UNDECORATED (f) = !NILP (tem) && !EQ (tem, Qunbound);
+ store_frame_param (f, Qundecorated, FRAME_UNDECORATED (f) ? Qt : Qnil);
+
+ tem = x_get_arg (dpyinfo, parameters, Qskip_taskbar, NULL, NULL,
+ RES_TYPE_BOOLEAN);
+ FRAME_SKIP_TASKBAR (f) = !NILP (tem) && !EQ (tem, Qunbound);
+ store_frame_param (f, Qskip_taskbar,
+ (NILP (tem) || EQ (tem, Qunbound)) ? Qnil : Qt);
+
/* By default, make scrollbars the system standard width and height. */
FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = GetSystemMetrics (SM_CXHSCROLL);
dpyinfo_refcount = dpyinfo->reference_count;
#endif /* GLYPH_DEBUG */
- /* Specify the parent under which to make this window. */
+ /* Specify the parent under which to make this window - this seems to
+ have no effect on Windows because parent_desc is explicitly reset
+ below. */
if (!NILP (parent))
{
/* Cast to UINT_PTR shuts up compiler warnings about cast to
"leftFringe", "LeftFringe", RES_TYPE_NUMBER);
x_default_parameter (f, parameters, Qright_fringe, Qnil,
"rightFringe", "RightFringe", RES_TYPE_NUMBER);
- /* Process alpha here (Bug#16619). */
- x_default_parameter (f, parameters, Qalpha, Qnil,
- "alpha", "Alpha", RES_TYPE_NUMBER);
+ x_default_parameter (f, parameters, Qno_focus_on_map, Qnil,
+ NULL, NULL, RES_TYPE_BOOLEAN);
+ x_default_parameter (f, parameters, Qno_accept_focus, Qnil,
+ NULL, NULL, RES_TYPE_BOOLEAN);
+
+ /* Process alpha here (Bug#16619). On XP this fails with child
+ frames. For `no-focus-on-map' frames delay processing of alpha
+ until the frame becomes visible. */
+ if (!FRAME_NO_FOCUS_ON_MAP (f))
+ x_default_parameter (f, parameters, Qalpha, Qnil,
+ "alpha", "Alpha", RES_TYPE_NUMBER);
/* Init faces first since we need the frame's column width/line
height in various occasions. */
init_frame_faces (f);
- /* The following call of change_frame_size is needed since otherwise
+ /* We have to call adjust_frame_size here since otherwise
x_set_tool_bar_lines will already work with the character sizes
- installed by init_frame_faces while the frame's pixel size is
- still calculated from a character size of 1 and we subsequently
- hit the (height >= 0) assertion in window_box_height.
+ installed by init_frame_faces while the frame's pixel size is still
+ calculated from a character size of 1 and we subsequently hit the
+ (height >= 0) assertion in window_box_height.
The non-pixelwise code apparently worked around this because it
had one frame line vs one toolbar line which left us with a zero
- root window height which was obviously wrong as well ... */
+ root window height which was obviously wrong as well ...
+
+ Also process `min-width' and `min-height' parameters right here
+ because `frame-windows-min-size' needs them. */
+ tem = x_get_arg (dpyinfo, parameters, Qmin_width, NULL, NULL,
+ RES_TYPE_NUMBER);
+ if (NUMBERP (tem))
+ store_frame_param (f, Qmin_width, tem);
+ tem = x_get_arg (dpyinfo, parameters, Qmin_height, NULL, NULL,
+ RES_TYPE_NUMBER);
+ if (NUMBERP (tem))
+ store_frame_param (f, Qmin_height, tem);
adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, true,
Qx_create_frame_1);
/* The X resources controlling the menu-bar and tool-bar are
processed specially at startup, and reflected in the mode
variables; ignore them here. */
- x_default_parameter (f, parameters, Qmenu_bar_lines,
- NILP (Vmenu_bar_mode)
- ? make_number (0) : make_number (1),
- NULL, NULL, RES_TYPE_NUMBER);
+ if (NILP (parent_frame))
+ {
+ x_default_parameter (f, parameters, Qmenu_bar_lines,
+ NILP (Vmenu_bar_mode)
+ ? make_number (0) : make_number (1),
+ NULL, NULL, RES_TYPE_NUMBER);
+ }
+ else
+ /* No menu bar for child frames. */
+ store_frame_param (f, Qmenu_bar_lines, make_number (0));
+
x_default_parameter (f, parameters, Qtool_bar_lines,
NILP (Vtool_bar_mode)
? make_number (0) : make_number (1),
x_default_parameter (f, parameters, Qtitle, Qnil,
"title", "Title", RES_TYPE_STRING);
- f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
-
f->output_data.w32->text_cursor = w32_load_cursor (IDC_IBEAM);
f->output_data.w32->nontext_cursor = w32_load_cursor (IDC_ARROW);
f->output_data.w32->modeline_cursor = w32_load_cursor (IDC_ARROW);
adjust_frame_size call. */
x_default_parameter (f, parameters, Qfullscreen, Qnil,
"fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
+ x_default_parameter (f, parameters, Qz_group, Qnil,
+ NULL, NULL, RES_TYPE_SYMBOL);
/* Make the window appear on the frame and enable display, unless
the caller says not to. However, with explicit parent, Emacs
cannot control visibility, so don't try. */
- if (! f->output_data.w32->explicit_parent)
+ if (!f->output_data.w32->explicit_parent)
{
- Lisp_Object visibility;
-
- visibility = x_get_arg (dpyinfo, parameters, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
- if (EQ (visibility, Qunbound))
- visibility = Qt;
+ Lisp_Object visibility
+ = x_get_arg (dpyinfo, parameters, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
if (EQ (visibility, Qicon))
x_iconify_frame (f);
- else if (! NILP (visibility))
- x_make_frame_visible (f);
else
{
- /* Must have been Qnil. */
- ;
+ if (EQ (visibility, Qunbound))
+ visibility = Qt;
+
+ if (!NILP (visibility))
+ x_make_frame_visible (f);
}
+
+ store_frame_param (f, Qvisibility, visibility);
}
+ /* For `no-focus-on-map' frames set alpha here. */
+ if (FRAME_NO_FOCUS_ON_MAP (f))
+ x_default_parameter (f, parameters, Qalpha, Qnil,
+ "alpha", "Alpha", RES_TYPE_NUMBER);
+
/* Initialize `default-minibuffer-frame' in case this is the first
frame on this terminal. */
if (FRAME_HAS_MINIBUF_P (f)
dpyinfo_refcount = dpyinfo->reference_count;
#endif /* GLYPH_DEBUG */
FRAME_KBOARD (f) = kb;
- f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
- f->output_data.w32->explicit_parent = false;
/* Set the name; the functions to which we pass f expect the name to
be set. */
f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
f->output_data.w32->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
+ f->output_data.w32->explicit_parent = false;
x_figure_window_size (f, parms, true, &x_width, &x_height);
return 0;
}
+void
+w32_dialog_in_progress (Lisp_Object in_progress)
+{
+ Lisp_Object frames, frame;
+
+ /* Don't let frames in `above' z-group obscure popups. */
+ FOR_EACH_FRAME (frames, frame)
+ {
+ struct frame *f = XFRAME (frame);
+
+ if (!NILP (in_progress) && FRAME_Z_GROUP_ABOVE (f))
+ x_set_z_group (f, Qabove_suspended, Qabove);
+ else if (NILP (in_progress) && FRAME_Z_GROUP_ABOVE_SUSPENDED (f))
+ x_set_z_group (f, Qabove, Qabove_suspended);
+ }
+}
+
DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0,
doc: /* Read file name, prompting with PROMPT in directory DIR.
Use a file selection dialog. Select DEFAULT-FILENAME in the dialog's file
{
int count = SPECPDL_INDEX ();
+
+ w32_dialog_in_progress (Qt);
+
/* Prevent redisplay. */
specbind (Qinhibit_redisplay, Qt);
+ record_unwind_protect (w32_dialog_in_progress, Qnil);
block_input ();
if (use_unicode)
{
}
}
+/**
+ * w32_frame_list_z_order:
+ *
+ * Recursively add list of all frames on the display specified via
+ * DPYINFO and whose window-system window's parent is specified by
+ * WINDOW to FRAMES and return FRAMES.
+ */
+static Lisp_Object
+w32_frame_list_z_order (struct w32_display_info *dpyinfo, HWND window)
+{
+ Lisp_Object frame, frames = Qnil;
+
+ while (window)
+ {
+ struct frame *f = x_window_to_frame (dpyinfo, window);
+
+ if (f)
+ {
+ XSETFRAME (frame, f);
+ frames = Fcons (frame, frames);
+ }
+
+ block_input ();
+ window = GetNextWindow (window, GW_HWNDNEXT);
+ unblock_input ();
+ }
+
+ return Fnreverse (frames);
+}
+
+DEFUN ("w32-frame-list-z-order", Fw32_frame_list_z_order,
+ Sw32_frame_list_z_order, 0, 1, 0,
+ doc: /* Return list of Emacs' frames, in Z (stacking) order.
+The optional argument DISPLAY specifies which display to ask about.
+DISPLAY should be either a frame or a display name (a string). If
+omitted or nil, that stands for the selected frame's display.
+
+As a special case, if DISPLAY is non-nil and specifies a live frame,
+return the child frames of that frame in Z (stacking) order.
+
+Frames are listed from topmost (first) to bottommost (last). */)
+ (Lisp_Object display)
+{
+ struct w32_display_info *dpyinfo = check_x_display_info (display);
+ HWND window;
+
+ block_input ();
+ if (FRAMEP (display) && FRAME_LIVE_P (XFRAME (display)))
+ window = GetWindow (FRAME_W32_WINDOW (XFRAME (display)), GW_CHILD);
+ else
+ window = GetTopWindow (NULL);
+ unblock_input ();
+
+ return w32_frame_list_z_order (dpyinfo, window);
+}
+
+/**
+ * w32_frame_restack:
+ *
+ * Restack frame F1 below frame F2, above if ABOVE_FLAG is non-nil. In
+ * practice this is a two-step action: The first step removes F1's
+ * window-system window from the display. The second step reinserts
+ * F1's window below (above if ABOVE_FLAG is true) that of F2.
+ */
+static void
+w32_frame_restack (struct frame *f1, struct frame *f2, bool above_flag)
+{
+ HWND hwnd1 = FRAME_W32_WINDOW (f1);
+ HWND hwnd2 = FRAME_W32_WINDOW (f2);
+
+ block_input ();
+ if (above_flag)
+ /* Put F1 above F2 in the z-order. */
+ {
+ if (GetNextWindow (hwnd1, GW_HWNDNEXT) != hwnd2)
+ {
+ /* Make sure F1 is below F2 first because we must not
+ change the relative position of F2 wrt any other
+ window but F1. */
+ if (GetNextWindow (hwnd2, GW_HWNDNEXT) != hwnd1)
+ SetWindowPos (hwnd1, hwnd2, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE
+ | SWP_FRAMECHANGED);
+ /* Now put F1 above F2. */
+ SetWindowPos (hwnd2, hwnd1, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE
+ | SWP_FRAMECHANGED);
+ }
+ }
+ else if (GetNextWindow (hwnd2, GW_HWNDNEXT) != hwnd1)
+ /* Put F1 below F2 in the z-order. */
+ SetWindowPos (hwnd1, hwnd2, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE
+ | SWP_FRAMECHANGED);
+ unblock_input ();
+}
+
+DEFUN ("w32-frame-restack", Fw32_frame_restack, Sw32_frame_restack, 2, 3, 0,
+ doc: /* Restack FRAME1 below FRAME2.
+This means that if both frames are visible and the display areas of
+these frames overlap, FRAME2 (partially) obscures FRAME1. If optional
+third argument ABOVE is non-nil, restack FRAME1 above FRAME2. This
+means that if both frames are visible and the display areas of these
+frames overlap, FRAME1 (partially) obscures FRAME2.
+
+This may be thought of as an atomic action performed in two steps: The
+first step removes FRAME1's window-system window from the display. The
+second step reinserts FRAME1's window below (above if ABOVE is true)
+that of FRAME2. Hence the position of FRAME2 in its display's Z
+\(stacking) order relative to all other frames excluding FRAME1 remains
+unaltered.
+
+Some window managers may refuse to restack windows. */)
+ (Lisp_Object frame1, Lisp_Object frame2, Lisp_Object above)
+{
+ struct frame *f1 = decode_live_frame (frame1);
+ struct frame *f2 = decode_live_frame (frame2);
+
+ if (FRAME_W32_P (f1) && FRAME_W32_P (f2))
+ {
+ w32_frame_restack (f1, f2, !NILP (above));
+ return Qt;
+ }
+ else
+ {
+ error ("Cannot restack frames");
+ return Qnil;
+ }
+}
+
DEFUN ("w32-mouse-absolute-pixel-position", Fw32_mouse_absolute_pixel_position,
Sw32_mouse_absolute_pixel_position, 0, 0, 0,
doc: /* Return absolute position of mouse cursor in pixels.
0, /* x_set_sticky */
0, /* x_set_tool_bar_position */
0, /* x_set_inhibit_double_buffering */
+ x_set_undecorated,
+ x_set_parent_frame,
+ x_set_skip_taskbar,
+ x_set_no_focus_on_map,
+ x_set_no_accept_focus,
+ x_set_z_group,
+ 0, /* x_set_override_redirect */
};
void
defsubr (&Sx_display_list);
defsubr (&Sw32_frame_geometry);
defsubr (&Sw32_frame_edges);
+ defsubr (&Sw32_frame_list_z_order);
+ defsubr (&Sw32_frame_restack);
defsubr (&Sw32_mouse_absolute_pixel_position);
defsubr (&Sw32_set_mouse_absolute_pixel_position);
defsubr (&Sx_synchronize);
SelectObject (hdc, oldobj);
ReleaseDC (FRAME_W32_WINDOW (f), hdc);
- if (!ChooseFont (&cf)
- || logfont_to_fcname (&lf, cf.iPointSize, buf, 100) < 0)
- return Qnil;
+ {
+ int count = SPECPDL_INDEX ();
+ Lisp_Object value = Qnil;
+
+ w32_dialog_in_progress (Qt);
+ specbind (Qinhibit_redisplay, Qt);
+ record_unwind_protect (w32_dialog_in_progress, Qnil);
+
+ if (ChooseFont (&cf)
+ && logfont_to_fcname (&lf, cf.iPointSize, buf, 100) >= 0)
+ value = DECODE_SYSTEM (build_string (buf));
- return DECODE_SYSTEM (build_string (buf));
+ unbind_to (count, Qnil);
+
+ return value;
+ }
}
static const char *const w32font_booleans [] = {
coordinates, so cast to short to interpret them correctly. */
p.x = (short) LOWORD (msg->msg.lParam);
p.y = (short) HIWORD (msg->msg.lParam);
- ScreenToClient (msg->msg.hwnd, &p);
+ /* For the case that F's w32 window is not msg->msg.hwnd. */
+ ScreenToClient (FRAME_W32_WINDOW (f), &p);
XSETINT (result->x, p.x);
XSETINT (result->y, p.y);
XSETFRAME (result->frame_or_window, f);
/* If mouse was grabbed on a frame, give coords for that
frame even if the mouse is now outside it. Otherwise
check for window under mouse on one of our frames. */
- f1 = (x_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
- : x_any_window_to_frame (dpyinfo, WindowFromPoint (pt)));
+ if (x_mouse_grabbed (dpyinfo))
+ f1 = dpyinfo->last_mouse_frame;
+ else
+ {
+ HWND wfp = WindowFromPoint (pt);
+
+ if (wfp && (f1 = x_any_window_to_frame (dpyinfo, wfp)))
+ {
+ HWND cwfp = ChildWindowFromPoint (wfp, pt);
+ struct frame *f2;
+
+ /* If cwfp exists it should be one of our windows ... */
+ if (cwfp && (f2 = x_any_window_to_frame (dpyinfo, cwfp)))
+ f1 = f2;
+ }
+ }
/* If not, is it one of our scroll bars? */
if (! f1)
/* Make sure scroll bar is "visible" before moving, to ensure the
area of the parent window now exposed will be refreshed. */
my_show_window (f, hwnd, SW_HIDE);
- MoveWindow (hwnd, left, top, width, max (height, 1), TRUE);
+/** MoveWindow (hwnd, left, top, width, max (height, 1), TRUE); **/
+ /* Try to not draw over child frames. */
+ SetWindowPos (hwnd, HWND_BOTTOM, left, top, width, max (height, 1),
+ SWP_FRAMECHANGED);
si.cbSize = sizeof (si);
si.fMask = SIF_RANGE;
/* Make sure scroll bar is "visible" before moving, to ensure the
area of the parent window now exposed will be refreshed. */
my_show_window (f, hwnd, SW_HIDE);
- MoveWindow (hwnd, left, top, width, max (height, 1), TRUE);
+/** MoveWindow (hwnd, left, top, width, max (height, 1), TRUE); **/
+ /* Try to not draw over child frames. */
+ SetWindowPos (hwnd, HWND_BOTTOM, left, top, max (width, 1), height,
+ SWP_FRAMECHANGED);
/* +++ SetScrollInfo +++ */
si.cbSize = sizeof (si);
in that case expose_frame will do nothing, and if
the various redisplay flags happen to be unset,
we are left with a blank frame. */
- if (!FRAME_GARBAGED_P (f))
+ if (!FRAME_GARBAGED_P (f) || FRAME_PARENT_FRAME (f))
{
HDC hdc = get_frame_dc (f);
if (f)
{
- /* Generate SELECT_WINDOW_EVENTs when needed. */
- if (!NILP (Vmouse_autoselect_window))
+ /* Maybe generate SELECT_WINDOW_EVENTs for
+ `mouse-autoselect-window'. */
+ if (!NILP (Vmouse_autoselect_window)
+ && (f == XFRAME (selected_frame)
+ /* Switch to f from another frame iff
+ focus_follows_mouse is set and f accepts
+ focus. */
+ || (!NILP (focus_follows_mouse)
+ && !FRAME_NO_ACCEPT_FOCUS (f))))
{
static Lisp_Object last_mouse_window;
Lisp_Object window = window_from_coordinates
only when it is active. */
if (WINDOWP (window)
&& !EQ (window, last_mouse_window)
- && !EQ (window, selected_window)
- /* For click-to-focus window managers
- create event iff we don't leave the
- selected frame. */
- && (focus_follows_mouse
- || (EQ (XWINDOW (window)->frame,
- XWINDOW (selected_window)->frame))))
+ && !EQ (window, selected_window))
{
inev.kind = SELECT_WINDOW_EVENT;
inev.frame_or_window = window;
}
+
/* Remember the last window where we saw the mouse. */
last_mouse_window = window;
}
+
if (!note_mouse_movement (f, &msg.msg))
help_echo_string = previous_help_echo_string;
}
if (tool_bar_p
|| (dpyinfo->w32_focus_frame
- && f != dpyinfo->w32_focus_frame))
+ && f != dpyinfo->w32_focus_frame
+ /* This does not help when the click happens in
+ a grand-parent frame. */
+ && !frame_ancestor_p (f, dpyinfo->w32_focus_frame)))
inev.kind = NO_EVENT;
}
if (f)
{
-
if (!dpyinfo->w32_focus_frame
|| f == dpyinfo->w32_focus_frame)
+ /* Emit an Emacs wheel-up/down event. */
{
- /* Emit an Emacs wheel-up/down event. */
construct_mouse_wheel (&inev, &msg, f);
+
+ /* Ignore any mouse motion that happened before this
+ event; any subsequent mouse-movement Emacs events
+ should reflect only motion after the ButtonPress. */
+ f->mouse_moved = false;
+ f->last_tool_bar_item = -1;
+ dpyinfo->last_mouse_frame = f;
+ }
+ else if (FRAME_NO_ACCEPT_FOCUS (f)
+ && !x_mouse_grabbed (dpyinfo))
+ {
+ Lisp_Object frame1 = get_frame_param (f, Qmouse_wheel_frame);
+ struct frame *f1 = FRAMEP (frame1) ? XFRAME (frame1) : NULL;
+
+ if (f1 && FRAME_LIVE_P (f1) && FRAME_W32_P (f1))
+ {
+ construct_mouse_wheel (&inev, &msg, f1);
+ f1->mouse_moved = false;
+ f1->last_tool_bar_item = -1;
+ dpyinfo->last_mouse_frame = f1;
+ }
+ else
+ dpyinfo->last_mouse_frame = f;
}
- /* Ignore any mouse motion that happened before this
- event; any subsequent mouse-movement Emacs events
- should reflect only motion after the
- ButtonPress. */
- f->mouse_moved = false;
- f->last_tool_bar_item = -1;
+ else
+ dpyinfo->last_mouse_frame = f;
}
- dpyinfo->last_mouse_frame = f;
+ else
+ dpyinfo->last_mouse_frame = f;
}
break;
w32fullscreen_hook (f);
}
}
+
check_visibility = 1;
break;
are computed correctly (Bug#21173). */
int display_left = 0;
int display_top = 0;
+ struct frame *p = FRAME_PARENT_FRAME (f);
+
if (flags & (XNegative | YNegative))
{
Lisp_Object list;
/* Treat negative positions as relative to the rightmost bottommost
position that fits on the screen. */
if (flags & XNegative)
- f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f))
- + display_left
- - FRAME_PIXEL_WIDTH (f)
- + f->left_pos
- - (left_right_borders_width - 1));
+ {
+ if (p)
+ f->left_pos = (FRAME_PIXEL_WIDTH (p)
+ - FRAME_PIXEL_WIDTH (f)
+ + f->left_pos
+ - (left_right_borders_width - 1));
+ else
+ f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f))
+ + display_left
+ - FRAME_PIXEL_WIDTH (f)
+ + f->left_pos
+ - (left_right_borders_width - 1));
+ }
if (flags & YNegative)
- f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
- + display_top
- - FRAME_PIXEL_HEIGHT (f)
- + f->top_pos
- - (top_bottom_borders_height - 1));
+ {
+ if (p)
+ f->top_pos = (FRAME_PIXEL_HEIGHT (p)
+ - FRAME_PIXEL_HEIGHT (f)
+ + f->top_pos
+ - (top_bottom_borders_height - 1));
+ else
+ f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
+ + display_top
+ - FRAME_PIXEL_HEIGHT (f)
+ + f->top_pos
+ - (top_bottom_borders_height - 1));
+ }
/* The left_pos and top_pos are now relative to the top and left
screen edges, so the flags should correspond. */
modified_left = f->left_pos;
modified_top = f->top_pos;
- my_set_window_pos (FRAME_W32_WINDOW (f),
- NULL,
- modified_left, modified_top,
- 0, 0,
- SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+ if (!FRAME_PARENT_FRAME (f))
+ my_set_window_pos (FRAME_W32_WINDOW (f), NULL,
+ modified_left, modified_top,
+ 0, 0,
+ SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
+ else
+ my_set_window_pos (FRAME_W32_WINDOW (f), HWND_TOP,
+ modified_left, modified_top,
+ 0, 0,
+ SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
unblock_input ();
}
Fcons (make_number (rect.right - rect.left),
make_number (rect.bottom - rect.top))));
- my_set_window_pos (FRAME_W32_WINDOW (f), NULL,
- 0, 0,
- rect.right - rect.left,
- rect.bottom - rect.top,
- SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
+ if (!FRAME_PARENT_FRAME (f))
+ my_set_window_pos (FRAME_W32_WINDOW (f), NULL,
+ 0, 0,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
+ else
+ my_set_window_pos (FRAME_W32_WINDOW (f), HWND_TOP,
+ 0, 0,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ SWP_NOMOVE | SWP_NOACTIVATE);
change_frame_size (f,
((pixelwidth == 0)
if (! FRAME_ICONIFIED_P (f)
&& ! f->output_data.w32->asked_for_visible)
{
- RECT workarea_rect;
- RECT window_rect;
-
- /* Adjust vertical window position in order to avoid being
- covered by a taskbar placed at the bottom of the desktop. */
- SystemParametersInfo (SPI_GETWORKAREA, 0, &workarea_rect, 0);
- GetWindowRect (FRAME_W32_WINDOW (f), &window_rect);
- if (window_rect.bottom > workarea_rect.bottom
- && window_rect.top > workarea_rect.top)
- f->top_pos = max (window_rect.top
- - window_rect.bottom + workarea_rect.bottom,
- workarea_rect.top);
+ if (!FRAME_PARENT_FRAME (f))
+ {
+ RECT workarea_rect;
+ RECT window_rect;
+
+ /* Adjust vertical window position in order to avoid being
+ covered by a taskbar placed at the bottom of the desktop. */
+ SystemParametersInfo (SPI_GETWORKAREA, 0, &workarea_rect, 0);
+ GetWindowRect (FRAME_W32_WINDOW (f), &window_rect);
+ if (window_rect.bottom > workarea_rect.bottom
+ && window_rect.top > workarea_rect.top)
+ f->top_pos = max (window_rect.top
+ - window_rect.bottom + workarea_rect.bottom,
+ workarea_rect.top);
+ }
x_set_offset (f, f->left_pos, f->top_pos, 0);
}
set for minimized windows that are still visible, so use that to
determine the appropriate flag to pass ShowWindow. */
my_show_window (f, FRAME_W32_WINDOW (f),
- FRAME_ICONIFIED_P (f) ? SW_RESTORE : SW_SHOWNORMAL);
+ FRAME_ICONIFIED_P (f)
+ ? SW_RESTORE
+ : FRAME_NO_FOCUS_ON_MAP (f)
+ ? SW_SHOWNOACTIVATE
+ : SW_SHOWNORMAL);
}
/* Synchronize to ensure Emacs knows the frame is visible
Lisp_Object value,
Lisp_Object oldval);
extern void initialize_frame_menubar (struct frame *);
+extern void w32_dialog_in_progress (Lisp_Object in_progress);
/* w32inevt.c */
extern int w32_kbd_patch_key (KEY_EVENT_RECORD *event, int cpId);
&& FRAME_KBOARD (tf) == FRAME_KBOARD (f)
&& !FRAME_MINIBUF_ONLY_P (tf)
&& !EQ (other_frame, tip_frame)
+ && !FRAME_PARENT_FRAME (tf)
&& (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf)))
break;
}
continue;
if (!EQ (frame, tooltip_frame)
+ && !FRAME_PARENT_FRAME (f)
&& (FRAME_ICONIFIED_P (f)
|| FRAME_VISIBLE_P (f) == 1
/* Exclude TTY frames that are obscured because they
continue;
run_window_size_change_functions (frame);
+
+ if (FRAME_PARENT_FRAME (f))
+ continue;
+
menu_bar_hooks_run = update_menu_bar (f, false, menu_bar_hooks_run);
#ifdef HAVE_WINDOW_SYSTEM
update_tool_bar (f, false);
#include <Xm/FileSB.h>
#include <Xm/List.h>
#include <Xm/TextF.h>
+#include <Xm/MwmUtil.h>
#endif
#ifdef USE_LUCID
static int dpyinfo_refcount;
#endif
+#ifndef USE_MOTIF
+#ifndef USE_GTK
+/** #define MWM_HINTS_FUNCTIONS (1L << 0) **/
+#define MWM_HINTS_DECORATIONS (1L << 1)
+/** #define MWM_HINTS_INPUT_MODE (1L << 2) **/
+/** #define MWM_HINTS_STATUS (1L << 3) **/
+
+#define MWM_DECOR_ALL (1L << 0)
+/** #define MWM_DECOR_BORDER (1L << 1) **/
+/** #define MWM_DECOR_RESIZEH (1L << 2) **/
+/** #define MWM_DECOR_TITLE (1L << 3) **/
+/** #define MWM_DECOR_MENU (1L << 4) **/
+/** #define MWM_DECOR_MINIMIZE (1L << 5) **/
+/** #define MWM_DECOR_MAXIMIZE (1L << 6) **/
+
+/** #define _XA_MOTIF_WM_HINTS "_MOTIF_WM_HINTS" **/
+
+typedef struct {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long input_mode;
+ unsigned long status;
+} PropMotifWmHints;
+
+#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
+#endif /* NOT USE_GTK */
+#endif /* NOT USE_MOTIF */
+
static struct x_display_info *x_display_info_for_name (Lisp_Object);
static void set_up_x_back_buffer (struct frame *f);
int win_x = 0, win_y = 0, outer_x = 0, outer_y = 0;
int real_x = 0, real_y = 0;
bool had_errors = false;
- Window win = f->output_data.x->parent_desc;
+ Window win = (FRAME_PARENT_FRAME (f)
+ ? FRAME_X_WINDOW (FRAME_PARENT_FRAME (f))
+ : f->output_data.x->parent_desc);
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
long max_len = 400;
Atom target_type = XA_CARDINAL;
outer_geom_cookie = xcb_get_geometry (xcb_conn,
FRAME_OUTER_WINDOW (f));
- if (dpyinfo->root_window == f->output_data.x->parent_desc)
+ if ((dpyinfo->root_window == f->output_data.x->parent_desc)
+ && !FRAME_PARENT_FRAME (f))
/* Try _NET_FRAME_EXTENTS if our parent is the root window. */
prop_cookie = xcb_get_property (xcb_conn, 0, win,
dpyinfo->Xatom_net_frame_extents,
#endif
}
- if (dpyinfo->root_window == f->output_data.x->parent_desc)
+ if ((dpyinfo->root_window == f->output_data.x->parent_desc)
+ && !FRAME_PARENT_FRAME (f))
{
/* Try _NET_FRAME_EXTENTS if our parent is the root window. */
#ifdef USE_XCB
unblock_input ();
}
+/**
+ * x_set_undecorated:
+ *
+ * Set frame F's `undecorated' parameter. If non-nil, F's window-system
+ * window is drawn without decorations, title, minimize/maximize boxes
+ * and external borders. This usually means that the window cannot be
+ * dragged, resized, iconified, maximized or deleted with the mouse. If
+ * nil, draw the frame with all the elements listed above unless these
+ * have been suspended via window manager settings.
+ *
+ * Some window managers may not honor this parameter.
+ */
+static void
+x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ if (!EQ (new_value, old_value))
+ {
+ FRAME_UNDECORATED (f) = NILP (new_value) ? false : true;
+#ifdef USE_GTK
+ xg_set_undecorated (f, new_value);
+#else
+ Display *dpy = FRAME_X_DISPLAY (f);
+ PropMotifWmHints hints;
+ Atom prop = XInternAtom (dpy, "_MOTIF_WM_HINTS", False);
+
+ memset (&hints, 0, sizeof(hints));
+ hints.flags = MWM_HINTS_DECORATIONS;
+ hints.decorations = NILP (new_value) ? MWM_DECOR_ALL : 0;
+
+ block_input ();
+ /* For some reason the third and fourth argument in the following
+ call must be identic: In the corresponding XGetWindowProperty
+ call in getMotifHints, xfwm has the third and seventh arg both
+ display_info->atoms[MOTIF_WM_HINTS]. Obviously, YMMV. */
+ XChangeProperty (dpy, FRAME_OUTER_WINDOW (f), prop, prop, 32,
+ PropModeReplace, (unsigned char *) &hints,
+ PROP_MOTIF_WM_HINTS_ELEMENTS);
+ unblock_input ();
+
+#endif /* USE_GTK */
+ }
+}
+
+/**
+ * x_set_parent_frame:
+ *
+ * Set frame F's `parent-frame' parameter. If non-nil, make F a child
+ * frame of the frame specified by that parameter. Technically, this
+ * makes F's window-system window a child window of the parent frame's
+ * window-system window. If nil, make F's window-system window a
+ * top-level window--a child of its display's root window.
+ *
+ * A child frame is clipped at the native edges of its parent frame.
+ * Its `left' and `top' parameters specify positions relative to the
+ * top-left corner of its parent frame's native rectangle. Usually,
+ * moving a parent frame moves all its child frames too, keeping their
+ * position relative to the parent unaltered. When a parent frame is
+ * iconified or made invisible, its child frames are made invisible.
+ * When a parent frame is deleted, its child frames are deleted too.
+ *
+ * A visible child frame always appears on top of its parent frame thus
+ * obscuring parts of it. When a frame has more than one child frame,
+ * their stacking order is specified just as that of non-child frames
+ * relative to their display.
+ *
+ * Whether a child frame has a menu or tool bar may be window-system or
+ * window manager dependent. It's advisable to disable both via the
+ * frame parameter settings.
+ *
+ * Some window managers may not honor this parameter.
+ */
+static void
+x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ struct frame *p = NULL;
+
+ if (!NILP (new_value)
+ && (!FRAMEP (new_value)
+ || !FRAME_LIVE_P (p = XFRAME (new_value))
+ || !FRAME_X_P (p)))
+ {
+ store_frame_param (f, Qparent_frame, old_value);
+ error ("Invalid specification of `parent-frame'");
+ }
+
+ if (p != FRAME_PARENT_FRAME (f))
+ {
+ block_input ();
+ XReparentWindow
+ (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+ p ? FRAME_X_WINDOW (p) : DefaultRootWindow (FRAME_X_DISPLAY (f)),
+ f->left_pos, f->top_pos);
+ unblock_input ();
+
+ fset_parent_frame (f, new_value);
+ }
+}
+
+/**
+ * x_set_no_focus_on_map:
+ *
+ * Set frame F's `no-focus-on-map' parameter which, if non-nil, means
+ * that F's window-system window does not want to receive input focus
+ * when it is mapped. (A frame's window is mapped when the frame is
+ * displayed for the first time and when the frame changes its state
+ * from `iconified' or `invisible' to `visible'.)
+ *
+ * Some window managers may not honor this parameter.
+ */
+static void
+x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ if (!EQ (new_value, old_value))
+ {
+#ifdef USE_GTK
+ xg_set_no_focus_on_map (f, new_value);
+#else /* not USE_GTK */
+ Display *dpy = FRAME_X_DISPLAY (f);
+ Atom prop = XInternAtom (dpy, "_NET_WM_USER_TIME", False);
+ Time timestamp = NILP (new_value) ? CurrentTime : 0;
+
+ XChangeProperty (dpy, FRAME_OUTER_WINDOW (f), prop,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) ×tamp, 1);
+#endif /* USE_GTK */
+ FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
+ }
+}
+
+/**
+ * x_set_no_accept_focus:
+ *
+ * Set frame F's `no-accept-focus' parameter which, if non-nil, hints
+ * that F's window-system window does not want to receive input focus
+ * via mouse clicks or by moving the mouse into it.
+ *
+ * If non-nil, this may have the unwanted side-effect that a user cannot
+ * scroll a non-selected frame with the mouse.
+ *
+ * Some window managers may not honor this parameter.
+ */
+static void
+x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ if (!EQ (new_value, old_value))
+ {
+#ifdef USE_GTK
+ xg_set_no_accept_focus (f, new_value);
+#else /* not USE_GTK */
+#ifdef USE_X_TOOLKIT
+ Arg al[1];
+
+ XtSetArg (al[0], XtNinput, NILP (new_value) ? True : False);
+ XtSetValues (f->output_data.x->widget, al, 1);
+#else /* not USE_X_TOOLKIT */
+ Window window = FRAME_X_WINDOW (f);
+
+ f->output_data.x->wm_hints.input = NILP (new_value) ? True : False;
+ XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
+#endif /* USE_X_TOOLKIT */
+#endif /* USE_GTK */
+ FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
+ }
+}
+
+/**
+ * x_set_override_redirect:
+ *
+ * Set frame F's `override_redirect' parameter which, if non-nil, hints
+ * that the window manager doesn't want to deal with F. Usually, such
+ * frames have no decorations and always appear on top of all frames.
+ *
+ * Some window managers may not honor this parameter.
+ */
+static void
+x_set_override_redirect (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ if (!EQ (new_value, old_value))
+ {
+ /* Here (xfwm) override_redirect can be changed for invisible
+ frames only. */
+ x_make_frame_invisible (f);
+
+#ifdef USE_GTK
+ xg_set_override_redirect (f, new_value);
+#else /* not USE_GTK */
+ XSetWindowAttributes attributes;
+
+ attributes.override_redirect = NILP (new_value) ? False : True;
+ XChangeWindowAttributes (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+ CWOverrideRedirect, &attributes);
+#endif
+ x_make_frame_visible (f);
+ FRAME_OVERRIDE_REDIRECT (f) = !NILP (new_value);
+ }
+}
+
+
#ifdef USE_GTK
/* Set icon from FILE for frame F. By using GTK functions the icon
most of the commands try to apply themselves to the minibuffer
frame itself, and get an error because you can't switch buffers
in or split the minibuffer window. */
- if (FRAME_MINIBUF_ONLY_P (f))
+ if (FRAME_MINIBUF_ONLY_P (f) || FRAME_PARENT_FRAME (f))
return;
if (TYPE_RANGED_INTEGERP (int, value))
and specify it.
Note that we do not specify here whether the position
is a user-specified or program-specified one.
- We pass that information later, in x_wm_set_size_hints. */
+ We pass that information later, in x_wm_set_size_hint. */
{
int left = f->left_pos;
bool xneg = (window_prompting & XNegative) != 0;
}
#endif /* HAVE_X_I18N */
- attribute_mask = CWEventMask;
+ attributes.override_redirect = FRAME_OVERRIDE_REDIRECT (f);
+ attribute_mask = CWEventMask | CWOverrideRedirect;
XChangeWindowAttributes (XtDisplay (shell_widget), XtWindow (shell_widget),
attribute_mask, &attributes);
x_set_name (f, name, explicit);
}
+ if (FRAME_UNDECORATED (f))
+ {
+ Display *dpy = FRAME_X_DISPLAY (f);
+ PropMotifWmHints hints;
+ Atom prop = XInternAtom (dpy, "_MOTIF_WM_HINTS", False);
+
+ memset (&hints, 0, sizeof(hints));
+ hints.flags = MWM_HINTS_DECORATIONS;
+ hints.decorations = 0;
+
+ /* For some reason the third and fourth argument in the following
+ call must be identic: In the corresponding XGetWindowProperty
+ call in getMotifHints, xfwm has the third and seventh arg both
+ display_info->atoms[MOTIF_WM_HINTS]. Obviously, YMMV. */
+ XChangeProperty (dpy, FRAME_OUTER_WINDOW (f), prop, prop, 32,
+ PropModeReplace, (unsigned char *) &hints,
+ PROP_MOTIF_WM_HINTS_ELEMENTS);
+ }
+
XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f->output_data.x->current_cursor
= f->output_data.x->text_cursor);
attributes.save_under = True;
attributes.event_mask = STANDARD_EVENT_SET;
attributes.colormap = FRAME_X_COLORMAP (f);
+ attributes.override_redirect = FRAME_OVERRIDE_REDIRECT (f);
attribute_mask = (CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
- | CWColormap);
+ | CWOverrideRedirect | CWColormap);
block_input ();
FRAME_X_WINDOW (f)
x_set_name (f, name, explicit);
}
+ if (FRAME_UNDECORATED (f))
+ {
+ Display *dpy = FRAME_X_DISPLAY (f);
+ PropMotifWmHints hints;
+ Atom prop = XInternAtom (dpy, "_MOTIF_WM_HINTS", False);
+
+ memset (&hints, 0, sizeof(hints));
+ hints.flags = MWM_HINTS_DECORATIONS;
+ hints.decorations = 0;
+
+ /* For some reason the third and fourth argument in the following
+ call must be identic: In the corresponding XGetWindowProperty
+ call in getMotifHints, xfwm has the third and seventh arg both
+ display_info->atoms[MOTIF_WM_HINTS]. Obviously, YMMV. */
+ XChangeProperty (dpy, FRAME_OUTER_WINDOW (f), prop, prop, 32,
+ PropModeReplace, (unsigned char *) &hints,
+ PROP_MOTIF_WM_HINTS_ELEMENTS);
+ }
+
+
XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
f->output_data.x->current_cursor
= f->output_data.x->text_cursor);
Lisp_Object frame, tem;
Lisp_Object name;
bool minibuffer_only = false;
+ bool undecorated = false, override_redirect = false;
long window_prompting = 0;
ptrdiff_t count = SPECPDL_INDEX ();
Lisp_Object display;
struct x_display_info *dpyinfo = NULL;
- Lisp_Object parent;
+ Lisp_Object parent, parent_frame;
struct kboard *kb;
int x_width = 0, x_height = 0;
else
f = make_frame (true);
+ parent_frame = x_get_arg (dpyinfo, parms, Qparent_frame, NULL, NULL,
+ RES_TYPE_SYMBOL);
+ /* Accept parent-frame iff parent-id was not specified. */
+ if (!NILP (parent)
+ || EQ (parent_frame, Qunbound)
+ || NILP (parent_frame)
+ || !FRAMEP (parent_frame)
+ || !FRAME_LIVE_P (XFRAME (parent_frame))
+ || !FRAME_X_P (XFRAME (parent_frame)))
+ parent_frame = Qnil;
+
+ fset_parent_frame (f, parent_frame);
+ store_frame_param (f, Qparent_frame, parent_frame);
+
+ if (!NILP (tem = (x_get_arg (dpyinfo, parms, Qundecorated, NULL, NULL,
+ RES_TYPE_BOOLEAN)))
+ && !(EQ (tem, Qunbound)))
+ undecorated = true;
+
+ FRAME_UNDECORATED (f) = undecorated;
+ store_frame_param (f, Qundecorated, undecorated ? Qt : Qnil);
+
+ if (!NILP (tem = (x_get_arg (dpyinfo, parms, Qoverride_redirect, NULL, NULL,
+ RES_TYPE_BOOLEAN)))
+ && !(EQ (tem, Qunbound)))
+ override_redirect = true;
+
+ FRAME_OVERRIDE_REDIRECT (f) = override_redirect;
+ store_frame_param (f, Qoverride_redirect, override_redirect ? Qt : Qnil);
+
XSETFRAME (frame, f);
f->terminal = dpyinfo->terminal;
init_iterator with a null face cache, which should not happen. */
init_frame_faces (f);
- /* The following call of change_frame_size is needed since otherwise
+ /* We have to call adjust_frame_size here since otherwise
x_set_tool_bar_lines will already work with the character sizes
- installed by init_frame_faces while the frame's pixel size is
- still calculated from a character size of 1 and we subsequently
- hit the (height >= 0) assertion in window_box_height.
+ installed by init_frame_faces while the frame's pixel size is still
+ calculated from a character size of 1 and we subsequently hit the
+ (height >= 0) assertion in window_box_height.
The non-pixelwise code apparently worked around this because it
had one frame line vs one toolbar line which left us with a zero
- root window height which was obviously wrong as well ... */
+ root window height which was obviously wrong as well ...
+
+ Also process `min-width' and `min-height' parameters right here
+ because `frame-windows-min-size' needs them. */
+ tem = x_get_arg (dpyinfo, parms, Qmin_width, NULL, NULL, RES_TYPE_NUMBER);
+ if (NUMBERP (tem))
+ store_frame_param (f, Qmin_width, tem);
+ tem = x_get_arg (dpyinfo, parms, Qmin_height, NULL, NULL, RES_TYPE_NUMBER);
+ if (NUMBERP (tem))
+ store_frame_param (f, Qmin_height, tem);
adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, true,
Qx_create_frame_1);
x_default_parameter (f, parms, Qalpha, Qnil,
"alpha", "Alpha", RES_TYPE_NUMBER);
+ if (!NILP (parent_frame))
+ {
+ struct frame *p = XFRAME (parent_frame);
+
+ block_input ();
+ XReparentWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+ FRAME_X_WINDOW (p), f->left_pos, f->top_pos);
+ unblock_input ();
+ }
+
+ x_default_parameter (f, parms, Qno_focus_on_map, Qnil,
+ NULL, NULL, RES_TYPE_BOOLEAN);
+ x_default_parameter (f, parms, Qno_accept_focus, Qnil,
+ NULL, NULL, RES_TYPE_BOOLEAN);
+
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
/* Create the menu bar. */
if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
/* Make the window appear on the frame and enable display, unless
the caller says not to. However, with explicit parent, Emacs
cannot control visibility, so don't try. */
- if (! f->output_data.x->explicit_parent)
+ if (!f->output_data.x->explicit_parent)
{
- Lisp_Object visibility;
-
- visibility = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
- RES_TYPE_SYMBOL);
- if (EQ (visibility, Qunbound))
- visibility = Qt;
+ Lisp_Object visibility
+ = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
if (EQ (visibility, Qicon))
x_iconify_frame (f);
- else if (! NILP (visibility))
- x_make_frame_visible (f);
else
{
- /* Must have been Qnil. */
+ if (EQ (visibility, Qunbound))
+ visibility = Qt;
+
+ if (!NILP (visibility))
+ x_make_frame_visible (f);
}
+
+ store_frame_param (f, Qvisibility, visibility);
}
block_input ();
if (dpyinfo->client_leader_window != 0)
{
XChangeProperty (FRAME_X_DISPLAY (f),
- FRAME_OUTER_WINDOW (f),
- dpyinfo->Xatom_wm_client_leader,
- XA_WINDOW, 32, PropModeReplace,
- (unsigned char *) &dpyinfo->client_leader_window, 1);
+ FRAME_OUTER_WINDOW (f),
+ dpyinfo->Xatom_wm_client_leader,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &dpyinfo->client_leader_window, 1);
}
unblock_input ();
+ /* Works iff frame has been already mapped. */
+ x_default_parameter (f, parms, Qskip_taskbar, Qnil,
+ NULL, NULL, RES_TYPE_BOOLEAN);
+ /* The `z-group' parameter works only for visible frames. */
+ x_default_parameter (f, parms, Qz_group, Qnil,
+ NULL, NULL, RES_TYPE_SYMBOL);
+
/* Initialize `default-minibuffer-frame' in case this is the first
frame on this terminal. */
if (FRAME_HAS_MINIBUF_P (f)
and similar functions. */
Vwindow_list = Qnil;
- return unbind_to (count, frame);
+ return unbind_to (count, frame);
}
struct frame *f = decode_live_frame (frame);
/** XWindowAttributes atts; **/
Window rootw;
- unsigned int ign, native_width, native_height;
- int xy_ign, xptr, yptr;
- int left_off, right_off, top_off, bottom_off;
+ unsigned int ign, native_width, native_height, x_border_width = 0;
+ int x_native = 0, y_native = 0, xptr = 0, yptr = 0;
+ int left_off = 0, right_off = 0, top_off = 0, bottom_off = 0;
int outer_left, outer_top, outer_right, outer_bottom;
int native_left, native_top, native_right, native_bottom;
int inner_left, inner_top, inner_right, inner_bottom;
block_input ();
XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
- &rootw, &xy_ign, &xy_ign, &native_width, &native_height,
- &ign, &ign);
+ &rootw, &x_native, &y_native, &native_width, &native_height,
+ &x_border_width, &ign);
/** XGetWindowAttributes (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), &atts); **/
- x_real_pos_and_offsets (f, &left_off, &right_off, &top_off, &bottom_off,
- NULL, NULL, &xptr, &yptr, NULL);
+ if (!FRAME_PARENT_FRAME (f))
+ x_real_pos_and_offsets (f, &left_off, &right_off, &top_off, &bottom_off,
+ NULL, NULL, &xptr, &yptr, NULL);
unblock_input ();
/** native_width = atts.width; **/
/** native_height = atts.height; **/
- outer_left = xptr;
- outer_top = yptr;
- outer_right = outer_left + left_off + native_width + right_off;
- outer_bottom = outer_top + top_off + native_height + bottom_off;
+ if (FRAME_PARENT_FRAME (f))
+ {
+ Lisp_Object parent, edges;
+
+ XSETFRAME (parent, FRAME_PARENT_FRAME (f));
+ edges = Fx_frame_edges (parent, Qnative_edges);
+ if (!NILP (edges))
+ {
+ x_native += XINT (Fnth (make_number (0), edges));
+ y_native += XINT (Fnth (make_number (1), edges));
+ }
+
+ outer_left = x_native;
+ outer_top = y_native;
+ outer_right = outer_left + native_width + 2 * x_border_width;
+ outer_bottom = outer_top + native_height + 2 * x_border_width;
+
+ native_left = x_native + x_border_width;
+ native_top = y_native + x_border_width;
+ native_right = native_left + native_width;
+ native_bottom = native_top + native_height;
+ }
+ else
+ {
+ outer_left = xptr;
+ outer_top = yptr;
+ outer_right = outer_left + left_off + native_width + right_off;
+ outer_bottom = outer_top + top_off + native_height + bottom_off;
- native_left = outer_left + left_off;
- native_top = outer_top + top_off;
- native_right = native_left + native_width;
- native_bottom = native_top + native_height;
+ native_left = outer_left + left_off;
+ native_top = outer_top + top_off;
+ native_right = native_left + native_width;
+ native_bottom = native_top + native_height;
+ }
internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f);
inner_left = native_left + internal_border_width;
make_number (inner_right), make_number (inner_bottom));
else
return
- listn (CONSTYPE_HEAP, 10,
+ listn (CONSTYPE_HEAP, 11,
Fcons (Qouter_position,
Fcons (make_number (outer_left),
make_number (outer_top))),
Fcons (Qexternal_border_size,
Fcons (make_number (right_off),
make_number (bottom_off))),
+ Fcons (Qouter_border_width, make_number (x_border_width)),
/* Approximate. */
Fcons (Qtitle_bar_size,
Fcons (make_number (0),
`outer-size' is a cons of the outer width and height of FRAME. The
outer size includes the title bar and the external borders as well as
- any menu and/or tool bar of frame.
+ any menu and/or tool bar of frame. For a child frame the value
+ includes FRAME's X borders, if any.
`external-border-size' is a cons of the horizontal and vertical width of
FRAME's external borders as supplied by the window manager.
FRAME.
`internal-border-width' is the width of the internal border of
- FRAME. */)
+ FRAME.
+
+`outer-border-width' is the width of the X border of FRAME. The X
+ border is usually only shown for frames without window manager
+ decorations like child and tooltip frames. */)
(Lisp_Object frame)
{
return frame_geometry (frame, Qnil);
: Qnative_edges));
}
+/**
+ * x_frame_list_z_order:
+ *
+ * Recursively add list of all frames on the display specified via
+ * DPYINFO and whose window-system window's parent is specified by
+ * WINDOW to FRAMES and return FRAMES.
+ */
+static Lisp_Object
+x_frame_list_z_order (Display* dpy, Window window)
+{
+ Window root, parent, *children;
+ unsigned int nchildren;
+ int i;
+ Lisp_Object frames = Qnil;
+
+ block_input ();
+ if (XQueryTree (dpy, window, &root, &parent, &children, &nchildren))
+ {
+ unblock_input ();
+ for (i = 0; i < nchildren; i++)
+ {
+ Lisp_Object frame, tail;
+
+ FOR_EACH_FRAME (tail, frame)
+ /* With a reparenting window manager the parent_desc field
+ usually specifies the topmost windows of our frames.
+ Otherwise FRAME_OUTER_WINDOW should do. */
+ if (XFRAME (frame)->output_data.x->parent_desc == children[i]
+ || FRAME_OUTER_WINDOW (XFRAME (frame)) == children[i])
+ frames = Fcons (frame, frames);
+ }
+
+ if (children) XFree ((char *)children);
+ }
+ else
+ unblock_input ();
+
+ return frames;
+}
+
+
+DEFUN ("x-frame-list-z-order", Fx_frame_list_z_order,
+ Sx_frame_list_z_order, 0, 1, 0,
+ doc: /* Return list of Emacs' frames, in Z (stacking) order.
+The optional argument TERMINAL specifies which display to ask about.
+TERMINAL should be either a frame or a display name (a string). If
+omitted or nil, that stands for the selected frame's display. Return
+nil if TERMINAL contains no Emacs frame.
+
+As a special case, if TERMINAL is non-nil and specifies a live frame,
+return the child frames of that frame in Z (stacking) order.
+
+Frames are listed from topmost (first) to bottommost (last). */)
+ (Lisp_Object terminal)
+{
+ struct x_display_info *dpyinfo = check_x_display_info (terminal);
+ Display *dpy = dpyinfo->display;
+ Window window;
+
+ if (FRAMEP (terminal) && FRAME_LIVE_P (XFRAME (terminal)))
+ window = FRAME_X_WINDOW (XFRAME (terminal));
+ else
+ window = dpyinfo->root_window;
+
+ return x_frame_list_z_order (dpy, window);
+}
+
+/**
+ * x_frame_restack:
+ *
+ * Restack frame F1 below frame F2, above if ABOVE_FLAG is non-nil. In
+ * practice this is a two-step action: The first step removes F1's
+ * window-system window from the display. The second step reinserts
+ * F1's window below (above if ABOVE_FLAG is true) that of F2.
+ */
+static void
+x_frame_restack (struct frame *f1, struct frame *f2, bool above_flag)
+{
+#ifdef USE_GTK
+ block_input ();
+ xg_frame_restack (f1, f2, above_flag);
+ unblock_input ();
+#else
+ Display *dpy = FRAME_X_DISPLAY (f1);
+ Window window1 = FRAME_OUTER_WINDOW (f1);
+ XWindowChanges wc;
+ unsigned long mask = (CWSibling | CWStackMode);
+
+ wc.sibling = FRAME_OUTER_WINDOW (f2);
+ wc.stack_mode = above_flag ? Above : Below;
+ block_input ();
+ /* Configure the window manager window (a normal XConfigureWindow
+ won't cut it). This should also work for child frames. */
+ XReconfigureWMWindow (dpy, window1, FRAME_X_SCREEN_NUMBER (f1), mask, &wc);
+ unblock_input ();
+#endif /* USE_GTK */
+}
+
+
+DEFUN ("x-frame-restack", Fx_frame_restack, Sx_frame_restack, 2, 3, 0,
+ doc: /* Restack FRAME1 below FRAME2.
+This means that if both frames are visible and the display areas of
+these frames overlap, FRAME2 (partially) obscures FRAME1. If optional
+third argument ABOVE is non-nil, restack FRAME1 above FRAME2. This
+means that if both frames are visible and the display areas of these
+frames overlap, FRAME1 (partially) obscures FRAME2.
+
+This may be thought of as an atomic action performed in two steps: The
+first step removes FRAME1's window-step window from the display. The
+second step reinserts FRAME1's window below (above if ABOVE is true)
+that of FRAME2. Hence the position of FRAME2 in its display's Z
+\(stacking) order relative to all other frames excluding FRAME1 remains
+unaltered.
+
+Some window managers may refuse to restack windows. */)
+ (Lisp_Object frame1, Lisp_Object frame2, Lisp_Object above)
+{
+ struct frame *f1 = decode_live_frame (frame1);
+ struct frame *f2 = decode_live_frame (frame2);
+
+ if (FRAME_OUTER_WINDOW (f1) && FRAME_OUTER_WINDOW (f2))
+ {
+ x_frame_restack (f1, f2, !NILP (above));
+ return Qt;
+ }
+ else
+ {
+ error ("Cannot restack frames");
+ return Qnil;
+ }
+}
+
+
DEFUN ("x-mouse-absolute-pixel-position", Fx_mouse_absolute_pixel_position,
Sx_mouse_absolute_pixel_position, 0, 0, 0,
doc: /* Return absolute position of mouse cursor in pixels.
if (popup_activated ())
error ("Trying to use a menu from within a menu-entry");
+ else
+ x_menu_set_in_use (true);
CHECK_STRING (prompt);
CHECK_STRING (dir);
if (popup_activated ())
error ("Trying to use a menu from within a menu-entry");
+ else
+ x_menu_set_in_use (true);
/* Prevent redisplay. */
specbind (Qinhibit_redisplay, Qt);
x_set_sticky,
x_set_tool_bar_position,
x_set_inhibit_double_buffering,
+ x_set_undecorated,
+ x_set_parent_frame,
+ x_set_skip_taskbar,
+ x_set_no_focus_on_map,
+ x_set_no_accept_focus,
+ x_set_z_group,
+ x_set_override_redirect,
};
void
defsubr (&Sx_display_monitor_attributes_list);
defsubr (&Sx_frame_geometry);
defsubr (&Sx_frame_edges);
+ defsubr (&Sx_frame_list_z_order);
+ defsubr (&Sx_frame_restack);
defsubr (&Sx_mouse_absolute_pixel_position);
defsubr (&Sx_set_mouse_absolute_pixel_position);
defsubr (&Sx_wm_set_size_hint);
void
x_menu_set_in_use (bool in_use)
{
+ Lisp_Object frames, frame;
+
menu_items_inuse = in_use ? Qt : Qnil;
popup_activated_flag = in_use;
#ifdef USE_X_TOOLKIT
if (popup_activated_flag)
x_activate_timeout_atimer ();
#endif
-}
+ /* Don't let frames in `above' z-group obscure popups. */
+ FOR_EACH_FRAME (frames, frame)
+ {
+ struct frame *f = XFRAME (frame);
+
+ if (in_use && FRAME_Z_GROUP_ABOVE (f))
+ x_set_z_group (f, Qabove_suspended, Qabove);
+ else if (!in_use && FRAME_Z_GROUP_ABOVE_SUSPENDED (f))
+ x_set_z_group (f, Qabove, Qabove_suspended);
+ }
+}
#endif
/* Wait for an X event to arrive or for a timer to expire. */
Do this unconditionally as this function is called on reparent when
alpha has not changed on the frame. */
- parent = x_find_topmost_parent (f);
- if (parent != None)
- XChangeProperty (dpy, parent, dpyinfo->Xatom_net_wm_window_opacity,
- XA_CARDINAL, 32, PropModeReplace,
- (unsigned char *) &opac, 1);
+ if (!FRAME_PARENT_FRAME (f))
+ {
+ parent = x_find_topmost_parent (f);
+ if (parent != None)
+ XChangeProperty (dpy, parent, dpyinfo->Xatom_net_wm_window_opacity,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) &opac, 1);
+ }
/* return unless necessary */
{
containing the pointer. */
{
Window win, child;
+#ifdef USE_GTK
+ Window first_win = 0;
+#endif
int win_x, win_y;
int parent_x = 0, parent_y = 0;
&child);
if (child == None || child == win)
- break;
+ {
+#ifdef USE_GTK
+ /* On GTK we have not inspected WIN yet. If it has
+ a frame and that frame has a parent, use it. */
+ struct frame *f = x_window_to_frame (dpyinfo, win);
+
+ if (f && FRAME_PARENT_FRAME (f))
+ first_win = win;
+#endif
+ break;
+ }
#ifdef USE_GTK
/* We don't wan't to know the innermost window. We
want the edit window. For non-Gtk+ the innermost
window is the edit window. For Gtk+ it might not
be. It might be the tool bar for example. */
if (x_window_to_frame (dpyinfo, win))
- break;
+ /* But don't hurry. We might find a child frame
+ beneath. */
+ first_win = win;
#endif
win = child;
parent_x = win_x;
parent_y = win_y;
}
+#ifdef USE_GTK
+ if (first_win)
+ win = first_win;
+#endif
+
/* Now we know that:
win is the innermost window containing the pointer
(XTC says it has no child containing the pointer),
Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar);
XtConfigureWidget (scroll_bar, left, top, width, max (height, 1), 0);
XtMapWidget (scroll_bar);
+ /* Don't obscure any child frames. */
+ XLowerWindow (FRAME_X_DISPLAY (f), bar->x_window);
#endif /* not USE_GTK */
}
#else /* not USE_TOOLKIT_SCROLL_BARS */
- XMapRaised (FRAME_X_DISPLAY (f), bar->x_window);
+ XMapWindow (FRAME_X_DISPLAY (f), bar->x_window);
+ /* Don't obscure any child frames. */
+ XLowerWindow (FRAME_X_DISPLAY (f), bar->x_window);
#endif /* not USE_TOOLKIT_SCROLL_BARS */
unblock_input ();
/* x, y, width, height */
0, 0, bar->width - 1, bar->height - 1);
- /* 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,
- FRAME_FOREGROUND_PIXEL (f));
+ /* 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,
+ FRAME_FOREGROUND_PIXEL (f));
unblock_input ();
f = x_top_window_to_frame (dpyinfo, event->xreparent.window);
if (f)
{
- f->output_data.x->parent_desc = event->xreparent.parent;
- x_real_positions (f, &f->left_pos, &f->top_pos);
+ /* Maybe we shouldn't set this for child frames ?? */
+ f->output_data.x->parent_desc = event->xreparent.parent;
+ if (!FRAME_PARENT_FRAME (f))
+ x_real_positions (f, &f->left_pos, &f->top_pos);
+ else
+ {
+ Window root;
+ unsigned int dummy_uint;
+
+ block_input ();
+ XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+ &root, &f->left_pos, &f->top_pos,
+ &dummy_uint, &dummy_uint, &dummy_uint, &dummy_uint);
+ unblock_input ();
+ }
/* Perhaps reparented due to a WM restart. Reset this. */
FRAME_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN;
/* Check if fullscreen was specified before we where mapped the
first time, i.e. from the command line. */
if (!f->output_data.x->has_been_visible)
- x_check_fullscreen (f);
+ {
+
+ x_check_fullscreen (f);
+#ifndef USE_GTK
+ /* For systems that cannot synthesize `skip_taskbar' for
+ unmapped windows do the following. */
+ if (FRAME_SKIP_TASKBAR (f))
+ x_set_skip_taskbar (f, Qt, Qnil);
+#endif /* Not USE_GTK */
+ }
+
+ if (!iconified)
+ {
+ /* The `z-group' is reset every time a frame becomes
+ invisible. Handle this here. */
+ if (FRAME_Z_GROUP (f) == z_group_above)
+ x_set_z_group (f, Qabove, Qnil);
+ else if (FRAME_Z_GROUP (f) == z_group_below)
+ x_set_z_group (f, Qbelow, Qnil);
+ }
SET_FRAME_VISIBLE (f, 1);
SET_FRAME_ICONIFIED (f, false);
#endif
if (f)
{
-
- /* Generate SELECT_WINDOW_EVENTs when needed.
- Don't let popup menus influence things (bug#1261). */
- if (!NILP (Vmouse_autoselect_window) && !popup_activated ())
+ /* Maybe generate a SELECT_WINDOW_EVENT for
+ `mouse-autoselect-window' but don't let popup menus
+ interfere with this (Bug#1261). */
+ if (!NILP (Vmouse_autoselect_window)
+ && !popup_activated ()
+ /* Don't switch if we're currently in the minibuffer.
+ This tries to work around problems where the
+ minibuffer gets unselected unexpectedly, and where
+ you then have to move your mouse all the way down to
+ the minibuffer to select it. */
+ && !MINI_WINDOW_P (XWINDOW (selected_window))
+ /* With `focus-follows-mouse' non-nil create an event
+ also when the target window is on another frame. */
+ && (f == XFRAME (selected_frame)
+ || !NILP (focus_follows_mouse)))
{
static Lisp_Object last_mouse_window;
Lisp_Object window = window_from_coordinates
(f, event->xmotion.x, event->xmotion.y, 0, false);
- /* 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 only when it is active. */
+ /* A window will be autoselected only when it is not
+ selected now and the last mouse movement event was
+ not in it. The remainder of the code is a bit vague
+ wrt what a "window" is. For immediate autoselection,
+ the window is usually the entire window but for GTK
+ where the scroll bars don't count. For delayed
+ autoselection the window is usually the window's text
+ area including the margins. */
if (WINDOWP (window)
&& !EQ (window, last_mouse_window)
- && !EQ (window, selected_window)
- /* For click-to-focus window managers
- create event iff we don't leave the
- selected frame. */
- && (focus_follows_mouse
- || (EQ (XWINDOW (window)->frame,
- XWINDOW (selected_window)->frame))))
+ && !EQ (window, selected_window))
{
inev.ie.kind = SELECT_WINDOW_EVENT;
inev.ie.frame_or_window = window;
}
+
/* Remember the last window where we saw the mouse. */
last_mouse_window = window;
}
+
if (!note_mouse_movement (f, &event->xmotion))
help_echo_string = previous_help_echo_string;
}
XSETFRAME (frame, f);
- x_real_positions (f, &f->left_pos, &f->top_pos);
+ if (!FRAME_PARENT_FRAME (f))
+ x_real_positions (f, &f->left_pos, &f->top_pos);
+ else
+ {
+ Window root;
+ unsigned int dummy_uint;
+
+ block_input ();
+ XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+ &root, &f->left_pos, &f->top_pos,
+ &dummy_uint, &dummy_uint, &dummy_uint, &dummy_uint);
+ unblock_input ();
+ }
if (old_left != f->left_pos || old_top != f->top_pos)
{
dpyinfo->last_mouse_glyph_frame = NULL;
x_display_set_last_user_time (dpyinfo, event->xbutton.time);
- f = (x_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
- : x_window_to_frame (dpyinfo, event->xbutton.window));
+ if (x_mouse_grabbed (dpyinfo))
+ f = dpyinfo->last_mouse_frame;
+ else
+ {
+ f = x_window_to_frame (dpyinfo, event->xbutton.window);
+
+ if (f && event->xbutton.type == ButtonPress
+ && !popup_activated ()
+ && !x_window_to_scroll_bar (event->xbutton.display,
+ event->xbutton.window, 2)
+ && !FRAME_NO_ACCEPT_FOCUS (f))
+ {
+ /* When clicking into a child frame or when clicking
+ into a parent frame with the child frame selected and
+ `no-accept-focus' is not set, select the clicked
+ frame. */
+ struct frame *hf = dpyinfo->x_highlight_frame;
+
+ if (FRAME_PARENT_FRAME (f) || frame_ancestor_p (f, hf))
+ {
+ block_input ();
+ XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+ RevertToParent, CurrentTime);
+ if (FRAME_PARENT_FRAME (f))
+ XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
+ unblock_input ();
+ }
+ }
+ }
#ifdef USE_GTK
if (f && xg_event_is_for_scrollbar (f, event))
x_calc_absolute_position (struct frame *f)
{
int flags = f->size_hint_flags;
+ struct frame *p = FRAME_PARENT_FRAME (f);
/* We have nothing to do if the current position
is already for the top-left corner. */
/* Treat negative positions as relative to the leftmost bottommost
position that fits on the screen. */
- if (flags & XNegative)
- f->left_pos = x_display_pixel_width (FRAME_DISPLAY_INFO (f))
- - FRAME_PIXEL_WIDTH (f) + f->left_pos;
+ if ((flags & XNegative) && (f->left_pos <= 0))
+ {
+ int width = FRAME_PIXEL_WIDTH (f);
- {
- int height = FRAME_PIXEL_HEIGHT (f);
+ /* A frame that has been visible at least once should have outer
+ edges. */
+ if (f->output_data.x->has_been_visible && !p)
+ {
+ Lisp_Object frame;
+ Lisp_Object edges = Qnil;
+
+ XSETFRAME (frame, f);
+ edges = Fx_frame_edges (frame, Qouter_edges);
+ if (!NILP (edges))
+ width = (XINT (Fnth (make_number (2), edges))
+ - XINT (Fnth (make_number (0), edges)));
+ }
+
+ if (p)
+ f->left_pos = (FRAME_PIXEL_WIDTH (p) - width - 2 * f->border_width
+ + f->left_pos);
+ else
+ f->left_pos = (x_display_pixel_width (FRAME_DISPLAY_INFO (f))
+ - width + f->left_pos);
+
+ }
+
+ if ((flags & YNegative) && (f->top_pos <= 0))
+ {
+ int height = FRAME_PIXEL_HEIGHT (f);
#if defined USE_X_TOOLKIT && defined USE_MOTIF
- /* Something is fishy here. When using Motif, starting Emacs with
- `-g -0-0', the frame appears too low by a few pixels.
+ /* Something is fishy here. When using Motif, starting Emacs with
+ `-g -0-0', the frame appears too low by a few pixels.
- This seems to be so because initially, while Emacs is starting,
- the column widget's height and the frame's pixel height are
- different. The column widget's height is the right one. In
- later invocations, when Emacs is up, the frame's pixel height
- is right, though.
+ This seems to be so because initially, while Emacs is starting,
+ the column widget's height and the frame's pixel height are
+ different. The column widget's height is the right one. In
+ later invocations, when Emacs is up, the frame's pixel height
+ is right, though.
- It's not obvious where the initial small difference comes from.
- 2000-12-01, gerd. */
+ It's not obvious where the initial small difference comes from.
+ 2000-12-01, gerd. */
- XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
+ XtVaGetValues (f->output_data.x->column_widget, XtNheight, &height, NULL);
#endif
- if (flags & YNegative)
- f->top_pos = x_display_pixel_height (FRAME_DISPLAY_INFO (f))
- - height + f->top_pos;
+ if (f->output_data.x->has_been_visible && !p)
+ {
+ Lisp_Object frame;
+ Lisp_Object edges = Qnil;
+
+ XSETFRAME (frame, f);
+ if (NILP (edges))
+ edges = Fx_frame_edges (frame, Qouter_edges);
+ if (!NILP (edges))
+ height = (XINT (Fnth (make_number (3), edges))
+ - XINT (Fnth (make_number (1), edges)));
+ }
+
+ if (p)
+ f->top_pos = (FRAME_PIXEL_HEIGHT (p) - height - 2 * f->border_width
+ + f->top_pos);
+ else
+ f->top_pos = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
+ - height + f->top_pos);
}
/* The left_pos and top_pos
need to compute the top/left offset adjustment for this frame. */
if (change_gravity != 0
+ && !FRAME_PARENT_FRAME (f)
&& (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
|| (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
&& (FRAME_X_OUTPUT (f)->move_offset_left == 0
dpyinfo->Xatom_net_wm_state_sticky, None);
}
+/**
+ * x_set_skip_taskbar:
+ *
+ * Set frame F's `skip-taskbar' parameter. If non-nil, this should
+ * remove F's icon from the taskbar associated with the display of F's
+ * window-system window and inhibit switching to F's window via
+ * <Alt>-<TAB>. If nil, lift these restrictions.
+ *
+ * Some window managers may not honor this parameter.
+ */
+void
+x_set_skip_taskbar (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ if (!EQ (new_value, old_value))
+ {
+#ifdef USE_GTK
+ xg_set_skip_taskbar (f, new_value);
+#else
+ Lisp_Object frame;
+ struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+
+ XSETFRAME (frame, f);
+ set_wm_state (frame, !NILP (new_value),
+ dpyinfo->Xatom_net_wm_state_skip_taskbar, None);
+#endif /* USE_GTK */
+ FRAME_SKIP_TASKBAR (f) = !NILP (new_value);
+ }
+}
+
+/**
+ * x_set_z_group:
+ *
+ * Set frame F's `z-group' parameter. If `above', F's window-system
+ * window is displayed above all windows that do not have the `above'
+ * property set. If nil, F's window is shown below all windows that
+ * have the `above' property set and above all windows that have the
+ * `below' property set. If `below', F's window is displayed below all
+ * windows that do not have the `below' property set.
+ *
+ * Some window managers may not honor this parameter.
+ */
+void
+x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+{
+ /* We don't care about old_value. The window manager might have
+ reset the value without telling us. */
+ Lisp_Object frame;
+ struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+
+ XSETFRAME (frame, f);
+
+ if (NILP (new_value))
+ {
+ set_wm_state (frame, false,
+ dpyinfo->Xatom_net_wm_state_above, None);
+ set_wm_state (frame, false,
+ dpyinfo->Xatom_net_wm_state_below, None);
+ FRAME_Z_GROUP (f) = z_group_none;
+ }
+ else if (EQ (new_value, Qabove))
+ {
+ set_wm_state (frame, true,
+ dpyinfo->Xatom_net_wm_state_above, None);
+ set_wm_state (frame, false,
+ dpyinfo->Xatom_net_wm_state_below, None);
+ FRAME_Z_GROUP (f) = z_group_above;
+ }
+ else if (EQ (new_value, Qbelow))
+ {
+ set_wm_state (frame, false,
+ dpyinfo->Xatom_net_wm_state_above, None);
+ set_wm_state (frame, true,
+ dpyinfo->Xatom_net_wm_state_below, None);
+ FRAME_Z_GROUP (f) = z_group_below;
+ }
+ else if (EQ (new_value, Qabove_suspended))
+ {
+ set_wm_state (frame, false,
+ dpyinfo->Xatom_net_wm_state_above, None);
+ FRAME_Z_GROUP (f) = z_group_above_suspended;
+ }
+ else
+ error ("Invalid z-group specification");
+}
+
+
/* Return the current _NET_WM_STATE.
SIZE_STATE is set to one of the FULLSCREEN_* values.
Set *STICKY to the sticky state.
int old_height = FRAME_PIXEL_HEIGHT (f);
Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);
- if (change_gravity) f->win_gravity = NorthWestGravity;
+ if (change_gravity)
+ f->win_gravity = NorthWestGravity;
x_wm_set_size_hint (f, 0, false);
/* When the frame is fullheight and we only want to change the width
void
x_make_frame_visible (struct frame *f)
{
+ if (FRAME_PARENT_FRAME (f))
+ {
+ if (!FRAME_VISIBLE_P (f))
+ {
+ block_input ();
+#ifdef USE_GTK
+ gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
+ XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+ f->left_pos, f->top_pos);
+#else
+ XMapRaised (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
+#endif
+ unblock_input ();
+
+ SET_FRAME_VISIBLE (f, true);
+ SET_FRAME_ICONIFIED (f, false);
+ }
+ return;
+ }
+
block_input ();
x_set_bitmap_icon (f);
because the window manager may choose the position
and we don't want to override it. */
- if (! FRAME_VISIBLE_P (f)
- && ! FRAME_ICONIFIED_P (f)
- && ! FRAME_X_EMBEDDED_P (f)
+ if (!FRAME_VISIBLE_P (f)
+ && !FRAME_ICONIFIED_P (f)
+ && !FRAME_X_EMBEDDED_P (f)
+ && !FRAME_PARENT_FRAME (f)
&& f->win_gravity == NorthWestGravity
&& previously_visible)
{
xembed_set_info (f, 0);
else
#endif
- {
- if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
- DefaultScreen (FRAME_X_DISPLAY (f))))
- {
- unblock_input ();
- error ("Can't notify window manager of window withdrawal");
- }
- }
+ if (! XWithdrawWindow (FRAME_X_DISPLAY (f), window,
+ DefaultScreen (FRAME_X_DISPLAY (f))))
+ {
+ unblock_input ();
+ error ("Can't notify window manager of window withdrawal");
+ }
+
+ x_sync (f);
/* We can't distinguish this from iconification
just by the event that we get from the server.
SET_FRAME_VISIBLE (f, 0);
SET_FRAME_ICONIFIED (f, false);
- x_sync (f);
-
unblock_input ();
}
ATOM_REFS_INIT ("SM_CLIENT_ID", Xatom_SM_CLIENT_ID)
ATOM_REFS_INIT ("_XSETTINGS_SETTINGS", Xatom_xsettings_prop)
ATOM_REFS_INIT ("MANAGER", Xatom_xsettings_mgr)
+ ATOM_REFS_INIT ("_NET_WM_STATE_SKIP_TASKBAR", Xatom_net_wm_state_skip_taskbar)
+ ATOM_REFS_INIT ("_NET_WM_STATE_ABOVE", Xatom_net_wm_state_above)
+ ATOM_REFS_INIT ("_NET_WM_STATE_BELOW", Xatom_net_wm_state_below)
};
int i;
/* Atoms dealing with EWMH (i.e. _NET_...) */
Atom Xatom_net_wm_state, Xatom_net_wm_state_fullscreen,
Xatom_net_wm_state_maximized_horz, Xatom_net_wm_state_maximized_vert,
- Xatom_net_wm_state_sticky, Xatom_net_wm_state_hidden,
- Xatom_net_frame_extents,
- Xatom_net_current_desktop, Xatom_net_workarea;
+ Xatom_net_wm_state_sticky, Xatom_net_wm_state_above, Xatom_net_wm_state_below,
+ Xatom_net_wm_state_hidden, Xatom_net_wm_state_skip_taskbar,
+ Xatom_net_frame_extents, Xatom_net_current_desktop, Xatom_net_workarea;
/* XSettings atoms and windows. */
Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr;
}
extern void x_set_sticky (struct frame *, Lisp_Object, Lisp_Object);
+extern void x_set_skip_taskbar (struct frame *, Lisp_Object, Lisp_Object);
+extern void x_set_z_group (struct frame *, Lisp_Object, Lisp_Object);
extern bool x_wm_supports (struct frame *, Atom);
extern void x_wait_for_event (struct frame *, int);
extern void x_clear_under_internal_border (struct frame *f);