* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) @ 2017-01-09 22:20 Arthur Miller 2017-01-10 8:23 ` martin rudalics ` (3 more replies) 0 siblings, 4 replies; 85+ messages in thread From: Arthur Miller @ 2017-01-09 22:20 UTC (permalink / raw) To: 25408 [-- Attachment #1: Type: text/plain, Size: 12122 bytes --] I would like to be able to run Emacs without frame decorations on Win OS. I don't like those since they break visual styles of my Emacs, especially if I use a dark theme. Also caption bar take some of vertical screen estate unnecessary. I didn't found any reliable way to do this from Emacs. It can be done via Win32 API SetWindowLongPtr by changing EMACS_CLASS style to WS_POPUP|WS_TABSTOP|WS_VISIBLE. It can be changed back to original by either saving old style in a variable or by setting corresponding style bits for standard window frame. I suggest either to implement this in a "border-width" property when border width is set to 0, or to implement a new variable/function that can be set in init file, such as for example "no-frame-borders t". I have made small prototype/mockup to illustrate what I mean which can be seen on https://www.youtube.com/watch?v=ii_gTRCuXog Care has to be taken to note that when removing caption bar and borders it will be no longer possible to move and resize window unless user have other means of performing those applications. I am using a small opensource app called alt-drag (https://stefansundin.github.io/altdrag/). For convienience one might implement moving/resizing ops in Emacs window procedure. For ex they can be faked by just sending corresponding messages back to wnd proc. I think standard way to do this is by handling WM_NCHITTEST, as for example: case WM_NCHITTEST: { LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam); if (hit == HTCLIENT) hit = HTCAPTION; return hit; } Similar could maybe work for HTSIZE but I haven't tested it myself though, so I can't tell for sure. In GNU Emacs 26.0.50.1 (x86_64-w64-mingw32) of 2017-01-05 built on DESKTOP-EBMFI2K Repository revision: d88cdad2847726438c7d1de9fd2651c4be9243aa Windowing system distributor 'Microsoft Corp.', version 10.0.14393 Recent messages: Wrote c:/Users/Arthur/.emacs [yas] Prepared just-in-time loading of snippets successfully. [2 times] Loading c:/Users/Arthur/.emacs.d/plugins/realgud/realgud/common/custom.el (source)...done Loading c:/Users/Arthur/.emacs.d/plugins/bookmark-plus/bookmark+-mac.el (source)...done Loading c:/Users/Arthur/.emacs.d/plugins/bookmark-plus/bookmark+-mac.el (source)...done Loading c:/Users/Arthur/.emacs.d/plugins/bookmark-plus/bookmark+-mac.el (source)...done Loading c:/Users/Arthur/.emacs.d/plugins/bookmark-plus/bookmark+-mac.el (source)...done Loading c:/Users/Arthur/.emacs.d/plugins/bookmark-plus/bookmark+-mac.el (source)...done Loading c:/Users/Arthur/.emacs.d/etc/recentf...done (Shell command succeeded with no output) [2 times] Configured using: 'configure --without-imagemagick --with-modules --without-makeinfo' Configured features: XPM JPEG TIFF GIF PNG RSVG SOUND NOTIFY ACL GNUTLS LIBXML2 ZLIB TOOLKIT_SCROLL_BARS MODULES Important settings: value of $LANG: SVE locale-coding-system: cp1252 Major mode: Emacs-Lisp Minor modes in effect: window-number-mode: t global-semanticdb-minor-mode: t global-semantic-idle-scheduler-mode: t semantic-mode: t global-ede-mode: t helm-mode: t shell-dirtrack-mode: t helm-autoresize-mode: t async-bytecomp-package-mode: t global-auto-complete-mode: t auto-complete-mode: t yas-global-mode: t yas-minor-mode: t global-undo-tree-mode: t undo-tree-mode: t override-global-mode: t which-function-mode: t save-place-mode: t global-auto-revert-mode: t global-hl-line-mode: t electric-pair-mode: t winner-mode: t show-paren-mode: t recentf-mode: t tooltip-mode: t global-eldoc-mode: t eldoc-mode: t electric-indent-mode: t mouse-wheel-mode: t file-name-shadow-mode: t global-font-lock-mode: t font-lock-mode: t blink-cursor-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t column-number-mode: t line-number-mode: t transient-mark-mode: t Load-path shadows: c:/Users/Arthur/.emacs.d/plugins/company/company-cmake hides c:/Users/Arthur/.emacs.d/plugins/company-cmake/company-cmake c:/Users/Arthur/.emacs.d/plugins/helm/helm hides c:/Users/Arthur/.emacs.d/plugins/helm-core/helm c:/Users/Arthur/.emacs.d/plugins/helm/helm-source hides c:/Users/Arthur/.emacs.d/plugins/helm-core/helm-source c:/Users/Arthur/.emacs.d/plugins/helm/helm-multi-match hides c:/Users/Arthur/.emacs.d/plugins/helm-core/helm-multi-match c:/Users/Arthur/.emacs.d/plugins/helm/helm-lib hides c:/Users/Arthur/.emacs.d/plugins/helm-core/helm-lib c:/Users/Arthur/.emacs.d/plugins/load-relative/el-get-install hides c:/Users/Arthur/.emacs.d/plugins/loc-changes/el-get-install c:/Users/Arthur/.emacs.d/plugins/load-relative/el-get-install hides c:/Users/Arthur/.emacs.d/plugins/realgud/el-get-install c:/Users/Arthur/.emacs.d/plugins/realgud/realgud hides c:/Users/Arthur/.emacs.d/plugins/xxrealgud/realgud c:/Users/Arthur/.emacs.d/plugins/loc-changes/test/test-basic hides c:/Users/Arthur/.emacs.d/plugins/test-simple/test/test-basic Features: (shadow flyspell ispell mail-extr emacsbug sendmail helm-command helm-elisp helm-eval edebug emms-player-simple-mpv-control-functions emms-player-simple-mpv extras emms-player-vlc emms-player-mplayer emms-setup emms-librefm-stream emms-librefm-scrobbler emms-playlist-limit emms-volume emms-volume-amixer emms-i18n emms-history emms-score emms-stream-info emms-metaplaylist-mode emms-bookmarks emms-cue emms-mode-line-icon emms-browser sort emms-playlist-sort emms-last-played emms-player-xine emms-player-mpd tq emms-playing-time emms-lyrics emms-url emms-player-simple emms-streams emms-show-all emms-tag-editor emms-info-metaflac emms-mark emms-mode-line emms-cache emms-info-ogginfo emms-info-mp3info emms-info later-do emms-playlist-mode emms-source-playlist emms-source-file locate emms emms-compat ztree ztree-diff ztree-diff-model ztree-dir ztree-view ztree-util rainbow-delimiters vline sanityinc-solarized-dark-theme color-theme-sanityinc-solarized neotree dired-xtra direx dired+ image-file bookmark+ bookmark+-key bookmark+-1 gnus-sum gnus-group gnus-undo gnus-start gnus-cloud nnimap nnmail mail-source tls gnutls utf7 netrc nnoo gnus-spec gnus-int gnus-range message puny rfc822 mml mml-sec epa epg epg-config mm-decode mm-bodies mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader gnus-win gnus nnheader gnus-util rmail rmail-loaddefs rfc2047 rfc2045 ietf-drums mail-utils mm-util mail-prsvr bookmark+-bmu bookmark+-lit bookmark+-mac ediff-merg ediff-wind ediff-diff ediff-mult ediff-help ediff-init ediff-util ediff realgud realgud-recursive-autoloads realgud-zshdb realgud:zshdb-track-mode realgud:zshdb-core realgud:zshdb-init realgud-trepan3k realgud:trepan3k-track-mode realgud:trepan3k-core realgud:trepan3k-init realgud-trepan2 realgud:trepan2-track-mode realgud:trepan2-core realgud:trepan2-init realgud-trepanpl realgud:trepanpl-track-mode realgud:trepanpl-core realgud:trepanpl-init realgud-trepanjs realgud:trepanjs-track-mode realgud:trepanjs-core realgud:trepanjs-init realgud-trepan realgud:trepan-track-mode realgud:trepan-core realgud:trepan-init realgud-remake realgud:remake-track-mode realgud:remake-core realgud:remake-init realgud-rdebug realgud-rdebug-track-mode realgud-rdebug-core realgud-rdebug-init realgud-perldb realgud:perldb-track-mode realgud:perldb-core realgud:perldb-init realgud-lang-perl realgud-pdb realgud:pdb-track-mode realgud:pdb-core realgud:pdb-init realgud-nodejs realgud:nodejs-track-mode realgud:nodejs-core realgud:nodejs-init realgud-lang-js realgud-kshdb realgud:kshdb-track-mode realgud:kshdb-core realgud:kshdb-init realgud-jdb realgud:jdb-track-mode realgud-lang-ruby realgud:jdb-core realgud:jdb-init gud realgud-ipdb realgud:ipdb-track-mode realgud:ipdb-core realgud:ipdb-init realgud-lang-python realgud-gub realgud:gub-track-mode realgud:gub-core realgud:gub-init realgud-gdb realgud:gdb-track-mode realgud:gdb-init realgud:gdb-core realgud-bashdb realgud:bashdb-track-mode realgud:bashdb-core realgud:bashdb-init realgud-lang-posix-shell realgud:run realgud-track-mode realgud-backtrace-mode realgud-track realgud-shortkey realgud-menu realgud-eval realgud-cmds realgud-send realgud-window realgud-utils realgud-init realgud-file esh-var esh-io esh-cmd esh-opt esh-ext esh-proc esh-arg esh-groups eshell esh-module esh-util esh-mode realgud-core realgud-reset realgud-buffer-helper realgud-buffer-backtrace realgud-buffer-command realgud-buffer-info realgud-regexp realgud-lochist the-org-mode-expansions org org-macro org-footnote org-pcomplete org-list org-faces org-entities noutline outline org-version ob-emacs-lisp ob ob-tangle ob-ref ob-lob ob-table ob-exp org-src ob-keys ob-comint ob-core ob-eval org-compat org-macs org-loaddefs cal-menu calendar cal-loaddefs realgud-bp realgud-bp-image-data realgud-loc realgud-buffer-source realgud-key realgud-custom key realgud-follow realgud-lang realgud-fringe realgud-helper test-simple loc-changes load-relative company avy window-number thing-edit sr-speedbar semantic/db-mode semantic/db semantic/idle semantic/ctxt semantic/sb semantic/sort semantic/format semantic/tag-ls semantic/find semantic/util-modes semantic/util semantic semantic/tag semantic/lex semantic/fw mode-local find-func ede/speedbar ede/files ede ede/detect ede/base ede/auto ede/source eieio-base eieio-speedbar speedbar sb-image ezimage dframe eieio-custom cedet indent-guide helm-gtags pulse ggtags ewoc helm-descbinds helm-mode helm-files rx image-dired image-mode tramp tramp-compat tramp-loaddefs trampver ucs-normalize shell pcomplete parse-time format-spec dired-x dired-aux ffap helm-buffers helm-elscreen helm-tags helm-bookmark helm-adaptive helm-info info bookmark pp helm-locate helm-grep helm-regexp helm-external helm-net xml url url-proxy url-privacy url-expand url-methods url-history url-cookie url-domsuf mailcap helm-utils helm-help helm-types helm helm-source eieio-compat helm-multi-match helm-lib dired dired-loaddefs helm-config helm-autoloads helm-easymenu async-bytecomp flymake compile comint ansi-color auto-complete-config auto-complete popup autopair fill-column-indicator js2-mode-expansions js2-mode etags xref project js-mode-expansions js html-mode-expansions sgml-mode subr-x dom json map seq cc-mode-expansions cc-mode cc-fonts cc-guess cc-menus cc-cmds cc-styles cc-align cc-engine cc-vars cc-defs yasnippet expand-region text-mode-expansions er-basic-expansions thingatpt expand-region-core expand-region-custom undo-tree derived edmacro kmacro diff cl smart-mode-line advice rich-minority speck async bind-key easy-mmode diminish misearch multi-isearch add-log browse-url url-util url-parse auth-source cl-seq eieio byte-opt bytecomp byte-compile cl-extra help-mode cconv eieio-core cl-macs gv eieio-loaddefs password-cache url-vars server warnings which-func imenu saveplace autorevert filenotify hl-line elec-pair winner ring paren time-date recentf tree-widget wid-edit cl-loaddefs pcase cl-lib easymenu mule-util tooltip eldoc electric uniquify ediff-hook vc-hooks lisp-float-type mwheel dos-w32 ls-lisp disp-table term/w32-win w32-win w32-vars term/common-win tool-bar dnd fontset image regexp-opt fringe tabulated-list replace newcomment text-mode elisp-mode lisp-mode prog-mode register page menu-bar rfn-eshadow isearch timer select scroll-bar mouse jit-lock font-lock syntax facemenu font-core term/tty-colors frame cl-generic cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese composite charscript case-table epa-hook jka-cmpr-hook help simple abbrev obarray minibuffer cl-preloaded nadvice loaddefs button faces cus-face macroexp files text-properties overlay sha1 md5 base64 format env code-pages mule custom widget hashtable-print-readable backquote w32notify w32 multi-tty make-network-process emacs) Memory information: ((conses 16 793703 34966) (symbols 56 60903 3) (miscs 48 166 213) (strings 32 132076 15794) (string-bytes 1 4760642) (vectors 16 81947) (vector-slots 8 1290395 16246) (floats 8 1646 412) (intervals 56 1557 50) (buffers 976 17)) [-- Attachment #2: Type: text/html, Size: 13092 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-09 22:20 bug#25408: Remove Decorations Around Emacs Frame (Windows OS) Arthur Miller @ 2017-01-10 8:23 ` martin rudalics 2017-01-10 17:07 ` Eli Zaretskii 2017-01-10 19:36 ` Richard Stallman ` (2 subsequent siblings) 3 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-01-10 8:23 UTC (permalink / raw) To: Arthur Miller, 25408 > I suggest either > to implement this in a "border-width" property when border width > is set to 0, or to implement a new variable/function that can be set in > init file, such as for example "no-frame-borders t". I'm using a frame parameter "undecorated" for this. On Windows it is handled by the following function in w32fns.c: 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 (); } where FRAME_UNDECORATED (f) returns false if f is currently decorated. If the `border-width' parameter is 0 the frame gets no border, otherwise it gets the standard Windows thin-line border. > Care has to be taken to note that when removing caption bar and borders > it will be no longer possible to move and resize window unless user > have other means of performing those applications. You can use the `left', `top', `width' and `height' frame parameters for that. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-10 8:23 ` martin rudalics @ 2017-01-10 17:07 ` Eli Zaretskii 2017-01-10 18:07 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Eli Zaretskii @ 2017-01-10 17:07 UTC (permalink / raw) To: martin rudalics; +Cc: arthur.miller.no1, 25408 > Date: Tue, 10 Jan 2017 09:23:02 +0100 > From: martin rudalics <rudalics@gmx.at> > > > I suggest either > > to implement this in a "border-width" property when border width > > is set to 0, or to implement a new variable/function that can be set in > > init file, such as for example "no-frame-borders t". > > I'm using a frame parameter "undecorated" for this. On Windows it is > handled by the following function in w32fns.c: > > void > x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) I don't see this in the current sources. Is this your local change? If so, is there a matching implementation for 'undecorated' on X? Can both be added to Emacs? If there's only an implementation of 'undecorated' for MS-Windows, I suggest to adapt it such that the same effect is produced when border-width is set to zero. The border-width parameter is already supported on X, so we will have no problem with that. WDYT? ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-10 17:07 ` Eli Zaretskii @ 2017-01-10 18:07 ` martin rudalics 2017-01-10 18:27 ` Eli Zaretskii 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-01-10 18:07 UTC (permalink / raw) To: Eli Zaretskii; +Cc: arthur.miller.no1, 25408 > I don't see this in the current sources. Is this your local change? Yes. > If so, is there a matching implementation for 'undecorated' on X? Can > both be added to Emacs? There is one for X and a separate one for GTK. All of them work here but I read that a few X window managers notoriously ignore them. BTW, the term "undecorated" is derived from gtk_window_set_decorated - just that our frames are by default decorated so I had to negate it. > If there's only an implementation of 'undecorated' for MS-Windows, I > suggest to adapt it such that the same effect is produced when > border-width is set to zero. The border-width parameter is already > supported on X, so we will have no problem with that. As mentioned before I process `border-width' specially on Windows - that is, I produce the one-pixel wide thin-line border if border-width is a positive number. X11 allows to specifiy an arbitrary border-width. So far I haven't been able to produce any border with GTK. But I have added an option to color the internal border which can then be used in a uniform manner on all frames. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-10 18:07 ` martin rudalics @ 2017-01-10 18:27 ` Eli Zaretskii 2017-01-10 20:39 ` Clément Pit--Claudel 0 siblings, 1 reply; 85+ messages in thread From: Eli Zaretskii @ 2017-01-10 18:27 UTC (permalink / raw) To: martin rudalics; +Cc: arthur.miller.no1, 25408 > Date: Tue, 10 Jan 2017 19:07:23 +0100 > From: martin rudalics <rudalics@gmx.at> > CC: arthur.miller.no1@gmail.com, 25408@debbugs.gnu.org > > > If so, is there a matching implementation for 'undecorated' on X? Can > > both be added to Emacs? > > There is one for X and a separate one for GTK. All of them work here > but I read that a few X window managers notoriously ignore them. Then I suggest to add this to Emacs. That some wm's ignore it is not a reason to avoid having the feature for those that don't ignore it. Thanks. ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-10 18:27 ` Eli Zaretskii @ 2017-01-10 20:39 ` Clément Pit--Claudel 2017-01-11 7:08 ` Arthur Miller 0 siblings, 1 reply; 85+ messages in thread From: Clément Pit--Claudel @ 2017-01-10 20:39 UTC (permalink / raw) To: Eli Zaretskii, martin rudalics; +Cc: arthur.miller.no1, 25408 [-- Attachment #1.1: Type: text/plain, Size: 224 bytes --] On 2017-01-10 13:27, Eli Zaretskii wrote: > Then I suggest to add this to Emacs. That some wm's ignore it is not > a reason to avoid having the feature for those that don't ignore it. Indeed, it would be wonderful! [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-10 20:39 ` Clément Pit--Claudel @ 2017-01-11 7:08 ` Arthur Miller 2017-01-11 7:24 ` Arthur Miller ` (2 more replies) 0 siblings, 3 replies; 85+ messages in thread From: Arthur Miller @ 2017-01-11 7:08 UTC (permalink / raw) To: Clément Pit--Claudel; +Cc: 25408 [-- Attachment #1: Type: text/plain, Size: 2948 bytes --] "We call it "Losedows" or "Lose OS", because if you use it, you lose your freedom. We're glad if Emacs gives you a taste of freedom, but a taste is all it can give you. To escape from Microsoft's power, you need to stop using Losedows." Haha :-) Indeed. I do run Arch Linux otherwise, but I do some consulting with programming databases and GUIs in access & spss and I also play some games occasionally, so I still need losedows. I know I could run it in wine and pass through vga, but I feel a bit too old for that :). This was a great excursion in Emacs src code. I added above mention method to my w32fns.c, added FRAME_DECORATED() macro to frame.h a boolean_bf undecorated :1, to frame struct, initiated it to false in "make_frame" added an entry to frame_parms: {"undecorated", SYMBOL_INDEX (Qundecorated)}, added connecction to w32_frame_parm_handlers[] to x_set_undecorated at same place where symbol is declared in frame_parms (last in the list), added an INLINE void fset_undecorated( ... ) to frame.h (not sure if it is needed), and now I can change my new param with lisp from emacs, but my connection seem never to be called. By the way, I think world is better without borders, so I have modified Martin's x_set_undecorated to 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));*/ /*Lisp_Object undecorated = Fcdr (Fassq (Qundecorated, f->param_alist));*/ block_input (); if (!NILP (new_value) && !FRAME_UNDECORATED (f)) { dwStyle = (dwStyle & ~WS_THICKFRAME & ~WS_CAPTION); 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 (); } So it should just switch on "undecorated" param and ignore borders (at least I hope). I am not sure where do I have to make change more to get it to work. 2017-01-10 21:39 GMT+01:00 Clément Pit--Claudel <clement.pit@gmail.com>: > On 2017-01-10 13:27, Eli Zaretskii wrote: > > Then I suggest to add this to Emacs. That some wm's ignore it is not > > a reason to avoid having the feature for those that don't ignore it. > > Indeed, it would be wonderful! > > [-- Attachment #2: Type: text/html, Size: 3882 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-11 7:08 ` Arthur Miller @ 2017-01-11 7:24 ` Arthur Miller 2017-01-11 7:48 ` Arthur Miller 2017-01-11 8:38 ` bug#25408: Remove Decorations Around Emacs Frame (Windows OS) martin rudalics 2017-01-11 16:39 ` Richard Stallman 2 siblings, 1 reply; 85+ messages in thread From: Arthur Miller @ 2017-01-11 7:24 UTC (permalink / raw) To: Clément Pit--Claudel; +Cc: 25408 [-- Attachment #1: Type: text/plain, Size: 3600 bytes --] I appologize, I was too fast to answer, I made a bad call from modify-frame-parameters when I tested it. It works like a charm as you say it in english. I have also changed the else-if statement in Martins method to else if (!NILP (new_value) && FRAME_UNDECORATED (f)) (check for !NILP) so I can switch back decorations. It works. Thanks all, it was great exercise to learn a bit of emacs internals and to make a simple hack. 2017-01-11 8:08 GMT+01:00 Arthur Miller <arthur.miller.no1@gmail.com>: > "We call it "Losedows" or "Lose OS", because if you use it, you lose > your freedom. > > We're glad if Emacs gives you a taste of freedom, but a taste is > all it can give you. To escape from Microsoft's power, you need to > stop using Losedows." > > Haha :-) Indeed. > > I do run Arch Linux otherwise, but I do some consulting with programming > databases and GUIs in access & spss and I also play some games > occasionally, so I still need losedows. I know I could run it in wine and > pass through vga, but I feel a bit too old for that :). > > This was a great excursion in Emacs src code. I added above mention > method to my w32fns.c, added FRAME_DECORATED() macro to frame.h > a boolean_bf undecorated :1, to frame struct, initiated it to false in > "make_frame" > added an entry to frame_parms: {"undecorated", SYMBOL_INDEX > (Qundecorated)}, > added connecction to w32_frame_parm_handlers[] to x_set_undecorated at same > place where symbol is declared in frame_parms (last in the list), added an > INLINE void fset_undecorated( ... ) to frame.h (not sure if it is needed), > and now > I can change my new param with lisp from emacs, but my connection seem > never to be called. > > By the way, I think world is better without borders, so I have modified > Martin's > x_set_undecorated to > > 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));*/ > /*Lisp_Object undecorated = Fcdr (Fassq (Qundecorated, > f->param_alist));*/ > > block_input (); > if (!NILP (new_value) && !FRAME_UNDECORATED (f)) > { > dwStyle = (dwStyle & ~WS_THICKFRAME & ~WS_CAPTION); > 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 (); > } > > So it should just switch on "undecorated" param and ignore borders (at > least I hope). I am not sure where do > I have to make change more to get it to work. > > 2017-01-10 21:39 GMT+01:00 Clément Pit--Claudel <clement.pit@gmail.com>: > >> On 2017-01-10 13:27, Eli Zaretskii wrote: >> > Then I suggest to add this to Emacs. That some wm's ignore it is not >> > a reason to avoid having the feature for those that don't ignore it. >> >> Indeed, it would be wonderful! >> >> > [-- Attachment #2: Type: text/html, Size: 4891 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-11 7:24 ` Arthur Miller @ 2017-01-11 7:48 ` Arthur Miller 2017-01-11 7:50 ` Arthur Miller 2017-01-11 8:39 ` martin rudalics 0 siblings, 2 replies; 85+ messages in thread From: Arthur Miller @ 2017-01-11 7:48 UTC (permalink / raw) To: Clément Pit--Claudel; +Cc: 25408 [-- Attachment #1: Type: text/plain, Size: 5345 bytes --] There is a slightly cosmetic issue with above function. When one switches back on decorations, the frame will not resize properly and minibuffer will be not visible. It's there but just covered by frame. Just resizing emacs framefixes it. Adding call to PostMessage(hwnd, WM_SIZE,0,0) in Martins function fixes it. 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));*/ /*Lisp_Object undecorated = Fcdr (Fassq (Qundecorated, f->param_alist));*/ block_input (); if (!NILP (new_value) && !FRAME_UNDECORATED (f)) { dwStyle = (dwStyle & ~WS_THICKFRAME & ~WS_CAPTION); 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); PostMessage(hwnd, WM_SIZE,0,0); FRAME_UNDECORATED (f) = false; } unblock_input (); } 2017-01-11 8:24 GMT+01:00 Arthur Miller <arthur.miller.no1@gmail.com>: > I appologize, I was too fast to answer, I made a bad call from > modify-frame-parameters > when I tested it. It works like a charm as you say it in english. I have > also changed > the else-if statement in Martins method to else if (!NILP (new_value) && > FRAME_UNDECORATED (f)) > (check for !NILP) so I can switch back decorations. It works. Thanks all, > it was great > exercise to learn a bit of emacs internals and to make a simple hack. > > 2017-01-11 8:08 GMT+01:00 Arthur Miller <arthur.miller.no1@gmail.com>: > >> "We call it "Losedows" or "Lose OS", because if you use it, you lose >> your freedom. >> >> We're glad if Emacs gives you a taste of freedom, but a taste is >> all it can give you. To escape from Microsoft's power, you need to >> stop using Losedows." >> >> Haha :-) Indeed. >> >> I do run Arch Linux otherwise, but I do some consulting with programming >> databases and GUIs in access & spss and I also play some games >> occasionally, so I still need losedows. I know I could run it in wine and >> pass through vga, but I feel a bit too old for that :). >> >> This was a great excursion in Emacs src code. I added above mention >> method to my w32fns.c, added FRAME_DECORATED() macro to frame.h >> a boolean_bf undecorated :1, to frame struct, initiated it to false in >> "make_frame" >> added an entry to frame_parms: {"undecorated", SYMBOL_INDEX >> (Qundecorated)}, >> added connecction to w32_frame_parm_handlers[] to x_set_undecorated at >> same >> place where symbol is declared in frame_parms (last in the list), added an >> INLINE void fset_undecorated( ... ) to frame.h (not sure if it is >> needed), and now >> I can change my new param with lisp from emacs, but my connection seem >> never to be called. >> >> By the way, I think world is better without borders, so I have modified >> Martin's >> x_set_undecorated to >> >> 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));*/ >> /*Lisp_Object undecorated = Fcdr (Fassq (Qundecorated, >> f->param_alist));*/ >> >> block_input (); >> if (!NILP (new_value) && !FRAME_UNDECORATED (f)) >> { >> dwStyle = (dwStyle & ~WS_THICKFRAME & ~WS_CAPTION); >> 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 (); >> } >> >> So it should just switch on "undecorated" param and ignore borders (at >> least I hope). I am not sure where do >> I have to make change more to get it to work. >> >> 2017-01-10 21:39 GMT+01:00 Clément Pit--Claudel <clement.pit@gmail.com>: >> >>> On 2017-01-10 13:27, Eli Zaretskii wrote: >>> > Then I suggest to add this to Emacs. That some wm's ignore it is not >>> > a reason to avoid having the feature for those that don't ignore it. >>> >>> Indeed, it would be wonderful! >>> >>> >> > [-- Attachment #2: Type: text/html, Size: 7349 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-11 7:48 ` Arthur Miller @ 2017-01-11 7:50 ` Arthur Miller 2017-01-11 8:15 ` Arthur Miller 2017-01-11 8:39 ` martin rudalics 1 sibling, 1 reply; 85+ messages in thread From: Arthur Miller @ 2017-01-11 7:50 UTC (permalink / raw) To: Clément Pit--Claudel; +Cc: 25408 [-- Attachment #1: Type: text/plain, Size: 5716 bytes --] Aha, my last message ended somehow in bad spot in message tree. I appologize for inconvenience. 2017-01-11 8:48 GMT+01:00 Arthur Miller <arthur.miller.no1@gmail.com>: > There is a slightly cosmetic issue with above function. When one switches > back on decorations, > the frame will not resize properly and minibuffer will be not visible. > It's there but just > covered by frame. Just resizing emacs framefixes it. > > Adding call to PostMessage(hwnd, WM_SIZE,0,0) in Martins function fixes it. > > 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));*/ > /*Lisp_Object undecorated = Fcdr (Fassq (Qundecorated, > f->param_alist));*/ > > block_input (); > if (!NILP (new_value) && !FRAME_UNDECORATED (f)) > { > dwStyle = (dwStyle & ~WS_THICKFRAME & ~WS_CAPTION); > 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); > PostMessage(hwnd, WM_SIZE,0,0); > FRAME_UNDECORATED (f) = false; > } > unblock_input (); > } > > > 2017-01-11 8:24 GMT+01:00 Arthur Miller <arthur.miller.no1@gmail.com>: > >> I appologize, I was too fast to answer, I made a bad call from >> modify-frame-parameters >> when I tested it. It works like a charm as you say it in english. I have >> also changed >> the else-if statement in Martins method to else if (!NILP (new_value) && >> FRAME_UNDECORATED (f)) >> (check for !NILP) so I can switch back decorations. It works. Thanks all, >> it was great >> exercise to learn a bit of emacs internals and to make a simple hack. >> >> 2017-01-11 8:08 GMT+01:00 Arthur Miller <arthur.miller.no1@gmail.com>: >> >>> "We call it "Losedows" or "Lose OS", because if you use it, you lose >>> your freedom. >>> >>> We're glad if Emacs gives you a taste of freedom, but a taste is >>> all it can give you. To escape from Microsoft's power, you need to >>> stop using Losedows." >>> >>> Haha :-) Indeed. >>> >>> I do run Arch Linux otherwise, but I do some consulting with programming >>> databases and GUIs in access & spss and I also play some games >>> occasionally, so I still need losedows. I know I could run it in wine >>> and >>> pass through vga, but I feel a bit too old for that :). >>> >>> This was a great excursion in Emacs src code. I added above mention >>> method to my w32fns.c, added FRAME_DECORATED() macro to frame.h >>> a boolean_bf undecorated :1, to frame struct, initiated it to false in >>> "make_frame" >>> added an entry to frame_parms: {"undecorated", SYMBOL_INDEX >>> (Qundecorated)}, >>> added connecction to w32_frame_parm_handlers[] to x_set_undecorated at >>> same >>> place where symbol is declared in frame_parms (last in the list), added >>> an >>> INLINE void fset_undecorated( ... ) to frame.h (not sure if it is >>> needed), and now >>> I can change my new param with lisp from emacs, but my connection seem >>> never to be called. >>> >>> By the way, I think world is better without borders, so I have modified >>> Martin's >>> x_set_undecorated to >>> >>> 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));*/ >>> /*Lisp_Object undecorated = Fcdr (Fassq (Qundecorated, >>> f->param_alist));*/ >>> >>> block_input (); >>> if (!NILP (new_value) && !FRAME_UNDECORATED (f)) >>> { >>> dwStyle = (dwStyle & ~WS_THICKFRAME & ~WS_CAPTION); >>> 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 (); >>> } >>> >>> So it should just switch on "undecorated" param and ignore borders (at >>> least I hope). I am not sure where do >>> I have to make change more to get it to work. >>> >>> 2017-01-10 21:39 GMT+01:00 Clément Pit--Claudel <clement.pit@gmail.com>: >>> >>>> On 2017-01-10 13:27, Eli Zaretskii wrote: >>>> > Then I suggest to add this to Emacs. That some wm's ignore it is not >>>> > a reason to avoid having the feature for those that don't ignore it. >>>> >>>> Indeed, it would be wonderful! >>>> >>>> >>> >> > [-- Attachment #2: Type: text/html, Size: 8217 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-11 7:50 ` Arthur Miller @ 2017-01-11 8:15 ` Arthur Miller 0 siblings, 0 replies; 85+ messages in thread From: Arthur Miller @ 2017-01-11 8:15 UTC (permalink / raw) To: Clément Pit--Claudel; +Cc: 25408 [-- Attachment #1: Type: text/plain, Size: 6318 bytes --] I am beggin of pardon, but I found that sometimes, just sometimes, even switching decorations on leaves some cosmetic issues. I took a screenshot and upload it to imgur: http://imgur.com/a/kCW8j . It is same issue as with putting decorations on. Adding that PostMessage to send wm_size after the if-else statement solves it in all cases. 2017-01-11 8:50 GMT+01:00 Arthur Miller <arthur.miller.no1@gmail.com>: > Aha, my last message ended somehow in bad spot in message tree. I > appologize for inconvenience. > > 2017-01-11 8:48 GMT+01:00 Arthur Miller <arthur.miller.no1@gmail.com>: > >> There is a slightly cosmetic issue with above function. When one switches >> back on decorations, >> the frame will not resize properly and minibuffer will be not visible. >> It's there but just >> covered by frame. Just resizing emacs framefixes it. >> >> Adding call to PostMessage(hwnd, WM_SIZE,0,0) in Martins function fixes >> it. >> >> 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));*/ >> /*Lisp_Object undecorated = Fcdr (Fassq (Qundecorated, >> f->param_alist));*/ >> >> block_input (); >> if (!NILP (new_value) && !FRAME_UNDECORATED (f)) >> { >> dwStyle = (dwStyle & ~WS_THICKFRAME & ~WS_CAPTION); >> 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); >> PostMessage(hwnd, WM_SIZE,0,0); >> FRAME_UNDECORATED (f) = false; >> } >> unblock_input (); >> } >> >> >> 2017-01-11 8:24 GMT+01:00 Arthur Miller <arthur.miller.no1@gmail.com>: >> >>> I appologize, I was too fast to answer, I made a bad call from >>> modify-frame-parameters >>> when I tested it. It works like a charm as you say it in english. I have >>> also changed >>> the else-if statement in Martins method to else if (!NILP (new_value) && >>> FRAME_UNDECORATED (f)) >>> (check for !NILP) so I can switch back decorations. It works. Thanks >>> all, it was great >>> exercise to learn a bit of emacs internals and to make a simple hack. >>> >>> 2017-01-11 8:08 GMT+01:00 Arthur Miller <arthur.miller.no1@gmail.com>: >>> >>>> "We call it "Losedows" or "Lose OS", because if you use it, you lose >>>> your freedom. >>>> >>>> We're glad if Emacs gives you a taste of freedom, but a taste is >>>> all it can give you. To escape from Microsoft's power, you need to >>>> stop using Losedows." >>>> >>>> Haha :-) Indeed. >>>> >>>> I do run Arch Linux otherwise, but I do some consulting with >>>> programming >>>> databases and GUIs in access & spss and I also play some games >>>> occasionally, so I still need losedows. I know I could run it in wine >>>> and >>>> pass through vga, but I feel a bit too old for that :). >>>> >>>> This was a great excursion in Emacs src code. I added above mention >>>> method to my w32fns.c, added FRAME_DECORATED() macro to frame.h >>>> a boolean_bf undecorated :1, to frame struct, initiated it to false in >>>> "make_frame" >>>> added an entry to frame_parms: {"undecorated", SYMBOL_INDEX >>>> (Qundecorated)}, >>>> added connecction to w32_frame_parm_handlers[] to x_set_undecorated at >>>> same >>>> place where symbol is declared in frame_parms (last in the list), added >>>> an >>>> INLINE void fset_undecorated( ... ) to frame.h (not sure if it is >>>> needed), and now >>>> I can change my new param with lisp from emacs, but my connection seem >>>> never to be called. >>>> >>>> By the way, I think world is better without borders, so I have modified >>>> Martin's >>>> x_set_undecorated to >>>> >>>> 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));*/ >>>> /*Lisp_Object undecorated = Fcdr (Fassq (Qundecorated, >>>> f->param_alist));*/ >>>> >>>> block_input (); >>>> if (!NILP (new_value) && !FRAME_UNDECORATED (f)) >>>> { >>>> dwStyle = (dwStyle & ~WS_THICKFRAME & ~WS_CAPTION); >>>> 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 (); >>>> } >>>> >>>> So it should just switch on "undecorated" param and ignore borders (at >>>> least I hope). I am not sure where do >>>> I have to make change more to get it to work. >>>> >>>> 2017-01-10 21:39 GMT+01:00 Clément Pit--Claudel <clement.pit@gmail.com> >>>> : >>>> >>>>> On 2017-01-10 13:27, Eli Zaretskii wrote: >>>>> > Then I suggest to add this to Emacs. That some wm's ignore it is not >>>>> > a reason to avoid having the feature for those that don't ignore it. >>>>> >>>>> Indeed, it would be wonderful! >>>>> >>>>> >>>> >>> >> > [-- Attachment #2: Type: text/html, Size: 9286 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-11 7:48 ` Arthur Miller 2017-01-11 7:50 ` Arthur Miller @ 2017-01-11 8:39 ` martin rudalics 2017-01-11 9:17 ` Arthur Miller 2017-02-07 5:28 ` Clément Pit--Claudel 1 sibling, 2 replies; 85+ messages in thread From: martin rudalics @ 2017-01-11 8:39 UTC (permalink / raw) To: Arthur Miller, Clément Pit--Claudel; +Cc: 25408 > There is a slightly cosmetic issue with above function. When one switches > back on decorations, > the frame will not resize properly and minibuffer will be not visible. It's > there but just > covered by frame. Just resizing emacs framefixes it. > > Adding call to PostMessage(hwnd, WM_SIZE,0,0) in Martins function fixes it. This is not necessary here. And it would be strange since the idea is that the outer frame size remains unchanged. Hence, any problem would manifest itself already when you remove the borders by leaving parts of the display area reserved for the frame not redrawn. The image you posted in the message you sent just now seems to confirm that. But I'm testing this on Windows XP and have not yet pulled the recent multi-thread Emacs changes. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-11 8:39 ` martin rudalics @ 2017-01-11 9:17 ` Arthur Miller 2017-01-11 10:20 ` Arthur Miller 2017-02-07 5:28 ` Clément Pit--Claudel 1 sibling, 1 reply; 85+ messages in thread From: Arthur Miller @ 2017-01-11 9:17 UTC (permalink / raw) To: martin rudalics; +Cc: 25408, Clément Pit--Claudel [-- Attachment #1: Type: text/plain, Size: 1083 bytes --] I took screenshot of just one version, it was problem with both on/off, at least on my machine. Just posting wm_size message after the change in your function solves issues in both cases for me. 2017-01-11 9:39 GMT+01:00 martin rudalics <rudalics@gmx.at>: > > There is a slightly cosmetic issue with above function. When one switches > > back on decorations, > > the frame will not resize properly and minibuffer will be not visible. > It's > > there but just > > covered by frame. Just resizing emacs framefixes it. > > > > Adding call to PostMessage(hwnd, WM_SIZE,0,0) in Martins function fixes > it. > > This is not necessary here. And it would be strange since the idea is > that the outer frame size remains unchanged. Hence, any problem would > manifest itself already when you remove the borders by leaving parts of > the display area reserved for the frame not redrawn. > > The image you posted in the message you sent just now seems to confirm > that. > > But I'm testing this on Windows XP and have not yet pulled the recent > multi-thread Emacs changes. > > martin > [-- Attachment #2: Type: text/html, Size: 1562 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-11 9:17 ` Arthur Miller @ 2017-01-11 10:20 ` Arthur Miller 2017-01-11 13:55 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Arthur Miller @ 2017-01-11 10:20 UTC (permalink / raw) To: martin rudalics; +Cc: 25408, Clément Pit--Claudel [-- Attachment #1: Type: text/plain, Size: 2399 bytes --] I have a small question: how do I make this take effect in my init file when I run in server/client mode? Seems like my client always insist on creating frames around emacs window, while when I run emacs "standalone" (for ex emacs --debug-init) it starts undecorated. I have tried following in my .emacs: (add-to-list 'default-frame-alist '(undecorated . 0)) (setq default-frame-alist '((undecorated . 0))) (setq initial-frame-alist '((undecorated . 0))) But that does not give any effect at all. I have following to switch off/on decorations interactively: (defvar decor 0) (defun toggle-frame-decor () (interactive) (progn (modify-frame-parameters (selected-frame) `((undecorated . ,'decor))) (if (= decor 0) (setq decor 1) (setq decor 0)))) (global-set-key [f9] 'toggle-frame-decor) If I place call to (toggle-frame-decor) in .emacs than it works for non-server mode, but not when I run emacsclient (which I do normally always). I tried to force loading .emacs when severs starts with -l ~/.emacs switch, but it didn't worked either. I admit I am just very uneducated about emacs & elisp and would really appreciate if a nice soul could help with my poor education. 2017-01-11 10:17 GMT+01:00 Arthur Miller <arthur.miller.no1@gmail.com>: > I took screenshot of just one version, it was problem with both on/off, at > least on my machine. > > Just posting wm_size message after the change in your function solves > issues in both cases for me. > > 2017-01-11 9:39 GMT+01:00 martin rudalics <rudalics@gmx.at>: > >> > There is a slightly cosmetic issue with above function. When one >> switches >> > back on decorations, >> > the frame will not resize properly and minibuffer will be not visible. >> It's >> > there but just >> > covered by frame. Just resizing emacs framefixes it. >> > >> > Adding call to PostMessage(hwnd, WM_SIZE,0,0) in Martins function fixes >> it. >> >> This is not necessary here. And it would be strange since the idea is >> that the outer frame size remains unchanged. Hence, any problem would >> manifest itself already when you remove the borders by leaving parts of >> the display area reserved for the frame not redrawn. >> >> The image you posted in the message you sent just now seems to confirm >> that. >> >> But I'm testing this on Windows XP and have not yet pulled the recent >> multi-thread Emacs changes. >> >> martin >> > > [-- Attachment #2: Type: text/html, Size: 3512 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-11 10:20 ` Arthur Miller @ 2017-01-11 13:55 ` martin rudalics 0 siblings, 0 replies; 85+ messages in thread From: martin rudalics @ 2017-01-11 13:55 UTC (permalink / raw) To: Arthur Miller; +Cc: 25408, Clément Pit--Claudel > (add-to-list 'default-frame-alist '(undecorated . 0)) > (setq default-frame-alist '((undecorated . 0))) > (setq initial-frame-alist '((undecorated . 0))) > > But that does not give any effect at all. "0" is a quite misleading value ;-) See below. But I think I understand what happens. In fact, I haven't told you the whole story: In Fx_create_frame I do additionally 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); somewhere _before_ w32_window (f, window_prompting, minibuffer_only) gets called. And in w32_createwindow I have else if (FRAME_UNDECORATED (f)) { f->output_data.w32->dwStyle = ~WS_THICKFRAME & ~WS_CAPTION; /* 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; } before any other f->output_data.w32->dwStyle assignment and certainly before the FRAME_W32_WINDOW (f) = hwnd = CreateWindow (EMACS_CLASS, f->namebuf, f->output_data.w32->dwStyle, ... call. Just make sure that any time you set f->output_data.w32->dwStyle you don't overrule a previous assignment. (I haven't sent you a patch because I have completely redesigned the assignments to this component and it probably would distract more than provide any help.) This way (add-to-list 'default-frame-alist '(undecorated . t)) (setq default-frame-alist '((undecorated . t))) (setq initial-frame-alist '((undecorated . t))) should all work. BTW, you can also do f->output_data.w32->dwStyle = WS_POPUP; because the only thing Windows forbids in this context is to set WS_POPUP for an existing overlapped window (IIRC). > (defvar decor 0) > (defun toggle-frame-decor () > (interactive) > (progn > (modify-frame-parameters (selected-frame) `((undecorated . ,'decor))) You likely mean (modify-frame-parameters (selected-frame) `((undecorated . ,decor))) here. And probably you want to do the following calculation > (if (= decor 0) > (setq decor 1) > (setq decor 0)))) before calling ‘modify-frame-parameters’ so the latter will see the new value. But even this won't work because you want to toggle beween nil and non-nil so (devfar decor nil) and (setq decor (not decor)) are more appropriate. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-11 8:39 ` martin rudalics 2017-01-11 9:17 ` Arthur Miller @ 2017-02-07 5:28 ` Clément Pit--Claudel 2017-02-07 6:53 ` martin rudalics 1 sibling, 1 reply; 85+ messages in thread From: Clément Pit--Claudel @ 2017-02-07 5:28 UTC (permalink / raw) To: martin rudalics, Arthur Miller; +Cc: 25408 [-- Attachment #1.1: Type: text/plain, Size: 480 bytes --] On 2017-01-11 03:39, martin rudalics wrote: > But I'm testing this on Windows XP and have not yet pulled the recent > multi-thread Emacs changes. Hey Martin, Are your changes available in a branch of the repo? I'd be very happy to test them, and some modes like company-mode would benefit significantly (I tried to tackle this in "Could x-show-tip be reimplemented in Elisp? How does one create borderless frames from Elisp?" a while ago). Thanks a lot! Clément. [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-07 5:28 ` Clément Pit--Claudel @ 2017-02-07 6:53 ` martin rudalics 2017-02-07 13:05 ` Clément Pit--Claudel 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-02-07 6:53 UTC (permalink / raw) To: Clément Pit--Claudel, Arthur Miller; +Cc: 25408 > Are your changes available in a branch of the repo? No. But I hope that I can post a patch by the end of this week. > I'd be very happy > to test them, and some modes like company-mode would benefit > significantly (I tried to tackle this in "Could x-show-tip be > reimplemented in Elisp? How does one create borderless frames from > Elisp?" a while ago). Creating borderless frames and giving them back their border is fairly trivial. The greater problem is how to synchronize the behavior of such a frame with that of another one (moving, sizing, focusing, restacking and the like) and do that consistently across our windows systems. I've practically solved all these problems but am not yet sure whether the issue I found in "A GTK-only problem when making frames invisible" could have a detrimental impact. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-07 6:53 ` martin rudalics @ 2017-02-07 13:05 ` Clément Pit--Claudel 2017-02-11 14:27 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Clément Pit--Claudel @ 2017-02-07 13:05 UTC (permalink / raw) To: martin rudalics, Arthur Miller; +Cc: 25408 [-- Attachment #1.1: Type: text/plain, Size: 1011 bytes --] On 2017-02-07 01:53, martin rudalics wrote: >> Are your changes available in a branch of the repo? > > No. But I hope that I can post a patch by the end of this week. Great, thanks a lot! >> I'd be very happy >> to test them, and some modes like company-mode would benefit >> significantly (I tried to tackle this in "Could x-show-tip be >> reimplemented in Elisp? How does one create borderless frames from >> Elisp?" a while ago). > > Creating borderless frames and giving them back their border is fairly > trivial. The greater problem is how to synchronize the behavior of such > a frame with that of another one (moving, sizing, focusing, restacking > and the like) and do that consistently across our windows systems. > > I've practically solved all these problems but am not yet sure whether > the issue I found in "A GTK-only problem when making frames invisible" > could have a detrimental impact. Ok; thanks for the clarification! I'm excited about this feature :) [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-07 13:05 ` Clément Pit--Claudel @ 2017-02-11 14:27 ` martin rudalics 2017-02-11 21:02 ` Clément Pit--Claudel 2017-04-12 17:38 ` Alan Third 0 siblings, 2 replies; 85+ messages in thread From: martin rudalics @ 2017-02-11 14:27 UTC (permalink / raw) To: Clément Pit--Claudel, Arthur Miller; +Cc: 25408 [-- Attachment #1: Type: text/plain, Size: 8088 bytes --] >>> Are your changes available in a branch of the repo? >> >> No. But I hope that I can post a patch by the end of this week. > > Great, thanks a lot! If you are on GNU/Linux or Windows then please apply the attached patch synch-frames.diff to your current version of master and rebuild. If you succeeded doing that, start emacs -Q and continue reading. To remove a frame's decorations, use the frame parameter `undecorated' as in (set-frame-parameter nil 'undecorated t) To give that frame back its decorations use (set-frame-parameter nil 'undecorated nil) To make a new frame undecorated use (make-frame '((undecorated . t))) To make frames undecorated by default add something like (custom-set-variables '(default-frame-alist '((undecorated . t)))) to your .emacs. If everything works as intended and your only interest was to make frames without decorations, you can finish reading here. If you didn't succeed removing a frame's decorations and you are on GNU/Linux, you're window manager probably doesn't honor the Motif window manager hints. Please post the types of your build and window manager. At the very least we can provide a list of the window managers that don't comply. Windows users might experience problems on anything past XP, I've only tested it there. Usually, the position of a frame's native rectangle doesn't change when adding/removing decorations. If you want to change it, use the `left' and `top' frame parameters. If you think you need to remove/add individual parts of the decorations (titlebar, buttons, external borders) post your wishes here. Some window managers might be able to do that. The rest of this text is concerned with describing additional features. If some of them don't work on your system, please tell me, usually they need a compliant window manager as well. A first group of parameters is concerned with focusing/switching to certain frames. To make a frame not show up on the taskbar use the frame parameter `skip-taskbar' as in (set-frame-parameter nil 'skip-taskbar t) This should remove your frame's icon from the taskbar and also disable the <Alt>-<Tab> functionality to switch to that frame. On some systems (notably Windows) iconifying such a frame may "roll in" its window at the bottom of the desktop. To make a new frame not receive focus initially or when deiconified, use the frame parameter `no-focus-on-map' as in (make-frame '((no-focus-on-map . t))) Usually this works but if you are using a focus follows mouse policy you might have to specify the `no-accept-focus' parameter as well as in (make-frame '((no-focus-on-map . t) (no-accept-focus . t))) The `no-accept-focus' parameter, if non-nil, tries to never give the frame focus in a "soft" way. Development might not be entirely complete in this area. If you want to avoid that C-x 5 o switches to a specific frame, set that frame's `no-other-frame' parameter as in (set-frame-parameter nil 'no-other-frame t) Using a clever combination of the `skip-taskbar', `no-focus-on-map', `no-accept-focus' and `no-other-frame' you might be able to make a completely catatonic frame which you can kill only with your task manager. If you want to make sure that a specific frame is deleted whenever another frame is deleted use the `delete-before' parameter. This avoids confusing Emacs as, for example, when putting `delete-frame' on `delete-frame-functions'. To make a frame as small as possible use the `min-width' and `min-height' parameters. Evaluating (let ((frame (make-frame `((tool-bar-lines . 0) (menu-bar-lines . 0) (vertical-scroll-bars . nil) (horizontal-scroll-bars . nil) (minibuffer . ,(minibuffer-window (selected-frame))) (left-fringe . 0) (right-fringe . 0) (background-color . "yellow") (undecorated . t) (border-width . 0) (width . 1) (height . 1) (left . ,(frame-parameter nil 'left)) (top . ,(frame-parameter nil 'top)) (min-width . 0) (min-height . 0) (delete-before . ,(selected-frame))))) (buffer (get-buffer-create "*x*"))) (set-window-buffer (frame-root-window frame) buffer) (with-current-buffer buffer (setq mode-line-format nil))) should give you a blinking cursor at the top left corner of your selected frame. The `mouse-wheel-frame' allows to specify mouse wheel scroll transparency wrt the frame below this one. Use it as in (make-frame `((undecorated . t) (no-accept-focus . t) (mouse-wheel-frame . ,(selected-frame)) (left . ,(/ (frame-pixel-width) 4)) (top . ,(/ (frame-pixel-height) 4)) (width . ,(/ (frame-width) 2)) (height . ,(/ (frame-height) 2)))) Mouse wheel scrolling the window in the new frame should now scroll the underlying window of the initial frame instead. I'm not sure whether I will implement mouse click (aka "hit") transparency in a similar way. A second group of parameters/functions is concerned with maintaining and investigating the stacking order of frames. The `z-group' parameter allows to put a frame in a separate group above or (not on Windows) below all other frames that are not in the same group. For example (set-frame-parameter nil 'z-group 'above) will make your frame (semi-)permanently appear above all other windows on your desktop (including the task bar). The implementation of this parameter is not entirely complete yet, it's easily possible that I will replace it by a simple function. My window manager apparently removes this property when the frame is iconified so I cannot always rely on it. Also a frame with this parameter equalling `above' currently appears above dialogue windows (to select files or fonts). This will be fixed soon but I'm not yet sure how. `frame-restack' already is a function. To test it try to play around with the following forms: (setq sframe (selected-frame)) (setq nframe (make-frame)) (frame-restack nframe sframe) (frame-restack sframe nframe) (frame-restack nframe sframe t) (frame-restack sframe nframe t) The function `frame-list-z-order' returns a list of your frames in the stacking order of your display - bottommost first. A final group of parameters/functions is concerned with making child frames. To make a frame a child frame of an existing frame you can use something like (set-frame-parameter nil 'parent-frame frame) where `frame' must be a live frame. This should work as in the following form (make-frame `((parent-frame . ,(selected-frame)) (undecorated . t) (no-accept-focus . t) (mouse-wheel-frame . ,(selected-frame)) (left . ,(/ (frame-pixel-width) 4)) (top . ,(/ (frame-pixel-height) 4)) (width . ,(/ (frame-width) 2)) (height . ,(/ (frame-height) 2)))) Note that child frames automatically move and (de-)iconify together with their parent frame without any further intervention from Emacs. Moreover they are clipped automatically at the borders of their parent. For normal (non-child) frames there's a new hook `move-frame-functions' called after a frame was moved so you can also synchronize the movements of two top-level frames. Child frames are not listed by `frame-list' but are listed by `frame-list-z-order'. `frame-child-frames' lists all child frames of a specific frame. On GTK neither child frames nor undecorated frames can get a border. If you want a unified-looking border on any system you can use the new face `internal-border' and set the frame parameter ‘internal-border-width’ to some non-zero value for any such frame. If the functions/parameters described here work sufficiently well, I'll post a number of toy algorithms that show how to synchronize two frames in a way that always shows one frame at a specified position on top of the other. The current version comes without info and frameset support. I hope that Juanma can help me with the latter. martin [-- Attachment #2: synch-frames.diff --] [-- Type: text/plain, Size: 162532 bytes --] diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 51c43c7..a507e30 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -286,7 +286,11 @@ minibuffer-prompt-properties--setter ;; 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 diff --git a/lisp/faces.el b/lisp/faces.el index d4f2f08..54eb294 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -2626,6 +2626,13 @@ window-divider-last-pixel :group 'window-divider :group 'basic-faces) +(defface internal-border + '((t nil)) + "Basic face for the internal border." + :version "26.1" + :group 'frames + :group 'basic-faces) + (defface minibuffer-prompt '((((background dark)) :foreground "cyan") ;; Don't use blue because many users of the MS-DOS port customize diff --git a/lisp/frame.el b/lisp/frame.el index 0a35b71..202a8d1 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -115,15 +115,19 @@ minibuffer-frame-alist (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 (cdr (frame-parameter frame-1 'parent-frame))) + (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)))) @@ -144,6 +148,13 @@ handle-focus-out This function runs the hook `focus-out-hook'." (interactive "e") (run-hooks 'focus-out-hook)) + +(defun handle-move-frame (event) + "Handle a move-frame event. +This function runs the abnormal hook `move-frame-functions'." + (interactive "e") + (let ((frame (posn-window (event-start event)))) + (run-hook-with-args 'move-frame-functions frame))) \f ;;;; Arrangement of frames at startup @@ -827,21 +838,24 @@ other-frame 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))) @@ -1483,6 +1497,56 @@ frame-monitor-attributes 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 bottommost (first) to topmost (last). +Child frames appear right after their parent frame. 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"))) \f ;;;; Frame/display capabilities. @@ -1877,8 +1941,8 @@ frame-geom-spec-cons (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. +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))) @@ -1887,14 +1951,16 @@ delete-other-frames ;; 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) + (eq (frame-parameter this 'parent-frame) 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) + (eq (frame-parameter this 'parent-frame) frame)) (delete-frame this)) (setq this next)))) diff --git a/lisp/mwheel.el b/lisp/mwheel.el index eaeb831..ee894b0 100644 --- a/lisp/mwheel.el +++ b/lisp/mwheel.el @@ -190,17 +190,39 @@ mwheel-scroll 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))) + (unless (eq scroll-window selected-window) + ;; Mark window to be scrolled for redisplay. + (select-window scroll-window 'mark-for-redisplay)) ;; Extract the actual amount or find the element that has no modifiers. (if amt (setq amt (cdr amt)) (let ((list-elt mouse-wheel-scroll-amount)) @@ -232,18 +254,18 @@ mwheel-scroll ;; 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) diff --git a/lisp/scroll-bar.el b/lisp/scroll-bar.el index 5290a7b..5835274 100644 --- a/lisp/scroll-bar.el +++ b/lisp/scroll-bar.el @@ -281,7 +281,7 @@ scroll-bar-drag (with-current-buffer (window-buffer window) (setq before-scroll point-before-scroll)) (save-selected-window - (select-window window) + (select-window window 'mark-for-redisplay) (setq before-scroll (or before-scroll (point)))) (scroll-bar-drag-1 event) @@ -326,7 +326,7 @@ scroll-bar-horizontal-drag (with-current-buffer (window-buffer window) (setq before-scroll point-before-scroll)) (save-selected-window - (select-window window) + (select-window window 'mark-for-redisplay) (setq before-scroll (or before-scroll (point)))) (scroll-bar-horizontal-drag-1 event) @@ -356,7 +356,7 @@ scroll-bar-scroll-down (unwind-protect (save-selected-window (let ((portion-whole (nth 2 end-position))) - (select-window window) + (select-window window 'mark-for-redisplay) (setq before-scroll (or before-scroll (point))) (scroll-down @@ -377,7 +377,7 @@ scroll-bar-scroll-up (unwind-protect (save-selected-window (let ((portion-whole (nth 2 end-position))) - (select-window window) + (select-window window 'mark-for-redisplay) (setq before-scroll (or before-scroll (point))) (scroll-up @@ -402,7 +402,7 @@ scroll-bar-toolkit-scroll (with-current-buffer (window-buffer window) (setq before-scroll point-before-scroll)) (save-selected-window - (select-window window) + (select-window window 'mark-for-redisplay) (setq before-scroll (or before-scroll (point))) (cond ((eq part 'above-handle) @@ -449,7 +449,7 @@ scroll-bar-toolkit-horizontal-scroll (with-current-buffer (window-buffer window) (setq before-scroll point-before-scroll)) (save-selected-window - (select-window window) + (select-window window 'mark-for-redisplay) (setq before-scroll (or before-scroll (point))) (cond ((eq part 'before-handle) diff --git a/lisp/window.el b/lisp/window.el index 358d7bc..9b1ff3a 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -1533,7 +1533,7 @@ window-min-size (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))))) @@ -8272,6 +8272,165 @@ shrink-window-if-larger-than-buffer (when (and (window-combined-p window) (pos-visible-in-window-p (point-min) window)) (fit-window-to-buffer window (window-total-height window)))) + +(defun window-largest-empty-rectangle--maximums-1 (quad maximums) + (cond + ((null maximums) + (list quad)) + ((> (car quad) (caar maximums)) + (cons quad maximums)) + (t + (cons (car maximums) + (window-largest-empty-rectangle--maximums-1 quad (cdr maximums)))))) + +(defun window-largest-empty-rectangle--maximums (quad maximums count) + (setq maximums (window-largest-empty-rectangle--maximums-1 quad maximums)) + (if (> (length maximums) count) + (nbutlast maximums) + maximums)) + +(defun window-largest-empty-rectangle--disjoint-maximums (maximums count) + (setq maximums (sort maximums (lambda (x y) (> (car x) (car y))))) + (let ((new-length 0) + new-maximums) + (while (and maximums (< new-length count)) + (let* ((maximum (car maximums)) + (at (nth 2 maximum)) + (to (nth 3 maximum))) + (catch 'drop + (dolist (new-maximum new-maximums) + (let ((new-at (nth 2 new-maximum)) + (new-to (nth 3 new-maximum))) + (when (if (< at new-at) (> to new-at) (< at new-to)) + ;; Intersection -> drop. + (throw 'drop nil)))) + (setq new-maximums (cons maximum new-maximums)) + (setq new-length (1+ new-length))) + (setq maximums (cdr maximums)))) + + (nreverse new-maximums))) + +(defun window-largest-empty-rectangle (&optional window count min-width min-height positions left) + "Return largest empty rectangle in WINDOW. +WINDOW must be live window and defaults to the selected one. + +The return value is a triple of the width and the start and end +Y-coordinates of the largest rectangle that can be inscribed into +the empty space (the space not displaying any text) of WINDOW. +The return value is nil if the current glyph matrix of WINDOW is +not up-to-date. + +Optional argument COUNT, if non-nil, specifies the maximum number +of rectangles to return. This means that the return value is a +list of triples specifying rectangles with the largest rectangle +first. COUNT can be also a cons cell whose car specifies the +number of rectangles to return and whose cdr, if non-nil, states +that all rectangles returned must be disjoint. + +Note that the right edge of any rectangle returned by this +function is the right edge of WINDOW (the left edge if its buffer +displays RTL text). + +Optional arguments MIN-WIDTH and MIN-HEIGHT, if non-nil, specify +the minimum width and height of any rectangle returned. + +Optional argument POSITIONS, if non-nil, is a cons cell whose car +specifies the uppermost and whose cdr specifies the lowermost +pixel position that must be covered by any rectangle returned. +Note that positions are counted from the start of the text area +of WINDOW. + +Optional argument LEFT, if non-nil, means to return values suitable for +buffers displaying right to left text." + ;; Process lines as returned by ‘window-lines-pixel-dimensions’. + ;; STACK is a stack that contains rows that have to be processed yet. + (let* ((window (window-normalize-window window t)) + (disjoint (and (consp count) (cdr count))) + (count (or (and (numberp count) count) + (and (consp count) (numberp (car count)) (car count)))) + (rows (window-lines-pixel-dimensions window nil nil t t left)) + (rows-at 0) + (max-size 0) + row stack stack-at stack-to + top top-width top-at top-to top-size + max-width max-at max-to maximums) + ;; ROWS-AT is the position where the first element of ROWS starts. + ;; STACK-AT is the position where the first element of STACK starts. + (while rows + (setq row (car rows)) + (if (or (not stack) (>= (car row) (caar stack))) + (progn + (unless stack + (setq stack-at rows-at)) + (setq stack (cons row stack)) + ;; Set ROWS-AT to where the first element of ROWS ends + ;; which, after popping ROW, makes it the start position of + ;; the next ROW. + (setq rows-at (cdr row)) + (setq rows (cdr rows))) + (setq top (car stack)) + (setq stack (cdr stack)) + (setq top-width (car top)) + (setq top-at (if stack (cdar stack) stack-at)) + (setq top-to (cdr top)) + (setq top-size (* top-width (- top-to top-at))) + (unless (or (and min-width (< top-width min-width)) + (and min-height (< (- top-to top-at) min-height)) + (and positions + (or (> top-at (car positions)) + (< top-to (cdr positions))))) + (if count + (if disjoint + (setq maximums (cons (list top-size top-width top-at top-to) + maximums)) + (setq maximums (window-largest-empty-rectangle--maximums + (list top-size top-width top-at top-to) + maximums count))) + (when (> top-size max-size) + (setq max-size top-size) + (setq max-width top-width) + (setq max-at top-at) + (setq max-to top-to)))) + (if (and stack (> (caar stack) (car row))) + ;; Have new top element of stack include old top. + (setq stack (cons (cons (caar stack) (cdr top)) (cdr stack))) + ;; Move rows-at backwards to top-at. + (setq rows-at top-at)))) + + (when stack + ;; STACK-TO is the position where the stack ends. + (setq stack-to (cdar stack)) + (while stack + (setq top (car stack)) + (setq stack (cdr stack)) + (setq top-width (car top)) + (setq top-at (if stack (cdar stack) stack-at)) + (setq top-size (* top-width (- stack-to top-at))) + (unless (or (and min-width (< top-width min-width)) + (and min-height (< (- stack-to top-at) min-height)) + (and positions + (or (> top-at (car positions)) + (< stack-to (cdr positions))))) + (if count + (if disjoint + (setq maximums (cons (list top-size top-width top-at stack-to) + maximums)) + (setq maximums (window-largest-empty-rectangle--maximums + (list top-size top-width top-at stack-to) + maximums count))) + (when (> top-size max-size) + (setq max-size top-size) + (setq max-width top-width) + (setq max-at top-at) + (setq max-to stack-to)))))) + + (cond + (maximums + (if disjoint + (window-largest-empty-rectangle--disjoint-maximums maximums count) + maximums)) + ((> max-size 0) + (list max-width max-at max-to max-size))))) \f (defun kill-buffer-and-window () "Kill the current buffer and delete the selected window." @@ -8764,8 +8923,11 @@ mouse-autoselect-window-select (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 window + (or (and (not (numberp mouse-autoselect-window)) + ;; Moved here to allow autoselection of window in + ;; child frames. + (not (eq window (selected-window)))) (and (>= mouse-autoselect-window 0) ;; If `mouse-autoselect-window' is non-negative, ;; select window if it's the same as before. @@ -8793,7 +8955,11 @@ mouse-autoselect-window-select (setq unread-command-events (cons (list 'select-window (list window)) unread-command-events)))) - ((or (and window (eq window (selected-window))) + ((or (not window) + ;; The following was commented out to allow autoselection of + ;; child windows. + + ;; (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 @@ -8807,9 +8973,13 @@ mouse-autoselect-window-select (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 (window-frame window))) (unless (or (not (window-live-p window)) - ;; Don't switch if we're currently in the minibuffer. + ;; Don't switch to a `no-accept-focus' frame. + (and (not (eq frame (selected-frame))) + (frame-parameter frame 'no-accept-focus)) + ;; 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 @@ -8838,6 +9008,11 @@ handle-select-window (run-hooks 'mouse-leave-buffer-hook)) ;; Clear echo area. (message nil) + (when (eq focus-follows-mouse 'auto-raise) + (raise-frame frame)) + ;; Ensure, if possible, that FRAME gets input focus. + (when (memq (window-system frame) '(x w32 ns)) + (x-focus-frame frame)) (select-window window)))) (defun truncated-partial-width-window-p (&optional window) diff --git a/src/dispextern.h b/src/dispextern.h index e030618..3f3166d 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1784,6 +1784,7 @@ enum face_id WINDOW_DIVIDER_FACE_ID, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID, + INTERNAL_BORDER_FACE_ID, BASIC_FACE_ID_SENTINEL }; diff --git a/src/frame.c b/src/frame.c index d0f653f..67fc1ff 100644 --- a/src/frame.c +++ b/src/frame.c @@ -324,11 +324,51 @@ struct frame * 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)); } @@ -643,6 +683,13 @@ struct frame * 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; + 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 @@ -1253,12 +1300,15 @@ of them (the selected terminal frame) is actually displayed. to that frame. */) (Lisp_Object event) { + Lisp_Object value; + /* Preserve prefix arg that the command loop just cleared. */ kset_prefix_arg (current_kboard, Vcurrent_prefix_arg); run_hook (Qmouse_leave_buffer_hook); /* `switch-frame' implies a focus in. */ + value = do_switch_frame (event, 0, 0, Qnil); call1 (intern ("handle-focus-in"), event); - return do_switch_frame (event, 0, 0, Qnil); + return value; } DEFUN ("selected-frame", Fselected_frame, Sselected_frame, 0, 0, 0, @@ -1270,16 +1320,48 @@ of them (the selected terminal frame) is actually displayed. \f DEFUN ("frame-list", Fframe_list, Sframe_list, 0, 0, 0, - doc: /* Return a list of all live frames. */) + doc: /* Return a list of all live frames. +Child frames are not included. */) (void) { - Lisp_Object frames; - frames = Fcopy_sequence (Vframe_list); #ifdef HAVE_WINDOW_SYSTEM - if (FRAMEP (tip_frame)) - frames = Fdelq (tip_frame, frames); + Lisp_Object list = Qnil, frames, frame; + struct frame *f; + + FOR_EACH_FRAME (frames, frame) + { + f = XFRAME (frame); + if (!FRAME_PARENT_FRAME (f) + && NILP (Fframe_parameter (frame, Qtooltip))) + list = Fcons (frame, list); + } + /* frame-list always returned frames in reverse chronological order, + i.e., with the most recently created frame first. Keep that. */ + return Fnreverse (list); +#else /* !HAVE_WINDOW_SYSTEM */ + return Fcopy_sequence (Vframe_list); #endif - return frames; +} + +DEFUN ("frame-child-frames", Fframe_child_frames, Sframe_child_frames, + 0, 1, 0, + doc: /* Return a list of all child frames of the specified FRAME. +FRAME nil or omitted means the selected frame. */) + (Lisp_Object frame) +{ +#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) + struct frame *f = decode_any_frame (frame); + + XSETFRAME (frame, f); + Lisp_Object list = Qnil, frames, frame1; + + FOR_EACH_FRAME (frames, frame1) + if (FRAME_PARENT_FRAME (XFRAME (frame1)) == f) + list = Fcons (frame1, list); + return Fnreverse (list); +#else /* !HAVE_WINDOW_SYSTEM or HAVE_NS */ + return Qnil; +#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */ } /* Return CANDIDATE if it can be used as 'other-than-FRAME' frame on the @@ -1302,7 +1384,9 @@ of them (the selected terminal frame) is actually displayed. || (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; @@ -1440,35 +1524,65 @@ of them (the selected terminal frame) is actually displayed. 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 @@ -1517,53 +1631,65 @@ of them (the selected terminal frame) is actually displayed. } -/* 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"); } @@ -1592,20 +1718,26 @@ of them (the selected terminal frame) is actually displayed. 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. @@ -1709,8 +1841,6 @@ of them (the selected terminal frame) is actually displayed. promise that the terminal of the frame must be valid until we have called the window-system-dependent frame destruction routine. */ - - { struct terminal *terminal; block_input (); @@ -1747,16 +1877,15 @@ of them (the selected terminal frame) is actually displayed. 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; } } @@ -1766,13 +1895,12 @@ of them (the selected terminal frame) is actually displayed. 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); @@ -1784,29 +1912,27 @@ of them (the selected terminal frame) is actually displayed. 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)) @@ -2119,7 +2245,7 @@ of them (the selected terminal frame) is actually displayed. { 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. */ @@ -2457,9 +2583,39 @@ of them (the selected terminal frame) is actually displayed. } } + /* 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)) @@ -2468,7 +2624,7 @@ of them (the selected terminal frame) is actually displayed. 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)) @@ -3099,6 +3255,12 @@ struct frame_parm_table { {"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)}, }; #ifdef HAVE_WINDOW_SYSTEM @@ -4886,6 +5048,13 @@ or a list (- N) meaning -N pixels relative to bottom/right corner. 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 (Qdelete_before, "delete-before"); DEFSYM (Qmodeline, "modeline"); DEFSYM (Qonly, "only"); DEFSYM (Qnone, "none"); @@ -5017,6 +5186,11 @@ or a list (- N) meaning -N pixels relative to bottom/right corner. 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 (Qmin_width, "min-width"); + DEFSYM (Qmin_height, "min-height"); + DEFSYM (Qmouse_wheel_frame, "mouse-wheel-frame"); { int i; @@ -5133,6 +5307,11 @@ even if the end of the buffer is shown (i.e. overscrolling). doc: /* Normal hook run when a frame loses input focus. */); Vfocus_out_hook = Qnil; + DEFVAR_LISP ("move-frame-functions", Vmove_frame_functions, + doc: /* Functions run after a frame was moved. +The functions are run with one arg, the frame that moved. */); + Vmove_frame_functions = Qnil; + DEFVAR_LISP ("delete-frame-functions", Vdelete_frame_functions, doc: /* Functions run before deleting a frame. The functions are run with one arg, the frame to be deleted. @@ -5179,12 +5358,51 @@ either customize it (see the info node `Easy Customization') 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. @@ -5286,6 +5504,7 @@ This variable is effective only with the X toolkit (and there only when defsubr (&Sselect_frame); defsubr (&Sselected_frame); defsubr (&Sframe_list); + defsubr (&Sframe_child_frames); defsubr (&Snext_frame); defsubr (&Sprevious_frame); defsubr (&Slast_nonminibuf_frame); diff --git a/src/frame.h b/src/frame.h index 7331352..a5198bc 100644 --- a/src/frame.h +++ b/src/frame.h @@ -45,6 +45,12 @@ enum fullscreen_type #endif }; +enum z_group +{ + z_group_none, + z_group_above, + z_group_below, +}; #endif /* HAVE_WINDOW_SYSTEM */ /* The structure representing a frame. */ @@ -68,6 +74,11 @@ struct 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 @@ -320,6 +331,25 @@ struct frame 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; + + /* 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; @@ -534,6 +564,13 @@ struct frame { 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) { @@ -850,7 +887,6 @@ struct frame #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) @@ -860,17 +896,39 @@ struct frame ((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) +#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_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_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) \ @@ -1037,7 +1095,8 @@ struct frame 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 @@ -1217,7 +1276,7 @@ extern void frame_size_history_add (struct frame *f, Lisp_Object fun_symbol, 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) { diff --git a/src/gtkutil.c b/src/gtkutil.c index b028254..9b545b3 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -813,30 +813,6 @@ struct xg_frame_tb_info } } -/* Clear under internal border if any. As we use a mix of Gtk+ and X calls - and use a GtkFixed widget, this doesn't happen automatically. */ - -void -xg_clear_under_internal_border (struct frame *f) -{ - if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0) - { - x_clear_area (f, 0, 0, - FRAME_PIXEL_WIDTH (f), FRAME_INTERNAL_BORDER_WIDTH (f)); - - x_clear_area (f, 0, 0, - FRAME_INTERNAL_BORDER_WIDTH (f), FRAME_PIXEL_HEIGHT (f)); - - x_clear_area (f, 0, - FRAME_PIXEL_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f), - FRAME_PIXEL_WIDTH (f), FRAME_INTERNAL_BORDER_WIDTH (f)); - - x_clear_area (f, - FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f), - 0, FRAME_INTERNAL_BORDER_WIDTH (f), FRAME_PIXEL_HEIGHT (f)); - } -} - static int xg_get_gdk_scale (void) { @@ -883,7 +859,7 @@ struct xg_frame_tb_info || pixelwidth != FRAME_PIXEL_WIDTH (f) || pixelheight != FRAME_PIXEL_HEIGHT (f)) { - xg_clear_under_internal_border (f); + x_clear_under_internal_border (f); change_frame_size (f, width, height, 0, 1, 0, 1); SET_FRAME_GARBAGED (f); cancel_mouse_face (f); @@ -911,7 +887,7 @@ struct xg_frame_tb_info &gwidth, &gheight); /* Do this before resize, as we don't know yet if we will be resized. */ - xg_clear_under_internal_border (f); + x_clear_under_internal_border (f); if (FRAME_VISIBLE_P (f)) { @@ -1178,7 +1154,14 @@ struct xg_frame_tb_info 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; @@ -1334,7 +1317,9 @@ struct xg_frame_tb_info /* 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); @@ -1460,6 +1445,86 @@ struct xg_frame_tb_info } } +/* 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 (); +} + /* Set the frame icon to ICON_PIXMAP/MASK. This must be done with GTK functions so GTK does not overwrite the icon. */ @@ -3740,6 +3805,7 @@ struct xg_dialog_data GtkWidget *wparent = gtk_widget_get_parent (wscroll); gint msl; int scale = xg_get_gdk_scale (); + bool hidden; top /= scale; left /= scale; @@ -3764,6 +3830,7 @@ struct xg_dialog_data the height is less than the min size. */ gtk_widget_hide (wparent); gtk_widget_hide (wscroll); + hidden = true; } else { @@ -3778,6 +3845,15 @@ struct xg_dialog_data 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. */ @@ -3843,6 +3919,15 @@ struct xg_dialog_data 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); diff --git a/src/gtkutil.h b/src/gtkutil.h index d67a7bc..12c8d68 100644 --- a/src/gtkutil.h +++ b/src/gtkutil.h @@ -150,7 +150,6 @@ extern void xg_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar, extern void free_frame_tool_bar (struct frame *f); extern void xg_change_toolbar_position (struct frame *f, Lisp_Object pos); -extern void xg_clear_under_internal_border (struct frame *f); extern void xg_frame_resized (struct frame *f, int pixelwidth, int pixelheight); @@ -172,6 +171,12 @@ extern void xg_set_frame_icon (struct frame *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 bool xg_prepare_tooltip (struct frame *f, Lisp_Object string, int *width, diff --git a/src/keyboard.c b/src/keyboard.c index ed8e71f..6f3eb09 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4056,6 +4056,14 @@ static Lisp_Object kbd_buffer_get_event (KBOARD **kbp, bool *used_mouse_menu, kbd_fetch_ptr = event + 1; } #endif +#if defined (HAVE_X11) || defined (HAVE_NTGUI) + else if (event->kind == MOVE_FRAME_EVENT) + { + /* Make an event (move-frame (FRAME)). */ + obj = list2 (Qmove_frame, list1 (event->ie.frame_or_window)); + kbd_fetch_ptr = event + 1; + } +#endif #ifdef HAVE_XWIDGETS else if (event->kind == XWIDGET_EVENT) { @@ -10972,6 +10980,7 @@ struct event_head {SYMBOL_INDEX (Qfocus_in), SYMBOL_INDEX (Qfocus_in)}, {SYMBOL_INDEX (Qfocus_out), SYMBOL_INDEX (Qfocus_out)}, + {SYMBOL_INDEX (Qmove_frame), SYMBOL_INDEX (Qmove_frame)}, {SYMBOL_INDEX (Qdelete_frame), SYMBOL_INDEX (Qdelete_frame)}, {SYMBOL_INDEX (Qiconify_frame), SYMBOL_INDEX (Qiconify_frame)}, {SYMBOL_INDEX (Qmake_frame_visible), SYMBOL_INDEX (Qmake_frame_visible)}, @@ -11144,6 +11153,7 @@ struct event_head DEFSYM (Qswitch_frame, "switch-frame"); DEFSYM (Qfocus_in, "focus-in"); DEFSYM (Qfocus_out, "focus-out"); + DEFSYM (Qmove_frame, "move-frame"); DEFSYM (Qdelete_frame, "delete-frame"); DEFSYM (Qiconify_frame, "iconify-frame"); DEFSYM (Qmake_frame_visible, "make-frame-visible"); @@ -11890,6 +11900,8 @@ shutdown when Emacs receives a fatal signal (e.g., a crash). "handle-focus-in"); initial_define_lispy_key (Vspecial_event_map, "focus-out", "handle-focus-out"); + initial_define_lispy_key (Vspecial_event_map, "move-frame", + "handle-move-frame"); } /* Mark the pointers in the kboard objects. diff --git a/src/nsfns.m b/src/nsfns.m index a709935..912493e 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -972,6 +972,12 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side 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 */ }; @@ -1248,6 +1254,12 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side 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); diff --git a/src/nsterm.m b/src/nsterm.m index 63f1b15..3cd569f 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -6307,7 +6307,7 @@ - (void)mouseMoved: (NSEvent *)e 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)))) { diff --git a/src/termhooks.h b/src/termhooks.h index 3b1b495..14ec397 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -202,6 +202,9 @@ enum event_kind FOCUS_OUT_EVENT, + /* Generated when a frame is moved. */ + MOVE_FRAME_EVENT, + /* Generated when mouse moves over window not currently selected. */ SELECT_WINDOW_EVENT, diff --git a/src/w32fns.c b/src/w32fns.c index 1b628b0..7256925 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -256,6 +256,10 @@ typedef BOOL (WINAPI * GetTitleBarInfo_Proc) # define WTS_SESSION_LOCK 0x7 #endif +#ifndef WS_EX_NOACTIVATE +#define WS_EX_NOACTIVATE 0x08000000L +#endif + /* Keyboard hook state data. */ static struct { @@ -367,17 +371,20 @@ struct frame * 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; @@ -1627,7 +1634,13 @@ struct frame * #endif } \f -static void +/** + * x_clear_under_internal_border: + * + * Clear area of frame F's internal border. If the internal border face + * of F has been specified (is not null), fill the area with that face. + */ +void x_clear_under_internal_border (struct frame *f) { int border = FRAME_INTERNAL_BORDER_WIDTH (f); @@ -1638,12 +1651,26 @@ struct frame * HDC hdc = get_frame_dc (f); int width = FRAME_PIXEL_WIDTH (f); int height = FRAME_PIXEL_HEIGHT (f); + struct face *face = FACE_FROM_ID_OR_NULL (f, INTERNAL_BORDER_FACE_ID); block_input (); - w32_clear_area (f, hdc, 0, FRAME_TOP_MARGIN_HEIGHT (f), width, border); - w32_clear_area (f, hdc, 0, 0, border, height); - w32_clear_area (f, hdc, width - border, 0, border, height); - w32_clear_area (f, hdc, 0, height - border, width, border); + if (face) + { + /* Fill border with internal border face. */ + unsigned long color = face->background; + + w32_fill_area (f, hdc, color, 0, FRAME_TOP_MARGIN_HEIGHT (f), width, border); + w32_fill_area (f, hdc, color, 0, 0, border, height); + w32_fill_area (f, hdc, color, width - border, 0, border, height); + w32_fill_area (f, hdc, color, 0, height - border, width, border); + } + else + { + w32_clear_area (f, hdc, 0, FRAME_TOP_MARGIN_HEIGHT (f), width, border); + w32_clear_area (f, hdc, 0, 0, border, height); + w32_clear_area (f, hdc, width - border, 0, border, height); + w32_clear_area (f, hdc, 0, height - border, width, border); + } release_frame_dc (f, hdc); unblock_input (); } @@ -1682,7 +1709,7 @@ struct frame * 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)) @@ -1955,6 +1982,227 @@ struct frame * 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) +{ + if (!EQ (new_value, 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, Qbelow)) + error ("Value `below' for z-group is not supported on Windows"); + else + error ("Invalid z-group specification"); + } +} \f /* Subroutines for creating a frame. */ @@ -2013,7 +2261,12 @@ struct 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); @@ -2022,7 +2275,12 @@ struct frame * 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); @@ -2031,20 +2289,55 @@ struct frame * 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) @@ -2059,18 +2352,16 @@ struct frame * } 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)); @@ -2086,6 +2377,12 @@ struct frame * /* 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; } @@ -4381,6 +4678,22 @@ struct frame * } } + 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 (); @@ -4486,6 +4799,10 @@ struct frame * 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); @@ -4712,19 +5029,34 @@ struct frame * } 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. */ @@ -4899,6 +5231,10 @@ struct frame * 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; } @@ -5130,7 +5466,8 @@ struct frame * 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) @@ -5318,7 +5655,7 @@ struct frame * 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; @@ -5355,10 +5692,11 @@ struct frame * 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. */ @@ -5381,6 +5719,31 @@ struct frame * 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); @@ -5408,7 +5771,9 @@ struct frame * 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 @@ -5492,23 +5857,42 @@ struct frame * "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); @@ -5516,10 +5900,17 @@ struct frame * /* 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), @@ -5530,9 +5921,7 @@ struct frame * 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); @@ -5597,29 +5986,36 @@ struct frame * 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) @@ -6568,8 +6964,6 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, 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. */ @@ -6635,6 +7029,7 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, 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); @@ -8555,6 +8950,140 @@ value is a list of the form (LEFT, TOP, RIGHT, BOTTOM). All values are } } +/** + * 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 frames) +{ + while (window) + { + HWND child; + struct frame *f = x_window_to_frame (dpyinfo, window); + Lisp_Object frame; + + /* Process child windows first - they precede their parent in the + z-order. */ + block_input (); + child = GetWindow (window, GW_CHILD); + unblock_input (); + if (child) + frames = w32_frame_list_z_order (dpyinfo, child, frames); + + if (f) + { + XSETFRAME (frame, f); + frames = Fcons (frame, frames); + } + + block_input (); + window = GetNextWindow (window, GW_HWNDNEXT); + unblock_input (); + } + + return 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. + +Frames are listed from bottommost (first) to topmost (last). Child +frames appear right after their parent frame. Return nil if DISPLAY +contains no Emacs frame. */) + (Lisp_Object display) +{ + struct w32_display_info *dpyinfo = check_x_display_info (display); + HWND window; + + block_input (); + window = GetTopWindow (NULL); + unblock_input (); + + return w32_frame_list_z_order (dpyinfo, window, Qnil); +} + +/** + * 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. @@ -9749,6 +10278,12 @@ enum NI_Severity { 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, }; void @@ -10128,6 +10663,8 @@ successive mouse move (or scroll bar drag) events before they are 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); diff --git a/src/w32term.c b/src/w32term.c index d6b78fd..b88a855 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -780,9 +780,23 @@ struct record block_input (); { HDC hdc = get_frame_dc (f); - w32_clear_area (f, hdc, 0, y, width, height); - w32_clear_area (f, hdc, FRAME_PIXEL_WIDTH (f) - width, - y, width, height); + struct face *face = FACE_FROM_ID_OR_NULL (f, INTERNAL_BORDER_FACE_ID); + + if (face) + { + /* Fill border with internal border face. */ + unsigned long color = face->background; + + w32_fill_area (f, hdc, color, 0, y, width, height); + w32_fill_area (f, hdc, color, FRAME_PIXEL_WIDTH (f) - width, + y, width, height); + } + else + { + w32_clear_area (f, hdc, 0, y, width, height); + w32_clear_area (f, hdc, FRAME_PIXEL_WIDTH (f) - width, + y, width, height); + } release_frame_dc (f, hdc); } unblock_input (); @@ -3082,7 +3096,8 @@ static void w32_draw_box_rect (struct glyph_string *, int, int, int, int, 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); @@ -3433,8 +3448,22 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object /* 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) @@ -3877,11 +3906,15 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object for them on the frame, we have to clear "under" them. */ w32_clear_area (f, hdc, left, top, width, height); release_frame_dc (f, hdc); + x_clear_under_internal_border (f); } /* 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; @@ -3975,11 +4008,15 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object for them on the frame, we have to clear "under" them. */ w32_clear_area (f, hdc, clear_left, top, clear_width, height); release_frame_dc (f, hdc); + x_clear_under_internal_border (f); } /* 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); @@ -4516,6 +4553,7 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object GetClientRect (window, &rect); select_palette (f, hdc); w32_clear_rect (f, hdc, &rect); + x_clear_under_internal_border (f); deselect_palette (f, hdc); ReleaseDC (window, hdc); @@ -4633,7 +4671,7 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object 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); @@ -4645,6 +4683,7 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object msg.rect.top, msg.rect.right - msg.rect.left, msg.rect.bottom - msg.rect.top); + x_clear_under_internal_border (f); } } break; @@ -4819,8 +4858,15 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object 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 @@ -4832,20 +4878,16 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object 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; } @@ -4948,21 +4990,40 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object 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; @@ -5015,6 +5076,7 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object w32fullscreen_hook (f); } } + check_visibility = 1; break; @@ -5022,7 +5084,11 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object f = x_window_to_frame (dpyinfo, msg.msg.hwnd); if (f && !FRAME_ICONIFIED_P (f)) - x_real_positions (f, &f->left_pos, &f->top_pos); + { + x_real_positions (f, &f->left_pos, &f->top_pos); + inev.kind = MOVE_FRAME_EVENT; + XSETFRAME (inev.frame_or_window, f); + } check_visibility = 1; break; @@ -5051,6 +5117,9 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object } #endif + if (f = x_window_to_frame (dpyinfo, msg.msg.hwnd)) + x_clear_under_internal_border (f); + check_visibility = 1; break; @@ -6026,11 +6095,16 @@ struct xim_inst_t 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 (); } @@ -6234,11 +6308,18 @@ struct xim_inst_t 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) @@ -6453,7 +6534,11 @@ struct xim_inst_t 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 diff --git a/src/w32term.h b/src/w32term.h index 990d379..eada7cc 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -706,7 +706,7 @@ struct scroll_bar { extern void w32_sys_ring_bell (struct frame *f); extern void x_delete_display (struct w32_display_info *dpyinfo); - +extern void x_clear_under_internal_border (struct frame *f); extern void x_query_color (struct frame *, XColor *); #define FILE_NOTIFICATIONS_SIZE 16384 diff --git a/src/window.c b/src/window.c index 9569044..a7b9afc 100644 --- a/src/window.c +++ b/src/window.c @@ -492,7 +492,7 @@ struct window * record_buffer before returning here. */ goto record_and_return; - if (NILP (norecord)) + if (NILP (norecord) || EQ (norecord, Qmark_for_redisplay)) { /* Mark the window for redisplay since the selected-window has a different mode-line. */ wset_redisplay (XWINDOW (selected_window)); @@ -571,7 +571,8 @@ struct window * Optional second arg NORECORD non-nil means do not put this buffer at the front of the buffer list and do not make this window the most recently -selected one. +selected one. Also, do not mark WINDOW for redisplay unless NORECORD +equals the special symbol `mark-for-redisplay'. Run `buffer-list-update-hook' unless NORECORD is non-nil. Note that applications and internal routines often select a window temporarily for @@ -1897,6 +1898,128 @@ of the (first) text line, YPOS is negative. return list4i (row->height + min (0, row->y) - crop, i, row->y, crop); } +DEFUN ("window-lines-pixel-dimensions", Fwindow_lines_pixel_dimensions, Swindow_lines_pixel_dimensions, 0, 6, 0, + doc: /* Return pixel dimensions of WINDOW's lines. +The return value is a list of the x- and y-coordinates of the lower +right corner of the last character of each line. Return nil if the +current glyph matrix of WINDOW is not up-to-date. + +Optional argument WINDOW specifies the window whose lines' dimensions +shall be returned. Nil or omitted means to return the dimensions for +the selected window. + +FIRST, if non-nil, specifies the first line whose dimensions shall be +returned. If FIRST is nil and BODY is non-nil, start with the first +text line of WINDOW. Otherwise, start with the first line of WINDOW. + +LAST, if non-nil, specifies the last line whose dimensions shall be +returned. If LAST is nil and BODY is non-nil, the last line is the last +line of the body (text area) of WINDOW. Otherwise, last is the last +line of WINDOW. + +INVERSE, if nil, means that the y-pixel value returned for a specific +line specifies the distance in pixels from the left edge (body edge if +BODY is non-nil) of WINDOW to the right edge of the last glyph of that +line. INVERSE non-nil means that the y-pixel value returned for a +specific line specifies the distance in pixels from the right edge of +the last glyph of that line to the right edge (body edge if BODY is +non-nil) of WINDOW. + +LEFT non-nil means to return the x- and y-coordinates of the lower left +corner of the leftmost character on each line. This is the value that +should be used for buffers that mostly display text from right to left. + +If LEFT is non-nil and INVERSE is nil, this means that the y-pixel value +returned for a specific line specifies the distance in pixels from the +left edge of the last (leftmost) glyph of that line to the right edge +(body edge if BODY is non-nil) of WINDOW. If LEFT and INVERSE are both +non-nil, the y-pixel value returned for a specific line specifies the +distance in pixels from the left edge (body edge if BODY is non-nil) of +WINDOW to the left edge of the last (leftmost) glyph of that line. + +Normally, the value of this function is not available while Emacs is +busy, for example, when processing a command. It should be retrievable +though when run from an idle timer with a delay of zero seconds. */) + (Lisp_Object window, Lisp_Object first, Lisp_Object last, Lisp_Object body, Lisp_Object inverse, Lisp_Object left) +{ + struct window *w = decode_live_window (window); + struct buffer *b; + struct glyph_row *row, *end_row; + int max_y = NILP (body) ? WINDOW_PIXEL_HEIGHT (w) : window_text_bottom_y (w); + Lisp_Object rows = Qnil; + int window_width = NILP (body) ? w->pixel_width : window_body_width (w, true); + int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); + int subtract = NILP (body) ? 0 : header_line_height; + bool invert = !NILP (inverse); + bool left_flag = !NILP (left); + + if (noninteractive || w->pseudo_window_p) + return Qnil; + + CHECK_BUFFER (w->contents); + b = XBUFFER (w->contents); + + /* Fail if current matrix is not up-to-date. */ + if (!w->window_end_valid + || windows_or_buffers_changed + || b->clip_changed + || b->prevent_redisplay_optimizations_p + || window_outdated (w)) + return Qnil; + + if (NILP (first)) + row = MATRIX_ROW (w->current_matrix, 0); + else if (NUMBERP (first)) + { + CHECK_RANGED_INTEGER (first, 0, w->current_matrix->nrows); + row = MATRIX_ROW (w->current_matrix, XINT (first)); + } + else if (!NILP (body)) + row = MATRIX_FIRST_TEXT_ROW (w->current_matrix); + else + error ("Invalid specification of first line"); + + if (NILP (last)) + end_row = MATRIX_ROW (w->current_matrix, w->current_matrix->nrows); + else if (NUMBERP (first)) + { + CHECK_RANGED_INTEGER (first, 0, w->current_matrix->nrows); + end_row = MATRIX_ROW (w->current_matrix, XINT (last)); + } + else if (!NILP (body)) + end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w); + else + error ("Invalid specification of last line"); + + while (row <= end_row && row->enabled_p + && row->y + row->height < max_y) + { + + if (left_flag) + { + struct glyph *glyph = row->glyphs[TEXT_AREA]; + + rows = Fcons (Fcons (make_number + (invert + ? glyph->pixel_width + : window_width - glyph->pixel_width), + make_number (row->y + row->height - subtract)), + rows); + } + else + rows = Fcons (Fcons (make_number + (invert + ? window_width - row->pixel_width + : row->pixel_width), /* maybe add left + margin here */ + make_number (row->y + row->height - subtract)), + rows); + row++; + } + + return Fnreverse (rows); +} + DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p, 0, 1, 0, doc: /* Return non-nil when WINDOW is dedicated to its buffer. @@ -7341,6 +7464,7 @@ Value is a list of the form (WIDTH COLUMNS VERTICAL-TYPE HEIGHT LINES DEFSYM (Qclone_of, "clone-of"); DEFSYM (Qfloor, "floor"); DEFSYM (Qceiling, "ceiling"); + DEFSYM (Qmark_for_redisplay, "mark-for-redisplay"); staticpro (&Vwindow_list); @@ -7584,6 +7708,7 @@ this value for parameters without read syntax (like windows or frames). defsubr (&Sset_window_point); defsubr (&Sset_window_start); defsubr (&Swindow_dedicated_p); + defsubr (&Swindow_lines_pixel_dimensions); defsubr (&Sset_window_dedicated_p); defsubr (&Swindow_display_table); defsubr (&Sset_window_display_table); diff --git a/src/xdisp.c b/src/xdisp.c index e59934d..4a754e4 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -11365,6 +11365,11 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) redraw_frame (f); else clear_current_matrices (f); + +#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) + x_clear_under_internal_border (f); +#endif /* HAVE_WINDOW_SYSTEM && !HAVE_NS */ + fset_redisplay (f); f->garbaged = false; f->resized_p = false; @@ -11427,7 +11432,14 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) been called, so that mode lines above the echo area are garbaged. This looks odd, so we prevent it here. */ if (!display_completed) - n = redisplay_mode_lines (FRAME_ROOT_WINDOW (f), false); + { + n = redisplay_mode_lines (FRAME_ROOT_WINDOW (f), false); + +#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) + x_clear_under_internal_border (f); +#endif /* HAVE_WINDOW_SYSTEM && !HAVE_NS */ + + } if (window_height_changed_p /* Don't do this if Emacs is shutting down. Redisplay @@ -11753,6 +11765,7 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) && 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; } @@ -11869,6 +11882,7 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) 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 @@ -11915,6 +11929,10 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) 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); @@ -14119,6 +14137,10 @@ static void debug_method_add (struct window *, char const *, ...) if (FRAME_GARBAGED_P (f) && FRAME_WINDOW_P (f)) goto retry; +#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) + x_clear_under_internal_border (f); +#endif /* HAVE_WINDOW_SYSTEM && !HAVE_NS */ + /* Prevent various kinds of signals during display update. stdio is not robust about handling signals, which can cause an apparent I/O error. */ diff --git a/src/xfaces.c b/src/xfaces.c index b5dbb53..ffe9cec 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -4474,6 +4474,10 @@ or lists of the form (RED GREEN BLUE). case CURSOR_FACE_ID: name = Qcursor; break; case MOUSE_FACE_ID: name = Qmouse; break; case MENU_FACE_ID: name = Qmenu; break; + case WINDOW_DIVIDER_FACE_ID: name = Qwindow_divider; break; + case WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID: name = Qwindow_divider_first_pixel; break; + case WINDOW_DIVIDER_LAST_PIXEL_FACE_ID: name = Qwindow_divider_last_pixel; break; + case INTERNAL_BORDER_FACE_ID: name = Qinternal_border; break; default: emacs_abort (); /* the caller is supposed to pass us a basic face id */ @@ -5168,6 +5172,7 @@ ALIST is an alist of (REGISTRY ALTERNATIVE1 ALTERNATIVE2 ...) entries. WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID); realize_named_face (f, Qwindow_divider_last_pixel, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); + realize_named_face (f, Qinternal_border, INTERNAL_BORDER_FACE_ID); /* Reflect changes in the `menu' face in menu bars. */ if (FRAME_FACE_CACHE (f)->menu_face_changed_p) @@ -6389,11 +6394,12 @@ ALIST is an alist of (REGISTRY ALTERNATIVE1 ALTERNATIVE2 ...) entries. DEFSYM (Qmouse, "mouse"); DEFSYM (Qmode_line_inactive, "mode-line-inactive"); DEFSYM (Qvertical_border, "vertical-border"); - - /* TTY color-related functions (defined in tty-colors.el). */ DEFSYM (Qwindow_divider, "window-divider"); DEFSYM (Qwindow_divider_first_pixel, "window-divider-first-pixel"); DEFSYM (Qwindow_divider_last_pixel, "window-divider-last-pixel"); + DEFSYM (Qinternal_border, "internal-border"); + + /* TTY color-related functions (defined in tty-colors.el). */ DEFSYM (Qtty_color_desc, "tty-color-desc"); DEFSYM (Qtty_color_standard_values, "tty-color-standard-values"); DEFSYM (Qtty_color_by_index, "tty-color-by-index"); diff --git a/src/xfns.c b/src/xfns.c index 97aa923..2fa3ce2 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -90,6 +90,7 @@ #include <Xm/FileSB.h> #include <Xm/List.h> #include <Xm/TextF.h> +#include <Xm/MwmUtil.h> #endif #ifdef USE_LUCID @@ -117,6 +118,35 @@ 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); @@ -185,7 +215,9 @@ struct x_display_info * 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; @@ -323,7 +355,8 @@ struct x_display_info * 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, @@ -437,7 +470,8 @@ struct x_display_info * #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 @@ -735,6 +769,171 @@ struct x_display_info * 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); + } +} + #ifdef USE_GTK /* Set icon from FILE for frame F. By using GTK functions the icon @@ -1272,7 +1471,7 @@ struct mouse_cursor_data { 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)) @@ -1474,12 +1673,7 @@ struct mouse_cursor_data { if (FRAME_X_WINDOW (f) != 0) { adjust_frame_size (f, -1, -1, 3, false, Qinternal_border_width); - -#ifdef USE_GTK - xg_clear_under_internal_border (f); -#else x_clear_under_internal_border (f); -#endif } } @@ -2803,6 +2997,25 @@ struct mouse_cursor_data { 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); @@ -2943,6 +3156,26 @@ struct mouse_cursor_data { 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); @@ -3285,11 +3518,12 @@ struct mouse_cursor_data { Lisp_Object frame, tem; Lisp_Object name; bool minibuffer_only = false; + bool undecorated = 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; @@ -3341,6 +3575,28 @@ struct mouse_cursor_data { 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); + XSETFRAME (frame, f); f->terminal = dpyinfo->terminal; @@ -3528,15 +3784,24 @@ struct mouse_cursor_data { 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); @@ -3611,6 +3876,21 @@ struct mouse_cursor_data { 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)) @@ -3652,27 +3932,29 @@ struct mouse_cursor_data { adjust_frame_size call. */ x_default_parameter (f, parms, Qfullscreen, Qnil, "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); + x_default_parameter (f, parms, 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.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 (); @@ -3685,14 +3967,18 @@ struct mouse_cursor_data { 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); + /* Initialize `default-minibuffer-frame' in case this is the first frame on this terminal. */ if (FRAME_HAS_MINIBUF_P (f) @@ -3710,7 +3996,7 @@ struct mouse_cursor_data { and similar functions. */ Vwindow_list = Qnil; - return unbind_to (count, frame); + return unbind_to (count, frame); } @@ -4845,6 +5131,141 @@ value is a list of the form (LEFT, TOP, RIGHT, BOTTOM). All values are : Qnative_edges)); } +/** + * 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 +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 = nchildren - 1; i >= 0; 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. + +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 bottommost (first) to topmost (last). Child +frames appear right after their parent frame. Return nil if TERMINAL +contains no Emacs frame. */) + (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. @@ -6979,6 +7400,12 @@ FRAMES should be nil (the selected frame), a frame, or a list of 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, }; void @@ -7183,6 +7610,8 @@ FRAMES should be nil (the selected frame), a frame, or a list of 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); diff --git a/src/xterm.c b/src/xterm.c index 38229a5..bcf7107 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -714,7 +714,7 @@ struct record #endif } -static void +void x_fill_rectangle (struct frame *f, GC gc, int x, int y, int width, int height) { #ifdef USE_CAIRO @@ -945,11 +945,14 @@ struct x_display_info * 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 */ { @@ -1292,8 +1295,12 @@ struct x_display_info * show_back_buffer (f); } -/* Clear under internal border if any (GTK has its own version). */ -#ifndef USE_GTK +/** + * x_clear_under_internal_border: + * + * Clear area of frame F's internal border. If the internal border face + * of F has been specified (is not null), fill the area with that face. + */ void x_clear_under_internal_border (struct frame *f) { @@ -1302,17 +1309,39 @@ struct x_display_info * int border = FRAME_INTERNAL_BORDER_WIDTH (f); int width = FRAME_PIXEL_WIDTH (f); int height = FRAME_PIXEL_HEIGHT (f); +#ifdef USE_GTK + int margin = 0; +#else int margin = FRAME_TOP_MARGIN_HEIGHT (f); +#endif + struct face *face = FACE_FROM_ID_OR_NULL (f, INTERNAL_BORDER_FACE_ID); block_input (); - x_clear_area (f, 0, 0, border, height); - x_clear_area (f, 0, margin, width, border); - x_clear_area (f, width - border, 0, border, height); - x_clear_area (f, 0, height - border, width, border); + + if (face) + { + unsigned long color = face->background; + Display *display = FRAME_X_DISPLAY (f); + GC gc = f->output_data.x->normal_gc; + + XSetForeground (display, gc, color); + x_fill_rectangle (f, gc, 0, margin, width, border); + x_fill_rectangle (f, gc, 0, 0, border, height); + x_fill_rectangle (f, gc, width - border, 0, border, height); + x_fill_rectangle (f, gc, 0, height - border, width, border); + XSetForeground (display, gc, FRAME_FOREGROUND_PIXEL (f)); + } + else + { + x_clear_area (f, 0, 0, border, height); + x_clear_area (f, 0, margin, width, border); + x_clear_area (f, width - border, 0, border, height); + x_clear_area (f, 0, height - border, width, border); + } + unblock_input (); } } -#endif /* Draw truncation mark bitmaps, continuation mark bitmaps, overlay arrow bitmaps, or clear the fringes if no bitmaps are required @@ -1348,10 +1377,25 @@ struct x_display_info * height > 0)) { int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y)); + struct face *face = FACE_FROM_ID_OR_NULL (f, INTERNAL_BORDER_FACE_ID); block_input (); - x_clear_area (f, 0, y, width, height); - x_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height); + if (face) + { + unsigned long color = face->background; + Display *display = FRAME_X_DISPLAY (f); + + XSetForeground (display, f->output_data.x->normal_gc, color); + x_fill_rectangle (f, f->output_data.x->normal_gc, + 0, y, width, height); + x_fill_rectangle (f, f->output_data.x->normal_gc, + FRAME_PIXEL_WIDTH (f) - width, y, width, height); + } + else + { + x_clear_area (f, 0, y, width, height); + x_clear_area (f, FRAME_PIXEL_WIDTH (f) - width, y, width, height); + } unblock_input (); } } @@ -3835,11 +3879,11 @@ Status x_parse_color (struct frame *f, const char *color_name, cairo_fill (cr); x_end_cr_clip (f); #else - if (FRAME_X_DOUBLE_BUFFERED_P (f)) - XFillRectangle (FRAME_X_DISPLAY (f), - FRAME_X_DRAWABLE (f), - f->output_data.x->reverse_gc, - x, y, width, height); + if (FRAME_X_DOUBLE_BUFFERED_P (f)) + XFillRectangle (FRAME_X_DISPLAY (f), + FRAME_X_DRAWABLE (f), + f->output_data.x->reverse_gc, + x, y, width, height); else x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), x, y, width, height, False); @@ -4953,6 +4997,9 @@ struct frame * 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; @@ -4999,20 +5046,37 @@ struct frame * &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), @@ -5273,20 +5337,22 @@ static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part, x_send_scroll_bar_event (window_being_scrolled, scroll_bar_end_scroll, 0, 0, true); w = XWINDOW (window_being_scrolled); - bar = XSCROLL_BAR (w->horizontal_scroll_bar); - - if (bar->dragging != -1) + if (!NILP (w->horizontal_scroll_bar)) { - bar->dragging = -1; - /* The thumb size is incorrect while dragging: fix it. */ - set_horizontal_scroll_bar (w); - } - window_being_scrolled = Qnil; + bar = XSCROLL_BAR (w->horizontal_scroll_bar); + if (bar->dragging != -1) + { + bar->dragging = -1; + /* The thumb size is incorrect while dragging: fix it. */ + set_horizontal_scroll_bar (w); + } + window_being_scrolled = Qnil; #if defined (USE_LUCID) - bar->last_seen_part = scroll_bar_nowhere; + bar->last_seen_part = scroll_bar_nowhere; #endif - /* Xt timeouts no longer needed. */ - toolkit_scroll_bar_interaction = false; + /* Xt timeouts no longer needed. */ + toolkit_scroll_bar_interaction = false; + } } } #endif /* not USE_GTK */ @@ -6485,10 +6551,14 @@ static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part, 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 (); @@ -7056,10 +7126,10 @@ static void x_send_scroll_bar_event (Lisp_Object, enum scroll_bar_part, /* 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 (); @@ -7828,8 +7898,21 @@ static void xembed_send_message (struct frame *f, Time, 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; @@ -7869,6 +7952,7 @@ static void xembed_send_message (struct frame *f, Time, event->xexpose.x, event->xexpose.y, event->xexpose.width, event->xexpose.height, 0); + x_clear_under_internal_border (f); #endif } @@ -7884,6 +7968,9 @@ static void xembed_send_message (struct frame *f, Time, #endif expose_frame (f, event->xexpose.x, event->xexpose.y, event->xexpose.width, event->xexpose.height); +#ifdef USE_GTK + x_clear_under_internal_border (f); +#endif } if (!FRAME_GARBAGED_P (f)) @@ -7932,7 +8019,10 @@ static void xembed_send_message (struct frame *f, Time, event->xgraphicsexpose.y, event->xgraphicsexpose.width, event->xgraphicsexpose.height); - show_back_buffer (f); +#ifdef USE_GTK + x_clear_under_internal_border (f); +#endif + show_back_buffer (f); } #ifdef USE_X_TOOLKIT else @@ -7989,7 +8079,16 @@ static void xembed_send_message (struct frame *f, Time, /* 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 */ + } SET_FRAME_VISIBLE (f, 1); SET_FRAME_ICONIFIED (f, false); @@ -8433,10 +8532,17 @@ static void xembed_send_message (struct frame *f, Time, #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 SELECT_WINDOW_EVENTs for + `mouse-autoselect-window' but don't let popup menus + interfere with this (Bug#1261). */ + if (!NILP (Vmouse_autoselect_window) + && !popup_activated () + && (f == dpyinfo->x_highlight_frame + /* Switch to f from another frame iff + focus_follows_mouse is set and f's + no_accept_focus parameter is nil. */ + || (!NILP (focus_follows_mouse) + && !FRAME_NO_FOCUS_ON_MAP (f)))) { static Lisp_Object last_mouse_window; Lisp_Object window = window_from_coordinates @@ -8447,13 +8553,7 @@ static void xembed_send_message (struct frame *f, Time, will be selected 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.ie.kind = SELECT_WINDOW_EVENT; inev.ie.frame_or_window = window; @@ -8601,7 +8701,34 @@ static void xembed_send_message (struct frame *f, Time, if (FRAME_GTK_OUTER_WIDGET (f) && gtk_widget_get_mapped (FRAME_GTK_OUTER_WIDGET (f))) #endif - x_real_positions (f, &f->left_pos, &f->top_pos); + { + int old_left = f->left_pos; + int old_top = f->top_pos; + Lisp_Object frame = Qnil; + + XSETFRAME (frame, f); + + 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) + { + inev.ie.kind = MOVE_FRAME_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); + } + } + #ifdef HAVE_X_I18N if (FRAME_XIC (f) && (FRAME_XIC_STYLE (f) & XIMStatusArea)) @@ -8622,8 +8749,37 @@ static void xembed_send_message (struct frame *f, Time, 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_FOCUS_ON_MAP (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) + || (hf && FRAME_LIVE_P (hf) + && f == FRAME_PARENT_FRAME (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)) @@ -10061,7 +10217,7 @@ struct x_error_message_stack { } XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), - modified_left, modified_top); + modified_left, modified_top); x_sync_with_move (f, f->left_pos, f->top_pos, FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN); @@ -10077,6 +10233,7 @@ struct x_error_message_stack { 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 @@ -10207,6 +10364,91 @@ struct x_error_message_stack { 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) +{ + if (!EQ (new_value, old_value)) + { + Lisp_Object frame; + struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); + + XSETFRAME (frame, f); + + if (NILP (new_value)) + { + if (FRAME_Z_GROUP_ABOVE (f)) + set_wm_state (frame, false, + dpyinfo->Xatom_net_wm_state_above, None); + else if (FRAME_Z_GROUP_BELOW (f)) + 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) && !FRAME_Z_GROUP_ABOVE (f)) + { + if (FRAME_Z_GROUP_BELOW (f)) + set_wm_state (frame, false, + dpyinfo->Xatom_net_wm_state_below, None); + set_wm_state (frame, true, + dpyinfo->Xatom_net_wm_state_above, None); + FRAME_Z_GROUP (f) = z_group_above; + } + else if (EQ (new_value, Qbelow) && !FRAME_Z_GROUP_BELOW (f)) + { + if (FRAME_Z_GROUP_ABOVE (f)) + 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 + 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. @@ -10999,6 +11241,26 @@ struct x_error_message_stack { 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); @@ -11067,9 +11329,10 @@ struct x_error_message_stack { 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) { @@ -11132,15 +11395,15 @@ struct x_error_message_stack { 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. @@ -11150,8 +11413,6 @@ struct x_error_message_stack { SET_FRAME_VISIBLE (f, 0); SET_FRAME_ICONIFIED (f, false); - x_sync (f); - unblock_input (); } @@ -12306,6 +12567,9 @@ struct x_display_info * 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; diff --git a/src/xterm.h b/src/xterm.h index 32c879b..3122a2b 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -447,9 +447,9 @@ struct x_display_info /* 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; @@ -1102,6 +1102,7 @@ extern bool x_alloc_lighter_color_for_widget (Widget, Display *, Colormap, extern bool x_alloc_nearest_color (struct frame *, Colormap, XColor *); extern void x_query_color (struct frame *f, XColor *); extern void x_clear_area (struct frame *f, int, int, int, int); +extern void x_fill_rectangle (struct frame *f, GC, int, int, int, int); #if !defined USE_X_TOOLKIT && !defined USE_GTK extern void x_mouse_leave (struct x_display_info *); #endif @@ -1168,6 +1169,8 @@ extern bool x_alloc_lighter_color_for_widget (Widget, Display *, Colormap, } 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); ^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-11 14:27 ` martin rudalics @ 2017-02-11 21:02 ` Clément Pit--Claudel 2017-02-11 21:10 ` Clément Pit--Claudel 2017-02-12 11:13 ` martin rudalics 2017-04-12 17:38 ` Alan Third 1 sibling, 2 replies; 85+ messages in thread From: Clément Pit--Claudel @ 2017-02-11 21:02 UTC (permalink / raw) To: martin rudalics, Arthur Miller; +Cc: 25408 [-- Attachment #1.1: Type: text/plain, Size: 5615 bytes --] On 2017-02-11 09:27, martin rudalics wrote: > If you are on GNU/Linux or Windows then please apply the attached patch > synch-frames.diff to your current version of master and rebuild. If you > succeeded doing that, start emacs -Q and continue reading. Thanks! The patch applied cleanly and everything compiled fine. > To remove a frame's decorations, use the frame parameter `undecorated' This works great. > To make a new frame undecorated use > (make-frame '((undecorated . t))) This works great too. > If everything works as intended and your only interest > was to make frames without decorations, you can finish reading here. Everything up to that point worked great :) > Usually, the position of a frame's native rectangle doesn't change when > adding/removing decorations. If you want to change it, use the `left' > and `top' frame parameters. That works fine. > If you think you need to remove/add individual parts of the decorations > (titlebar, buttons, external borders) post your wishes here. Some > window managers might be able to do that. I haven't needed this yet :) > The rest of this text is concerned with describing additional features. > If some of them don't work on your system, please tell me, usually they > need a compliant window manager as well. Thanks. Maybe this is a good time to introduce my use case: I'd like to replace company-mode's overlay-based "tooltips" with proper tooltip-like frames. show-x-tooltip almost works for that purpose, but not quite: most importantly, there can at any time only be at most one pop-up. > To make a frame not show up on the taskbar use the > frame parameter `skip-taskbar' ✓ > To make a new frame not receive focus initially or when deiconified, use > the frame parameter `no-focus-on-map' ✓, although if I create a frame with no-focus-on-map I then need a call to raise-frame to raise it — even if its z-group is 'above. Maybe when z-group is "above" the frame should be automatically raised? > Usually this works but if you are using a focus follows mouse policy you > might have to specify the `no-accept-focus' parameter as well as in > > (make-frame '((no-focus-on-map . t) (no-accept-focus . t))) ✓ > If you want to avoid that C-x 5 o switches to a specific frame, set > that frame's `no-other-frame' parameter as in ✓ > A second group of parameters/functions is concerned with maintaining and > investigating the stacking order of frames. The `z-group' parameter > allows to put a frame in a separate group above or (not on Windows) > below all other frames that are not in the same group. For example > > (set-frame-parameter nil 'z-group 'above) ✓, although it would be nice to automatically raise the frame when x-group is above. I can call raise-frame, but it doesn't work correctly when the frame is invisible (and setting the visibility to t before raising the frame doesn't work either). > For normal (non-child) frames there's a new hook `move-frame-functions' > called after a frame was moved so you can also synchronize the movements > of two top-level frames. Cool. I should use this to make sure the popup stays around. > If the functions/parameters described here work sufficiently well, I'll > post a number of toy algorithms that show how to synchronize two frames > in a way that always shows one frame at a specified position on top of > the other. I think this is wonderful work; thanks so much for doing all this. I've posted the code I used to test this with company. f you eval this and run M-x company-tooltip--add-advice, completion should use an x frame in addition to its regular overlay-based tooltips. This works very nicely, except for a few problems listed below: * Creating a frame is rather slow; the following is an excerpt of a profile: - make-frame 442 29% - frame-creation-function 440 29% - apply 440 29% - #<compiled 0x4862dd> 440 29% - x-create-frame-with-faces 440 29% - face-set-after-frame-default 307 20% - face-spec-recalc 276 18% - make-face-x-resource-internal 217 14% - set-face-attributes-from-resources 213 14% - set-face-attribute-from-resource 190 12% - face-name 126 8% + check-face 118 7% + face-spec-reset-face 44 2% + face-spec-set-2 7 0% set-face-attribute 8 0% normal-erase-is-backspace-setup-frame 2 0% * Frames with z-group set to 'above are not automatically raised when no-focus-on-map is set, so I need to call x-raise-frame on them; this doesn't work when they are invisible (instead it makes them visible without raising them, it seems). * Creating a frame / making it visible uses my WM's frame creating animation — is there a way to disable this (x-show-tip doesn't have it)? Thanks again for all this cool stuff! It would be great to use proper frames for company's completion popups. [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-11 21:02 ` Clément Pit--Claudel @ 2017-02-11 21:10 ` Clément Pit--Claudel 2017-02-12 11:13 ` martin rudalics 1 sibling, 0 replies; 85+ messages in thread From: Clément Pit--Claudel @ 2017-02-11 21:10 UTC (permalink / raw) To: martin rudalics, Arthur Miller; +Cc: 25408 [-- Attachment #1.1: Type: text/plain, Size: 98 bytes --] > I've posted the code I used to test this with company. Of course, I forgot the attachment. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1.2: company-tooltip.el --] [-- Type: text/x-emacs-lisp; name="company-tooltip.el", Size: 5973 bytes --] ;;; company-tooltip.el --- Use a real ppup to show company candidates ;;; Commentary: ;; ;;; Code: (require 'company) (defun company-tooltip--frame-params (parent-frame) `(;; Initial state (fullscreen . nil) (line-spacing . 0) ;; Size (min-height . 0) (min-width . 0) ;; Borders and fringes (left-fringe . 0) (right-fringe . 0) (right-divider-width . 0) (bottom-divider-width . 0) (border-width . 0) (internal-border-width . 0) ;; UI components (undecorated . t) (menu-bar-lines . 0) (tool-bar-lines . 0) (vertical-scroll-bars . nil) (horizontal-scroll-bars . nil) ;; Buffers (minibuffer . nil) (unsplittable . t) ;; Appearance (cursor-type . nil) ;; FIXME Also use cursor-type and cursor-in-non-selected-windows variables (background-color . ,(face-attribute 'company-tooltip :background)) ;; Behavior (delete-before . ,parent-frame) (no-focus-on-map . t) (skip-taskbar . t) (no-other-frame . t) (no-accept-focus . t) (z-group . above))) (defvar company-tooltip--frame nil) (defvar company-tooltip--buffer nil) (defun company-tooltip--adjust-frame (x y width height) "Move company tooltip to X, Y and resize to WIDTH, HEIGHT." (set-frame-position company-tooltip--frame x y) (set-frame-width company-tooltip--frame width) (set-frame-height company-tooltip--frame height)) (defun company-tooltip--ensure-frame (x y width height) "Create or return the company tooltip frame. X, Y, WIDTH, HEIGHT: see `company-tooltip--adjust-frame'." (unless (frame-live-p company-tooltip--frame) ;; (cl-letf (((symbol-function 'face-set-after-frame-default) ;; (symbol-function 'ignore))) (setq company-tooltip--frame (make-frame `((top . ,y) (left . ,x) (width . ,width) (height . ,height) ,@(company-tooltip--frame-params (selected-frame)))))) (company-tooltip--adjust-frame x y width height) ;; (make-frame-visible company-tooltip--frame) ;; FIXME raise-frame doesn't work when called right after make-frame-visible (raise-frame company-tooltip--frame)) (defvar company-tooltip--map (let ((map (make-keymap))) ;; FIXME this doesn't cause mouse events to be ignored (define-key map [t] 'ignore) map)) (define-derived-mode company-tooltip--mode fundamental-mode "tooltip" "Major mode for company tooltip frames." (setq-local overriding-local-map company-tooltip--map) (setq-local truncate-lines t) (setq-local mode-line-format nil) (setq-local cursor-type nil) (setq-local cursor-in-non-selected-windows nil)) ;; (kill-buffer "*company-tooltip*") (defun company-tooltip--ensure-buffer () "Create or return the company tooltip buffer." (unless company-tooltip--buffer (with-current-buffer (get-buffer-create "*company-tooltip*") (company-tooltip--mode) (setq company-tooltip--buffer (current-buffer))))) (defun company-tooltip--set-buffer () "Set buffer of company tooltip frame." (company-tooltip--ensure-buffer) (set-window-buffer (frame-root-window company-tooltip--frame) company-tooltip--buffer)) (defun company-tooltip--posn-x-y (position) "Return X and Y coordinates of bottom-left corner of POSITION." (let* ((point-x-y (posn-x-y position)) (window (posn-window position)) (win-edges (window-edges window nil t t)) (win-x-y (cons (nth 0 win-edges) (nth 1 win-edges))) (frame-x-y (cons (frame-parameter (selected-frame) 'top) (frame-parameter (selected-frame) 'left)))) (cons (+ (car point-x-y) (car win-x-y)) (+ (cdr point-x-y) (cdr win-x-y) (line-pixel-height) (window-header-line-height window))))) (defun company-tooltip--update-1 (width height contents) "Update position, WIDTH, HEIGHT, CONTENTS, and visibility of tooltip frame." (let* ((x-y (company-tooltip--posn-x-y (save-excursion (backward-char (length company-prefix)) (posn-at-point))))) (company-tooltip--ensure-frame (car x-y) (cdr x-y) width (abs height)) (company-tooltip--set-buffer) (with-current-buffer company-tooltip--buffer (erase-buffer) (insert contents)))) (defun company-tooltip--update (height selection) "Wrapper around `company-tooltip--update'. HEIGHT is passed unmodified. SELECTION is used to compute width and contents." (let* ((lines (company--create-lines selection (abs height))) (contents (mapconcat (lambda (l) (concat l "")) lines "\n"))) (company-tooltip--update-1 (string-width (car lines)) height contents))) (defun company-tooltip-show (row column selection) (company-tooltip--update (company--pseudo-tooltip-height) selection)) (defun company-tooltip-edit (selection) (company-tooltip--update (overlay-get company-pseudo-tooltip-overlay 'company-height) selection)) (defun company-tooltip-hide () (when (frame-live-p company-tooltip--frame) ;; FIXME: this should work: (make-frame-invisible company-tooltip--frame) (delete-frame company-tooltip--frame))) (defun company-tooltip--add-advice () (interactive) (advice-add 'company-pseudo-tooltip-show :after 'company-tooltip-show) (advice-add 'company-pseudo-tooltip-edit :after 'company-tooltip-edit) (advice-add 'company-pseudo-tooltip-hide :after 'company-tooltip-hide)) (defun company-tooltip--remove-advice () (interactive) (advice-remove 'company-pseudo-tooltip-show 'company-tooltip-show) (advice-remove 'company-pseudo-tooltip-edit 'company-tooltip-edit) (advice-remove 'company-pseudo-tooltip-hide 'company-tooltip-hide)) (provide 'company-tooltip) ;;; company-tooltip.el ends here [-- Attachment #2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 1979 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-11 21:02 ` Clément Pit--Claudel 2017-02-11 21:10 ` Clément Pit--Claudel @ 2017-02-12 11:13 ` martin rudalics 2017-02-15 19:49 ` Arthur Miller 2017-04-12 9:27 ` martin rudalics 1 sibling, 2 replies; 85+ messages in thread From: martin rudalics @ 2017-02-12 11:13 UTC (permalink / raw) To: Clément Pit--Claudel, Arthur Miller; +Cc: 25408 [-- Attachment #1: Type: text/plain, Size: 5066 bytes --] > Thanks! The patch applied cleanly and everything compiled fine. Thanks for testing. Please tell me your build and window manager types. > ✓, although if I create a frame with no-focus-on-map I then need a > call to raise-frame to raise it — even if its z-group is 'above. > Maybe when z-group is "above" the frame should be automatically > raised? Not so here (with a GTK 3.4.2 build on Debian running xfwm). Evaluating (make-frame '((no-focus-on-map . t) (z-group . above))) makes a new frame on top of the existing one regardless of whether xfwm is set up to use focus follows mouse or not. We probably have to investigate that further. > ✓, although it would be nice to automatically raise the frame when > x-group is above. I can call raise-frame, but it doesn't work > correctly when the frame is invisible (and setting the visibility to t > before raising the frame doesn't work either). I mentioned that: When a frame is made invisible, its z-group is reset to nil by the window system or manager. x_set_z_group can't cope with that because the last line of x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) { if (!EQ (new_value, old_value)) still assumes that the frame is "above". For the moment try with (set-frame-parameter frame 'z-group nil) ... (set-frame-parameter frame 'z-group 'above) as a workaround. I'm not yet sure whether it's better to (1) have x_make_frame_invisible and x_iconify_frame reset the z-group parameter explicitly, (2) change x_set_z_group so it always issues a request to the window system, or (3) remove the z-group parameter and make the z-group setting an option of the `frame-restack' function. Unfortunately, the z-group equivalents in X 11 are a complete mess: You can put a window simultaneously in the ‘above’ and the ‘below’ groups and it notwhere says what should prevail and what happens when you later remove a window from one of these groups (I trioed to avoid this dilemma with the z-group concept). And restacking may probably remove a window from these groups and maybe not allow to put it there and so on ... And why not avoid z-groups at all? Because you cannot simply restack a frame on top of the "active" frame. If you try (via a foucs-in-hooked function) you will see that your window system uses up all available resources because the window system wants to raise the active frame and Emacs wants to raise the other one. So to put a frame on top of the "active" frame you have to put that frame in the ‘above’ group. > * Creating a frame is rather slow; the following is an excerpt of a profile: > > - make-frame 442 29% > - frame-creation-function 440 29% > - apply 440 29% > - #<compiled 0x4862dd> 440 29% > - x-create-frame-with-faces 440 29% > - face-set-after-frame-default 307 20% > - face-spec-recalc 276 18% > - make-face-x-resource-internal 217 14% > - set-face-attributes-from-resources 213 14% > - set-face-attribute-from-resource 190 12% > - face-name 126 8% > + check-face 118 7% > + face-spec-reset-face 44 2% > + face-spec-set-2 7 0% > set-face-attribute 8 0% > normal-erase-is-backspace-setup-frame 2 0% But isn't that the problem I tried to tackle (for tooltip frames) with the option ‘tooltip-reuse-hidden-frame’? All this face-related stuff is an ecological disaster IMHO. Here, creating a tooltip frame caused up to two GC cycles before I added that option. So as a rule create your frames (lazily) once for each session and hide them when you don't need them. > * Frames with z-group set to 'above are not automatically raised when > no-focus-on-map is set, so I need to call x-raise-frame on them; this > doesn't work when they are invisible (instead it makes them visible > without raising them, it seems). I hope I described the problem and a workaround above. I attach my functions for testing attached frames so you can see how I handle this currently. > * Creating a frame / making it visible uses my WM's frame creating animation — is there a way to disable this (x-show-tip doesn't have it)? No idea. I can look into that (as a rule I turn off all animations here). Do you use GTK tooltips or Emacs' native ones? martin [-- Attachment #2: synch-frame-x.el --] [-- Type: application/emacs-lisp, Size: 14587 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-12 11:13 ` martin rudalics @ 2017-02-15 19:49 ` Arthur Miller 2017-02-16 8:04 ` martin rudalics 2017-04-12 9:27 ` martin rudalics 1 sibling, 1 reply; 85+ messages in thread From: Arthur Miller @ 2017-02-15 19:49 UTC (permalink / raw) To: martin rudalics; +Cc: 25408, Clément Pit--Claudel [-- Attachment #1: Type: text/plain, Size: 5915 bytes --] That's great. Are you going to push your patch to git-repo? When it comes to other platforms than Windows, I have no idea about OS X since I don't own any macs, but for X11, we have different means to controll decorations and their looks & behaviour. On X11 we have window managers that makes it easy to configure (or remove) borders, decorations etc, so in my humble opinion I don't think you have to spend countless time to make it work with every possible window manager etc. I didn't even thought of this on Linux, I only needed it for windows, to make Emacs behave more like it does on Linux. 2017-02-12 12:13 GMT+01:00 martin rudalics <rudalics@gmx.at>: > > Thanks! The patch applied cleanly and everything compiled fine. > > Thanks for testing. Please tell me your build and window manager types. > > > ✓, although if I create a frame with no-focus-on-map I then need a > > call to raise-frame to raise it — even if its z-group is 'above. > > Maybe when z-group is "above" the frame should be automatically > > raised? > > Not so here (with a GTK 3.4.2 build on Debian running xfwm). Evaluating > > (make-frame '((no-focus-on-map . t) (z-group . above))) > > makes a new frame on top of the existing one regardless of whether xfwm > is set up to use focus follows mouse or not. > > We probably have to investigate that further. > > > ✓, although it would be nice to automatically raise the frame when > > x-group is above. I can call raise-frame, but it doesn't work > > correctly when the frame is invisible (and setting the visibility to t > > before raising the frame doesn't work either). > > I mentioned that: When a frame is made invisible, its z-group is reset > to nil by the window system or manager. x_set_z_group can't cope with > that because the last line of > > x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object > old_value) > { > if (!EQ (new_value, old_value)) > > still assumes that the frame is "above". For the moment try with > > (set-frame-parameter frame 'z-group nil) > ... > (set-frame-parameter frame 'z-group 'above) > > as a workaround. I'm not yet sure whether it's better to (1) have > x_make_frame_invisible and x_iconify_frame reset the z-group parameter > explicitly, (2) change x_set_z_group so it always issues a request to > the window system, or (3) remove the z-group parameter and make the > z-group setting an option of the `frame-restack' function. > > Unfortunately, the z-group equivalents in X 11 are a complete mess: You > can put a window simultaneously in the ‘above’ and the ‘below’ groups > and it notwhere says what should prevail and what happens when you later > remove a window from one of these groups (I trioed to avoid this dilemma > with the z-group concept). And restacking may probably remove a window > from these groups and maybe not allow to put it there and so on ... > > And why not avoid z-groups at all? Because you cannot simply restack a > frame on top of the "active" frame. If you try (via a foucs-in-hooked > function) you will see that your window system uses up all available > resources because the window system wants to raise the active frame and > Emacs wants to raise the other one. So to put a frame on top of the > "active" frame you have to put that frame in the ‘above’ group. > > > * Creating a frame is rather slow; the following is an excerpt of a > profile: > > > > - make-frame 442 > 29% > > - frame-creation-function 440 > 29% > > - apply 440 > 29% > > - #<compiled 0x4862dd> 440 > 29% > > - x-create-frame-with-faces 440 > 29% > > - face-set-after-frame-default 307 > 20% > > - face-spec-recalc 276 > 18% > > - make-face-x-resource-internal 217 > 14% > > - set-face-attributes-from-resources 213 > 14% > > - set-face-attribute-from-resource 190 > 12% > > - face-name 126 > 8% > > + check-face 118 > 7% > > + face-spec-reset-face 44 > 2% > > + face-spec-set-2 7 > 0% > > set-face-attribute 8 > 0% > > normal-erase-is-backspace-setup-frame > 2 0% > > But isn't that the problem I tried to tackle (for tooltip frames) with > the option ‘tooltip-reuse-hidden-frame’? All this face-related stuff is > an ecological disaster IMHO. Here, creating a tooltip frame caused up > to two GC cycles before I added that option. > > So as a rule create your frames (lazily) once for each session and hide > them when you don't need them. > > > * Frames with z-group set to 'above are not automatically raised when > > no-focus-on-map is set, so I need to call x-raise-frame on them; this > > doesn't work when they are invisible (instead it makes them visible > > without raising them, it seems). > > I hope I described the problem and a workaround above. I attach my > functions for testing attached frames so you can see how I handle this > currently. > > > * Creating a frame / making it visible uses my WM's frame creating > animation — is there a way to disable this (x-show-tip doesn't have it)? > > No idea. I can look into that (as a rule I turn off all animations > here). Do you use GTK tooltips or Emacs' native ones? > > martin > [-- Attachment #2: Type: text/html, Size: 7258 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-15 19:49 ` Arthur Miller @ 2017-02-16 8:04 ` martin rudalics 2017-02-16 13:22 ` Arthur Miller 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-02-16 8:04 UTC (permalink / raw) To: Arthur Miller; +Cc: 25408, Clément Pit--Claudel > That's great. Are you going to push your patch to git-repo? After having resolved some remaining issues, yes. > When it comes to other platforms than Windows, I have no idea about OS X > since I don't own any macs, but for X11, we have different means to > controll decorations and their looks & behaviour. On X11 we have window > managers that makes it easy to configure (or remove) borders, decorations > etc, so in my humble opinion I don't think you have to spend countless time > to make it work with every possible window manager etc. The concern here is not how to turn off decorations for all windows (or maybe all windows of a certain application), something which themes most likely already provide to some extent. The concern is how to control aspects like appearance, placement, focusing and stacking order of some specific Emacs frames, without affecting the remaining frames. Consider the need to display some explanatory information for the editing activity you are about to accomplish. If you don't want to pop up a new "normal" window or frame for that purpose, you currently have two possibilites: Use the echo area or the tooltip frame. Both are ephemeral and have to be shared with all other applications pursuing a similar goal. Hence the need for some sort of minor frames which are OT1H less ephemeral and can be more easily replicated than tooltips or the echo area and are OTOH visually and habitually less obtrusive than normal frames or windows. Some desirable properties of such minor frames are: (1) Do not show any window manager decorations provided their visibility and placement can be controlled by the application. (2) Do not show them on the taskbar. (3) Do not focus them when they pop up. (4) Do not give them focus via mouse movements, mouse wheel scrolling or accidental mouse clicks. (5) Allow to attach them to some normal Emacs frame or window. This means to automatically move, resize and stack them along with that frame/window without affecting the appearance of any other object on your display. It may also mean to make them obscure as few as possible text of the frame they have been attached to. (6) Apart from (1)--(5) give them the full functionality of "normal" Emacs frames. Obviously, (6) is the most difficult part. For example, displaying such a frame without making it continuously vanish and reappear. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-16 8:04 ` martin rudalics @ 2017-02-16 13:22 ` Arthur Miller 2017-02-16 14:06 ` Arthur Miller 2017-02-17 7:03 ` martin rudalics 0 siblings, 2 replies; 85+ messages in thread From: Arthur Miller @ 2017-02-16 13:22 UTC (permalink / raw) To: martin rudalics; +Cc: 25408, Clément Pit--Claudel [-- Attachment #1: Type: text/plain, Size: 3976 bytes --] If they don't get focus when they pop-up, and not get focus via mouse and if they also don't have decorations, what is considered as full functionality of "normal" frames? That sounds to me a bit like a popup window. Do you give them focus by switching with keyboard, like moving focus to "other window"? "The concern is how to control aspects like appearance, placement, focusing and stacking order of some specific Emacs frames, without affecting the remaining frames." As you yourself point out, certain WMs does allow you to create rules per windows. On some managers one can set rule based on window title bar, window class or class name, xid, role etc. I don't know if title bar property can be used if titlebar exist but is hidden. Maybe a separate class name could be used for that kind of windows so one can set appropriate hints for that frame. Or maybe you are already doing that? Just an idea, I haven't looked at your patch to be honest. I cloned code today from git and compilations is crashing on me, when dumping lisp code: (without your patch applied): Loading /home/arthur/emacs/lisp/international/characters.el (source)... Wrong type argument: char-table-p, nil make[1]: *** [Makefile:752: bootstrap-emacs] Error 255 make[1]: Leaving directory '/home/arthur/emacs/src' make: *** [Makefile:409: src] Error 2 Will be interesting to test it once I manage to compile Emacs. 2017-02-16 9:04 GMT+01:00 martin rudalics <rudalics@gmx.at>: > > That's great. Are you going to push your patch to git-repo? > > After having resolved some remaining issues, yes. > > > When it comes to other platforms than Windows, I have no idea about OS X > > since I don't own any macs, but for X11, we have different means to > > controll decorations and their looks & behaviour. On X11 we have window > > managers that makes it easy to configure (or remove) borders, decorations > > etc, so in my humble opinion I don't think you have to spend countless > time > > to make it work with every possible window manager etc. > > The concern here is not how to turn off decorations for all windows (or > maybe all windows of a certain application), something which themes most > likely already provide to some extent. The concern is how to control > aspects like appearance, placement, focusing and stacking order of some > specific Emacs frames, without affecting the remaining frames. > > Consider the need to display some explanatory information for the > editing activity you are about to accomplish. If you don't want to pop > up a new "normal" window or frame for that purpose, you currently have > two possibilites: Use the echo area or the tooltip frame. Both are > ephemeral and have to be shared with all other applications pursuing a > similar goal. > > Hence the need for some sort of minor frames which are OT1H less > ephemeral and can be more easily replicated than tooltips or the echo > area and are OTOH visually and habitually less obtrusive than normal > frames or windows. > > Some desirable properties of such minor frames are: > > (1) Do not show any window manager decorations provided their visibility > and placement can be controlled by the application. > > (2) Do not show them on the taskbar. > > (3) Do not focus them when they pop up. > > (4) Do not give them focus via mouse movements, mouse wheel scrolling or > accidental mouse clicks. > > (5) Allow to attach them to some normal Emacs frame or window. This > means to automatically move, resize and stack them along with that > frame/window without affecting the appearance of any other object on > your display. It may also mean to make them obscure as few as > possible text of the frame they have been attached to. > > (6) Apart from (1)--(5) give them the full functionality of "normal" > Emacs frames. > > Obviously, (6) is the most difficult part. For example, displaying such > a frame without making it continuously vanish and reappear. > > martin > [-- Attachment #2: Type: text/html, Size: 4926 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-16 13:22 ` Arthur Miller @ 2017-02-16 14:06 ` Arthur Miller 2017-02-17 7:03 ` martin rudalics 2017-02-17 7:03 ` martin rudalics 1 sibling, 1 reply; 85+ messages in thread From: Arthur Miller @ 2017-02-16 14:06 UTC (permalink / raw) To: martin rudalics; +Cc: 25408, Clément Pit--Claudel [-- Attachment #1: Type: text/plain, Size: 4404 bytes --] After checking out a commit previous to Generate upcase and downcase tables from Unicode data (bug#24603) <https://github.com/emacs-mirror/emacs/commit/5ec3a58462e99533ea5200de356302181d634d0b> I was able to build it. 2017-02-16 14:22 GMT+01:00 Arthur Miller <arthur.miller.no1@gmail.com>: > If they don't get focus when they pop-up, and not get focus via mouse and > if they also > don't have decorations, what is considered as full functionality of > "normal" frames? > That sounds to me a bit like a popup window. Do you give them focus by > switching > with keyboard, like moving focus to "other window"? > > "The concern is how to control > aspects like appearance, placement, focusing and stacking order of some > specific Emacs frames, without affecting the remaining frames." > > As you yourself point out, certain WMs does allow you to create rules per > windows. On some > managers one can set rule based on window title bar, window class or class > name, > xid, role etc. I don't know if title bar property can be used if titlebar > exist but is hidden. > > Maybe a separate class name could be used for that kind of windows so one > can set > appropriate hints for that frame. Or maybe you are already doing that? > Just an idea, > I haven't looked at your patch to be honest. > > I cloned code today from git and compilations is crashing on me, when > dumping lisp code: > (without your patch applied): > > Loading /home/arthur/emacs/lisp/international/characters.el (source)... > Wrong type argument: char-table-p, nil > make[1]: *** [Makefile:752: bootstrap-emacs] Error 255 > make[1]: Leaving directory '/home/arthur/emacs/src' > make: *** [Makefile:409: src] Error 2 > > Will be interesting to test it once I manage to compile Emacs. > > > 2017-02-16 9:04 GMT+01:00 martin rudalics <rudalics@gmx.at>: > >> > That's great. Are you going to push your patch to git-repo? >> >> After having resolved some remaining issues, yes. >> >> > When it comes to other platforms than Windows, I have no idea about OS X >> > since I don't own any macs, but for X11, we have different means to >> > controll decorations and their looks & behaviour. On X11 we have window >> > managers that makes it easy to configure (or remove) borders, >> decorations >> > etc, so in my humble opinion I don't think you have to spend countless >> time >> > to make it work with every possible window manager etc. >> >> The concern here is not how to turn off decorations for all windows (or >> maybe all windows of a certain application), something which themes most >> likely already provide to some extent. The concern is how to control >> aspects like appearance, placement, focusing and stacking order of some >> specific Emacs frames, without affecting the remaining frames. >> >> Consider the need to display some explanatory information for the >> editing activity you are about to accomplish. If you don't want to pop >> up a new "normal" window or frame for that purpose, you currently have >> two possibilites: Use the echo area or the tooltip frame. Both are >> ephemeral and have to be shared with all other applications pursuing a >> similar goal. >> >> Hence the need for some sort of minor frames which are OT1H less >> ephemeral and can be more easily replicated than tooltips or the echo >> area and are OTOH visually and habitually less obtrusive than normal >> frames or windows. >> >> Some desirable properties of such minor frames are: >> >> (1) Do not show any window manager decorations provided their visibility >> and placement can be controlled by the application. >> >> (2) Do not show them on the taskbar. >> >> (3) Do not focus them when they pop up. >> >> (4) Do not give them focus via mouse movements, mouse wheel scrolling or >> accidental mouse clicks. >> >> (5) Allow to attach them to some normal Emacs frame or window. This >> means to automatically move, resize and stack them along with that >> frame/window without affecting the appearance of any other object on >> your display. It may also mean to make them obscure as few as >> possible text of the frame they have been attached to. >> >> (6) Apart from (1)--(5) give them the full functionality of "normal" >> Emacs frames. >> >> Obviously, (6) is the most difficult part. For example, displaying such >> a frame without making it continuously vanish and reappear. >> >> martin >> > > [-- Attachment #2: Type: text/html, Size: 6389 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-16 14:06 ` Arthur Miller @ 2017-02-17 7:03 ` martin rudalics 0 siblings, 0 replies; 85+ messages in thread From: martin rudalics @ 2017-02-17 7:03 UTC (permalink / raw) To: Arthur Miller; +Cc: 25408, Clément Pit--Claudel > After checking out a commit previous to > > Generate upcase and downcase tables from Unicode data (bug#24603) > <https://github.com/emacs-mirror/emacs/commit/5ec3a58462e99533ea5200de356302181d634d0b> > > I was able to build it. If you don't read this list I can inform you as soon as people believe that master builds again. Have you tried my patch then? martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-16 13:22 ` Arthur Miller 2017-02-16 14:06 ` Arthur Miller @ 2017-02-17 7:03 ` martin rudalics 1 sibling, 0 replies; 85+ messages in thread From: martin rudalics @ 2017-02-17 7:03 UTC (permalink / raw) To: Arthur Miller; +Cc: 25408, Clément Pit--Claudel > If they don't get focus when they pop-up, and not get focus via mouse and > if they also > don't have decorations, what is considered as full functionality of > "normal" frames? > That sounds to me a bit like a popup window. Do you give them focus by > switching > with keyboard, like moving focus to "other window"? Unless that's forbidden too via the ‘no-other-frame’ parameter ;-) But the function that created such a frame usually has a handle to it and can manipulate it like a "normal" frame. And anyone else can find out about the frame via ‘frame-list’ or ‘frame-child-frames’ and can manipulate it like a "normal" frame. > "The concern is how to control > aspects like appearance, placement, focusing and stacking order of some > specific Emacs frames, without affecting the remaining frames." > > As you yourself point out, certain WMs does allow you to create rules per > windows. On some > managers one can set rule based on window title bar, window class or class > name, > xid, role etc. I don't know if title bar property can be used if titlebar > exist but is hidden. > > Maybe a separate class name could be used for that kind of windows so one > can set > appropriate hints for that frame. Or maybe you are already doing that? Just > an idea, > I haven't looked at your patch to be honest. I'd rather leave it to the application or the end user to pick what they like most than give them some predefined classes to choose from. This way they should be able to fine-tune the behavior and appearance of a separate minibuffer frame, the ediff control panel or the speedbar to their like. > I cloned code today from git and compilations is crashing on me, when > dumping lisp code: > (without your patch applied): > > Loading /home/arthur/emacs/lisp/international/characters.el (source)... > Wrong type argument: char-table-p, nil > make[1]: *** [Makefile:752: bootstrap-emacs] Error 255 > make[1]: Leaving directory '/home/arthur/emacs/src' > make: *** [Makefile:409: src] Error 2 Next time you encounter such a thing please report it immediately (you apparently were ahead of Glenn by 15 hours). Usually, nobody on this list builds from a clean repository. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-12 11:13 ` martin rudalics 2017-02-15 19:49 ` Arthur Miller @ 2017-04-12 9:27 ` martin rudalics 2017-05-06 0:06 ` Clément Pit-Claudel 1 sibling, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-04-12 9:27 UTC (permalink / raw) To: Clément Pit--Claudel, Arthur Miller; +Cc: 25408 I now installed most of the changes from my earlier patch. Minor changes for an `internal-border' face, `x-focus-frame' and `select-window' will follow. Also a major documentation rewrite will be installed in the next days. Till then, the major purpose of installing was to check whether we get any breakage of existing code. If people can see anything fishy, please report immediately. Affected might be among others scroll bars, frame deletion and selection. Also, most of the new parameters won't work on NS. Hopefully, Alan or Anders can help us with some of them. > So as a rule create your frames (lazily) once for each session and hide > them when you don't need them. Did you try that in the meantime? > > * Creating a frame / making it visible uses my WM's frame creating animation — is there a way to disable this (x-show-tip doesn't have it)? > > No idea. I can look into that (as a rule I turn off all animations > here). Do you use GTK tooltips or Emacs' native ones? For X I have now also provided an `override-redirect' parameter which should replicate what the tooltip code does. If you still get animations then I think you will have to explicitly tell the WM (for example, via the frame title) to turn them off. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-04-12 9:27 ` martin rudalics @ 2017-05-06 0:06 ` Clément Pit-Claudel 2017-05-06 7:13 ` Eli Zaretskii ` (2 more replies) 0 siblings, 3 replies; 85+ messages in thread From: Clément Pit-Claudel @ 2017-05-06 0:06 UTC (permalink / raw) To: martin rudalics, Arthur Miller; +Cc: 25408 On 2017-04-12 05:27, martin rudalics wrote: > I now installed most of the changes from my earlier patch. Minor > changes for an `internal-border' face, `x-focus-frame' and > `select-window' will follow. Also a major documentation rewrite will be > installed in the next days. Till then, the major purpose of installing > was to check whether we get any breakage of existing code. > > If people can see anything fishy, please report immediately. Affected > might be among others scroll bars, frame deletion and selection. Also, > most of the new parameters won't work on NS. Hopefully, Alan or Anders > can help us with some of them. > >> So as a rule create your frames (lazily) once for each session and hide >> them when you don't need them. > > Did you try that in the meantime? Yes :) I just did. It works great. >> > * Creating a frame / making it visible uses my WM's frame creating animation — is there a way to disable this (x-show-tip doesn't have it)? >> >> No idea. I can look into that (as a rule I turn off all animations >> here). Do you use GTK tooltips or Emacs' native ones? > > For X I have now also provided an `override-redirect' parameter which > should replicate what the tooltip code does. If you still get > animations then I think you will have to explicitly tell the WM (for > example, via the frame title) to turn them off. This works perfectly. I've run into another small issue: there doesn't seem to be a way to turn off truncation marks in tooltip frames. Is that correct? This bit of xdisp.c seems to take care of that for Emacs' default tip frame; is there a way to emulate this for Lisp-created frames? /* Get dimensions of truncation and continuation glyphs. These are displayed as fringe bitmaps under X, but we need them for such frames when the fringes are turned off. But leave the dimensions zero for tooltip frames, as these glyphs look ugly there and also sabotage calculations of tooltip dimensions in x-show-tip. */ #ifdef HAVE_WINDOW_SYSTEM if (!(FRAME_WINDOW_P (it->f) && FRAMEP (tip_frame) && it->f == XFRAME (tip_frame))) #endif Thanks! Clément. ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-06 0:06 ` Clément Pit-Claudel @ 2017-05-06 7:13 ` Eli Zaretskii 2017-05-06 13:26 ` Clément Pit-Claudel 2017-05-06 7:40 ` martin rudalics 2017-06-25 11:02 ` martin rudalics 2 siblings, 1 reply; 85+ messages in thread From: Eli Zaretskii @ 2017-05-06 7:13 UTC (permalink / raw) To: Clément Pit-Claudel; +Cc: 25408, arthur.miller.no1 > From: Clément Pit-Claudel <cpitclaudel@gmail.com> > Date: Fri, 5 May 2017 20:06:46 -0400 > Cc: 25408@debbugs.gnu.org > > I've run into another small issue: there doesn't seem to be a way to turn off truncation marks in tooltip frames. Is that correct? This bit of xdisp.c seems to take care of that for Emacs' default tip frame; is there a way to emulate this for Lisp-created frames? > > /* Get dimensions of truncation and continuation glyphs. These are > displayed as fringe bitmaps under X, but we need them for such > frames when the fringes are turned off. But leave the dimensions > zero for tooltip frames, as these glyphs look ugly there and also > sabotage calculations of tooltip dimensions in x-show-tip. */ > #ifdef HAVE_WINDOW_SYSTEM > if (!(FRAME_WINDOW_P (it->f) > && FRAMEP (tip_frame) > && it->f == XFRAME (tip_frame))) > #endif Doing that will have a disadvantage: text will be truncated on display, but there will be no visual cue for that truncation. Tooltip frames don't suffer from this problem, because their size is computed in advance to have the text fit exactly on the line, but AFAIU these "undecorated" frames are just normal frames in that regard, so they will be adversely affected. Therefore, if we are going to allow disabling truncation and continuation glyphs on such frames, it should be via a frame parameter which is by default off. ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-06 7:13 ` Eli Zaretskii @ 2017-05-06 13:26 ` Clément Pit-Claudel 0 siblings, 0 replies; 85+ messages in thread From: Clément Pit-Claudel @ 2017-05-06 13:26 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 25408, arthur.miller.no1 On 2017-05-06 03:13, Eli Zaretskii wrote: > Therefore, if we are going to allow disabling truncation and > continuation glyphs on such frames, it should be via a frame parameter > which is by default off. Yes, of course :) ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-06 0:06 ` Clément Pit-Claudel 2017-05-06 7:13 ` Eli Zaretskii @ 2017-05-06 7:40 ` martin rudalics 2017-05-06 9:41 ` martin rudalics 2017-06-25 11:02 ` martin rudalics 2 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-05-06 7:40 UTC (permalink / raw) To: Clément Pit-Claudel, Arthur Miller; +Cc: 25408 [-- Attachment #1: Type: text/plain, Size: 1032 bytes --] > I've run into another small issue: there doesn't seem to be a way to turn off truncation marks in tooltip frames. Is that correct? This bit of xdisp.c seems to take care of that for Emacs' default tip frame; is there a way to emulate this for Lisp-created frames? > > /* Get dimensions of truncation and continuation glyphs. These are > displayed as fringe bitmaps under X, but we need them for such > frames when the fringes are turned off. But leave the dimensions > zero for tooltip frames, as these glyphs look ugly there and also > sabotage calculations of tooltip dimensions in x-show-tip. */ > #ifdef HAVE_WINDOW_SYSTEM > if (!(FRAME_WINDOW_P (it->f) > && FRAMEP (tip_frame) > && it->f == XFRAME (tip_frame))) > #endif Please try the attached patch (I only checked whether it compiles and builds on Windows). You have to add a non-nil 'no-special-glyphs' frame parameter to suppress such glyphs. And please test the new behavior for tooltip frames as well. Thanks, martin [-- Attachment #2: no-special-glyphs.diff --] [-- Type: text/plain, Size: 2581 bytes --] diff --git a/lisp/tooltip.el b/lisp/tooltip.el index 367114b..5260be2 100644 --- a/lisp/tooltip.el +++ b/lisp/tooltip.el @@ -119,7 +119,8 @@ tooltip-y-offset (defcustom tooltip-frame-parameters '((name . "tooltip") (internal-border-width . 2) - (border-width . 1)) + (border-width . 1) + (no-special-glyphs . t)) "Frame parameters used for tooltips. If `left' or `top' parameters are included, they specify the absolute diff --git a/src/frame.c b/src/frame.c index 4d17a07..920df22 100644 --- a/src/frame.c +++ b/src/frame.c @@ -684,6 +684,7 @@ struct frame * f->horizontal_scroll_bars = false; f->want_fullscreen = FULLSCREEN_NONE; f->undecorated = false; + f->no_special_glyphs = false; #ifndef HAVE_NTGUI f->override_redirect = false; #endif @@ -3289,6 +3290,7 @@ struct frame_parm_table { {"no-accept-focus", SYMBOL_INDEX (Qno_accept_focus)}, {"z-group", SYMBOL_INDEX (Qz_group)}, {"override-redirect", SYMBOL_INDEX (Qoverride_redirect)}, + {"no-special-glyphs", SYMBOL_INDEX (Qno_special_glyphs)}, }; #ifdef HAVE_WINDOW_SYSTEM @@ -5077,6 +5079,7 @@ or a list (- N) meaning -N pixels relative to bottom/right corner. DEFSYM (Qicon, "icon"); DEFSYM (Qminibuffer, "minibuffer"); DEFSYM (Qundecorated, "undecorated"); + DEFSYM (Qno_special_glyphs, "no-special-glyphs"); DEFSYM (Qparent_frame, "parent-frame"); DEFSYM (Qskip_taskbar, "skip-taskbar"); DEFSYM (Qno_focus_on_map, "no-focus-on-map"); diff --git a/src/frame.h b/src/frame.h index 4aa7c34..6991583 100644 --- a/src/frame.h +++ b/src/frame.h @@ -354,7 +354,11 @@ struct frame /* The z-group this frame's window belongs to. */ ENUM_BF (z_group) z_group : 2; -#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */ + + /* Non-zero if display of truncation and continuation glyphs outside + the fringes is suppressed. */ + bool_bf no_special_glyphs : 1; +#endif /* HAVE_WINDOW_SYSTEM */ /* Whether new_height and new_width shall be interpreted in pixels. */ diff --git a/src/xdisp.c b/src/xdisp.c index 41458c3..95b8a34 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -2838,9 +2838,7 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object, zero for tooltip frames, as these glyphs look ugly there and also sabotage calculations of tooltip dimensions in x-show-tip. */ #ifdef HAVE_WINDOW_SYSTEM - if (!(FRAME_WINDOW_P (it->f) - && FRAMEP (tip_frame) - && it->f == XFRAME (tip_frame))) + if (!(FRAME_WINDOW_P (it->f) && it->f->no_special_glyphs)) #endif { if (it->line_wrap == TRUNCATE) ^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-06 7:40 ` martin rudalics @ 2017-05-06 9:41 ` martin rudalics 2017-05-06 13:28 ` Clément Pit-Claudel 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-05-06 9:41 UTC (permalink / raw) To: Clément Pit-Claudel, Arthur Miller; +Cc: 25408 > Please try the attached patch (I only checked whether it compiles and > builds on Windows). You have to add a non-nil 'no-special-glyphs' frame > parameter to suppress such glyphs. Sorry, that patch was complete scrap. Hopefully, I'll come up with a better one later. What do those glyphs look like - "\" for continuation and "$" for truncation? martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-06 9:41 ` martin rudalics @ 2017-05-06 13:28 ` Clément Pit-Claudel 2017-05-06 14:20 ` Eli Zaretskii 2017-05-07 8:40 ` martin rudalics 0 siblings, 2 replies; 85+ messages in thread From: Clément Pit-Claudel @ 2017-05-06 13:28 UTC (permalink / raw) To: martin rudalics, Arthur Miller; +Cc: 25408 On 2017-05-06 05:41, martin rudalics wrote: >> Please try the attached patch (I only checked whether it compiles and >> builds on Windows). You have to add a non-nil 'no-special-glyphs' frame >> parameter to suppress such glyphs. > > Sorry, that patch was complete scrap. Hopefully, I'll come up with a > better one later. > > What do those glyphs look like - "\" for continuation and "$" for > truncation? Yup, exactly :) Thanks for your help! ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-06 13:28 ` Clément Pit-Claudel @ 2017-05-06 14:20 ` Eli Zaretskii 2017-05-06 21:01 ` Clément Pit-Claudel 2017-05-07 8:41 ` martin rudalics 2017-05-07 8:40 ` martin rudalics 1 sibling, 2 replies; 85+ messages in thread From: Eli Zaretskii @ 2017-05-06 14:20 UTC (permalink / raw) To: Clément Pit-Claudel; +Cc: 25408, arthur.miller.no1 > From: Clément Pit-Claudel <cpitclaudel@gmail.com> > Date: Sat, 6 May 2017 09:28:02 -0400 > Cc: 25408@debbugs.gnu.org > > On 2017-05-06 05:41, martin rudalics wrote: > >> Please try the attached patch (I only checked whether it compiles and > >> builds on Windows). You have to add a non-nil 'no-special-glyphs' frame > >> parameter to suppress such glyphs. > > > > Sorry, that patch was complete scrap. Hopefully, I'll come up with a > > better one later. > > > > What do those glyphs look like - "\" for continuation and "$" for > > truncation? > > Yup, exactly :) Thanks for your help! Not sure why Martin asked, but to be more accurate: the actual glyphs are stored in a display-table, and can be changed. ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-06 14:20 ` Eli Zaretskii @ 2017-05-06 21:01 ` Clément Pit-Claudel 2017-05-07 2:30 ` Eli Zaretskii 2017-05-07 8:41 ` martin rudalics 1 sibling, 1 reply; 85+ messages in thread From: Clément Pit-Claudel @ 2017-05-06 21:01 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 25408, arthur.miller.no1 On 2017-05-06 10:20, Eli Zaretskii wrote: >> From: Clément Pit-Claudel <cpitclaudel@gmail.com> >> Date: Sat, 6 May 2017 09:28:02 -0400 >> Cc: 25408@debbugs.gnu.org >> >> On 2017-05-06 05:41, martin rudalics wrote: >>>> Please try the attached patch (I only checked whether it compiles and >>>> builds on Windows). You have to add a non-nil 'no-special-glyphs' frame >>>> parameter to suppress such glyphs. >>> >>> Sorry, that patch was complete scrap. Hopefully, I'll come up with a >>> better one later. >>> >>> What do those glyphs look like - "\" for continuation and "$" for >>> truncation? >> >> Yup, exactly :) Thanks for your help! > > Not sure why Martin asked, but to be more accurate: the actual glyphs > are stored in a display-table, and can be changed. Right (though not, AFAICT, fully disabled, right?) ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-06 21:01 ` Clément Pit-Claudel @ 2017-05-07 2:30 ` Eli Zaretskii 0 siblings, 0 replies; 85+ messages in thread From: Eli Zaretskii @ 2017-05-07 2:30 UTC (permalink / raw) To: Clément Pit-Claudel; +Cc: 25408, arthur.miller.no1 > Cc: rudalics@gmx.at, arthur.miller.no1@gmail.com, 25408@debbugs.gnu.org > From: Clément Pit-Claudel <cpitclaudel@gmail.com> > Date: Sat, 6 May 2017 17:01:14 -0400 > > > Not sure why Martin asked, but to be more accurate: the actual glyphs > > are stored in a display-table, and can be changed. > > Right (though not, AFAICT, fully disabled, right?) Right. ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-06 14:20 ` Eli Zaretskii 2017-05-06 21:01 ` Clément Pit-Claudel @ 2017-05-07 8:41 ` martin rudalics 1 sibling, 0 replies; 85+ messages in thread From: martin rudalics @ 2017-05-07 8:41 UTC (permalink / raw) To: Eli Zaretskii, Clément Pit-Claudel; +Cc: arthur.miller.no1, 25408 > Not sure why Martin asked, My initial attempts failed due to a number of silly bugs and I was no more sure whether Clément and I even meant the same thing. > but to be more accurate: the actual glyphs > are stored in a display-table, and can be changed. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-06 13:28 ` Clément Pit-Claudel 2017-05-06 14:20 ` Eli Zaretskii @ 2017-05-07 8:40 ` martin rudalics 2017-05-07 17:19 ` Eli Zaretskii 1 sibling, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-05-07 8:40 UTC (permalink / raw) To: Clément Pit-Claudel, Arthur Miller; +Cc: 25408 [-- Attachment #1: Type: text/plain, Size: 476 bytes --] >>> Please try the attached patch (I only checked whether it compiles and >>> builds on Windows). You have to add a non-nil 'no-special-glyphs' frame >>> parameter to suppress such glyphs. >> >> Sorry, that patch was complete scrap. Hopefully, I'll come up with a >> better one later. >> >> What do those glyphs look like - "\" for continuation and "$" for >> truncation? > > Yup, exactly :) Thanks for your help! Please try the revised patch I attached. Thanks, martin [-- Attachment #2: no-special-glyphs.diff --] [-- Type: text/plain, Size: 7339 bytes --] diff --git a/lisp/tooltip.el b/lisp/tooltip.el index 367114b..c011f1b 100644 --- a/lisp/tooltip.el +++ b/lisp/tooltip.el @@ -119,7 +119,8 @@ tooltip-y-offset (defcustom tooltip-frame-parameters '((name . "tooltip") (internal-border-width . 2) - (border-width . 1)) + (border-width . 1) + (no-special-glyphs . t)) "Frame parameters used for tooltips. If `left' or `top' parameters are included, they specify the absolute @@ -130,7 +131,8 @@ tooltip-frame-parameters :type '(repeat (cons :format "%v" (symbol :tag "Parameter") (sexp :tag "Value"))) - :group 'tooltip) + :group 'tooltip + :version "26.1") (defface tooltip '((((class color)) diff --git a/src/frame.c b/src/frame.c index 4d17a07..6442c3b 100644 --- a/src/frame.c +++ b/src/frame.c @@ -684,6 +684,7 @@ struct frame * f->horizontal_scroll_bars = false; f->want_fullscreen = FULLSCREEN_NONE; f->undecorated = false; + f->no_special_glyphs = false; #ifndef HAVE_NTGUI f->override_redirect = false; #endif @@ -3289,6 +3290,7 @@ struct frame_parm_table { {"no-accept-focus", SYMBOL_INDEX (Qno_accept_focus)}, {"z-group", SYMBOL_INDEX (Qz_group)}, {"override-redirect", SYMBOL_INDEX (Qoverride_redirect)}, + {"no-special-glyphs", SYMBOL_INDEX (Qno_special_glyphs)}, }; #ifdef HAVE_WINDOW_SYSTEM @@ -4204,12 +4206,29 @@ struct frame_parm_table { return; } + +/** + * x_set_no_special_glyphs: + * + * Set frame F's `no-special-glyphs' parameter which, if non-nil, + * suppresses the display of truncation and continuation glyphs + * outside fringes. + */ +void +x_set_no_special_glyphs (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + if (!EQ (new_value, old_value)) + FRAME_NO_SPECIAL_GLYPHS (f) = !NILP (new_value); +} + + #ifndef HAVE_NS /* Non-zero if mouse is grabbed on DPYINFO and we know the frame where it is. */ -bool x_mouse_grabbed (Display_Info *dpyinfo) +bool +x_mouse_grabbed (Display_Info *dpyinfo) { return (dpyinfo->grabbed && dpyinfo->last_mouse_frame @@ -5077,6 +5096,7 @@ or a list (- N) meaning -N pixels relative to bottom/right corner. DEFSYM (Qicon, "icon"); DEFSYM (Qminibuffer, "minibuffer"); DEFSYM (Qundecorated, "undecorated"); + DEFSYM (Qno_special_glyphs, "no-special-glyphs"); DEFSYM (Qparent_frame, "parent-frame"); DEFSYM (Qskip_taskbar, "skip-taskbar"); DEFSYM (Qno_focus_on_map, "no-focus-on-map"); diff --git a/src/frame.h b/src/frame.h index 4aa7c34..dbb3675 100644 --- a/src/frame.h +++ b/src/frame.h @@ -354,7 +354,11 @@ struct frame /* The z-group this frame's window belongs to. */ ENUM_BF (z_group) z_group : 2; -#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */ + + /* Non-zero if display of truncation and continuation glyphs outside + the fringes is suppressed. */ + bool_bf no_special_glyphs : 1; +#endif /* HAVE_WINDOW_SYSTEM */ /* Whether new_height and new_width shall be interpreted in pixels. */ @@ -928,6 +932,7 @@ struct 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_NO_SPECIAL_GLYPHS(f) ((f)->no_special_glyphs) #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) @@ -941,6 +946,7 @@ struct frame #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_NO_SPECIAL_GLYPHS(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) @@ -1498,6 +1504,7 @@ extern void x_set_bottom_divider_width (struct frame *, Lisp_Object, extern long x_figure_window_size (struct frame *, Lisp_Object, bool, int *, int *); extern void x_set_alpha (struct frame *, Lisp_Object, Lisp_Object); +extern void x_set_no_special_glyphs (struct frame *, Lisp_Object, Lisp_Object); extern void validate_x_resource_name (void); diff --git a/src/nsfns.m b/src/nsfns.m index cbe0ffb..38945b8 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -983,6 +983,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side x_set_no_accept_focus, x_set_z_group, /* x_set_z_group */ 0, /* x_set_override_redirect */ + x_set_no_special_glyphs, }; @@ -1255,6 +1256,8 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side "leftFringe", "LeftFringe", RES_TYPE_NUMBER); x_default_parameter (f, parms, Qright_fringe, Qnil, "rightFringe", "RightFringe", RES_TYPE_NUMBER); + x_default_parameter (f, parameters, Qno_special_glyphs, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); init_frame_faces (f); diff --git a/src/w32fns.c b/src/w32fns.c index e490588..bb73253 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -5889,6 +5889,8 @@ struct frame * NULL, NULL, RES_TYPE_BOOLEAN); x_default_parameter (f, parameters, Qno_accept_focus, Qnil, NULL, NULL, RES_TYPE_BOOLEAN); + x_default_parameter (f, parameters, Qno_special_glyphs, 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 @@ -10330,6 +10332,7 @@ enum NI_Severity { x_set_no_accept_focus, x_set_z_group, 0, /* x_set_override_redirect */ + x_set_no_special_glyphs, }; void diff --git a/src/xdisp.c b/src/xdisp.c index 41458c3..c546198 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -2834,13 +2834,12 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object, /* Get dimensions of truncation and continuation glyphs. These are displayed as fringe bitmaps under X, but we need them for such - frames when the fringes are turned off. But leave the dimensions - zero for tooltip frames, as these glyphs look ugly there and also - sabotage calculations of tooltip dimensions in x-show-tip. */ + frames when the fringes are turned off. The no_special_glyphs slot + of the iterator's frame, when set, suppresses their display - by + default for tooltip frames and when set via the 'no-special-glyphs' + frame parameter. */ #ifdef HAVE_WINDOW_SYSTEM - if (!(FRAME_WINDOW_P (it->f) - && FRAMEP (tip_frame) - && it->f == XFRAME (tip_frame))) + if (!(FRAME_WINDOW_P (it->f) && it->f->no_special_glyphs)) #endif { if (it->line_wrap == TRUNCATE) diff --git a/src/xfns.c b/src/xfns.c index e463391..3f2a499 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -3814,6 +3814,8 @@ struct mouse_cursor_data { "leftFringe", "LeftFringe", RES_TYPE_NUMBER); x_default_parameter (f, parms, Qright_fringe, Qnil, "rightFringe", "RightFringe", RES_TYPE_NUMBER); + x_default_parameter (f, parms, Qno_special_glyphs, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground, "scrollBarForeground", @@ -7486,6 +7488,7 @@ FRAMES should be nil (the selected frame), a frame, or a list of x_set_no_accept_focus, x_set_z_group, x_set_override_redirect, + x_set_no_special_glyphs, }; void ^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-07 8:40 ` martin rudalics @ 2017-05-07 17:19 ` Eli Zaretskii 2017-05-07 18:07 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Eli Zaretskii @ 2017-05-07 17:19 UTC (permalink / raw) To: martin rudalics; +Cc: arthur.miller.no1, cpitclaudel, 25408 > Date: Sun, 07 May 2017 10:40:50 +0200 > From: martin rudalics <rudalics@gmx.at> > Cc: 25408@debbugs.gnu.org > > Please try the revised patch I attached. Please test vertical cursor motion in frames with this parameter set, including when visual-line-mode is turned on. There might be dragons. Thanks. ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-07 17:19 ` Eli Zaretskii @ 2017-05-07 18:07 ` martin rudalics 2017-05-07 18:33 ` Eli Zaretskii 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-05-07 18:07 UTC (permalink / raw) To: Eli Zaretskii; +Cc: arthur.miller.no1, cpitclaudel, 25408 > Please test vertical cursor motion in frames with this parameter set, > including when visual-line-mode is turned on. There might be dragons. I've seen nothing special here. But if you can think of a specific location where they might hide please tell me. Also, IIUC Clément has no intention to make such buffers scrollable, editable or focusable. So if necessary we can also forbid such actions. Thanks, martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-07 18:07 ` martin rudalics @ 2017-05-07 18:33 ` Eli Zaretskii 2017-05-08 6:48 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Eli Zaretskii @ 2017-05-07 18:33 UTC (permalink / raw) To: martin rudalics; +Cc: arthur.miller.no1, cpitclaudel, 25408 > Date: Sun, 07 May 2017 20:07:46 +0200 > From: martin rudalics <rudalics@gmx.at> > CC: cpitclaudel@gmail.com, arthur.miller.no1@gmail.com, > 25408@debbugs.gnu.org > > > Please test vertical cursor motion in frames with this parameter set, > > including when visual-line-mode is turned on. There might be dragons. > > I've seen nothing special here. But if you can think of a specific > location where they might hide please tell me. What happens when the line is full-width, i.e. the last character is flushed all the way to the right edge of the window? What happens when you set wrap-prefix to some string value and then turn on visual-line-mode in a buffer with lines longer than the window width? > Also, IIUC Clément has no intention to make such buffers scrollable, > editable or focusable. So if necessary we can also forbid such actions. ??? This is a general-purpose feature, not something created for a single use case. And I don't quite see how you can forbid cursor motion without also forbidding a lot of other useful features. ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-07 18:33 ` Eli Zaretskii @ 2017-05-08 6:48 ` martin rudalics 2017-05-08 14:41 ` Eli Zaretskii 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-05-08 6:48 UTC (permalink / raw) To: Eli Zaretskii; +Cc: arthur.miller.no1, cpitclaudel, 25408 > What happens when the line is full-width, i.e. the last character is > flushed all the way to the right edge of the window? Tested with normal continuation lines, truncated line and visual line mode and all sorts of window widths. No problems. > What happens > when you set wrap-prefix to some string value and then turn on > visual-line-mode in a buffer with lines longer than the window width? No special problems found but for one: If the window is narrower than the wrap-prefix, Emacs may hang with all processor cycles it can get. But this is easily reproducible here without setting the new parameter. I use the following recipe: With emacs -Q I evaluate (let ((frame (make-frame))) (find-file-noselect "dnd.el") (set-window-buffer (frame-root-window frame) "dnd.el") (with-current-buffer (window-buffer (frame-root-window frame)) (setq wrap-prefix "-------------") (visual-line-mode 1))) Then I make the new frame as narrow as possible by dragging one of its borders with the mouse. Now alternatively using (1) <down> to move the cursor towards the end of the buffer _and_ (2) <wheel-down> to scroll the buffer end out of view sooner or later hangs my Emacs 25.2 here. >> Also, IIUC Clément has no intention to make such buffers scrollable, >> editable or focusable. So if necessary we can also forbid such actions. > > ??? This is a general-purpose feature, not something created for a > single use case. And I don't quite see how you can forbid cursor > motion without also forbidding a lot of other useful features. We could treat such frames like tooltip frames. But I currently see no need for such harsh measures. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-08 6:48 ` martin rudalics @ 2017-05-08 14:41 ` Eli Zaretskii 0 siblings, 0 replies; 85+ messages in thread From: Eli Zaretskii @ 2017-05-08 14:41 UTC (permalink / raw) To: martin rudalics; +Cc: arthur.miller.no1, cpitclaudel, 25408 > Date: Mon, 08 May 2017 08:48:12 +0200 > From: martin rudalics <rudalics@gmx.at> > CC: cpitclaudel@gmail.com, arthur.miller.no1@gmail.com, > 25408@debbugs.gnu.org > > > What happens > > when you set wrap-prefix to some string value and then turn on > > visual-line-mode in a buffer with lines longer than the window width? > > No special problems found but for one: If the window is narrower than > the wrap-prefix, Emacs may hang with all processor cycles it can get. > But this is easily reproducible here without setting the new parameter. This should probably be reported as a separate bug, but if it exists with previous code, it's unrelated to this feature. > >> Also, IIUC Clément has no intention to make such buffers scrollable, > >> editable or focusable. So if necessary we can also forbid such actions. > > > > ??? This is a general-purpose feature, not something created for a > > single use case. And I don't quite see how you can forbid cursor > > motion without also forbidding a lot of other useful features. > > We could treat such frames like tooltip frames. But I currently see no > need for such harsh measures. Agreed. ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-05-06 0:06 ` Clément Pit-Claudel 2017-05-06 7:13 ` Eli Zaretskii 2017-05-06 7:40 ` martin rudalics @ 2017-06-25 11:02 ` martin rudalics 2017-06-25 16:23 ` Clément Pit-Claudel 2 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-06-25 11:02 UTC (permalink / raw) To: Clément Pit-Claudel, Arthur Miller; +Cc: 25408-done > I've run into another small issue: there doesn't seem to be a way to > turn off truncation marks in tooltip frames. Is that correct? This bit > of xdisp.c seems to take care of that for Emacs' default tip frame; is > there a way to emulate this for Lisp-created frames? Truncation glyphs can be now turned off via the 'no-special-glyphs' frame parameter. Closing this bug. Thanks, martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-06-25 11:02 ` martin rudalics @ 2017-06-25 16:23 ` Clément Pit-Claudel 0 siblings, 0 replies; 85+ messages in thread From: Clément Pit-Claudel @ 2017-06-25 16:23 UTC (permalink / raw) To: martin rudalics, Arthur Miller; +Cc: 25408-done On 2017-06-25 07:02, martin rudalics wrote: >> I've run into another small issue: there doesn't seem to be a way to >> turn off truncation marks in tooltip frames. Is that correct? This bit >> of xdisp.c seems to take care of that for Emacs' default tip frame; is >> there a way to emulate this for Lisp-created frames? > > Truncation glyphs can be now turned off via the 'no-special-glyphs' > frame parameter. Closing this bug. Thanks for all the hard work! ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-02-11 14:27 ` martin rudalics 2017-02-11 21:02 ` Clément Pit--Claudel @ 2017-04-12 17:38 ` Alan Third 2017-04-12 19:13 ` martin rudalics 1 sibling, 1 reply; 85+ messages in thread From: Alan Third @ 2017-04-12 17:38 UTC (permalink / raw) To: martin rudalics; +Cc: Arthur Miller, 25408, Clément Pit--Claudel On Sat, Feb 11, 2017 at 03:27:36PM +0100, martin rudalics wrote: > > To remove a frame's decorations, use the frame parameter `undecorated' > as in > > (set-frame-parameter nil 'undecorated t) > > To give that frame back its decorations use > > (set-frame-parameter nil 'undecorated nil) > > To make a new frame undecorated use > > (make-frame '((undecorated . t))) Hi Martin, this is really good. I’ve got this semi‐working in the NS port, but I have a strange problem, and I want to check it’s not intentional. Should an undecorated frame be resizable? ie. if you run something like (set-frame-size nil 20 20) would you expect the frame to resize? Mine currently resizes if the frame was created with decorations and they were removed, but not if it was created without them. I suspect creating it without decorations is breaking some NS → Emacs event path. Thanks! -- Alan Third ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-04-12 17:38 ` Alan Third @ 2017-04-12 19:13 ` martin rudalics 2017-04-12 19:51 ` Alan Third 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-04-12 19:13 UTC (permalink / raw) To: Alan Third; +Cc: Arthur Miller, 25408, Clément Pit--Claudel > Should an undecorated frame be resizable? ie. if you run something > like > > (set-frame-size nil 20 20) > > would you expect the frame to resize? Definitively! Undecorated frames should behave like normal frames - just without decorations. > Mine currently resizes if the frame was created with decorations and > they were removed, When can you remove the decorations? Does it flicker when you do that? > but not if it was created without them. I suspect > creating it without decorations is breaking some NS → Emacs event > path. Why do you think so? I never looked into the NS event set but I would expect to receive the usual map, focus-in and visibility notifications. Nothing that would allow to derive that the window cannot be resized any more. Can you add the decorations later, resize the frame and remove the decorations afterwards? martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-04-12 19:13 ` martin rudalics @ 2017-04-12 19:51 ` Alan Third 2017-04-13 7:10 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Alan Third @ 2017-04-12 19:51 UTC (permalink / raw) To: martin rudalics; +Cc: Arthur Miller, 25408, Clément Pit--Claudel [-- Attachment #1: Type: text/plain, Size: 1475 bytes --] On Wed, Apr 12, 2017 at 09:13:15PM +0200, martin rudalics wrote: > > Should an undecorated frame be resizable? ie. if you run something > > like > > > > (set-frame-size nil 20 20) > > > > would you expect the frame to resize? > > Definitively! Undecorated frames should behave like normal frames - > just without decorations. Excellent, that’s what I wanted to know so I didn’t go chasing after a behaviour that wasn’t right. > > Mine currently resizes if the frame was created with decorations and > > they were removed, > > When can you remove the decorations? Does it flicker when you do that? I mean, it *can* resize after I remove the decorations. There’s no flickering, it’s all quite smooth. > > but not if it was created without them. I suspect > > creating it without decorations is breaking some NS → Emacs event > > path. > > Why do you think so? The actual macOS window resizes, but the contents of that window (Emacs) don’t. I’ve attached a screenshot that will hopefully explain it better. If I add decorations and remove them again: (set-frame-parameter nil 'undecorated nil) (set-frame-parameter nil 'undecorated t) Then I can resize it fine. So it seems like the decorations are adding something that allows the resize to work. I’ve tried turning on NSTRACE, but the output looks identical whether resizing works or not. I’ll just keep looking at it. Hopefully I’ll be able to track it down. -- Alan Third [-- Attachment #2: undecorated Window issue --] [-- Type: image/png, Size: 56836 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-04-12 19:51 ` Alan Third @ 2017-04-13 7:10 ` martin rudalics 2017-04-13 10:30 ` Alan Third 2017-04-15 16:29 ` Alan Third 0 siblings, 2 replies; 85+ messages in thread From: martin rudalics @ 2017-04-13 7:10 UTC (permalink / raw) To: Alan Third; +Cc: Arthur Miller, 25408, Clément Pit--Claudel >> When can you remove the decorations? Does it flicker when you do that? > > I mean, it *can* resize after I remove the decorations. I wanted to know "when" in the sense of "what do you have to wait for" to remove the decorations? Can you send two requests in a row - a first one to create a decorated frame and a second one to remove the decorations - or do you have to wait for a response for the first request before issuing the second one. > There’s no > flickering, it’s all quite smooth. Then I see no problems with an approach that makes the frame initially decorated and removes the decorations ASAP. > The actual macOS window resizes, but the contents of that window > (Emacs) don’t. I’ve attached a screenshot that will hopefully explain > it better. > > If I add decorations and remove them again: > > (set-frame-parameter nil 'undecorated nil) > (set-frame-parameter nil 'undecorated t) > > Then I can resize it fine. So it seems like the decorations are adding > something that allows the resize to work. > > I’ve tried turning on NSTRACE, but the output looks identical whether > resizing works or not. Is this in windowDidResize or windowWillResize? I have no idea how the NS API works. But if the redecorate/reundecorate approach works well, I wouldn't care too much. Can you look also into three other things I added: - Provide a `move-frame-functions' hook. - Provide "frame restacking" which should work via orderWindow. I suppose NS has no equivalent for z-groups. - Provide "child frames" which should work via parentWindow. I don't know whether NS child windows always behave like NS "drawers" or may also occlude the parent frame like under X or Windows. Eventually I'd like to have them both (like Wayland's subsurfaces if I understand them correctly). Drawers look like a pain when you are in fullscreen mode - IIUC there's no way to open them "into" a fullscreen frame. X/Windows child windows are annoying when you are in a normal, fairly small frame where they get clipped too easily. Thanks, martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-04-13 7:10 ` martin rudalics @ 2017-04-13 10:30 ` Alan Third 2017-04-13 11:56 ` martin rudalics 2017-04-15 16:29 ` Alan Third 1 sibling, 1 reply; 85+ messages in thread From: Alan Third @ 2017-04-13 10:30 UTC (permalink / raw) To: martin rudalics; +Cc: Arthur Miller, 25408, Clément Pit--Claudel On Thu, Apr 13, 2017 at 09:10:26AM +0200, martin rudalics wrote: > >> When can you remove the decorations? Does it flicker when you do that? > > > > I mean, it *can* resize after I remove the decorations. > > I wanted to know "when" in the sense of "what do you have to wait for" > to remove the decorations? Can you send two requests in a row - a first > one to create a decorated frame and a second one to remove the > decorations - or do you have to wait for a response for the first > request before issuing the second one. I’ve worked it out: the toolbar is considered a ‘decoration’ by Cocoa, so it is automatically removed when I change a frame to undecorated. However, when I create a new undecorated frame the frame redrawing code waits for the toolbar to be drawn, which will never happen. I think this gives me two options: 1. Get Emacs to disable the toolbar when switching to undecorated frames. 2. Use a different method of removing the titlebar when the toolbar is enabled than when the toolbar is disabled. This option will only work in macOS 10.11 and above. Option 1 seems preferable to me, although we could add option 2 later. > Can you look also into three other things I added: > > - Provide a `move-frame-functions' hook. > > - Provide "frame restacking" which should work via orderWindow. I > suppose NS has no equivalent for z-groups. > > - Provide "child frames" which should work via parentWindow. > > I don't know whether NS child windows always behave like NS "drawers" or > may also occlude the parent frame like under X or Windows. Eventually > I'd like to have them both (like Wayland's subsurfaces if I understand > them correctly). Drawers look like a pain when you are in fullscreen > mode - IIUC there's no way to open them "into" a fullscreen frame. > X/Windows child windows are annoying when you are in a normal, fairly > small frame where they get clipped too easily. I don’t know enough about NS to be able to answer this. I’ll give it a go and see what happens. -- Alan Third ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-04-13 10:30 ` Alan Third @ 2017-04-13 11:56 ` martin rudalics 0 siblings, 0 replies; 85+ messages in thread From: martin rudalics @ 2017-04-13 11:56 UTC (permalink / raw) To: Alan Third; +Cc: Arthur Miller, 25408, Clément Pit--Claudel > I’ve worked it out: the toolbar is considered a ‘decoration’ by Cocoa, > so it is automatically removed when I change a frame to undecorated. > However, when I create a new undecorated frame the frame redrawing > code waits for the toolbar to be drawn, which will never happen. > > I think this gives me two options: > > 1. Get Emacs to disable the toolbar when switching to undecorated > frames. > > 2. Use a different method of removing the titlebar when the toolbar > is enabled than when the toolbar is disabled. This option will > only work in macOS 10.11 and above. > > Option 1 seems preferable to me, although we could add option 2 later. Agreed. What happens in an undecorated frame with `tool-bar-mode' turned off when you turn on `tool-bar-mode'? > I don’t know enough about NS to be able to answer this. I’ll give it a > go and see what happens. Fine. Thanks, martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-04-13 7:10 ` martin rudalics 2017-04-13 10:30 ` Alan Third @ 2017-04-15 16:29 ` Alan Third 2017-04-15 19:39 ` martin rudalics 1 sibling, 1 reply; 85+ messages in thread From: Alan Third @ 2017-04-15 16:29 UTC (permalink / raw) To: martin rudalics; +Cc: Arthur Miller, 25408, Clément Pit--Claudel I’ve done some further reading. On Thu, Apr 13, 2017 at 09:10:26AM +0200, martin rudalics wrote: > Can you look also into three other things I added: > > - Provide a `move-frame-functions' hook. > > - Provide "frame restacking" which should work via orderWindow. I > suppose NS has no equivalent for z-groups. If I understand your description right, there is a direct equivalent for z‐groups: levels. Here’s Apple’s documentation on them: > The levels you typically use are: NSNormalWindowLevel, which > specifies the default level; NSFloatingWindowLevel, which specifies > the level for floating palettes; and NSScreenSaverWindowLevel, which > specifies the level for a screen saver window. You might also use > NSStatusWindowLevel for a status window, or NSModalPanelWindowLevel > for a modal panel. This is in addition to the basic ‘layers’, which orderWindow deals with and which only affects windows in the same ‘level’. > - Provide "child frames" which should work via parentWindow. > > I don't know whether NS child windows always behave like NS "drawers" or > may also occlude the parent frame like under X or Windows. Eventually > I'd like to have them both (like Wayland's subsurfaces if I understand > them correctly). Drawers look like a pain when you are in fullscreen > mode - IIUC there's no way to open them "into" a fullscreen frame. > X/Windows child windows are annoying when you are in a normal, fairly > small frame where they get clipped too easily. It appears that a child window in NS is just a normal window which moves and closes with its parent. So I think that means it’s more like X’s child windows, except they don’t get clipped at the parent window’s edges. They can also end up below the parent window. I think this is probably what we want, for now at least. FYI: there are also drawers and something called sheets, which appear to be some sort of special modal drawer type thing used for error messages and such. I’ve pretty much got the undecorated frames sorted with only one major bug I’m aware of when the frame is nearly the full height of the screen. I think I may have to ask Anders about that as I can’t understand the code that keeps the frame on‐screen, and I think it may be the culprit. -- Alan Third ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-04-15 16:29 ` Alan Third @ 2017-04-15 19:39 ` martin rudalics 2017-04-17 14:56 ` bug#25408: Remove Decorations Around Emacs Frame (NS port) Alan Third 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-04-15 19:39 UTC (permalink / raw) To: Alan Third; +Cc: Arthur Miller, 25408, Clément Pit--Claudel > If I understand your description right, there is a direct equivalent > for z‐groups: levels. Here’s Apple’s documentation on them: > >> The levels you typically use are: NSNormalWindowLevel, which >> specifies the default level; NSFloatingWindowLevel, which specifies >> the level for floating palettes; and NSScreenSaverWindowLevel, which >> specifies the level for a screen saver window. You might also use >> NSStatusWindowLevel for a status window, or NSModalPanelWindowLevel >> for a modal panel. Maybe the last two could be used for emulating the 'above' group. It would be nice to have a common interface for that. > This is in addition to the basic ‘layers’, which orderWindow deals > with and which only affects windows in the same ‘level’. This should conform with what we have on X and Windows. > It appears that a child window in NS is just a normal window which > moves and closes with its parent. So I think that means it’s more like > X’s child windows, except they don’t get clipped at the parent > window’s edges. They can also end up below the parent window. It sounds like NS can do more than Windows and X here. The clipping issue is a nuisance. Could you try to create one and play around with it a bit? > I think this is probably what we want, for now at least. Certainly. > FYI: there are also drawers and something called sheets, which appear > to be some sort of special modal drawer type thing used for error > messages and such. > > I’ve pretty much got the undecorated frames sorted with only one major > bug I’m aware of when the frame is nearly the full height of the > screen. I think I may have to ask Anders about that as I can’t > understand the code that keeps the frame on‐screen, and I think it may > be the culprit. On X decorating an undecorated maximized frame can be funny too. There may be no visible change. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-15 19:39 ` martin rudalics @ 2017-04-17 14:56 ` Alan Third 2017-04-17 15:43 ` martin rudalics 2017-04-19 11:24 ` Anders Lindgren 0 siblings, 2 replies; 85+ messages in thread From: Alan Third @ 2017-04-17 14:56 UTC (permalink / raw) To: martin rudalics Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren [-- Attachment #1: Type: text/plain, Size: 1055 bytes --] On Sat, Apr 15, 2017 at 09:39:32PM +0200, martin rudalics wrote: > > It appears that a child window in NS is just a normal window which > > moves and closes with its parent. So I think that means it’s more like > > X’s child windows, except they don’t get clipped at the parent > > window’s edges. They can also end up below the parent window. > > It sounds like NS can do more than Windows and X here. The clipping > issue is a nuisance. Could you try to create one and play around with > it a bit? I’ve attached a partial patch for NS. It should handle undecorated frames and parent‐child frame relationships. I’ll keep working on the rest, but thought I’d throw this out there in case anyone can spot anything obviously wrong. Anders, I hope it’s OK CCing you in. I think you might appreciate the following (after applying the patch): emacs -Q (set-frame-parameter nil 'undecorated t) (setq ns-auto-hide-menu-bar t) (toggle-frame-maximized) More info at: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25408#77 -- Alan Third [-- Attachment #2: parent and undecorated frames on NS --] [-- Type: text/plain, Size: 23382 bytes --] From bd8ffa277c1af68a3ed8008683b01a0249fa108e Mon Sep 17 00:00:00 2001 From: Alan Third <alan@idiocy.org> Date: Fri, 14 Apr 2017 10:02:38 +0100 Subject: [PATCH] Add undecorated and parent frames to NS port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * src/frame.h: * src/frame.c: Enable ‘undecorated’ and ‘parent’ frame definitions. * src/nsfns.m: Add x_set_parent_frame and x_set_undecorated to handler struct. (Fx-create_frame): Handle ‘parent-frame’ and ‘undecorated’ frame parameter. * src/nsmenu.m (free_frame_tool_bar, update_frame_tool_bar): FRAME_TOOLBAR_HEIGHT is no longer a variable. * src/nsterm.h (NS_PARENT_WINDOW_LEFT_POS, NS_PARENT_WINDOW_TOP_POS): Add #defines to find the screen position of the parent frame. (EmacsView): Remove redundant toolbar variables and add createToolbar method. (FRAME_NS_TITLEBAR_HEIGHT, FRAME_TOOLBAR_HEIGHT): Always calculate the values instead of storing them in a variable. * src/nsterm.m (x_set_offset, windowDidMove): Take parent frame position into account when positioning frames. (initFrameFromEmacs): Link parent frame, and take position into account when creating new frame. (x_set_window_size): Remove toolbar height calculation. (x_set_parent_frame): (x_set_undecorated): New function. (updateFrameSize): Change NSTRACE message to reflect new reality and no longer reset frame size. (windowWillResize): Don’t change NS window name when the titlebar is invisible. (createToolbar): Move toolbar creation code into it’s own method. (initFrameFromEmacs): Handle case where frame is created without a titlebar and remove toolbar creation code. (toggleFullScreen): FRAME_TOOLBAR_HEIGHT and FRAME_NS_TITLEBAR_HEIGHT are no longer variables. --- src/frame.c | 2 - src/frame.h | 14 ++-- src/nsfns.m | 23 ++++++- src/nsmenu.m | 8 --- src/nsterm.h | 39 ++++++++++- src/nsterm.m | 217 +++++++++++++++++++++++++++++++++++++++++++---------------- 6 files changed, 221 insertions(+), 82 deletions(-) diff --git a/src/frame.c b/src/frame.c index 282b691c27..681a245ee0 100644 --- a/src/frame.c +++ b/src/frame.c @@ -683,7 +683,6 @@ make_frame (bool mini_p) 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; @@ -692,7 +691,6 @@ make_frame (bool mini_p) 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 diff --git a/src/frame.h b/src/frame.h index 36af6e6780..4aa7c34a29 100644 --- a/src/frame.h +++ b/src/frame.h @@ -75,10 +75,10 @@ struct frame Usually it is nil. */ Lisp_Object title; -#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) /* This frame's parent frame, if it has one. */ Lisp_Object parent_frame; -#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */ +#endif /* HAVE_WINDOW_SYSTEM */ /* The frame which should receive keystrokes that occur in this frame, or nil if they should go to the frame itself. This is @@ -332,7 +332,7 @@ struct frame bool_bf horizontal_scroll_bars : 1; #endif /* HAVE_WINDOW_SYSTEM */ -#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) /* True if this is an undecorated frame. */ bool_bf undecorated : 1; @@ -570,7 +570,7 @@ fset_face_alist (struct frame *f, Lisp_Object val) { f->face_alist = val; } -#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) INLINE void fset_parent_frame (struct frame *f, Lisp_Object val) { @@ -914,7 +914,7 @@ default_pixels_per_inch_y (void) #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) ((void) f, 0) #endif /* HAVE_WINDOW_SYSTEM */ -#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) #define FRAME_UNDECORATED(f) ((f)->undecorated) #ifdef HAVE_NTGUI #define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0) @@ -934,7 +934,7 @@ default_pixels_per_inch_y (void) #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 */ +#else /* not HAVE_WINDOW_SYSTEM */ #define FRAME_UNDECORATED(f) ((void) f, 0) #define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0) #define FRAME_PARENT_FRAME(f) ((void) f, NULL) @@ -945,7 +945,7 @@ default_pixels_per_inch_y (void) #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 */ +#endif /* HAVE_WINDOW_SYSTEM */ /* Whether horizontal scroll bars are currently enabled for frame F. */ #if USE_HORIZONTAL_SCROLL_BARS diff --git a/src/nsfns.m b/src/nsfns.m index 8a923dd393..6dddc64cb4 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -972,8 +972,8 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side 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 */ + x_set_undecorated, /* x_set_undecorated */ + x_set_parent_frame, /* x_set_parent_frame */ 0, /* x_set_skip_taskbar */ 0, /* x_set_no_focus_on_map */ 0, /* x_set_no_accept_focus */ @@ -1087,7 +1087,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side ptrdiff_t count = specpdl_ptr - specpdl; Lisp_Object display; struct ns_display_info *dpyinfo = NULL; - Lisp_Object parent; + Lisp_Object parent, parent_frame; struct kboard *kb; static int desc_ctr = 1; int x_width = 0, x_height = 0; @@ -1265,6 +1265,23 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1, Qx_create_frame_1); + tem = x_get_arg (dpyinfo, parms, Qundecorated, NULL, NULL, RES_TYPE_BOOLEAN); + FRAME_UNDECORATED (f) = !NILP (tem) && !EQ (tem, Qunbound); + store_frame_param (f, Qundecorated, FRAME_UNDECORATED (f) ? Qt : Qnil); + + 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))) + parent_frame = Qnil; + + fset_parent_frame (f, parent_frame); + store_frame_param (f, Qparent_frame, parent_frame); + /* The resources controlling the menu-bar and tool-bar are processed specially at startup, and reflected in the mode variables; ignore them here. */ diff --git a/src/nsmenu.m b/src/nsmenu.m index 59ea3855ed..1262c9cb4d 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -995,8 +995,6 @@ - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f block_input (); view->wait_for_tool_bar = NO; - FRAME_TOOLBAR_HEIGHT (f) = 0; - /* Note: This trigger an animation, which calls windowDidResize repeatedly. */ f->output_data.ns->in_animation = 1; @@ -1129,12 +1127,6 @@ - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f } #endif - FRAME_TOOLBAR_HEIGHT (f) = - NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)]) - - FRAME_NS_TITLEBAR_HEIGHT (f); - if (FRAME_TOOLBAR_HEIGHT (f) < 0) // happens if frame is fullscreen. - FRAME_TOOLBAR_HEIGHT (f) = 0; - if (oldh != FRAME_TOOLBAR_HEIGHT (f)) [view updateFrameSize:YES]; if (view->wait_for_tool_bar && FRAME_TOOLBAR_HEIGHT (f) > 0) diff --git a/src/nsterm.h b/src/nsterm.h index 53d9344cc7..34aab9c543 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -430,7 +430,7 @@ char const * nstrace_fullscreen_type_name (int); NSString *workingText; BOOL processingCompose; int fs_state, fs_before_fs, next_maximized; - int tibar_height, tobar_height, bwidth; + int bwidth; int maximized_width, maximized_height; NSWindow *nonfs_window; BOOL fs_is_native; @@ -454,6 +454,7 @@ char const * nstrace_fullscreen_type_name (int); /* Emacs-side interface */ - initFrameFromEmacs: (struct frame *) f; +- (void) createToolbar: (struct frame *)f; - (void) setRows: (int) r andColumns: (int) c; - (void) setWindowClosing: (BOOL)closing; - (EmacsToolbar *) toolbar; @@ -1012,8 +1013,6 @@ struct x_output #define NS_FACE_FOREGROUND(f) ((f)->foreground) #define NS_FACE_BACKGROUND(f) ((f)->background) -#define FRAME_NS_TITLEBAR_HEIGHT(f) ((f)->output_data.ns->titlebar_height) -#define FRAME_TOOLBAR_HEIGHT(f) ((f)->output_data.ns->toolbar_height) #define FRAME_DEFAULT_FACE(f) FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID) @@ -1029,6 +1028,25 @@ struct x_output #define XNS_SCROLL_BAR(vec) XSAVE_POINTER (vec, 0) #endif +/* Compute pixel height of the frame's titlebar. */ +#define FRAME_NS_TITLEBAR_HEIGHT(f) \ + (NSHeight([FRAME_NS_VIEW (f) frame]) == 0 ? \ + 0 \ + : (int)(NSHeight([FRAME_NS_VIEW (f) window].frame) \ + - NSHeight([NSWindow contentRectForFrameRect: \ + [[FRAME_NS_VIEW (f) window] frame] \ + styleMask:[[FRAME_NS_VIEW (f) window] styleMask]]))) + +/* Compute pixel height of the toolbar. */ +#define FRAME_TOOLBAR_HEIGHT(f) \ + (([[FRAME_NS_VIEW (f) window] toolbar] == nil \ + || ! [[FRAME_NS_VIEW (f) window] toolbar].visible) ? \ + 0 \ + : (int)(NSHeight([NSWindow contentRectForFrameRect: \ + [[FRAME_NS_VIEW (f) window] frame] \ + styleMask:[[FRAME_NS_VIEW (f) window] styleMask]]) \ + - NSHeight([[[FRAME_NS_VIEW (f) window] contentView] frame]))) + /* Compute pixel size for vertical scroll bars */ #define NS_SCROLL_BAR_WIDTH(f) \ (FRAME_HAS_VERTICAL_SCROLL_BARS (f) \ @@ -1066,6 +1084,17 @@ struct x_output #define NS_TOP_POS(f) ((f)->top_pos) #endif +/* Calculate system coordinates of the left and top of the parent + window or, if there is no parent window, the screen. */ +#define NS_PARENT_WINDOW_LEFT_POS(f) \ + (FRAME_PARENT_FRAME (f) != nil \ + ? [[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.x : 0) +#define NS_PARENT_WINDOW_TOP_POS(f) \ + (FRAME_PARENT_FRAME (f) != nil \ + ? ([[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.y \ + + [[FRAME_NS_VIEW (f) window] parentWindow].frame.size.height) \ + : [[[FRAME_NS_VIEW (f) window] screen] frame].size.height) + #define FRAME_NS_FONT_TABLE(f) (FRAME_DISPLAY_INFO (f)->font_table) #define FRAME_FONTSET(f) ((f)->output_data.ns->fontset) @@ -1185,6 +1214,10 @@ extern int x_display_pixel_width (struct ns_display_info *); /* This in nsterm.m */ extern float ns_antialias_threshold; extern void x_destroy_window (struct frame *f); +extern void x_set_undecorated (struct frame *f, Lisp_Object new_value, + Lisp_Object old_value); +extern void x_set_parent_frame (struct frame *f, Lisp_Object new_value, + Lisp_Object old_value); extern int ns_select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timespec const *timeout, sigset_t const *sigmask); diff --git a/src/nsterm.m b/src/nsterm.m index 162980a651..d614322ad1 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1711,8 +1711,9 @@ -(void)remove #endif /* Constrain the setFrameTopLeftPoint so we don't move behind the menu bar. */ - NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos), - SCREENMAXBOUND ([fscreen frame].size.height + NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos + + NS_PARENT_WINDOW_LEFT_POS (f)), + SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f) - NS_TOP_POS (f))); NSTRACE_POINT ("setFrameTopLeftPoint", pt); [[view window] setFrameTopLeftPoint: pt]; @@ -1764,25 +1765,6 @@ -(void)remove pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height); } - /* If we have a toolbar, take its height into account. */ - if (tb && ! [view isFullscreen]) - { - /* NOTE: previously this would generate wrong result if toolbar not - yet displayed and fixing toolbar_height=32 helped, but - now (200903) seems no longer needed */ - FRAME_TOOLBAR_HEIGHT (f) = - NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)]) - - FRAME_NS_TITLEBAR_HEIGHT (f); -#if 0 - /* Only breaks things here, removed by martin 2015-09-30. */ -#ifdef NS_IMPL_GNUSTEP - FRAME_TOOLBAR_HEIGHT (f) -= 3; -#endif -#endif - } - else - FRAME_TOOLBAR_HEIGHT (f) = 0; - wr.size.width = pixelwidth + f->border_width; wr.size.height = pixelheight; if (! [view isFullscreen]) @@ -1811,6 +1793,106 @@ -(void)remove 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. + */ +void +x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); + NSWindow *window = [view window]; + + if (!EQ (new_value, old_value)) + { + block_input (); + + if (NILP (new_value)) + { + FRAME_UNDECORATED (f) = false; + [window setStyleMask: ((window.styleMask | NSWindowStyleMaskTitled) + ^ NSWindowStyleMaskBorderless)]; + + [view createToolbar: f]; + } + else + { + [window setToolbar: nil]; + /* Do I need to release the toolbar here? */ + + FRAME_UNDECORATED (f) = true; + [window setStyleMask: ((window.styleMask | NSWindowStyleMaskBorderless) + ^ NSWindowStyleMaskTitled)]; + } + + /* At this point it seems we don't have an active NSResponder, + so some key presses (TAB) are swallowed by the system. */ + [window makeFirstResponder: view]; + + [view updateFrameSize: NO]; + 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's `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. + * + * Whether a child frame has a tool bar may be window-system or window + * manager dependent. It's advisable to disable it via the frame + * parameter settings. + * + * Some window managers may not honor this parameter. + */ +void +x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + struct frame *p = NULL; + NSWindow *parent, *child; + + 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)) + { + parent = [FRAME_NS_VIEW (p) window]; + child = [FRAME_NS_VIEW (f) window]; + + block_input (); + [parent addChildWindow: child + ordered: NSWindowAbove]; + unblock_input (); + + fset_parent_frame (f, new_value); + } +} static void ns_fullscreen_hook (struct frame *f) @@ -6399,7 +6481,8 @@ - (void) updateFrameSize: (BOOL) delay; newh = (int)wr.size.height - extra; NSTRACE_SIZE ("New size", NSMakeSize (neww, newh)); - NSTRACE_MSG ("tool_bar_height: %d", emacsframe->tool_bar_height); + NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe)); + NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe)); cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww); rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh); @@ -6424,9 +6507,11 @@ - (void) updateFrameSize: (BOOL) delay; SET_FRAME_GARBAGED (emacsframe); cancel_mouse_face (emacsframe); - wr = NSMakeRect (0, 0, neww, newh); + /* The next two lines appear to be setting the frame to the same + size as it already is. Why are they there? */ + // wr = NSMakeRect (0, 0, neww, newh); - [view setFrame: wr]; + // [view setFrame: wr]; // to do: consider using [NSNotificationCenter postNotificationName:]. [self windowDidMove: // Update top/left. @@ -6489,7 +6574,8 @@ - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize old_title = 0; } } - else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize) + else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize + && [[self window] titleVisibility]) { char *size_title; NSWindow *window = [self window]; @@ -6692,6 +6778,34 @@ - (BOOL)isOpaque } +- (void)createToolbar: (struct frame *)f +{ + EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); + NSWindow *window = [view window]; + + toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier: + [NSString stringWithFormat: @"Emacs Frame %d", + ns_window_num]]; + [window setToolbar: toolbar]; + [toolbar setVisible: NO]; + + /* Don't set frame garbaged until tool bar is up to date? + This avoids an extra clear and redraw (flicker) at frame creation. */ + if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES; + else wait_for_tool_bar = NO; + + +#ifdef NS_IMPL_COCOA + { + NSButton *toggleButton; + toggleButton = [window standardWindowButton: NSWindowToolbarButton]; + [toggleButton setTarget: self]; + [toggleButton setAction: @selector (toggleToolbar: )]; + } +#endif +} + + - initFrameFromEmacs: (struct frame *)f { NSRect r, wr; @@ -6729,11 +6843,13 @@ - (BOOL)isOpaque maximizing_resize = NO; #endif - win = [[EmacsWindow alloc] + win = [[EmacsFSWindow alloc] initWithContentRect: r styleMask: (NSWindowStyleMaskResizable | #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - NSWindowStyleMaskTitled | + (FRAME_UNDECORATED (f) ? + NSWindowStyleMaskBorderless : + NSWindowStyleMaskTitled) | #endif NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable) @@ -6746,7 +6862,6 @@ - (BOOL)isOpaque wr = [win frame]; bwidth = f->border_width = wr.size.width - r.size.width; - tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height; [win setAcceptsMouseMovedEvents: YES]; [win setDelegate: self]; @@ -6766,42 +6881,32 @@ - (BOOL)isOpaque [win setTitle: name]; /* toolbar support */ - toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier: - [NSString stringWithFormat: @"Emacs Frame %d", - ns_window_num]]; - [win setToolbar: toolbar]; - [toolbar setVisible: NO]; - - /* Don't set frame garbaged until tool bar is up to date? - This avoids an extra clear and redraw (flicker) at frame creation. */ - if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES; - else wait_for_tool_bar = NO; - - -#ifdef NS_IMPL_COCOA - { - NSButton *toggleButton; - toggleButton = [win standardWindowButton: NSWindowToolbarButton]; - [toggleButton setTarget: self]; - [toggleButton setAction: @selector (toggleToolbar: )]; - } -#endif - FRAME_TOOLBAR_HEIGHT (f) = 0; + if (! FRAME_UNDECORATED (f)) + [self createToolbar: f]; tem = f->icon_name; if (!NILP (tem)) [win setMiniwindowTitle: [NSString stringWithUTF8String: SSDATA (tem)]]; + if (FRAME_PARENT_FRAME (f) != nil) + { + EmacsWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window]; + [parent addChildWindow: win + ordered: NSWindowAbove]; + } + { NSScreen *screen = [win screen]; if (screen != 0) { NSPoint pt = NSMakePoint - (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX), + (IN_BOUND (-SCREENMAX, f->left_pos + + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX), IN_BOUND (-SCREENMAX, - [screen frame].size.height - NS_TOP_POS (f), SCREENMAX)); + NS_PARENT_WINDOW_TOP_POS (f) - NS_TOP_POS (f), + SCREENMAX)); [win setFrameTopLeftPoint: pt]; @@ -6843,9 +6948,9 @@ - (void)windowDidMove: sender return; if (screen != nil) { - emacsframe->left_pos = r.origin.x; + emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe); emacsframe->top_pos = - [screen frame].size.height - (r.origin.y + r.size.height); + NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height); } } @@ -7262,9 +7367,6 @@ - (void)toggleFullScreen: (id)sender [fw setOpaque: NO]; f->border_width = 0; - FRAME_NS_TITLEBAR_HEIGHT (f) = 0; - tobar_height = FRAME_TOOLBAR_HEIGHT (f); - FRAME_TOOLBAR_HEIGHT (f) = 0; nonfs_window = w; @@ -7298,9 +7400,6 @@ - (void)toggleFullScreen: (id)sender [w setOpaque: NO]; f->border_width = bwidth; - FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height; - if (FRAME_EXTERNAL_TOOL_BAR (f)) - FRAME_TOOLBAR_HEIGHT (f) = tobar_height; // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications. -- 2.12.0 ^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-17 14:56 ` bug#25408: Remove Decorations Around Emacs Frame (NS port) Alan Third @ 2017-04-17 15:43 ` martin rudalics 2017-04-17 16:21 ` Alan Third 2017-04-19 11:24 ` Anders Lindgren 1 sibling, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-04-17 15:43 UTC (permalink / raw) To: Alan Third Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren Looks good to me. I suppose though this won't work with GNUStep so I can't try it. Two remarks below. > + * 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. I suppose you want to mention the removal of the toolbar here. If so, we'll have to mention that in the manual as well. When you re-add the decorations, does the inner frame move or are the decorations drawn around an unmoved inner frame? > + * A child frame's `left' and `top' parameters specify positions > + * relative to the top-left corner of its parent frame's native > + * rectangle. Does the above hold for NS? Does a (set-frame-position child 0 0) really put child in the upper left corner of its parent? Also we would have to describe the deviant clipping behavior for NS. Many thanks, martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-17 15:43 ` martin rudalics @ 2017-04-17 16:21 ` Alan Third 2017-04-17 17:20 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Alan Third @ 2017-04-17 16:21 UTC (permalink / raw) To: martin rudalics Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren On Mon, Apr 17, 2017 at 05:43:57PM +0200, martin rudalics wrote: > Looks good to me. I suppose though this won't work with GNUStep so I > can't try it. Two remarks below. I’m not sure about the decoration stuff, but I think, from a quick glance at the GNUStep docs, the parent/child window stuff should work. I’ll try and build it under GNUStep at some point to check it works. I’ve got a GNU/Linux virtual machine around here somewhere... > > + * 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. > > I suppose you want to mention the removal of the toolbar here. If so, > we'll have to mention that in the manual as well. Yes, good point. > When you re-add the decorations, does the inner frame move or are > the decorations drawn around an unmoved inner frame? There are only two situations where the inner frame will move. The first is if you have the toolbar enabled, when you re‐add the decorations the toolbar reappears and slides the rest of the frame down. (Similarly when you remove the toolbar the rest of the frame slides up.) The other is if the titlebar would be behind the menubar, then the system moves the whole frame down just enough to keep it completely visible. > > + * A child frame's `left' and `top' parameters specify positions > > + * relative to the top-left corner of its parent frame's native > > + * rectangle. > > Does the above hold for NS? Does a (set-frame-position child 0 0) > really put child in the upper left corner of its parent? Most of the time spent implementing the child/parent frames was getting that working right, so yes, it does. Now, one thing that may be wrong is that (0 0) is actually the very top, including the titlebar. I could probably fix that if it’s not right just by offsetting by the height of the titlebar. -- Alan Third ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-17 16:21 ` Alan Third @ 2017-04-17 17:20 ` martin rudalics 2017-04-17 18:55 ` Alan Third 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-04-17 17:20 UTC (permalink / raw) To: Alan Third Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren > I’m not sure about the decoration stuff, but I think, from a quick > glance at the GNUStep docs, the parent/child window stuff should work. > > I’ll try and build it under GNUStep at some point to check it works. > I’ve got a GNU/Linux virtual machine around here somewhere... Here, building with GNUStep currently fails as follows: ../../src/nsterm.m: In function ‘x_set_offset’: ../../src/nsterm.m:1714:33: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m:1714:33: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m:1714:33: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m:1716:33: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m:1716:33: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m:1716:33: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m: In function ‘x_set_window_size’: ../../src/nsterm.m:1742:7: warning: unused variable ‘tb’ [-Wunused-variable] ../../src/nsterm.m: In function ‘x_set_undecorated’: ../../src/nsterm.m:1822:34: warning: ‘NSWindow’ may not respond to ‘-setStyleMask:’ [enabled by default] ../../src/nsterm.m:1822:34: warning: (Messages without a matching method signature [enabled by default] ../../src/nsterm.m:1822:34: warning: will be assumed to return ‘id’ and accept [enabled by default] ../../src/nsterm.m:1822:34: warning: ‘...’ as arguments.) [enabled by default] ../../src/nsterm.m:1833:34: warning: ‘NSWindow’ may not respond to ‘-setStyleMask:’ [enabled by default] ../../src/nsterm.m: In function ‘ns_read_socket’: ../../src/nsterm.m:4160:21: warning: unused variable ‘specpdl_count’ [-Wunused-variable] ../../src/nsfns.m: In function ‘frame_geometry’: ../../src/nsfns.m:2853:3: error: no ‘visible’ getter found ../../src/nsterm.m: In function ‘-[EmacsView initFrameFromEmacs:]’: ../../src/nsterm.m:6892:30: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m:6894:30: warning: initialization from distinct Objective-C type [enabled by default] ../../src/nsterm.m:6905:12: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m:6905:12: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m:6905:12: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m:6907:12: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m:6907:12: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m:6907:12: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m: In function ‘-[EmacsView windowDidMove:]’: ../../src/nsterm.m:6951:43: warning: comparison of distinct pointer types lacks a cast [enabled by default] ../../src/nsterm.m:6953:9: warning: comparison of distinct pointer types lacks a cast [enabled by default] make[1]: *** [nsfns.o] Fehler 1 make[1]: *** Warte auf noch nicht beendete Prozesse... ../../src/nsterm.m: In function ‘-[EmacsView updateFrameSize:]’: ../../src/nsterm.m:6467:9: error: no ‘visible’ getter found ../../src/nsterm.m:6472:7: error: no ‘visible’ getter found ../../src/nsterm.m: In function ‘-[EmacsView windowWillResize:toSize:]’: ../../src/nsterm.m:6554:9: error: no ‘visible’ getter found ../../src/nsterm.m: In function ‘x_set_window_size’: ../../src/nsterm.m:1772:7: error: no ‘visible’ getter found ../../src/nsterm.m:1788:5: error: no ‘visible’ getter found ../../src/nsterm.m: In function ‘x_set_offset’: ../../src/nsterm.m:1706:12: error: no ‘visible’ getter found make[1]: *** [nsterm.o] Fehler 1 make[1]: Leaving directory `/home/martin/emacs-git/trunk/obj-ns/src' make: *** [src] Fehler 2 No good idea what made it choke. The plethora of warnings is terribly confusing. > Now, one thing that may be wrong is that (0 0) is actually the very > top, including the titlebar. I could probably fix that if it’s not > right just by offsetting by the height of the titlebar. No really great deal. If you don't, we'll mention it in the documentation. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-17 17:20 ` martin rudalics @ 2017-04-17 18:55 ` Alan Third 2017-04-19 7:26 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Alan Third @ 2017-04-17 18:55 UTC (permalink / raw) To: martin rudalics Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren [-- Attachment #1: Type: text/plain, Size: 1105 bytes --] On Mon, Apr 17, 2017 at 07:20:20PM +0200, martin rudalics wrote: > > I’m not sure about the decoration stuff, but I think, from a quick > > glance at the GNUStep docs, the parent/child window stuff should work. > > > > I’ll try and build it under GNUStep at some point to check it works. > > I’ve got a GNU/Linux virtual machine around here somewhere... > > Here, building with GNUStep currently fails as follows: > <snip> > > No good idea what made it choke. The plethora of warnings is terribly > confusing. I think it was the use of the ‘visible’ method on NSToolbar, which it appears I’ve made up, but which works on Cocoa. I’ve changed it to look directly at the ‘isVisible’ instance variable. I also noticed that it doesn’t like NSWindow:setStyleMask, so I’ve changed that to directly update the relevant instance variable too. I think some of the warnings are related to comparing an Objective C object to NULL instead of nil, or vice versa. I can’t see any difference between them here, and I don’t get any warnings from clang. New patch attached. -- Alan Third [-- Attachment #2: Add parent/child & undecorate to NS --] [-- Type: text/plain, Size: 23443 bytes --] From 7456d41a9aeac4f252cc98a5396fd7cf38451a38 Mon Sep 17 00:00:00 2001 From: Alan Third <alan@idiocy.org> Date: Fri, 14 Apr 2017 10:02:38 +0100 Subject: [PATCH] Add undecorated and parent frames to NS port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * src/frame.h: * src/frame.c: Enable ‘undecorated’ and ‘parent’ frame definitions. * src/nsfns.m: Add x_set_parent_frame and x_set_undecorated to handler struct. (Fx-create_frame): Handle ‘parent-frame’ and ‘undecorated’ frame parameter. * src/nsmenu.m (free_frame_tool_bar, update_frame_tool_bar): FRAME_TOOLBAR_HEIGHT is no longer a variable. * src/nsterm.h (NS_PARENT_WINDOW_LEFT_POS, NS_PARENT_WINDOW_TOP_POS): Add #defines to find the screen position of the parent frame. (EmacsView): Remove redundant toolbar variables and add createToolbar method. (FRAME_NS_TITLEBAR_HEIGHT, FRAME_TOOLBAR_HEIGHT): Always calculate the values instead of storing them in a variable. * src/nsterm.m (x_set_offset, windowDidMove): Take parent frame position into account when positioning frames. (initFrameFromEmacs): Link parent frame, and take position into account when creating new frame. (x_set_window_size): Remove toolbar height calculation. (x_set_parent_frame): (x_set_undecorated): New function. (updateFrameSize): Change NSTRACE message to reflect new reality and no longer reset frame size. (windowWillResize): Don’t change NS window name when the titlebar is invisible. (createToolbar): Move toolbar creation code into it’s own method. (initFrameFromEmacs): Handle case where frame is created without a titlebar and remove toolbar creation code. (toggleFullScreen): FRAME_TOOLBAR_HEIGHT and FRAME_NS_TITLEBAR_HEIGHT are no longer variables. --- src/frame.c | 2 - src/frame.h | 14 ++-- src/nsfns.m | 23 ++++++- src/nsmenu.m | 8 --- src/nsterm.h | 40 ++++++++++- src/nsterm.m | 217 +++++++++++++++++++++++++++++++++++++++++++---------------- 6 files changed, 222 insertions(+), 82 deletions(-) diff --git a/src/frame.c b/src/frame.c index 282b691c27..681a245ee0 100644 --- a/src/frame.c +++ b/src/frame.c @@ -683,7 +683,6 @@ make_frame (bool mini_p) 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; @@ -692,7 +691,6 @@ make_frame (bool mini_p) 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 diff --git a/src/frame.h b/src/frame.h index 36af6e6780..4aa7c34a29 100644 --- a/src/frame.h +++ b/src/frame.h @@ -75,10 +75,10 @@ struct frame Usually it is nil. */ Lisp_Object title; -#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) /* This frame's parent frame, if it has one. */ Lisp_Object parent_frame; -#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */ +#endif /* HAVE_WINDOW_SYSTEM */ /* The frame which should receive keystrokes that occur in this frame, or nil if they should go to the frame itself. This is @@ -332,7 +332,7 @@ struct frame bool_bf horizontal_scroll_bars : 1; #endif /* HAVE_WINDOW_SYSTEM */ -#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) /* True if this is an undecorated frame. */ bool_bf undecorated : 1; @@ -570,7 +570,7 @@ fset_face_alist (struct frame *f, Lisp_Object val) { f->face_alist = val; } -#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) INLINE void fset_parent_frame (struct frame *f, Lisp_Object val) { @@ -914,7 +914,7 @@ default_pixels_per_inch_y (void) #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) ((void) f, 0) #endif /* HAVE_WINDOW_SYSTEM */ -#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) #define FRAME_UNDECORATED(f) ((f)->undecorated) #ifdef HAVE_NTGUI #define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0) @@ -934,7 +934,7 @@ default_pixels_per_inch_y (void) #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 */ +#else /* not HAVE_WINDOW_SYSTEM */ #define FRAME_UNDECORATED(f) ((void) f, 0) #define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0) #define FRAME_PARENT_FRAME(f) ((void) f, NULL) @@ -945,7 +945,7 @@ default_pixels_per_inch_y (void) #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 */ +#endif /* HAVE_WINDOW_SYSTEM */ /* Whether horizontal scroll bars are currently enabled for frame F. */ #if USE_HORIZONTAL_SCROLL_BARS diff --git a/src/nsfns.m b/src/nsfns.m index 8a923dd393..6dddc64cb4 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -972,8 +972,8 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side 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 */ + x_set_undecorated, /* x_set_undecorated */ + x_set_parent_frame, /* x_set_parent_frame */ 0, /* x_set_skip_taskbar */ 0, /* x_set_no_focus_on_map */ 0, /* x_set_no_accept_focus */ @@ -1087,7 +1087,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side ptrdiff_t count = specpdl_ptr - specpdl; Lisp_Object display; struct ns_display_info *dpyinfo = NULL; - Lisp_Object parent; + Lisp_Object parent, parent_frame; struct kboard *kb; static int desc_ctr = 1; int x_width = 0, x_height = 0; @@ -1265,6 +1265,23 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1, Qx_create_frame_1); + tem = x_get_arg (dpyinfo, parms, Qundecorated, NULL, NULL, RES_TYPE_BOOLEAN); + FRAME_UNDECORATED (f) = !NILP (tem) && !EQ (tem, Qunbound); + store_frame_param (f, Qundecorated, FRAME_UNDECORATED (f) ? Qt : Qnil); + + 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))) + parent_frame = Qnil; + + fset_parent_frame (f, parent_frame); + store_frame_param (f, Qparent_frame, parent_frame); + /* The resources controlling the menu-bar and tool-bar are processed specially at startup, and reflected in the mode variables; ignore them here. */ diff --git a/src/nsmenu.m b/src/nsmenu.m index 59ea3855ed..1262c9cb4d 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -995,8 +995,6 @@ - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f block_input (); view->wait_for_tool_bar = NO; - FRAME_TOOLBAR_HEIGHT (f) = 0; - /* Note: This trigger an animation, which calls windowDidResize repeatedly. */ f->output_data.ns->in_animation = 1; @@ -1129,12 +1127,6 @@ - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f } #endif - FRAME_TOOLBAR_HEIGHT (f) = - NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)]) - - FRAME_NS_TITLEBAR_HEIGHT (f); - if (FRAME_TOOLBAR_HEIGHT (f) < 0) // happens if frame is fullscreen. - FRAME_TOOLBAR_HEIGHT (f) = 0; - if (oldh != FRAME_TOOLBAR_HEIGHT (f)) [view updateFrameSize:YES]; if (view->wait_for_tool_bar && FRAME_TOOLBAR_HEIGHT (f) > 0) diff --git a/src/nsterm.h b/src/nsterm.h index 53d9344cc7..03cf399aad 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -430,7 +430,7 @@ char const * nstrace_fullscreen_type_name (int); NSString *workingText; BOOL processingCompose; int fs_state, fs_before_fs, next_maximized; - int tibar_height, tobar_height, bwidth; + int bwidth; int maximized_width, maximized_height; NSWindow *nonfs_window; BOOL fs_is_native; @@ -454,6 +454,7 @@ char const * nstrace_fullscreen_type_name (int); /* Emacs-side interface */ - initFrameFromEmacs: (struct frame *) f; +- (void) createToolbar: (struct frame *)f; - (void) setRows: (int) r andColumns: (int) c; - (void) setWindowClosing: (BOOL)closing; - (EmacsToolbar *) toolbar; @@ -1012,8 +1013,6 @@ struct x_output #define NS_FACE_FOREGROUND(f) ((f)->foreground) #define NS_FACE_BACKGROUND(f) ((f)->background) -#define FRAME_NS_TITLEBAR_HEIGHT(f) ((f)->output_data.ns->titlebar_height) -#define FRAME_TOOLBAR_HEIGHT(f) ((f)->output_data.ns->toolbar_height) #define FRAME_DEFAULT_FACE(f) FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID) @@ -1029,6 +1028,25 @@ struct x_output #define XNS_SCROLL_BAR(vec) XSAVE_POINTER (vec, 0) #endif +/* Compute pixel height of the frame's titlebar. */ +#define FRAME_NS_TITLEBAR_HEIGHT(f) \ + (NSHeight([FRAME_NS_VIEW (f) frame]) == 0 ? \ + 0 \ + : (int)(NSHeight([FRAME_NS_VIEW (f) window].frame) \ + - NSHeight([NSWindow contentRectForFrameRect: \ + [[FRAME_NS_VIEW (f) window] frame] \ + styleMask:[[FRAME_NS_VIEW (f) window] styleMask]]))) + +/* Compute pixel height of the toolbar. */ +#define FRAME_TOOLBAR_HEIGHT(f) \ + (([[FRAME_NS_VIEW (f) window] toolbar] == nil \ + || ! [[FRAME_NS_VIEW (f) window] toolbar].isVisible) ? \ + 0 \ + : (int)(NSHeight([NSWindow contentRectForFrameRect: \ + [[FRAME_NS_VIEW (f) window] frame] \ + styleMask:[[FRAME_NS_VIEW (f) window] styleMask]]) \ + - NSHeight([[[FRAME_NS_VIEW (f) window] contentView] frame]))) + /* Compute pixel size for vertical scroll bars */ #define NS_SCROLL_BAR_WIDTH(f) \ (FRAME_HAS_VERTICAL_SCROLL_BARS (f) \ @@ -1066,6 +1084,18 @@ struct x_output #define NS_TOP_POS(f) ((f)->top_pos) #endif +/* Calculate system coordinates of the left and top of the parent + window or, if there is no parent window, the screen. */ +#define NS_PARENT_WINDOW_LEFT_POS(f) \ + (FRAME_PARENT_FRAME (f) != NULL \ + ? [[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.x : 0) +#define NS_PARENT_WINDOW_TOP_POS(f) \ + (FRAME_PARENT_FRAME (f) != NULL \ + ? ([[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.y \ + + [[FRAME_NS_VIEW (f) window] parentWindow].frame.size.height \ + - FRAME_NS_TITLEBAR_HEIGHT (FRAME_PARENT_FRAME (f))) \ + : [[[FRAME_NS_VIEW (f) window] screen] frame].size.height) + #define FRAME_NS_FONT_TABLE(f) (FRAME_DISPLAY_INFO (f)->font_table) #define FRAME_FONTSET(f) ((f)->output_data.ns->fontset) @@ -1185,6 +1215,10 @@ extern int x_display_pixel_width (struct ns_display_info *); /* This in nsterm.m */ extern float ns_antialias_threshold; extern void x_destroy_window (struct frame *f); +extern void x_set_undecorated (struct frame *f, Lisp_Object new_value, + Lisp_Object old_value); +extern void x_set_parent_frame (struct frame *f, Lisp_Object new_value, + Lisp_Object old_value); extern int ns_select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timespec const *timeout, sigset_t const *sigmask); diff --git a/src/nsterm.m b/src/nsterm.m index 162980a651..07c48bc0e3 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1711,8 +1711,9 @@ -(void)remove #endif /* Constrain the setFrameTopLeftPoint so we don't move behind the menu bar. */ - NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos), - SCREENMAXBOUND ([fscreen frame].size.height + NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos + + NS_PARENT_WINDOW_LEFT_POS (f)), + SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f) - NS_TOP_POS (f))); NSTRACE_POINT ("setFrameTopLeftPoint", pt); [[view window] setFrameTopLeftPoint: pt]; @@ -1764,25 +1765,6 @@ -(void)remove pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height); } - /* If we have a toolbar, take its height into account. */ - if (tb && ! [view isFullscreen]) - { - /* NOTE: previously this would generate wrong result if toolbar not - yet displayed and fixing toolbar_height=32 helped, but - now (200903) seems no longer needed */ - FRAME_TOOLBAR_HEIGHT (f) = - NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)]) - - FRAME_NS_TITLEBAR_HEIGHT (f); -#if 0 - /* Only breaks things here, removed by martin 2015-09-30. */ -#ifdef NS_IMPL_GNUSTEP - FRAME_TOOLBAR_HEIGHT (f) -= 3; -#endif -#endif - } - else - FRAME_TOOLBAR_HEIGHT (f) = 0; - wr.size.width = pixelwidth + f->border_width; wr.size.height = pixelheight; if (! [view isFullscreen]) @@ -1811,6 +1793,106 @@ -(void)remove 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. + */ +void +x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); + NSWindow *window = [view window]; + + if (!EQ (new_value, old_value)) + { + block_input (); + + if (NILP (new_value)) + { + FRAME_UNDECORATED (f) = false; + window.styleMask = ((window.styleMask | NSWindowStyleMaskTitled) + ^ NSWindowStyleMaskBorderless); + + [view createToolbar: f]; + } + else + { + [window setToolbar: nil]; + /* Do I need to release the toolbar here? */ + + FRAME_UNDECORATED (f) = true; + window.styleMask = ((window.styleMask | NSWindowStyleMaskBorderless) + ^ NSWindowStyleMaskTitled); + } + + /* At this point it seems we don't have an active NSResponder, + so some key presses (TAB) are swallowed by the system. */ + [window makeFirstResponder: view]; + + [view updateFrameSize: NO]; + 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's `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. + * + * Whether a child frame has a tool bar may be window-system or window + * manager dependent. It's advisable to disable it via the frame + * parameter settings. + * + * Some window managers may not honor this parameter. + */ +void +x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + struct frame *p = NULL; + NSWindow *parent, *child; + + 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)) + { + parent = [FRAME_NS_VIEW (p) window]; + child = [FRAME_NS_VIEW (f) window]; + + block_input (); + [parent addChildWindow: child + ordered: NSWindowAbove]; + unblock_input (); + + fset_parent_frame (f, new_value); + } +} static void ns_fullscreen_hook (struct frame *f) @@ -6399,7 +6481,8 @@ - (void) updateFrameSize: (BOOL) delay; newh = (int)wr.size.height - extra; NSTRACE_SIZE ("New size", NSMakeSize (neww, newh)); - NSTRACE_MSG ("tool_bar_height: %d", emacsframe->tool_bar_height); + NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe)); + NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe)); cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww); rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh); @@ -6424,9 +6507,11 @@ - (void) updateFrameSize: (BOOL) delay; SET_FRAME_GARBAGED (emacsframe); cancel_mouse_face (emacsframe); - wr = NSMakeRect (0, 0, neww, newh); + /* The next two lines appear to be setting the frame to the same + size as it already is. Why are they there? */ + // wr = NSMakeRect (0, 0, neww, newh); - [view setFrame: wr]; + // [view setFrame: wr]; // to do: consider using [NSNotificationCenter postNotificationName:]. [self windowDidMove: // Update top/left. @@ -6489,7 +6574,8 @@ - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize old_title = 0; } } - else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize) + else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize + && [[self window] titleVisibility]) { char *size_title; NSWindow *window = [self window]; @@ -6692,6 +6778,34 @@ - (BOOL)isOpaque } +- (void)createToolbar: (struct frame *)f +{ + EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); + NSWindow *window = [view window]; + + toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier: + [NSString stringWithFormat: @"Emacs Frame %d", + ns_window_num]]; + [window setToolbar: toolbar]; + [toolbar setVisible: NO]; + + /* Don't set frame garbaged until tool bar is up to date? + This avoids an extra clear and redraw (flicker) at frame creation. */ + if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES; + else wait_for_tool_bar = NO; + + +#ifdef NS_IMPL_COCOA + { + NSButton *toggleButton; + toggleButton = [window standardWindowButton: NSWindowToolbarButton]; + [toggleButton setTarget: self]; + [toggleButton setAction: @selector (toggleToolbar: )]; + } +#endif +} + + - initFrameFromEmacs: (struct frame *)f { NSRect r, wr; @@ -6729,11 +6843,13 @@ - (BOOL)isOpaque maximizing_resize = NO; #endif - win = [[EmacsWindow alloc] + win = [[EmacsFSWindow alloc] initWithContentRect: r styleMask: (NSWindowStyleMaskResizable | #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - NSWindowStyleMaskTitled | + (FRAME_UNDECORATED (f) ? + NSWindowStyleMaskBorderless : + NSWindowStyleMaskTitled) | #endif NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable) @@ -6746,7 +6862,6 @@ - (BOOL)isOpaque wr = [win frame]; bwidth = f->border_width = wr.size.width - r.size.width; - tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height; [win setAcceptsMouseMovedEvents: YES]; [win setDelegate: self]; @@ -6766,42 +6881,32 @@ - (BOOL)isOpaque [win setTitle: name]; /* toolbar support */ - toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier: - [NSString stringWithFormat: @"Emacs Frame %d", - ns_window_num]]; - [win setToolbar: toolbar]; - [toolbar setVisible: NO]; - - /* Don't set frame garbaged until tool bar is up to date? - This avoids an extra clear and redraw (flicker) at frame creation. */ - if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES; - else wait_for_tool_bar = NO; - - -#ifdef NS_IMPL_COCOA - { - NSButton *toggleButton; - toggleButton = [win standardWindowButton: NSWindowToolbarButton]; - [toggleButton setTarget: self]; - [toggleButton setAction: @selector (toggleToolbar: )]; - } -#endif - FRAME_TOOLBAR_HEIGHT (f) = 0; + if (! FRAME_UNDECORATED (f)) + [self createToolbar: f]; tem = f->icon_name; if (!NILP (tem)) [win setMiniwindowTitle: [NSString stringWithUTF8String: SSDATA (tem)]]; + if (FRAME_PARENT_FRAME (f) != NULL) + { + NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window]; + [parent addChildWindow: win + ordered: NSWindowAbove]; + } + { NSScreen *screen = [win screen]; if (screen != 0) { NSPoint pt = NSMakePoint - (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX), + (IN_BOUND (-SCREENMAX, f->left_pos + + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX), IN_BOUND (-SCREENMAX, - [screen frame].size.height - NS_TOP_POS (f), SCREENMAX)); + NS_PARENT_WINDOW_TOP_POS (f) - NS_TOP_POS (f), + SCREENMAX)); [win setFrameTopLeftPoint: pt]; @@ -6843,9 +6948,9 @@ - (void)windowDidMove: sender return; if (screen != nil) { - emacsframe->left_pos = r.origin.x; + emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe); emacsframe->top_pos = - [screen frame].size.height - (r.origin.y + r.size.height); + NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height); } } @@ -7262,9 +7367,6 @@ - (void)toggleFullScreen: (id)sender [fw setOpaque: NO]; f->border_width = 0; - FRAME_NS_TITLEBAR_HEIGHT (f) = 0; - tobar_height = FRAME_TOOLBAR_HEIGHT (f); - FRAME_TOOLBAR_HEIGHT (f) = 0; nonfs_window = w; @@ -7298,9 +7400,6 @@ - (void)toggleFullScreen: (id)sender [w setOpaque: NO]; f->border_width = bwidth; - FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height; - if (FRAME_EXTERNAL_TOOL_BAR (f)) - FRAME_TOOLBAR_HEIGHT (f) = tobar_height; // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications. -- 2.12.0 ^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-17 18:55 ` Alan Third @ 2017-04-19 7:26 ` martin rudalics 2017-04-19 14:33 ` Alan Third 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-04-19 7:26 UTC (permalink / raw) To: Alan Third Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren > New patch attached. Thank you. Building works now. Invoking a "non-installed" emacs gets me 2017-04-19 09:16:03.808 emacs[5292] FTC_ImageCache_Lookup() failed with error 00000006 2017-04-19 09:16:03.921 emacs[5292] FTC_ImageCache_Lookup() failed with error 00000006 2017-04-19 09:16:03.953 emacs[5292] KeySym NoSymbol not found; disabling GSSecondControlKey 2017-04-19 09:16:03.953 emacs[5292] KeySym NoSymbol not found; disabling GSFirstCommandKey 2017-04-19 09:16:03.953 emacs[5292] KeySym NoSymbol not found; disabling GSSecondCommandKey which is normal here. If at this time I do within the just started Emacs (set-frame-parameter nil 'undecorated t) I get /home/martin/emacs-git/trunk/obj-ns/src/emacs: Uncaught exception NSInvalidArgumentException, reason: -[EmacsFSWindow setStyleMask:]: unrecognized selector sent to instance 0x30a37d0 Setting the 'parent-frame' parameter of a frame has no impact, neither when I do it during frame creation not when doing it at any later time. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-19 7:26 ` martin rudalics @ 2017-04-19 14:33 ` Alan Third 2017-04-19 16:01 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Alan Third @ 2017-04-19 14:33 UTC (permalink / raw) To: martin rudalics Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren [-- Attachment #1: Type: text/plain, Size: 1370 bytes --] On Wed, Apr 19, 2017 at 09:26:23AM +0200, martin rudalics wrote: > If at this time I do within the just started Emacs > > (set-frame-parameter nil 'undecorated t) > > I get > > /home/martin/emacs-git/trunk/obj-ns/src/emacs: Uncaught exception NSInvalidArgumentException, reason: -[EmacsFSWindow setStyleMask:]: unrecognized selector sent to instance 0x30a37d0 It turns out that GNUStep doesn’t let you change the decorated state of an existing window. It should be able to create a new undecorated window. > Setting the 'parent-frame' parameter of a frame has no impact, neither > when I do it during frame creation not when doing it at any later time. I believe it is setting the parent/child relationship, but in GNUStep it doesn’t seem to mean the child moves with the parent. I think this is a bug in GNUStep, but the behaviour isn’t documented yet, so I’m not sure if it’s intentional. The child will minimise and close with the parent and moving it to (0 0) will put it in the top left corner of the parent. Except it doesn’t quite, because there’s a hard‐coded titlebar height for GNUStep which is guaranteed to be wrong for every WM. At least I think that’s what going on. Z‐groups are working, but again in GNUStep it seems a bit hit and miss as the frames seem to forget their state if you click on their titlebars. -- Alan Third [-- Attachment #2: NS frame patch --] [-- Type: text/plain, Size: 31211 bytes --] From 5584fbe6402083853b71b3de251670752a5d7af2 Mon Sep 17 00:00:00 2001 From: Alan Third <alan@idiocy.org> Date: Fri, 14 Apr 2017 10:02:38 +0100 Subject: [PATCH] Add new frame functionality to NS port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * lisp/frame.el (frame-restack): Call ns-frame-restack. * src/keyboard.c (kbd_buffer_get_event) [HAVE_NS]: Enable MOVE_FRAME_EVENT handling. * src/frame.h: * src/frame.c: Enable 'z-group', 'undecorated' and 'parent' frame definitions. * src/nsfns.m: Add x_set_z_group, x_set_parent_frame and x_set_undecorated (Cocoa only) to handler struct. (Fx-create_frame): Handle 'z-code', 'parent-frame' and 'undecorated' frame parameter. (Fns_frame_restack): New function. * src/nsmenu.m (free_frame_tool_bar, update_frame_tool_bar): FRAME_TOOLBAR_HEIGHT is no longer a variable. * src/nsterm.h (NS_PARENT_WINDOW_LEFT_POS, NS_PARENT_WINDOW_TOP_POS): Add #defines to find the screen position of the parent frame. (NS_TOP_POS): Remove defun. (EmacsView): Remove redundant toolbar variables and add createToolbar method. (FRAME_NS_TITLEBAR_HEIGHT, FRAME_TOOLBAR_HEIGHT): Always calculate the values instead of storing them in a variable. * src/nsterm.m (x_set_offset, windowDidMove): Take parent frame position into account when positioning frames. (initFrameFromEmacs): Remove toolbar creation code and handle new frame parameters. (x_set_window_size): Remove toolbar height calculation. (x_set_z_group): (x_set_parent_frame): (x_set_undecorated) [NS_IMPL_COCOA]: New function. (x_destroy_window): Detach parent if child closes. (updateFrameSize): Change NSTRACE message to reflect new reality and no longer reset frame size. (windowWillResize): Don’t change NS window name when the titlebar is invisible. (createToolbar): Move toolbar creation code into it’s own method. (toggleFullScreen): FRAME_TOOLBAR_HEIGHT and FRAME_NS_TITLEBAR_HEIGHT are no longer variables. (windowDidMove): Fire MOVE_FRAME_EVENT Emacs event. --- lisp/frame.el | 4 +- src/frame.c | 2 - src/frame.h | 14 +-- src/keyboard.c | 2 +- src/nsfns.m | 63 +++++++++++- src/nsmenu.m | 8 -- src/nsterm.h | 47 +++++++-- src/nsterm.m | 302 ++++++++++++++++++++++++++++++++++++++++++++------------- 8 files changed, 341 insertions(+), 101 deletions(-) diff --git a/lisp/frame.el b/lisp/frame.el index 86a0e26e39..e632b5943f 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -1548,7 +1548,9 @@ frame-restack ((eq frame-type 'x) (x-frame-restack frame1 frame2 above)) ((eq frame-type 'w32) - (w32-frame-restack frame1 frame2 above)))) + (w32-frame-restack frame1 frame2 above)) + ((eq frame-type 'ns) + (ns-frame-restack frame1 frame2 above)))) (error "Cannot restack frames"))) (defun frame-size-changed-p (&optional frame) diff --git a/src/frame.c b/src/frame.c index 282b691c27..681a245ee0 100644 --- a/src/frame.c +++ b/src/frame.c @@ -683,7 +683,6 @@ make_frame (bool mini_p) 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; @@ -692,7 +691,6 @@ make_frame (bool mini_p) 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 diff --git a/src/frame.h b/src/frame.h index 36af6e6780..4aa7c34a29 100644 --- a/src/frame.h +++ b/src/frame.h @@ -75,10 +75,10 @@ struct frame Usually it is nil. */ Lisp_Object title; -#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) /* This frame's parent frame, if it has one. */ Lisp_Object parent_frame; -#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */ +#endif /* HAVE_WINDOW_SYSTEM */ /* The frame which should receive keystrokes that occur in this frame, or nil if they should go to the frame itself. This is @@ -332,7 +332,7 @@ struct frame bool_bf horizontal_scroll_bars : 1; #endif /* HAVE_WINDOW_SYSTEM */ -#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) /* True if this is an undecorated frame. */ bool_bf undecorated : 1; @@ -570,7 +570,7 @@ fset_face_alist (struct frame *f, Lisp_Object val) { f->face_alist = val; } -#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) INLINE void fset_parent_frame (struct frame *f, Lisp_Object val) { @@ -914,7 +914,7 @@ default_pixels_per_inch_y (void) #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) ((void) f, 0) #endif /* HAVE_WINDOW_SYSTEM */ -#if defined (HAVE_WINDOW_SYSTEM) && !defined (HAVE_NS) +#if defined (HAVE_WINDOW_SYSTEM) #define FRAME_UNDECORATED(f) ((f)->undecorated) #ifdef HAVE_NTGUI #define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0) @@ -934,7 +934,7 @@ default_pixels_per_inch_y (void) #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 */ +#else /* not HAVE_WINDOW_SYSTEM */ #define FRAME_UNDECORATED(f) ((void) f, 0) #define FRAME_OVERRIDE_REDIRECT(f) ((void) f, 0) #define FRAME_PARENT_FRAME(f) ((void) f, NULL) @@ -945,7 +945,7 @@ default_pixels_per_inch_y (void) #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 */ +#endif /* HAVE_WINDOW_SYSTEM */ /* Whether horizontal scroll bars are currently enabled for frame F. */ #if USE_HORIZONTAL_SCROLL_BARS diff --git a/src/keyboard.c b/src/keyboard.c index 3e50142f7c..c9fa2a9f5e 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4056,7 +4056,7 @@ kbd_buffer_get_event (KBOARD **kbp, kbd_fetch_ptr = event + 1; } #endif -#if defined (HAVE_X11) || defined (HAVE_NTGUI) +#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (HAVE_NS) else if (event->kind == MOVE_FRAME_EVENT) { /* Make an event (move-frame (FRAME)). */ diff --git a/src/nsfns.m b/src/nsfns.m index 8a923dd393..f1a5df8f27 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -972,12 +972,16 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side 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 */ +#ifdef NS_IMPL_COCOA + x_set_undecorated, /* x_set_undecorated */ +#else + 0, /*x_set_undecorated */ +#endif + x_set_parent_frame, /* 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 */ + x_set_z_group, /* x_set_z_group */ 0, /* x_set_override_redirect */ }; @@ -1087,7 +1091,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side ptrdiff_t count = specpdl_ptr - specpdl; Lisp_Object display; struct ns_display_info *dpyinfo = NULL; - Lisp_Object parent; + Lisp_Object parent, parent_frame; struct kboard *kb; static int desc_ctr = 1; int x_width = 0, x_height = 0; @@ -1265,6 +1269,25 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1, Qx_create_frame_1); + tem = x_get_arg (dpyinfo, parms, Qundecorated, NULL, NULL, RES_TYPE_BOOLEAN); + FRAME_UNDECORATED (f) = !NILP (tem) && !EQ (tem, Qunbound); + store_frame_param (f, Qundecorated, FRAME_UNDECORATED (f) ? Qt : Qnil); + + 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))) + parent_frame = Qnil; + + fset_parent_frame (f, parent_frame); + store_frame_param (f, Qparent_frame, parent_frame); + + x_default_parameter (f, parms, Qz_group, Qnil, NULL, NULL, RES_TYPE_SYMBOL); + /* The resources controlling the menu-bar and tool-bar are processed specially at startup, and reflected in the mode variables; ignore them here. */ @@ -1405,6 +1428,37 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side } } +DEFUN ("ns-frame-restack", Fns_frame_restack, Sns_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. + +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_NS_VIEW (f1) && FRAME_NS_VIEW (f2)) + { + NSWindow *window = [FRAME_NS_VIEW (f1) window]; + NSInteger window2 = [[FRAME_NS_VIEW (f2) window] windowNumber]; + NSWindowOrderingMode flag = NILP (above) ? NSWindowBelow : NSWindowAbove; + + [window orderWindow: flag + relativeTo: window2]; + + return Qt; + } + else + { + error ("Cannot restack frames"); + return Qnil; + } +} DEFUN ("ns-popup-font-panel", Fns_popup_font_panel, Sns_popup_font_panel, 0, 1, "", @@ -3134,6 +3188,7 @@ - (NSString *)panel: (id)sender userEnteredFilename: (NSString *)filename defsubr (&Sns_display_monitor_attributes_list); defsubr (&Sns_frame_geometry); defsubr (&Sns_frame_edges); + defsubr (&Sns_frame_restack); defsubr (&Sx_display_mm_width); defsubr (&Sx_display_mm_height); defsubr (&Sx_display_screens); diff --git a/src/nsmenu.m b/src/nsmenu.m index 59ea3855ed..1262c9cb4d 100644 --- a/src/nsmenu.m +++ b/src/nsmenu.m @@ -995,8 +995,6 @@ - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f block_input (); view->wait_for_tool_bar = NO; - FRAME_TOOLBAR_HEIGHT (f) = 0; - /* Note: This trigger an animation, which calls windowDidResize repeatedly. */ f->output_data.ns->in_animation = 1; @@ -1129,12 +1127,6 @@ - (Lisp_Object)runMenuAt: (NSPoint)p forFrame: (struct frame *)f } #endif - FRAME_TOOLBAR_HEIGHT (f) = - NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)]) - - FRAME_NS_TITLEBAR_HEIGHT (f); - if (FRAME_TOOLBAR_HEIGHT (f) < 0) // happens if frame is fullscreen. - FRAME_TOOLBAR_HEIGHT (f) = 0; - if (oldh != FRAME_TOOLBAR_HEIGHT (f)) [view updateFrameSize:YES]; if (view->wait_for_tool_bar && FRAME_TOOLBAR_HEIGHT (f) > 0) diff --git a/src/nsterm.h b/src/nsterm.h index 53d9344cc7..2f8c4269b0 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -430,7 +430,7 @@ char const * nstrace_fullscreen_type_name (int); NSString *workingText; BOOL processingCompose; int fs_state, fs_before_fs, next_maximized; - int tibar_height, tobar_height, bwidth; + int bwidth; int maximized_width, maximized_height; NSWindow *nonfs_window; BOOL fs_is_native; @@ -454,6 +454,7 @@ char const * nstrace_fullscreen_type_name (int); /* Emacs-side interface */ - initFrameFromEmacs: (struct frame *) f; +- (void) createToolbar: (struct frame *)f; - (void) setRows: (int) r andColumns: (int) c; - (void) setWindowClosing: (BOOL)closing; - (EmacsToolbar *) toolbar; @@ -1012,8 +1013,6 @@ struct x_output #define NS_FACE_FOREGROUND(f) ((f)->foreground) #define NS_FACE_BACKGROUND(f) ((f)->background) -#define FRAME_NS_TITLEBAR_HEIGHT(f) ((f)->output_data.ns->titlebar_height) -#define FRAME_TOOLBAR_HEIGHT(f) ((f)->output_data.ns->toolbar_height) #define FRAME_DEFAULT_FACE(f) FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID) @@ -1029,6 +1028,25 @@ struct x_output #define XNS_SCROLL_BAR(vec) XSAVE_POINTER (vec, 0) #endif +/* Compute pixel height of the frame's titlebar. */ +#define FRAME_NS_TITLEBAR_HEIGHT(f) \ + (NSHeight([FRAME_NS_VIEW (f) frame]) == 0 ? \ + 0 \ + : (int)(NSHeight([FRAME_NS_VIEW (f) window].frame) \ + - NSHeight([NSWindow contentRectForFrameRect: \ + [[FRAME_NS_VIEW (f) window] frame] \ + styleMask:[[FRAME_NS_VIEW (f) window] styleMask]]))) + +/* Compute pixel height of the toolbar. */ +#define FRAME_TOOLBAR_HEIGHT(f) \ + (([[FRAME_NS_VIEW (f) window] toolbar] == nil \ + || ! [[FRAME_NS_VIEW (f) window] toolbar].isVisible) ? \ + 0 \ + : (int)(NSHeight([NSWindow contentRectForFrameRect: \ + [[FRAME_NS_VIEW (f) window] frame] \ + styleMask:[[FRAME_NS_VIEW (f) window] styleMask]]) \ + - NSHeight([[[FRAME_NS_VIEW (f) window] contentView] frame]))) + /* Compute pixel size for vertical scroll bars */ #define NS_SCROLL_BAR_WIDTH(f) \ (FRAME_HAS_VERTICAL_SCROLL_BARS (f) \ @@ -1059,12 +1077,17 @@ struct x_output (FRAME_SCROLL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f) \ - NS_SCROLL_BAR_HEIGHT (f)) : 0) -/* XXX: fix for GNUstep inconsistent accounting for titlebar */ -#ifdef NS_IMPL_GNUSTEP -#define NS_TOP_POS(f) ((f)->top_pos + 18) -#else -#define NS_TOP_POS(f) ((f)->top_pos) -#endif +/* Calculate system coordinates of the left and top of the parent + window or, if there is no parent window, the screen. */ +#define NS_PARENT_WINDOW_LEFT_POS(f) \ + (FRAME_PARENT_FRAME (f) != NULL \ + ? [[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.x : 0) +#define NS_PARENT_WINDOW_TOP_POS(f) \ + (FRAME_PARENT_FRAME (f) != NULL \ + ? ([[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.y \ + + [[FRAME_NS_VIEW (f) window] parentWindow].frame.size.height \ + - FRAME_NS_TITLEBAR_HEIGHT (FRAME_PARENT_FRAME (f))) \ + : [[[FRAME_NS_VIEW (f) window] screen] frame].size.height) #define FRAME_NS_FONT_TABLE(f) (FRAME_DISPLAY_INFO (f)->font_table) @@ -1185,6 +1208,12 @@ extern int x_display_pixel_width (struct ns_display_info *); /* This in nsterm.m */ extern float ns_antialias_threshold; extern void x_destroy_window (struct frame *f); +extern void x_set_undecorated (struct frame *f, Lisp_Object new_value, + Lisp_Object old_value); +extern void x_set_parent_frame (struct frame *f, Lisp_Object new_value, + Lisp_Object old_value); +extern void x_set_z_group (struct frame *f, Lisp_Object new_value, + Lisp_Object old_value); extern int ns_select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timespec const *timeout, sigset_t const *sigmask); diff --git a/src/nsterm.m b/src/nsterm.m index 4725991aff..fbbcdbe4bc 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1668,6 +1668,17 @@ -(void)remove -------------------------------------------------------------------------- */ { NSTRACE ("x_destroy_window"); + + /* If this frame has a parent window, detach it as not doing so can + cause a crash in GNUStep. */ + if (FRAME_PARENT_FRAME (f) != NULL) + { + NSWindow *child = [FRAME_NS_VIEW (f) window]; + NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window]; + + [parent removeChildWindow: child]; + } + check_window_system (f); x_free_frame_resources (f); ns_window_num--; @@ -1706,14 +1717,18 @@ -(void)remove - FRAME_TOOLBAR_HEIGHT (f)) : f->top_pos; #ifdef NS_IMPL_GNUSTEP - if (f->left_pos < 100) - f->left_pos = 100; /* don't overlap menu */ + if (FRAME_PARENT_FRAME (f) == NULL) + { + if (f->left_pos < 100) + f->left_pos = 100; /* don't overlap menu */ + } #endif /* Constrain the setFrameTopLeftPoint so we don't move behind the menu bar. */ - NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos), - SCREENMAXBOUND ([fscreen frame].size.height - - NS_TOP_POS (f))); + NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos + + NS_PARENT_WINDOW_LEFT_POS (f)), + SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f) + - f->top_pos)); NSTRACE_POINT ("setFrameTopLeftPoint", pt); [[view window] setFrameTopLeftPoint: pt]; f->size_hint_flags &= ~(XNegative|YNegative); @@ -1738,7 +1753,6 @@ -(void)remove EmacsView *view = FRAME_NS_VIEW (f); NSWindow *window = [view window]; NSRect wr = [window frame]; - int tb = FRAME_EXTERNAL_TOOL_BAR (f); int pixelwidth, pixelheight; int orig_height = wr.size.height; @@ -1764,25 +1778,6 @@ -(void)remove pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height); } - /* If we have a toolbar, take its height into account. */ - if (tb && ! [view isFullscreen]) - { - /* NOTE: previously this would generate wrong result if toolbar not - yet displayed and fixing toolbar_height=32 helped, but - now (200903) seems no longer needed */ - FRAME_TOOLBAR_HEIGHT (f) = - NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)]) - - FRAME_NS_TITLEBAR_HEIGHT (f); -#if 0 - /* Only breaks things here, removed by martin 2015-09-30. */ -#ifdef NS_IMPL_GNUSTEP - FRAME_TOOLBAR_HEIGHT (f) -= 3; -#endif -#endif - } - else - FRAME_TOOLBAR_HEIGHT (f) = 0; - wr.size.width = pixelwidth + f->border_width; wr.size.height = pixelheight; if (! [view isFullscreen]) @@ -1811,6 +1806,150 @@ -(void)remove unblock_input (); } +#ifdef NS_IMPL_COCOA +void +x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +/* -------------------------------------------------------------------------- + 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. + + GNUStep cannot change an existing window's style. + -------------------------------------------------------------------------- */ +{ + EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); + NSWindow *window = [view window]; + + if (!EQ (new_value, old_value)) + { + block_input (); + + if (NILP (new_value)) + { + FRAME_UNDECORATED (f) = false; + [window setStyleMask: ((window.styleMask + | NSWindowStyleMaskTitled + | NSWindowStyleMaskResizable + | NSWindowStyleMaskMiniaturizable + | NSWindowStyleMaskClosable) + ^ NSWindowStyleMaskBorderless)]; + + [view createToolbar: f]; + } + else + { + [window setToolbar: nil]; + /* Do I need to release the toolbar here? */ + + FRAME_UNDECORATED (f) = true; + [window setStyleMask: ((window.styleMask | NSWindowStyleMaskBorderless) + ^ (NSWindowStyleMaskTitled + | NSWindowStyleMaskResizable + | NSWindowStyleMaskMiniaturizable + | NSWindowStyleMaskClosable))]; + } + + /* At this point it seems we don't have an active NSResponder, + so some key presses (TAB) are swallowed by the system. */ + [window makeFirstResponder: view]; + + [view updateFrameSize: NO]; + unblock_input (); + } +} +#endif /* NS_IMPL_COCOA */ + +void +x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +/* -------------------------------------------------------------------------- + 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's `left' and `top' parameters specify positions + relative to the top-left corner of its parent frame's native + rectangle. On macOS 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. + + Whether a child frame has a tool bar may be window-system or window + manager dependent. It's advisable to disable it via the frame + parameter settings. + + Some window managers may not honor this parameter. + -------------------------------------------------------------------------- */ +{ + struct frame *p = NULL; + NSWindow *parent, *child; + + 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)) + { + parent = [FRAME_NS_VIEW (p) window]; + child = [FRAME_NS_VIEW (f) window]; + + block_input (); + [parent addChildWindow: child + ordered: NSWindowAbove]; + unblock_input (); + + fset_parent_frame (f, new_value); + } +} + +void +x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +/* 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. + + Some window managers may not honor this parameter. */ +{ + EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); + NSWindow *window = [view window]; + + if (NILP (new_value)) + { + window.level = NSNormalWindowLevel; + FRAME_Z_GROUP (f) = z_group_none; + } + else if (EQ (new_value, Qabove)) + { + window.level = NSNormalWindowLevel + 1; + FRAME_Z_GROUP (f) = z_group_above; + } + else if (EQ (new_value, Qabove_suspended)) + { + /* Not sure what level this should be. */ + window.level = NSNormalWindowLevel + 1; + FRAME_Z_GROUP (f) = z_group_above_suspended; + } + else if (EQ (new_value, Qbelow)) + { + window.level = NSNormalWindowLevel - 1; + FRAME_Z_GROUP (f) = z_group_below; + } + else + error ("Invalid z-group specification"); +} static void ns_fullscreen_hook (struct frame *f) @@ -2683,7 +2822,7 @@ -(void)remove for (i = 0; i < full_height; i++) cbits[i] = bits[i]; - img = [[EmacsImage alloc] initFromXBM: cbits width: 8 + img = [[EmacsImage alloc] XBM: cbits width: 8 height: full_height fg: 0 bg: 0]; bimgs[p->which - 1] = img; @@ -6399,7 +6538,8 @@ - (void) updateFrameSize: (BOOL) delay; newh = (int)wr.size.height - extra; NSTRACE_SIZE ("New size", NSMakeSize (neww, newh)); - NSTRACE_MSG ("tool_bar_height: %d", emacsframe->tool_bar_height); + NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe)); + NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe)); cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww); rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh); @@ -6424,9 +6564,11 @@ - (void) updateFrameSize: (BOOL) delay; SET_FRAME_GARBAGED (emacsframe); cancel_mouse_face (emacsframe); - wr = NSMakeRect (0, 0, neww, newh); + /* The next two lines appear to be setting the frame to the same + size as it already is. Why are they there? */ + // wr = NSMakeRect (0, 0, neww, newh); - [view setFrame: wr]; + // [view setFrame: wr]; // to do: consider using [NSNotificationCenter postNotificationName:]. [self windowDidMove: // Update top/left. @@ -6489,7 +6631,8 @@ - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize old_title = 0; } } - else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize) + else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize + && [[self window] titleVisibility]) { char *size_title; NSWindow *window = [self window]; @@ -6692,6 +6835,34 @@ - (BOOL)isOpaque } +- (void)createToolbar: (struct frame *)f +{ + EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); + NSWindow *window = [view window]; + + toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier: + [NSString stringWithFormat: @"Emacs Frame %d", + ns_window_num]]; + [toolbar setVisible: NO]; + [window setToolbar: toolbar]; + + /* Don't set frame garbaged until tool bar is up to date? + This avoids an extra clear and redraw (flicker) at frame creation. */ + if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES; + else wait_for_tool_bar = NO; + + +#ifdef NS_IMPL_COCOA + { + NSButton *toggleButton; + toggleButton = [window standardWindowButton: NSWindowToolbarButton]; + [toggleButton setTarget: self]; + [toggleButton setAction: @selector (toggleToolbar: )]; + } +#endif +} + + - initFrameFromEmacs: (struct frame *)f { NSRect r, wr; @@ -6729,14 +6900,14 @@ - (BOOL)isOpaque maximizing_resize = NO; #endif - win = [[EmacsWindow alloc] + win = [[EmacsFSWindow alloc] initWithContentRect: r - styleMask: (NSWindowStyleMaskResizable | -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - NSWindowStyleMaskTitled | -#endif - NSWindowStyleMaskMiniaturizable | - NSWindowStyleMaskClosable) + styleMask: (FRAME_UNDECORATED (f) + ? NSWindowStyleMaskBorderless + : NSWindowStyleMaskTitled + | NSWindowStyleMaskResizable + | NSWindowStyleMaskMiniaturizable + | NSWindowStyleMaskClosable) backing: NSBackingStoreBuffered defer: YES]; @@ -6746,7 +6917,6 @@ - (BOOL)isOpaque wr = [win frame]; bwidth = f->border_width = wr.size.width - r.size.width; - tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height; [win setAcceptsMouseMovedEvents: YES]; [win setDelegate: self]; @@ -6766,42 +6936,36 @@ - (BOOL)isOpaque [win setTitle: name]; /* toolbar support */ - toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier: - [NSString stringWithFormat: @"Emacs Frame %d", - ns_window_num]]; - [win setToolbar: toolbar]; - [toolbar setVisible: NO]; - - /* Don't set frame garbaged until tool bar is up to date? - This avoids an extra clear and redraw (flicker) at frame creation. */ - if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES; - else wait_for_tool_bar = NO; - - -#ifdef NS_IMPL_COCOA - { - NSButton *toggleButton; - toggleButton = [win standardWindowButton: NSWindowToolbarButton]; - [toggleButton setTarget: self]; - [toggleButton setAction: @selector (toggleToolbar: )]; - } -#endif - FRAME_TOOLBAR_HEIGHT (f) = 0; + if (! FRAME_UNDECORATED (f)) + [self createToolbar: f]; tem = f->icon_name; if (!NILP (tem)) [win setMiniwindowTitle: [NSString stringWithUTF8String: SSDATA (tem)]]; + if (FRAME_PARENT_FRAME (f) != NULL) + { + NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window]; + [parent addChildWindow: win + ordered: NSWindowAbove]; + } + + if (!NILP (FRAME_Z_GROUP (f))) + win.level = NSNormalWindowLevel + + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1); + { NSScreen *screen = [win screen]; if (screen != 0) { NSPoint pt = NSMakePoint - (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX), + (IN_BOUND (-SCREENMAX, f->left_pos + + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX), IN_BOUND (-SCREENMAX, - [screen frame].size.height - NS_TOP_POS (f), SCREENMAX)); + NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos, + SCREENMAX)); [win setFrameTopLeftPoint: pt]; @@ -6843,9 +7007,15 @@ - (void)windowDidMove: sender return; if (screen != nil) { - emacsframe->left_pos = r.origin.x; + emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe); emacsframe->top_pos = - [screen frame].size.height - (r.origin.y + r.size.height); + NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height); + + if (emacs_event) + { + emacs_event->kind = MOVE_FRAME_EVENT; + EV_TRAILER ((id)nil); + } } } @@ -7262,9 +7432,6 @@ - (void)toggleFullScreen: (id)sender [fw setOpaque: NO]; f->border_width = 0; - FRAME_NS_TITLEBAR_HEIGHT (f) = 0; - tobar_height = FRAME_TOOLBAR_HEIGHT (f); - FRAME_TOOLBAR_HEIGHT (f) = 0; nonfs_window = w; @@ -7298,9 +7465,6 @@ - (void)toggleFullScreen: (id)sender [w setOpaque: NO]; f->border_width = bwidth; - FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height; - if (FRAME_EXTERNAL_TOOL_BAR (f)) - FRAME_TOOLBAR_HEIGHT (f) = tobar_height; // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications. -- 2.12.0 ^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-19 14:33 ` Alan Third @ 2017-04-19 16:01 ` martin rudalics 2017-04-19 17:04 ` Alan Third 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-04-19 16:01 UTC (permalink / raw) To: Alan Third Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren > It turns out that GNUStep doesn’t let you change the decorated state > of an existing window. OK. It's not important that the GNUStep build is capable of doing anything useful. It should build and if possible not crash. The only person currently using it (only for checking whether a change might break the NS build) is me, I presume. > It should be able to create a new undecorated > window. It does so. > I believe it is setting the parent/child relationship, but in GNUStep > it doesn’t seem to mean the child moves with the parent. I think this > is a bug in GNUStep, but the behaviour isn’t documented yet, so I’m > not sure if it’s intentional. > > The child will minimise and close with the parent and moving it to (0 > 0) will put it in the top left corner of the parent. It is created initially at the top left corner of the parent frame and inconifies and deiconifies correctly with its parent. > Except it doesn’t quite, because there’s a hard‐coded titlebar height > for GNUStep which is guaranteed to be wrong for every WM. At least I > think that’s what going on. The top edge is below the native top edge of the parent by a few pixels, maybe the two Anders mentioned. Nothing to worry about. > Z‐groups are working, but again in GNUStep it seems a bit hit and miss > as the frames seem to forget their state if you click on their > titlebars. Don't worry. I just tried to type something and when I reached the right edge of the window I got an abort as 2017-04-19 17:36:59.480 emacs[4423] Problem posting notification: <NSException: 0x4167070> NAME:NSInvalidArgumentException REASON:-[EmacsImage XBM:width:height:fg:bg:]: unrecognized selector sent to instance 0x3e0bf40 INFO:(null) /home/martin/emacs-git/trunk/obj-ns/src/emacs: Uncaught exception NSInvalidArgumentException, reason: -[EmacsImage XBM:width:height:fg:bg:]: unrecognized selector sent to instance 0x3ec20a0 As it is, the GNUStep build is certainly not suited for doing anything useful at the moment. I think you should install your changes so people can test them. In the ChangeLog please fix the below: > (Fx-create_frame): Handle 'z-code', 'parent-frame' and 'undecorated' Fx_create_frame 'z-group' Many thanks, martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-19 16:01 ` martin rudalics @ 2017-04-19 17:04 ` Alan Third 2017-04-19 18:07 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Alan Third @ 2017-04-19 17:04 UTC (permalink / raw) To: martin rudalics Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren On Wed, Apr 19, 2017 at 06:01:52PM +0200, martin rudalics wrote: > > It turns out that GNUStep doesn’t let you change the decorated state > > of an existing window. > > OK. It's not important that the GNUStep build is capable of doing > anything useful. It should build and if possible not crash. The only > person currently using it (only for checking whether a change might > break the NS build) is me, I presume. I have had this suspicion. If I can get it working in GNUStep without too much hassle it’s probably best, though. > I just tried to type something and when I reached the > right edge of the window I got an abort as > > 2017-04-19 17:36:59.480 emacs[4423] Problem posting notification: <NSException: 0x4167070> > NAME:NSInvalidArgumentException REASON:-[EmacsImage XBM:width:height:fg:bg:]: unrecognized selector sent to instance > 0x3e0bf40 INFO:(null) > /home/martin/emacs-git/trunk/obj-ns/src/emacs: Uncaught exception NSInvalidArgumentException, reason: -[EmacsImage > XBM:width:height:fg:bg:]: unrecognized selector sent to instance 0x3ec20a0 That was my fault. I think I mashed the keys in the wrong place and deleted something without realising. I’ve pushed another commit to fix it. (I don’t know how I didn’t notice it before now!) > I think you should install your changes so people can test them. Done. Thanks for your help. Oh, I just remembered I’ve not yet done frame-list-z-order. It should be easy enough, NSApplication has an orderedWindows function which, I think, should return an ordered array of NSWindow objects. Should I look into no-focus-on-map and no-accept-focus too? -- Alan Third ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-19 17:04 ` Alan Third @ 2017-04-19 18:07 ` martin rudalics 2017-06-10 15:38 ` Alan Third 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-04-19 18:07 UTC (permalink / raw) To: Alan Third Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren >> I just tried to type something and when I reached the >> right edge of the window I got an abort as >> >> 2017-04-19 17:36:59.480 emacs[4423] Problem posting notification: <NSException: 0x4167070> >> NAME:NSInvalidArgumentException REASON:-[EmacsImage XBM:width:height:fg:bg:]: unrecognized selector sent to instance >> 0x3e0bf40 INFO:(null) >> /home/martin/emacs-git/trunk/obj-ns/src/emacs: Uncaught exception NSInvalidArgumentException, reason: -[EmacsImage >> XBM:width:height:fg:bg:]: unrecognized selector sent to instance 0x3ec20a0 > > That was my fault. I think I mashed the keys in the wrong place and > deleted something without realising. I’ve pushed another commit to fix > it. Ahh.. it was you. Anyway, works now. And frame restacking works well too. There's only one incredible hassle at the moment which must have started somewhere in 2015. Whenever I mouse scroll a window the menu redraws itself so it flickers continuously. > Oh, I just remembered I’ve not yet done frame-list-z-order. It should > be easy enough, NSApplication has an orderedWindows function which, I > think, should return an ordered array of NSWindow objects. Please do that. > Should I look into no-focus-on-map and no-accept-focus too? That would be fine. There's also the 'skip-taskbar' parameter but I have no idea whether NS allows that and whether NS provides Alt-tabbing. And please have a look into the Elisp manual: Maybe you find something worth mentioning (the fact that removing decorations removes the tool bar should certainly go there). martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-19 18:07 ` martin rudalics @ 2017-06-10 15:38 ` Alan Third 2017-06-11 8:10 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Alan Third @ 2017-06-10 15:38 UTC (permalink / raw) To: martin rudalics Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren I forgot that this bug is still open. Is it waiting for me to finish up the NS stuff? On Wed, Apr 19, 2017 at 08:07:05PM +0200, martin rudalics wrote: > > Oh, I just remembered I’ve not yet done frame-list-z-order. It should > > be easy enough, NSApplication has an orderedWindows function which, I > > think, should return an ordered array of NSWindow objects. > > Please do that. This is done. > > Should I look into no-focus-on-map and no-accept-focus too? > > That would be fine. There's also the 'skip-taskbar' parameter but I > have no idea whether NS allows that and whether NS provides Alt-tabbing. no-accept-focus is done, but no-focus-on-map is harder. I believe I can get a new frame to not be focused on creation, but I don’t see any way to prevent a minimized frame from becoming focused when unminimized. macOS has alt‐tabbing between applications, but also alt‐` switches between application windows. I haven’t yet found a way to disable this. FWIW, no-accept-focus, as implemented, prevents a frame from *ever* accepting focus (although it can still accept input, which is strange!). Rereading your description makes me wonder if I’ve done that wrong and the current behaviour is closer to no-accept-focus, no-focus-on-map and skip-taskbar all being on? I’m not sure I can do it any other way, though. > And please have a look into the Elisp manual: Maybe you find something > worth mentioning (the fact that removing decorations removes the tool > bar should certainly go there). This is done. -- Alan Third ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-06-10 15:38 ` Alan Third @ 2017-06-11 8:10 ` martin rudalics 2017-06-11 16:35 ` Alan Third 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-06-11 8:10 UTC (permalink / raw) To: Alan Third Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren > I forgot that this bug is still open. Is it waiting for me to finish > up the NS stuff? By no means. You've already accomplished much more than I would have expected. I still want to check in the ‘no-special-glyphs’ parameter code mentioned elsewhere in this thread. Then I intend to close this bug. >>> Should I look into no-focus-on-map and no-accept-focus too? >> >> That would be fine. There's also the 'skip-taskbar' parameter but I >> have no idea whether NS allows that and whether NS provides Alt-tabbing. > > no-accept-focus is done, but no-focus-on-map is harder. I believe I > can get a new frame to not be focused on creation, but I don’t see any > way to prevent a minimized frame from becoming focused when > unminimized. Don't worry. Unminimizing is different from mapping. The former works on already mapped frames only, the latter on invisible frames only. "on-map" stands for "on making the frame visible" which might happen some time after the frame was created. Once visible you cannot map the frame until you make it invisible again. Alt-tabbing and unminimizing OTOH work on visible frames only, you cannot really unminimize an invisible window (although the window manager might remember the requested fullscreen status somewhere and later, when it makes the window visible, apply that state). ‘no-focus-on-map’ behaves well for all platforms and builds I tried so far. It would be nice to have it for NS builds too. So all that is afforded by ‘no-focus-on-map’ is that, whenever a frame changes from the invisible to the visible state, it does not get focus. > macOS has alt‐tabbing between applications, but also alt‐` switches > between application windows. I haven’t yet found a way to disable > this. There's certainly no need to do that. I wouldn't even know how to type alt-` with my keyboard layout. > FWIW, no-accept-focus, as implemented, prevents a frame from *ever* > accepting focus (although it can still accept input, which is > strange!). Rereading your description makes me wonder if I’ve done > that wrong and the current behaviour is closer to no-accept-focus, > no-focus-on-map and skip-taskbar all being on? ‘no-accept-focus’ is not overly dear to me. I provided it because it works out of the box on GNU Linux. But the workaround I wrote for Windows is very harsh and I don't recommend it. The idea is to provide a behavior similar to tooltips - you cannot focus a tooltip window - with something like "but you can still focus it via C-x 5 o, if you need to". > I’m not sure I can do it any other way, though. Never mind. If it has some very special behavior and you feel like it, add a remark about it in the Elisp documentation. >> And please have a look into the Elisp manual: Maybe you find something >> worth mentioning (the fact that removing decorations removes the tool >> bar should certainly go there). This one still stupefies me because it's a deviation from the other builds. It certainly should be documented. Did you document that a fullscreen NS screen doesn't have a toolbar either? BTW, I meanwhile wrote some code to resize and move undecorated frames with the mouse. For this purpose I need some mouse pointers indicating that a frame corner (not a frame edge) can be dragged. Under X I use XC_top_left_corner, XC_top_right_corner, ... On Windows I use the IDC_SIZENWSE and IDC_SIZENESW arrows. I have not found any equivalent for NS. How does NS indicate that the corner of a decorated frame can be dragged when the mouse is over it? Thanks for all your work, martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-06-11 8:10 ` martin rudalics @ 2017-06-11 16:35 ` Alan Third 2017-06-12 6:09 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Alan Third @ 2017-06-11 16:35 UTC (permalink / raw) To: martin rudalics Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren [-- Attachment #1: Type: text/plain, Size: 2933 bytes --] On Sun, Jun 11, 2017 at 10:10:44AM +0200, martin rudalics wrote: > > no-accept-focus is done, but no-focus-on-map is harder. I believe I > > can get a new frame to not be focused on creation, but I don’t see any > > way to prevent a minimized frame from becoming focused when > > unminimized. > > Don't worry. Unminimizing is different from mapping. The former works > on already mapped frames only, the latter on invisible frames only. > "on-map" stands for "on making the frame visible" which might happen > some time after the frame was created. Once visible you cannot map the > frame until you make it invisible again. > > Alt-tabbing and unminimizing OTOH work on visible frames only, you > cannot really unminimize an invisible window (although the window > manager might remember the requested fullscreen status somewhere and > later, when it makes the window visible, apply that state). > > ‘no-focus-on-map’ behaves well for all platforms and builds I tried so > far. It would be nice to have it for NS builds too. So all that is > afforded by ‘no-focus-on-map’ is that, whenever a frame changes from the > invisible to the visible state, it does not get focus. Your explanation made it much clearer what was required. I believe I’ve got it sorted now. I’ve attached a patch. > >> And please have a look into the Elisp manual: Maybe you find something > >> worth mentioning (the fact that removing decorations removes the tool > >> bar should certainly go there). > > This one still stupefies me because it's a deviation from the other > builds. It certainly should be documented. Did you document that a > fullscreen NS screen doesn't have a toolbar either? It actually does, it’s just hidden, along with the title‐bar and menu‐bar. At least that’s how it works on macOS, I’m unsure how GNUStep deals with full‐screen as it’s using a different mechanism, if it handles it at all. I’m struggling to find where this should be documented. Any ideas which part of the manual covers full‐screen? > BTW, I meanwhile wrote some code to resize and move undecorated frames > with the mouse. For this purpose I need some mouse pointers indicating > that a frame corner (not a frame edge) can be dragged. Under X I use > XC_top_left_corner, XC_top_right_corner, ... On Windows I use the > IDC_SIZENWSE and IDC_SIZENESW arrows. I have not found any equivalent > for NS. How does NS indicate that the corner of a decorated frame can > be dragged when the mouse is over it? macOS uses double‐headed diagonal arrows, but they’re undocumented: https://stackoverflow.com/questions/27242353/cocoa-predefined-resize-mouse-cursor GNUStep doesn’t implement them and doesn’t seem to have any equivalent. On macOS we can actually make undecorated frames resizable quite easily just by including the resizable style mask. GNUstep doesn’t like that, of course. -- Alan Third [-- Attachment #2: 0001-Add-no-focus-on-map-to-NS-build-bug-25408.patch --] [-- Type: text/plain, Size: 4608 bytes --] From 72ec4de5701cb3029cb3ae2c4c3262144c4eff76 Mon Sep 17 00:00:00 2001 From: Alan Third <alan@idiocy.org> Date: Sun, 11 Jun 2017 17:07:28 +0100 Subject: [PATCH] Add no-focus-on-map to NS build (bug#25408) * src/nsfns.m (ns_frame_parm_handlers): Add x_set_no_focus_on_map. (x-create-frame): Check for no-focus-on-map. * src/nsterm.h (x_set_no_focus_on_map): New function. * src/nsterm.m (x_set_no_focus_on_map): New function. (ns_raise_frame): Add parameter for specifying whether to focus the frame. (ns_frame_raise_lower): (x_make_frame_visible): Handle new parameter for ns_raise_frame. --- src/nsfns.m | 4 +++- src/nsterm.h | 2 ++ src/nsterm.m | 33 +++++++++++++++++++++++++++++---- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/nsfns.m b/src/nsfns.m index 0c865070fb..dbce279da6 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -980,7 +980,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side #endif x_set_parent_frame, 0, /* x_set_skip_taskbar */ - 0, /* x_set_no_focus_on_map */ + x_set_no_focus_on_map, x_set_no_accept_focus, x_set_z_group, /* x_set_z_group */ 0, /* x_set_override_redirect */ @@ -1288,6 +1288,8 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side store_frame_param (f, Qparent_frame, parent_frame); x_default_parameter (f, parms, Qz_group, Qnil, NULL, NULL, RES_TYPE_SYMBOL); + 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); diff --git a/src/nsterm.h b/src/nsterm.h index f75e3759e4..bed0b92c79 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -1218,6 +1218,8 @@ extern void x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value); extern void x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value); +extern void x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, + Lisp_Object old_value); extern void x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value); extern void x_set_z_group (struct frame *f, Lisp_Object new_value, diff --git a/src/nsterm.m b/src/nsterm.m index 633ca3bf76..b298e4a153 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1463,7 +1463,7 @@ -(void)remove static void -ns_raise_frame (struct frame *f) +ns_raise_frame (struct frame *f, BOOL make_key) /* -------------------------------------------------------------------------- Bring window to foreground and make it active -------------------------------------------------------------------------- */ @@ -1474,7 +1474,12 @@ -(void)remove view = FRAME_NS_VIEW (f); block_input (); if (FRAME_VISIBLE_P (f)) - [[view window] makeKeyAndOrderFront: NSApp]; + { + if (make_key) + [[view window] makeKeyAndOrderFront: NSApp]; + else + [[view window] orderFront: NSApp]; + } unblock_input (); } @@ -1504,7 +1509,7 @@ -(void)remove NSTRACE ("ns_frame_raise_lower"); if (raise) - ns_raise_frame (f); + ns_raise_frame (f, YES); else ns_lower_frame (f); } @@ -1567,7 +1572,7 @@ -(void)remove EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); SET_FRAME_VISIBLE (f, 1); - ns_raise_frame (f); + ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f)); /* Making a new frame from a fullscreen frame will make the new frame fullscreen also. So skip handleFS as this will print an error. */ @@ -1926,6 +1931,26 @@ so some key presses (TAB) are swallowed by the system. */ } } +/** + * 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. + */ +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); + } +} + void x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) /* Set frame F's `no-accept-focus' parameter which, if non-nil, hints -- 2.12.0 ^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-06-11 16:35 ` Alan Third @ 2017-06-12 6:09 ` martin rudalics 2017-06-12 17:59 ` Alan Third 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-06-12 6:09 UTC (permalink / raw) To: Alan Third Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren > Your explanation made it much clearer what was required. I believe > I’ve got it sorted now. I’ve attached a patch. The second part of this comment /* -------------------------------------------------------------------------- Bring window to foreground and make it active -------------------------------------------------------------------------- */ seems to be a bit misleading then. > I’m struggling to find where this should be documented. Any ideas > which part of the manual covers full‐screen? The Elisp manual in section 29.4.3.3 Size Parameters. > macOS uses double‐headed diagonal arrows, but they’re undocumented: > > https://stackoverflow.com/questions/27242353/cocoa-predefined-resize-mouse-cursor In NSCursor.h I can find these + (id)_windowResizeNorthWestSouthEastCursor; + (id)_windowResizeNorthEastSouthWestCursor; But there I see also + (id)_windowResizeSouthWestCursor; + (id)_windowResizeSouthEastCursor; + (id)_windowResizeNorthWestCursor; + (id)_windowResizeNorthEastCursor; so NS apparently can implement both, the X and the Windows ones. > GNUStep doesn’t implement them and doesn’t seem to have any > equivalent. > > On macOS we can actually make undecorated frames resizable quite > easily just by including the resizable style mask. GNUstep doesn’t > like that, of course. I added code for manual mouse-moving and -resizing of frames because under X there's apparently no support to do that for child frames. Since the Windows API provides such support I have to find some substitute on X and want to make that as uniform as possible for other platforms as well. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-06-12 6:09 ` martin rudalics @ 2017-06-12 17:59 ` Alan Third 2017-06-13 7:24 ` martin rudalics 2017-06-22 9:10 ` martin rudalics 0 siblings, 2 replies; 85+ messages in thread From: Alan Third @ 2017-06-12 17:59 UTC (permalink / raw) To: martin rudalics Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren On Mon, Jun 12, 2017 at 08:09:03AM +0200, martin rudalics wrote: > > Your explanation made it much clearer what was required. I believe > > I’ve got it sorted now. I’ve attached a patch. > > The second part of this comment > > /* -------------------------------------------------------------------------- > Bring window to foreground and make it active > -------------------------------------------------------------------------- */ > > seems to be a bit misleading then. Very good point. I’ve fixed it and pushed it to master. Anything else you’d like me to look at here? -- Alan Third ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-06-12 17:59 ` Alan Third @ 2017-06-13 7:24 ` martin rudalics 2017-06-22 9:10 ` martin rudalics 1 sibling, 0 replies; 85+ messages in thread From: martin rudalics @ 2017-06-13 7:24 UTC (permalink / raw) To: Alan Third Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren > Very good point. I’ve fixed it and pushed it to master. Thanks. > Anything else you’d like me to look at here? For the moment no. I'll get back to you when I push the remaining parts of the child frame code. Thanks again for all the good work, martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-06-12 17:59 ` Alan Third 2017-06-13 7:24 ` martin rudalics @ 2017-06-22 9:10 ` martin rudalics 2017-06-25 14:22 ` Alan Third 1 sibling, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-06-22 9:10 UTC (permalink / raw) To: Alan Third Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren [-- Attachment #1: Type: text/plain, Size: 1097 bytes --] > Anything else you’d like me to look at here? Attached find the changes I intend to push in the next few days plus a ChangeLog. You will find this particular change there: + f->output_data.ns->left_edge_cursor = [NSCursor resizeLeftRightCursor]; + f->output_data.ns->top_left_corner_cursor = [NSCursor arrowCursor]; + f->output_data.ns->top_edge_cursor = [NSCursor resizeUpDownCursor]; + f->output_data.ns->top_right_corner_cursor = [NSCursor arrowCursor]; + f->output_data.ns->right_edge_cursor = [NSCursor resizeLeftRightCursor]; + f->output_data.ns->bottom_right_corner_cursor = [NSCursor arrowCursor]; + f->output_data.ns->bottom_edge_cursor = [NSCursor resizeUpDownCursor]; + f->output_data.ns->bottom_left_corner_cursor = [NSCursor arrowCursor]; It would be nice to have something better on NS for the top_left_corner_cursor, top_right_corner_cursor, bottom_right_corner_cursor and bottom_left_corner_cursor cases. If you want to play around with child frames, try the attached file my-child-frame.el. Any feedback welcome. Thanks in advance, martin [-- Attachment #2: child-frames.diff --] [-- Type: text/plain, Size: 216179 bytes --] diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 4de55fd..04c5ba2 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -1974,6 +1974,71 @@ Size of Displayed Text height of both, if present, in the return value. @end defun +@code{window-text-pixel-size} treats the text displayed in a window as a +whole and does not care about the size of individual lines. The +following function does. + +@defun window-lines-pixel-dimensions &optional window first last body inverse +This function calculates the pixel dimensions of each line displayed in +the specified @var{window}. It does so by walking @var{window}'s +current glyph matrix---a matrix storing the glyph (@pxref{Glyphs}) of +each buffer character currently displayed in @var{window}. If +successful, it returns a list of cons pairs representing the x- and +y-coordinates of the lower right corner of the last character of each +line. Coordinates are measured in pixels from an origin (0, 0) at the +top-left corner of @var{window}. @var{window} must be a live window and +defaults to the selected one. + +If the optional argument @var{first} is an integer, it denotes the index +(starting with 0) of the first line of @var{window}'s glyph matrix to be +returned. Note that if @var{window} has a header line, the line with +index 0 is that header line. If @var{first} is nil, the first line to +be considered is determined by the value of the optional argument +@var{body}: If @var{body} is non-@code{nil}, this means to start with +the first line of @var{window}'s body, skipping any header line, if +present. Otherwise, this function will start with the first line of +@var{window}'s glyph matrix, possibly the header line. + +If the optional argument @var{last} is an integer, it denotes the index +of the last line of @var{window}'s glyph matrix that shall be returned. +If @var{last} is nil, the last line to be considered is determined by +the value of @var{body}: If @var{body} is non-@code{nil}, this means to +use the last line of @var{window}'s body, omitting @var{window}'s mode +line, if present. Otherwise, this means to use the last line of +@var{window} which may be the mode line. + +The optional argument @var{inverse}, if @code{nil}, means that the +y-pixel value returned for any line specifies the distance in pixels +from the left edge (body edge if @var{body} is non-@code{nil}) of +@var{window} to the right edge of the last glyph of that line. +@var{inverse} non-@code{nil} means that the y-pixel value returned for +any line specifies the distance in pixels from the right edge of the +last glyph of that line to the right edge (body edge if @var{body} is +non-@code{nil}) of @var{window}. This is useful for determining the +amount of slack space at the end of each line. + +The optional argument @var{left}, if non-@code{nil} means to return the +x- and y-coordinates of the lower left corner of the leftmost character +on each line. This is the value that should be used for windows that +mostly display text from right to left. + +If @var{left} is non-@code{nil} and @var{inverse} is @code{nil}, this +means that the y-pixel value returned for any line specifies the +distance in pixels from the left edge of the last (leftmost) glyph of +that line to the right edge (body edge if @var{body} is non-@code{nil}) +of @var{window}. If @var{left} and @var{inverse} are both +non-@code{nil}, the y-pixel value returned for any line specifies the +distance in pixels from the left edge (body edge if @var{body} is +non-@code{nil}) of @var{window} to the left edge of the last (leftmost) +glyph of that line. + +This function returns @code{nil} if the current glyph matrix of +@var{window} is not up-to-date which usually happens when Emacs is busy, +for example, when processing a command. The value should be retrievable +though when this function is run from an idle timer with a delay of zero +seconds. +@end defun + @defun line-pixel-height This function returns the height in pixels of the line at point in the selected window. The value includes the line spacing of the line diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index 7cc91a8..4bedea3 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -1130,6 +1130,8 @@ Top * Buffer Parameters:: Which buffers have been or should be shown. * Frame Interaction Parameters:: Parameters for interacting with other frames. +* Mouse Dragging Parameters:: Parameters for resizing and moving + frames with the mouse. * Management Parameters:: Communicating with the window manager. * Cursor Parameters:: Controlling the cursor appearance. * Font and Color Parameters:: Fonts and colors for the frame text. diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index 50467d1..b430f7c 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -974,14 +974,7 @@ Frame Size the help of an X-style geometry specification. @xref{Emacs Invocation,, Command Line Arguments for Emacs Invocation, emacs, The GNU Emacs Manual}. Below we list some functions to access and set the size of an -existing, visible frame. - -@defun frame-text-height &optional frame -@defunx frame-text-width &optional frame -These functions return the height and width of the text area of -@var{frame} (@pxref{Frame Layout}), measured in pixels. For a text -terminal, the results are in characters rather than pixels. -@end defun +existing, visible frame, by default the selected one. @defun frame-height &optional frame @defunx frame-width &optional frame @@ -997,11 +990,33 @@ Frame Size fit into the text area. @end defun -@defun frame-pixel-height &optional frame -@defunx frame-pixel-width &optional frame -These functions return the native width and height, see @ref{Frame -Layout}) of @var{frame} in pixels. For a text terminal, the results are -in characters rather than pixels. +The functions following next return the pixel widths and heights of the +native, outer and inner frame and the text area (@pxref{Frame Layout}) +of a given frame. For a text terminal, the results are in characters +rather than pixels. + +@defun frame-outer-width &optional frame +@defunx frame-outer-height &optional frame +These functions return the outer width and height of @var{frame} in +pixels. +@end defun + +@defun frame-native-height &optional frame +@defunx frame-native-width &optional frame +These functions return the native width and height of @var{frame} in +pixels. +@end defun + +@defun frame-inner-width &optional frame +@defunx frame-inner-height &optional frame +These functions return the inner width and height of @var{frame} in +pixels. +@end defun + +@defun frame-text-width &optional frame +@defunx frame-text-height &optional frame +These functions return the width and height of the text area of +@var{frame} in pixels. @end defun On window systems that support it, Emacs tries by default to make the @@ -1345,6 +1360,8 @@ Window Frame Parameters * Buffer Parameters:: Which buffers have been or should be shown. * Frame Interaction Parameters:: Parameters for interacting with other frames. +* Mouse Dragging Parameters:: Parameters for resizing and moving + frames with the mouse. * Management Parameters:: Communicating with the window manager. * Cursor Parameters:: Controlling the cursor appearance. * Font and Color Parameters:: Fonts and colors for the frame text. @@ -1404,18 +1421,19 @@ Position Parameters @cindex frame position Parameters describing the X- and Y-offsets of a frame are always -measured in pixels. For normal, non-child frames they specify the -frame's absolute outer position (@pxref{Frame Geometry}) with respect to -its display's origin. For a child frame (@pxref{Child Frames}) they -specify the frame's outer position relative to the native position of -the frame's parent frame. (Note that none of these parameters is -meaningful on TTY frames.) +measured in pixels. For a normal, non-child frame they specify the +frame's outer position (@pxref{Frame Geometry}) relative to its +display's origin. For a child frame (@pxref{Child Frames}) they specify +the frame's outer position relative to the native position of the +frame's parent frame. (Note that none of these parameters is meaningful +on TTY frames.) @table @code @vindex left, a frame parameter @item left The position, in pixels, of the left outer edge of the frame with -respect to the left edge of the frame's display or parent frame. +respect to the left edge of the frame's display or parent frame. It can +be specified in one of the following ways. @table @asis @item an integer @@ -1436,6 +1454,30 @@ Position Parameters positive or negative; a negative value specifies a position outside the screen or parent frame or on a monitor other than the primary one (for multi-monitor displays). + +@cindex left position ratio +@cindex top position ratio +@item a floating-point value +A floating-point value in the range 0.0 to 1.0 specifies the left edge's +offset via the @dfn{left position ratio} of the frame---the ratio of the +left edge of its outer frame to the width of the frame's workarea +(@pxref{Multiple Terminals}) or its parent's native frame (@pxref{Child +Frames}) minus the width of the outer frame. Thus, a left position +ratio of 0.0 flushes a frame to the left, a ratio of 0.5 centers it and +a ratio of 1.0 flushes it to the right of its display or parent frame. +Similarly, the @dfn{top position ratio} of a frame is the ratio of the +frame's top position to the height of its workarea or parent frame minus +the height of the frame. + +Emacs will try to keep the position ratios of a child frame unaltered if +that frame has a non-@code{nil} @code{keep-ratio} parameter +(@pxref{Frame Interaction Parameters}) and its parent frame is resized. + +Since the outer size of a frame (@pxref{Frame Geometry}) is usually +unavailable before a frame has been made visible, it is generally not +advisable to use floating-point values when creating decorated frames. +Floating-point values are more suited for ensuring that an (undecorated) +child frame is positioned nicely within the area of its parent frame. @end table Some window managers ignore program-specified positions. If you want to @@ -1448,17 +1490,19 @@ Position Parameters nil '((user-position . t) (left . (+ -4)))) @end example -In general, it is not a good idea to specify negative offsets to -position a frame relative to the right or bottom edge of its display. -Positioning the initial or a new frame is either not accurate (because -the size of the outer frame is not yet fully known before the frame has -been made visible) or will cause additional flicker (if the frame is -repositioned after becoming visible). +In general, it is not a good idea to position a frame relative to the +right or bottom edge of its display. Positioning the initial or a new +frame is either not accurate (because the size of the outer frame is not +yet fully known before the frame has been made visible) or will cause +additional flicker (if the frame has to be repositioned after becoming +visible). - Note also, that negative offsets are not stored internally and are not -returned by the function @code{frame-parameters}. This means that the -desktop saving routines will restore the frame from the positive offsets -obtained by that function. + Note also, that positions specified relative to the right/bottom edge +of a display, workarea or parent frame as well as floating-point offsets +are stored internally as integer offsets relative to the left/top edge +of the display, workarea or parent frame edge. They are also returned +as such by functions like @code{frame-parameters} and restored as such +by the desktop saving routines. @vindex top, a frame parameter @item top @@ -1523,24 +1567,61 @@ Size Parameters @subsubsection Size Parameters @cindex window size on display - Frame parameters specify frame sizes in character units. On -graphical displays, the @code{default} face determines the actual -pixel sizes of these character units (@pxref{Face Attributes}). +Frame parameters usually specify frame sizes in character units. On +graphical displays, the @code{default} face determines the actual pixel +sizes of these character units (@pxref{Face Attributes}). @table @code @vindex width, a frame parameter @item width -The width of the frame's text area (@pxref{Frame Geometry}), in -characters. The value can be also a cons cell of the symbol -@code{text-pixels} and an integer denoting the width of the text area in -pixels. +This parameter specifies the width of the frame. It can be specified as +in the following ways: + +@table @asis +@item an integer +A positive integer specifies the width of the frame's text area +(@pxref{Frame Geometry}) in characters. + +@item a cons cell +If this is a cons cell with the symbol @code{text-pixels} in its +@sc{car}, the @sc{cdr} of that cell specifies the width of the frame's +text area in pixels. + +@cindex frame width ratio +@cindex frame height ratio +@item a floating-point value +A floating-point number between 0.0 and 1.0 can be used to specify the +width of a frame via its @dfn{width ratio}---the ratio of its outer +width (@pxref{Frame Geometry}) to the width of the frame's workarea +(@pxref{Multiple Terminals}) or its parent frame's (@pxref{Child +Frames}) native frame. Thus, a value of 0.5 makes the frame occupy half +of the width of its workarea or parent frame, a value of 1.0 the full +width. Similarly, the @dfn{height ratio} of a frame is the ratio of its +outer height to the height of its workarea or its parent's native frame. + +Emacs will try to keep the width and height ratio of a child frame +unaltered if that frame has a non-@code{nil} @code{keep-ratio} parameter +(@pxref{Frame Interaction Parameters}) and its parent frame is resized. + +Since the outer size of a frame is usually unavailable before a frame +has been made visible, it is generally not advisable to use +floating-point values when creating decorated frames. Floating-point +values are more suited to ensure that a child frame always fits within +the area of its parent frame as, for example, when customizing +@code{display-buffer-alist} (@pxref{Choosing Window}) via +@code{display-buffer-in-child-frame}. +@end table + +Regardless of how this parameter was specified, functions reporting the +value of this parameter like @code{frame-parameters} always report the +width of the frame's text area in characters as an integer rounded, if +necessary, to a multiple of the frame's default character width. That +value is also used by the desktop saving routines. @vindex height, a frame parameter @item height -The height of the frame's text area (@pxref{Frame Geometry}), in -characters. The value can be also a cons cell of the symbol -@code{text-pixels} and an integer denoting the height of the text area -in pixels. +This parameter specifies the height of the frame. It works just like +@code{width}, except vertically instead of horizontally. @vindex user-size, a frame parameter @item user-size @@ -1551,25 +1632,25 @@ Size Parameters @vindex min-width, a frame parameter @item min-width -This parameter specifies the minimum native width of the frame -(@pxref{Frame Geometry}), in characters. Normally, the functions that +This parameter specifies the minimum native width (@pxref{Frame +Geometry}) of the frame, in characters. Normally, the functions that establish a frame's initial width or resize a frame horizontally make sure that all the frame's windows, vertical scroll bars, fringes, margins and vertical dividers can be displayed. This parameter, if non-@code{nil} allows to make a frame narrower than that with the -consequence that any components that do not fit on the frame will be -clipped by the window manager. +consequence that any components that do not fit will be clipped by the +window manager. @vindex min-height, a frame parameter @item min-height -This parameter specifies the minimum height of the native (@pxref{Frame -Geometry}), in characters. Normally, the functions that establish a -frame's initial size or resize a frame make sure that all the frame's -windows, horizontal scroll bars and dividers, mode and header lines, the -echo area and the internal menu and tool bar can be displayed. This -parameter, if non-@code{nil} allows to make a frame smaller than that -with the consequence that any components that do not fit on the frame -will be clipped by the window-system or window manager. +This parameter specifies the minimum native height (@pxref{Frame +Geometry}) of the frame, in characters. Normally, the functions that +establish a frame's initial size or resize a frame make sure that all +the frame's windows, horizontal scroll bars and dividers, mode and +header lines, the echo area and the internal menu and tool bar can be +displayed. This parameter, if non-@code{nil} allows to make a frame +smaller than that with the consequence that any components that do not +fit will be clipped by the window manager. @cindex fullboth frames @cindex fullheight frames @@ -1623,6 +1704,20 @@ Size Parameters This will give a new frame full height after typing in it @key{F11} for the first time. + +@vindex fit-frame-to-buffer-margins, a frame parameter +@item fit-frame-to-buffer-margins +This parameter allows to override the value of the option +@code{fit-frame-to-buffer-margins} when fitting this frame to the buffer +of its root window with @code{fit-frame-to-buffer} (@pxref{Resizing +Windows}). + +@vindex fit-frame-to-buffer-sizes, a frame parameter +@item fit-frame-to-buffer-sizes +This parameter allows to override the value of the option +@code{fit-frame-to-buffer-sizes} when fitting this frame to the buffer +of its root window with @code{fit-frame-to-buffer} (@pxref{Resizing +Windows}). @end table @@ -1646,9 +1741,9 @@ Layout Parameters @vindex vertical-scroll-bars, a frame parameter @item vertical-scroll-bars -Whether the frame has scroll bars for vertical scrolling, and which side -of the frame they should be on. The possible values are @code{left}, -@code{right}, and @code{nil} for no scroll bars. +Whether the frame has scroll bars (@pxref{Scroll Bars}) for vertical +scrolling, and which side of the frame they should be on. The possible +values are @code{left}, @code{right}, and @code{nil} for no scroll bars. @vindex horizontal-scroll-bars, a frame parameter @item horizontal-scroll-bars @@ -1692,30 +1787,40 @@ Layout Parameters @vindex menu-bar-lines frame parameter @item menu-bar-lines -The number of lines to allocate at the top of the frame for a menu bar. -The default is one if Menu Bar mode is enabled and zero otherwise. -@xref{Menu Bars,,,emacs, The GNU Emacs Manual}. For an external menu -bar, this value remains unchanged even when the menu bar wraps to two or -more lines. In that case, the @code{menu-bar-size} value returned by -@code{frame-geometry} (@pxref{Frame Geometry}) allows to derive whether -the menu bar actually occupies one or more lines. +The number of lines to allocate at the top of the frame for a menu bar +(@pxref{Menu Bar}). The default is one if Menu Bar mode is enabled and +zero otherwise. @xref{Menu Bars,,,emacs, The GNU Emacs Manual}. For an +external menu bar (@pxref{Frame Layout}), this value remains unchanged +even when the menu bar wraps to two or more lines. In that case, the +@code{menu-bar-size} value returned by @code{frame-geometry} +(@pxref{Frame Geometry}) allows to derive whether the menu bar actually +occupies one or more lines. @vindex tool-bar-lines frame parameter @item tool-bar-lines -The number of lines to use for the tool bar. The default is one if Tool -Bar mode is enabled and zero otherwise. @xref{Tool Bars,,,emacs, The -GNU Emacs Manual}. This value may change whenever the tool bar wraps. +The number of lines to use for the tool bar (@pxref{Tool Bar}). The +default is one if Tool Bar mode is enabled and zero otherwise. +@xref{Tool Bars,,,emacs, The GNU Emacs Manual}. This value may change +whenever the tool bar wraps (@pxref{Frame Layout}). @vindex tool-bar-position frame parameter @item tool-bar-position -The position of the tool bar. Currently only for the GTK tool bar. -Value can be one of @code{top}, @code{bottom} @code{left}, @code{right}. -The default is @code{top}. +The position of the tool bar when Emacs was built with GTK+. Its value +can be one of @code{top}, @code{bottom} @code{left}, @code{right}. The +default is @code{top}. @vindex line-spacing, a frame parameter @item line-spacing Additional space to leave below each text line, in pixels (a positive integer). @xref{Line Height}, for more information. + +@vindex no-special-glyphs, a frame parameter +@item no-special-glyphs +If this is non-@code{nil}, it suppresses the display of any truncation +and continuation glyphs (@pxref{Truncation}) for all buffers displayed +by this frame. This is useful to eliminate such glyphs when fitting a +frame to its buffer via @code{fit-frame-to-buffer} (@pxref{Resizing +Windows}). @end table @@ -1781,15 +1886,115 @@ Frame Interaction Parameters @item mouse-wheel-frame If non-@code{nil}, this parameter specifies the frame whose windows will be scrolled whenever the mouse wheel is scrolled with the mouse pointer -hovering over this frame (@pxref{Mouse Commands,,, emacs, The GNU Emacs -Manual}). +hovering over this frame, see @ref{Mouse Commands,,, emacs, The GNU +Emacs Manual}. @vindex no-other-frame, a frame parameter @item no-other-frame If this is non-@code{nil}, then this frame is not eligible as candidate for the functions @code{next-frame}, @code{previous-frame} -(@pxref{Finding All Frames}) and @code{other-frame} (@pxref{Frame -Commands,,, emacs, The GNU Emacs Manual}). +(@pxref{Finding All Frames}) and @code{other-frame}, see @ref{Frame +Commands,,, emacs, The GNU Emacs Manual}. + +@vindex auto-hide-function, a frame parameter +@item auto-hide-function +When this parameter specifies a function, that function will be called +instead of the function specified by the variable +@code{frame-auto-hide-function} when quitting the frame's only window +(@pxref{Quitting Windows}) and there are other frames left. + +@vindex minibuffer-exit, a frame parameter +@item minibuffer-exit +When this parameter is non-@code{nil}, Emacs will by default make this +frame invisible whenever the minibuffer (@pxref{Minibuffers}) is exited. +Alternatively, it can specify the functions @code{iconify-frame} and +@code{delete-frame}. This parameter is useful to make a child frame +disappear automatically (similar to how Emacs deals with a window) when +exiting the minibuffer. + +@vindex keep-ratio, a frame parameter +@item keep-ratio +This parameter is currently meaningful for child frames (@pxref{Child +Frames}) only. If it is non-@code{nil}, then Emacs will try to keep the +frame's size (width and height) ratios (@pxref{Size Parameters}) as well +as its left and right position ratios (@pxref{Position Parameters}) +unaltered whenever its parent frame is resized. + +If the value of this parameter is @code{nil}, the frame's position and +size remain unaltered when the parent frame is resized, so the position +and size ratios may change. If the value of this parameter is @code{t}, +Emacs will try to preserve the frame's size and position ratios, hence +the frame's size and position relative to its parent frame may change. + +More individual control is possible by using a cons cell: In that case +the frame's width ratio is preserved if the @sc{car} of the cell is +either @code{t} or @code{width-only}. The height ratio is preserved if +the @sc{car} of the cell is either @code{t} or @code{height-only}. The +left position ratio is preserved if the @sc{cdr} of the cell is either +@code{t} or @code{left-only}. The top position ratio is preserved if +the @sc{cdr} of the cell is either @code{t} or @code{top-only}. +@end table + + +@node Mouse Dragging Parameters +@subsubsection Mouse Dragging Parameters +@cindex mouse dragging parameters +@cindex parameters for resizing frames with the mouse +@cindex parameters for moving frames with the mouse + +The parameters described below provide support for resizing a frame by +dragging its internal borders with the mouse. They also allow moving a +frame with the mouse by dragging the header line of its topmost or the +mode line of its bottommost window. + +These parameters are mostly useful for child frames (@pxref{Child +Frames}) that come without window manager decorations. If necessary, +they can be used for undecorated top-level frames as well. + +@table @code +@vindex drag-internal-border, a frame parameter +@item drag-internal-border +If non-@code{nil}, the frame can be resized by dragging its internal +borders, if present, with the mouse. + +@vindex drag-with-header-line, a frame parameter +@item drag-with-header-line +If non-@code{nil}, the frame can be moved with the mouse by dragging the +header line of its topmost window. + +@vindex drag-with-mode-line, a frame parameter +@item drag-with-mode-line +If non-@code{nil}, the frame can be moved with the mouse by dragging the +mode line of its bottommost window. Note that such a frame is not +allowed to have its own minibuffer window. + +@vindex snap-width, a frame parameter +@item snap-width +A frame that is moved with the mouse will ``snap'' at the border(s) of +the display or its parent frame whenever it is dragged as near to such +an edge as the number of pixels specified by this parameter. + +@vindex top-visible, a frame parameter +@item top-visible +If this parameter is a number, the top edge of the frame never appears +above the top edge of its display or parent frame. Moreover, as many +pixels of the frame as specified by that number will remain visible when +the frame is moved against any of the remaining edges of its display or +parent frame. Setting this parameter is useful to guard against +dragging a child frame with a non-@code{nil} +@code{drag-with-header-line} parameter completely out of the area +of its parent frame. + +@vindex bottom-visible, a frame parameter +@item bottom-visible +If this parameter is a number, the bottom edge of the frame never +appears below the bottom edge of its display or parent frame. Moreover, +as many pixels of the frame as specified by that number will remain +visible when the frame is moved against any of the remaining edges of +its display or parent frame. Setting this parameter is useful to guard +against dragging a child frame with a non-@code{nil} +@code{drag-with-mode-line} parameter completely out of the area of +its parent frame. @end table @@ -1797,9 +2002,9 @@ Management Parameters @subsubsection Window Management Parameters @cindex window manager interaction, and frame parameters - The following frame parameters control various aspects of the -frame's interaction with the window manager. They have no effect on -text terminals. + The following frame parameters control various aspects of the frame's +interaction with the window manager or window system. They have no +effect on text terminals. @table @code @vindex visibility, a frame parameter @@ -1908,7 +2113,8 @@ Management Parameters frame---a frame not handled by window managers under X. Override redirect frames have no window manager decorations, can be positioned and resized only via Emacs' positioning and resizing functions and are -usually drawn on top of all other frames. +usually drawn on top of all other frames. Setting this parameter has +no effect on MS-Windows. @ignore @vindex parent-id, a frame parameter @@ -2080,6 +2286,9 @@ Font and Color Parameters @code{(@var{active} . @var{inactive})}, where @var{active} is the opacity of the frame when it is selected, and @var{inactive} is the opacity when it is not selected. + +Some window systems do not support the @code{alpha} parameter for child +frames (@pxref{Child Frames}). @end table The following frame parameters are semi-obsolete in that they are @@ -2824,57 +3033,78 @@ Child Frames @cindex child frames @cindex parent frames -On some window-systems the @code{parent-frame} parameter (@pxref{Frame -Interaction Parameters}) can be used to make a frame a child of the -frame specified by that parameter. The frame specified by that -parameter will then be the frame's parent frame as long as the parameter -is not changed or reset. Technically, this makes the child frame's -window-system window a child window of the parent frame's window-system -window. +Child frames are objects halfway between windows (@pxref{Windows}) and +``normal'' frames. Like windows, they are attached to an owning frame. +Unlike windows, they may overlap each other---changing the size or +position of one child frame does not change the size or position of any +of its sibling child frames. + + By design, operations to make or modify child frames are implemented +with the help of frame parameters (@pxref{Frame Parameters}) without any +specialized functions or customizable variables. Note that child frames +are meaningful on graphical terminals only. + + To create a new child frame or to convert a normal frame into a child +frame, set that frame's @code{parent-frame} parameter (@pxref{Frame +Interaction Parameters}) to that of an already existing frame. The +frame specified by that parameter will then be the frame's parent frame +as long as the parameter is not changed or reset. Technically, this +makes the child frame's window-system window a child window of the +parent frame's window-system window. +@cindex top-level frame +@cindex reparent frame +@cindex nest frame The @code{parent-frame} parameter can be changed at any time. Setting -it to another frame ``reparents'' the child frame. Setting it to -another child frame makes the frame a ``nested'' child frame. Setting -it to @code{nil} restores the frame's status as a top-level frame---one -whose window-system window is a child of its display's root window. +it to another frame @dfn{reparents} the child frame. Setting it to +another child frame makes the frame a @dfn{nested} child frame. Setting +it to @code{nil} restores the frame's status as a @dfn{top-level +frame}---a frame whose window-system window is a child of its display's +root window. Since child frames can be arbitrarily nested, a frame can be both a child and a parent frame. Also, the relative roles of child and parent frame may be reversed at any time (though it's usually a good idea to -keep the size of child frames sufficiently smaller than that of their +keep the size of a child frame sufficiently smaller than that of its parent). An error will be signaled for the attempt to make a frame an ancestor of itself. - A child frame is clipped at the native edges (@pxref{Frame Geometry}) -of its parent frame---everything outside these edges is invisible. Its -@code{left} and @code{top} parameters specify positions relative to the -top-left corner of its parent's native frame. When either of the frames -is resized, the relative position of the child frame remains unaltered. -Hence, resizing either of these frames can hide or reveal parts of the -child frame. + Most window-systems clip a child frame at the native edges +(@pxref{Frame Geometry}) of its parent frame---everything outside these +edges is usually invisible. A child frame's @code{left} and @code{top} +parameters specify a position relative to the top-left corner of its +parent's native frame. When the parent frame is resized, this position +remains conceptually unaltered. NS builds do not clip child frames at the parent frame's edges, -allowing them to be positioned so they do not obscure the parent -frame while still being visible themselves. +allowing them to be positioned so they do not obscure the parent frame +while still being visible themselves. Usually, moving a parent frame moves along all its child frames and their descendants as well, keeping their relative positions unaltered. -The hook @code{move-frame-functions} (@pxref{Frame Position}) is run for -a child frame only when the position of the child frame relative to its -parent frame changes. When a parent frame is resized, the child frame -retains its position respective to the left and upper native edges of -its parent. In this case, the position respective to the lower or right -native edge of the parent frame is usually lost. +Note that the hook @code{move-frame-functions} (@pxref{Frame Position}) +is run for a child frame only when the position of the child frame +relative to its parent frame changes. It is not run for a child frame +when the position of the parent frame changes. + + When a parent frame is resized, its child frames conceptually retain +their previous sizes and their positions relative to the left upper +corner of the parent. This means that a child frame may become +(partially) invisible when its parent frame shrinks. The parameter +@code{keep-ratio} (@pxref{Frame Interaction Parameters}) can be used to +resize and reposition a child frame proportionally whenever its parent +frame is resized. This may avoid obscuring parts of a frame when its +parent frame is shrunk. A visible child frame always appears on top of its parent frame thus obscuring parts of it, except on NS builds where it may be positioned -beneath the parent. This is comparable to the window-system window of -a top-level frame which also always appears on top of its parent -window---the desktop's root window. When a parent frame is iconified -or made invisible (@pxref{Visibility of Frames}), its child frames are -made invisible. When a parent frame is deiconified or made visible, -its child frames are made visible. When a parent frame is about to be -deleted, (@pxref{Deleting Frames}) its child frames are recursively +beneath the parent. This is comparable to the window-system window of a +top-level frame which also always appears on top of its parent +window---the desktop's root window. When a parent frame is iconified or +made invisible (@pxref{Visibility of Frames}), its child frames are made +invisible. When a parent frame is deiconified or made visible, its +child frames are made visible. When a parent frame is about to be +deleted (@pxref{Deleting Frames}), its child frames are recursively deleted before it. Whether a child frame can have a menu or tool bar is window-system or @@ -2892,7 +3122,55 @@ Child Frames border width will show a one-pixel wide external border. Under all window-systems, the internal border can be used. In either case, it's advisable to disable a child frame's window manager decorations with the -@code{undecorated} frame parameter @pxref{Management Parameters}). +@code{undecorated} frame parameter (@pxref{Management Parameters}). + + To resize or move an undecorated child frame with the mouse, special +frame parameters (@pxref{Mouse Dragging Parameters}) have to be used. +The internal border of a child frame, if present, can be used to resize +the frame with the mouse, provided that frame has a non-@code{nil} +@code{drag-internal-border} parameter. If set, the @code{snap-width} +parameter indicates the number of pixels where the frame @dfn{snaps} at +the respective edge or corner of its parent frame. + + There are two ways to drag an entire child frame with the mouse: The +@code{drag-with-mode-line} parameter, if non-@code{nil}, allows to drag +a frame without minibuffer window (@pxref{Minibuffer Windows}) via the +mode line area of its bottommost window. The +@code{drag-with-header-line} parameter, if non-@code{nil}, allows to +drag the frame via the header line area of its topmost window. + + In order to give a child frame a draggable header or mode line, the +window parameters @code{mode-line-format} and @code{header-line-format} +are handy (@pxref{Window Parameters}). These allow to remove an +unwanted mode line (when @code{drag-with-header-line} is chosen) and to +remove mouse-sensitive areas which might interfere with frame dragging. + + To avoid that dragging moves a frame completely out of its parent's +native frame, something which might happen when the mouse cursor +overshoots and makes the frame difficult to retrieve once the mouse +button has been released, it is advisable to set the frame's +@code{top-visible} or @code{bottom-visible} parameter correspondingly. + + The @code{top-visible} parameter specifies the number of pixels at the +top of the frame that always remain visible within the parent's native +frame during dragging and should be set when specifying a non-@code{nil} +@code{drag-with-header-line} parameter. The @code{bottom-visible} +parameter specifies the number of pixels at the bottom of the frame that +always remain visible within the parent's native frame during dragging +and should be preferred when specifying a non-@code{nil} +@code{drag-with-mode-line} parameter. + + When a child frame is used for displaying a buffer via +@code{display-buffer-in-child-frame} (@pxref{Display Action Functions}), +the frame's @code{auto-hide-function} parameter (@pxref{Frame +Interaction Parameters}) can be set to a function, in order to +appropriately deal with the frame when the window displaying the buffer +shall be quit. + + When a child frame is used during minibuffer interaction, for example, +to display completions in a separate window, the @code{minibuffer-exit} +parameter (@pxref{Frame Interaction Parameters}) is useful in order to +deal with the frame when the minibuffer is exited. The behavior of child frames deviates from that of top-level frames in a number of other ways as well. Here we sketch a few of them: @@ -2930,7 +3208,7 @@ Child Frames frame or on some ancestor instead. @end itemize - The following two functions may be useful when working with child and + The following two functions can be useful when working with child and parent frames: @defun frame-parent &optional frame @@ -2951,6 +3229,12 @@ Child Frames frame. @end defun +Note also the function @code{window-largest-empty-rectangle} +(@pxref{Coordinates and Windows}) which can be used to inscribe a child +frame in the largest empty area of an existing window. This can be +useful to avoid that a child frame obscures any text shown in that +window. + @node Mouse Tracking @section Mouse Tracking diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi index 0e476b4..f7013da 100644 --- a/doc/lispref/modes.texi +++ b/doc/lispref/modes.texi @@ -1737,7 +1737,9 @@ Mode Line Basics displayed on the buffer's mode line. The value of @code{header-line-format} specifies the buffer's header line in the same way. All windows for the same buffer use the same -@code{mode-line-format} and @code{header-line-format}. +@code{mode-line-format} and @code{header-line-format} unless a +@code{mode-line-format} or @code{header-line-format} parameter has been +specified for that window (@pxref{Window Parameters}). For efficiency, Emacs does not continuously recompute each window's mode line and header line. It does so when circumstances appear to call diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index d9b4b74..eb5c2fc 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -752,6 +752,7 @@ Window Sizes minimum size of @var{window} counted in pixels. @end defun + @node Resizing Windows @section Resizing Windows @cindex window resizing @@ -943,7 +944,8 @@ Resizing Windows @defopt fit-frame-to-buffer-margins This option can be used to specify margins around frames to be fit by @code{fit-frame-to-buffer}. Such margins can be useful to avoid, for -example, that such frames overlap the taskbar. +example, that the resized frame overlaps the taskbar or parts of its +parent frame. It specifies the numbers of pixels to be left free on the left, above, the right, and below a frame that shall be fit. The default specifies @@ -2484,6 +2486,25 @@ Display Action Functions is added to the newly created frame's parameters. @end defun +@defun display-buffer-in-child-frame buffer alist +This function tries to display @var{buffer} in a child frame +(@pxref{Child Frames}) of the selected frame, either reusing an existing +child frame or by making a new one. If @var{alist} has a non-@code{nil} +@code{child-frame-parameters} entry, the corresponding value is an alist +of frame parameters to give the new frame. A @code{parent-frame} +parameter specifying the selected frame is provided by default. If the +child frame should be or become the child of another frame, a +corresponding entry must be added to @var{alist}. + +The appearance of child frames is largely dependent on the parameters +provided via @var{alist}. It is advisable to use at least ratios to +specify the size (@pxref{Size Parameters}) and the position +(@pxref{Position Parameters}) of the child frame and to add the +@code{keep-ratio} in order to make sure that the child frame remains +visible. For other parameters that should be considered see @ref{Child +Frames}. +@end defun + @defun display-buffer-use-some-frame buffer alist This function tries to display @var{buffer} by trying to find a frame that meets a predicate (by default any frame other than the @@ -3124,12 +3145,17 @@ Quitting Windows The default is to call @code{iconify-frame} (@pxref{Visibility of Frames}). Alternatively, you may specify either @code{delete-frame} (@pxref{Deleting Frames}) to remove the frame from its display, -@code{ignore} to leave the frame unchanged, or any other function that -can take a frame as its sole argument. +@code{make-frame-invisible} to make the frame invisible, @code{ignore} +to leave the frame unchanged, or any other function that can take a +frame as its sole argument. Note that the function specified by this option is called only if the specified frame contains just one live window and there is at least one other frame on the same terminal. + +For a particular frame, the value specified here may be overridden by +that frame's @code{auto-hide-function} frame parameter (@pxref{Frame +Interaction Parameters}). @end defopt @@ -4364,13 +4390,12 @@ Coordinates and Windows @cindex coordinate, relative to frame @cindex window position -This section describes functions that report the position of a window. -Most of these functions report positions relative to an origin at the -native position of the window's frame (@pxref{Frame Geometry}). Some -functions report positions relative to the origin of the display of the -window's frame. In any case, the origin has the coordinates (0, 0) and -X and Y coordinates increase rightward and downward -respectively. +This section describes functions that report positions of and within a +window. Most of these functions report positions relative to an origin +at the native position of the window's frame (@pxref{Frame Geometry}). +Some functions report positions relative to the origin of the display of +the window's frame. In any case, the origin has the coordinates (0, 0) +and X and Y coordinates increase rightward and downward respectively. For the following functions, X and Y coordinates are reported in integer character units, i.e., numbers of lines and columns @@ -4608,6 +4633,49 @@ Coordinates and Windows @end example @end defun +The following function returns the largest rectangle that can be +inscribed in a window without covering text displayed in that window. + +@defun window-largest-empty-rectangle &optional window count min-width min-height positions left +This function calculates the dimensions of the largest empty rectangle +that can be inscribed in the specified @var{window}'s text area. +@var{window} must be a live window and defaults to the selected one. + +The return value is a triple of the width and the start and end +y-coordinates of the largest rectangle that can be inscribed into the +empty space (space not displaying any text) of the text area of +@var{window}. No x-coordinates are returned by this function---any such +rectangle is assumed to end at the right edge of @var{window}'s text +area. If no empty space can be found, the return value is @code{nil}. + +The optional argument @var{count}, if non-@code{nil}, specifies a +maximum number of rectangles to return. This means that the return +value is a list of triples specifying rectangles with the largest +rectangle first. @var{count} can be also a cons cell whose car +specifies the number of rectangles to return and whose @sc{cdr}, if +non-@code{nil}, states that all rectangles returned must be disjoint. + +The optional arguments @var{min-width} and @var{min-height}, if +non-@code{nil}, specify the minimum width and height of any rectangle +returned. + +The optional argument @var{positions}, if non-@code{nil}, is a cons cell +whose @sc{car} specifies the uppermost and whose @sc{cdr} specifies the +lowermost pixel position that must be covered by any rectangle returned. +These positions measure from the start of the text area of @var{window}. + +The optional argument @var{left}, if non-@code{nil}, means to return +values suitable for buffers displaying right to left text. In that +case, any rectangle returned is assumed to start at the left edge of +@var{window}'s text area. + +Note that this function has to retrieve the dimensions of each line of +@var{window}'s glyph matrix via @code{window-lines-pixel-dimensions} +(@pxref{Size of Displayed Text}). Hence, this function may also return +@code{nil} when the current glyph matrix of @var{window} is not +up-to-date. +@end defun + @node Mouse Window Auto-selection @section Mouse Window Auto-selection @@ -4911,37 +4979,45 @@ Window Parameters The following parameters are currently used by the window management code: -@table @asis -@item @code{delete-window} +@table @code +@item delete-window +@vindex delete-window, a window parameter This parameter affects the execution of @code{delete-window} (@pxref{Deleting Windows}). -@item @code{delete-other-windows} +@item delete-other-windows +@vindex delete-other-windows, a window parameter This parameter affects the execution of @code{delete-other-windows} (@pxref{Deleting Windows}). -@item @code{no-delete-other-window} +@item no-delete-other-window +@vindex no-delete-other-window, a window parameter This parameter marks the window as not deletable by @code{delete-other-windows} (@pxref{Deleting Windows}). -@item @code{split-window} +@item split-window +@vindex split-window, a window parameter This parameter affects the execution of @code{split-window} (@pxref{Splitting Windows}). -@item @code{other-window} +@item other-window +@vindex other-window, a window parameter This parameter affects the execution of @code{other-window} (@pxref{Cyclic Window Ordering}). -@item @code{no-other-window} +@item no-other-window +@vindex no-other-window, a window parameter This parameter marks the window as not selectable by @code{other-window} (@pxref{Cyclic Window Ordering}). -@item @code{clone-of} +@item clone-of +@vindex clone-of, a window parameter This parameter specifies the window that this one has been cloned from. It is installed by @code{window-state-get} (@pxref{Window Configurations}). -@item @code{preserved-size} +@item preserved-size +@vindex preserved-size, a window parameter This parameter specifies a buffer, a direction where @code{nil} means vertical and @code{t} horizontal, and a size in pixels. If this window displays the specified buffer and its size in the indicated direction @@ -4950,7 +5026,8 @@ Window Parameters parameter is installed and updated by the function @code{window-preserve-size} (@pxref{Preserving Window Sizes}). -@item @code{quit-restore} +@item quit-restore +@vindex quit-restore, a window parameter This parameter is installed by the buffer display functions (@pxref{Choosing Window}) and consulted by @code{quit-restore-window} (@pxref{Quitting Windows}). It contains four elements: @@ -4981,15 +5058,37 @@ Window Parameters See the description of @code{quit-restore-window} in @ref{Quitting Windows} for details. -@item @code{window-side} @code{window-slot} +@item window-side window-slot +@vindex window-side, a window parameter +@vindex window-slot, a window parameter These parameters are used for implementing side windows (@pxref{Side Windows}). -@item @code{window-atom} +@item window-atom +@vindex window-atom, a window parameter This parameter is used for implementing atomic windows, see @ref{Atomic Windows}. -@item @code{min-margins} +@item mode-line-format +@vindex mode-line-format, a window parameter +This parameter replaces the value of the buffer-local variable +@code{mode-line-format} (@pxref{Mode Line Basics}) of this window's +buffer whenever this window is displayed. The symbol @code{none} means +to suppress display of a mode line for this window. Display and +contents of the mode line on other windows showing this buffer are not +affected. + +@item header-line-format +@vindex header-line-format, a window parameter +This parameter replaces the value of the buffer-local variable +@code{header-line-format} (@pxref{Mode Line Basics}) of this window's +buffer whenever this window is displayed. The symbol @code{none} means +to suppress display of a header line for this window. Display and +contents of the header line on other windows showing this buffer are not +affected. + +@item min-margins +@vindex min-margins, a window parameter The value of this parameter is a cons cell whose @sc{car} and @sc{cdr}, if non-@code{nil}, specify the minimum values (in columns) for the left and right margin of this window. When present, Emacs will use these diff --git a/etc/NEWS b/etc/NEWS index 78d37484..430bab4 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1203,7 +1203,7 @@ run. frame's outer border. +++ -*** New frame parameters +*** New frame parameters and changed semantics for older ones +++ **** 'z-group' positions a frame above or below all others. @@ -1248,10 +1248,32 @@ focus via the mouse. frame. +++ -*** The 'width' and 'height' frame parameters allow to specify pixel -values now. +**** 'width' and 'height' allow to specify pixel values and ratios now. +++ +**** 'left' and 'top' allow to specify ratios now. + ++++ +**** 'keep-ratio' preserves size and position of child frames when their +parent frame is resized. + ++++ +**** 'no-special-glyphs' suppresses display of truncation and +continuation glyphs in a frame. + ++++ +**** 'auto-hide-function' and 'minibuffer-exit' handle auto hiding of +frames and exiting from minibuffer individually. + ++++ +**** 'fit-frame-to-buffer-margins' and 'fit-frame-to-buffer-sizes' +handle fitting a frame to its buffer individually. + ++++ +**** 'drag-internal-border', 'drag-with-header-line', +'drag-with-mode-line', 'snap-width', 'top-visible' and 'bottom-visible' +allow to drag and resize frames with the mouse. + *** The new function 'frame-list-z-order' returns a list of all frames in Z (stacking) order. @@ -1310,6 +1332,10 @@ a new window when opening man pages when there's already one, use its window gets deleted by 'delete-other-windows'. +++ +*** New window parameters 'mode-line-format' and 'header-line-format' +allow to override the buffer-local formats for this window. + ++++ *** New command 'window-swap-states' swaps the states of two live windows. @@ -1319,6 +1345,15 @@ windows. window changed size when 'window-size-change-functions' are run. +++ +*** The new function 'window-lines-pixel-dimensions' returns the pixel +dimensions of a window's text lines. + ++++ +*** The new function 'window-largest-empty-rectangle' returns the +dimensions of the largest rectangular area not occupying any text in a +window's body. + ++++ *** The semantics of 'mouse-autoselect-window' has changed slightly. For details see the section "Mouse Window Auto-selection" in the Elisp manual. @@ -1364,7 +1399,7 @@ This is in contrast to the default action on POSIX Systems, where it causes the receiving process to terminate with a core dump if no debugger has been attached to it. -** `set-mouse-position' and `set-mouse-absolute-pixel-position' work +** 'set-mouse-position' and 'set-mouse-absolute-pixel-position' work on macOS. \f diff --git a/lisp/frame.el b/lisp/frame.el index b7a5516..b54df6f 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -1110,6 +1110,38 @@ frame-width If FRAME is omitted, describe the currently selected frame." (cdr (assq 'width (frame-parameters frame)))) +(defalias 'frame-border-width 'frame-internal-border-width) +(defalias 'frame-pixel-width 'frame-native-width) +(defalias 'frame-pixel-height 'frame-native-height) + +(defun frame-inner-width (&optional frame) + "Return inner width of FRAME in pixels. +FRAME defaults to the selected frame." + (setq frame (window-normalize-frame frame)) + (- (frame-native-width frame) + (* 2 (frame-internal-border-width frame)))) + +(defun frame-inner-height (&optional frame) + "Return inner height of FRAME in pixels. +FRAME defaults to the selected frame." + (setq frame (window-normalize-frame frame)) + (- (frame-native-height frame) + (* 2 (frame-internal-border-width frame)))) + +(defun frame-outer-width (&optional frame) + "Return outer width of FRAME in pixels. +FRAME defaults to the selected frame." + (setq frame (window-normalize-frame frame)) + (let ((edges (frame-edges frame 'outer-edges))) + (- (nth 2 edges) (nth 0 edges)))) + +(defun frame-outer-height (&optional frame) + "Return outer height of FRAME in pixels. +FRAME defaults to the selected frame." + (setq frame (window-normalize-frame frame)) + (let ((edges (frame-edges frame 'outer-edges))) + (- (nth 3 edges) (nth 1 edges)))) + (declare-function x-list-fonts "xfaces.c" (pattern &optional face frame maximum width)) diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index c3480cd..e5b1029 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -746,7 +746,7 @@ completion-show-inline-help (defcustom completion-auto-help t "Non-nil means automatically provide help for invalid completion input. -If the value is t the *Completion* buffer is displayed whenever completion +If the value is t the *Completions* buffer is displayed whenever completion is requested but cannot be done. If the value is `lazy', the *Completions* buffer is only displayed after the second failed attempt to complete." diff --git a/lisp/mouse.el b/lisp/mouse.el index 9b6b169..e079443 100644 --- a/lisp/mouse.el +++ b/lisp/mouse.el @@ -380,7 +380,7 @@ mouse-split-window-horizontally (defun mouse-drag-line (start-event line) "Drag a mode line, header line, or vertical line with the mouse. -START-EVENT is the starting mouse-event of the drag action. LINE +START-EVENT is the starting mouse event of the drag action. LINE must be one of the symbols `header', `mode', or `vertical'." ;; Give temporary modes such as isearch a chance to turn off. (run-hooks 'mouse-leave-buffer-hook) @@ -405,29 +405,15 @@ mouse-drag-line ;; window's edge we drag. (cond ((eq line 'header) - (if (window-at-side-p window 'top) - ;; We can't drag the header line of a topmost window. - (setq draggable nil) - ;; Drag bottom edge of window above the header line. - (setq window (window-in-direction 'above window t)))) - ((eq line 'mode) - (if (and (window-at-side-p window 'bottom) - ;; Allow resizing the minibuffer window if it's on the - ;; same frame as and immediately below `window', and it's - ;; either active or `resize-mini-windows' is nil. - (let ((minibuffer-window (minibuffer-window frame))) - (not (and (eq (window-frame minibuffer-window) frame) - (or (not resize-mini-windows) - (eq minibuffer-window - (active-minibuffer-window))))))) - (setq draggable nil))) + ;; Drag bottom edge of window above the header line. + (setq window (window-in-direction 'above window t))) + ((eq line 'mode)) ((eq line 'vertical) (let ((divider-width (frame-right-divider-width frame))) (when (and (or (not (numberp divider-width)) (zerop divider-width)) (eq (frame-parameter frame 'vertical-scroll-bars) 'left)) (setq window (window-in-direction 'left window t)))))) - (let* ((exitfun nil) (move (lambda (event) (interactive "e") @@ -530,20 +516,405 @@ mouse-drag-line t (lambda () (setq track-mouse old-track-mouse))))))) (defun mouse-drag-mode-line (start-event) - "Change the height of a window by dragging on the mode line." + "Change the height of a window by dragging on its mode line. +START-EVENT is the starting mouse event of the drag action. + +If the drag happens in a mode line on the bottom of a frame and +that frame's `drag-with-mode-line' parameter is non-nil, drag the +frame instead." (interactive "e") - (mouse-drag-line start-event 'mode)) + (let* ((start (event-start start-event)) + (window (posn-window start)) + (frame (window-frame window))) + (cond + ((not (window-live-p window))) + ((or (not (window-at-side-p window 'bottom)) + ;; Allow resizing the minibuffer window if it's on the + ;; same frame as and immediately below `window', and it's + ;; either active or `resize-mini-windows' is nil. + (let ((minibuffer-window (minibuffer-window frame))) + (and (eq (window-frame minibuffer-window) frame) + (or (not resize-mini-windows) + (eq minibuffer-window + (active-minibuffer-window)))))) + (mouse-drag-line start-event 'mode)) + ((and (frame-parameter frame 'drag-with-mode-line) + (window-at-side-p window 'bottom) + (let ((minibuffer-window (minibuffer-window frame))) + (not (eq (window-frame minibuffer-window) frame)))) + ;; Drag frame when the window is on the bottom of its frame and + ;; there is no minibuffer window below. + (mouse-drag-frame start-event 'move))))) (defun mouse-drag-header-line (start-event) - "Change the height of a window by dragging on the header line." + "Change the height of a window by dragging on its header line. +START-EVENT is the starting mouse event of the drag action. + +If the drag happens in a header line on the top of a frame and +that frame's `drag-with-header-line' parameter is non-nil, drag +the frame instead." (interactive "e") - (mouse-drag-line start-event 'header)) + (let* ((start (event-start start-event)) + (window (posn-window start))) + (if (and (window-live-p window) + (not (window-at-side-p window 'top))) + (mouse-drag-line start-event 'header) + (let ((frame (window-frame window))) + (when (frame-parameter frame 'drag-with-header-line) + (mouse-drag-frame start-event 'move)))))) (defun mouse-drag-vertical-line (start-event) - "Change the width of a window by dragging on the vertical line." + "Change the width of a window by dragging on a vertical line. +START-EVENT is the starting mouse event of the drag action." (interactive "e") (mouse-drag-line start-event 'vertical)) \f +(defun mouse-resize-frame (frame x-diff y-diff &optional x-move y-move) + "Helper function for `mouse-drag-frame'." + (let* ((frame-x-y (frame-position frame)) + (frame-x (car frame-x-y)) + (frame-y (cdr frame-x-y)) + alist) + (if (> x-diff 0) + (when x-move + (setq x-diff (min x-diff frame-x)) + (setq x-move (- frame-x x-diff))) + (let* ((min-width (frame-windows-min-size frame t nil t)) + (min-diff (max 0 (- (frame-inner-width frame) min-width)))) + (setq x-diff (max x-diff (- min-diff))) + (when x-move + (setq x-move (+ frame-x (- x-diff)))))) + + (if (> y-diff 0) + (when y-move + (setq y-diff (min y-diff frame-y)) + (setq y-move (- frame-y y-diff))) + (let* ((min-height (frame-windows-min-size frame nil nil t)) + (min-diff (max 0 (- (frame-inner-height frame) min-height)))) + (setq y-diff (max y-diff (- min-diff))) + (when y-move + (setq y-move (+ frame-y (- y-diff)))))) + + (unless (zerop x-diff) + (when x-move + (push `(left . ,x-move) alist)) + (push `(width . (text-pixels . ,(+ (frame-text-width frame) x-diff))) + alist)) + (unless (zerop y-diff) + (when y-move + (push `(top . ,y-move) alist)) + (push `(height . (text-pixels . ,(+ (frame-text-height frame) y-diff))) + alist)) + (when alist + (modify-frame-parameters frame alist)))) + +(defun mouse-drag-frame (start-event part) + "Drag a frame or one of its edges with the mouse. +START-EVENT is the starting mouse event of the drag action. Its +position window denotes the frame that will be dragged. + +PART specifies the part that has been dragged and must be one of +the symbols 'left', 'top', 'right', 'bottom', 'top-left', +'top-right', 'bottom-left', 'bottom-right' to drag an internal +border or edge. If PART equals 'move', this means to move the +frame with the mouse." + ;; Give temporary modes such as isearch a chance to turn off. + (run-hooks 'mouse-leave-buffer-hook) + (let* ((echo-keystrokes 0) + (start (event-start start-event)) + (window (posn-window start)) + ;; FRAME is the frame to drag. + (frame (if (window-live-p window) + (window-frame window) + window)) + (width (frame-native-width frame)) + (height (frame-native-height frame)) + ;; PARENT is the parent frame of FRAME or, if FRAME is a + ;; top-level frame, FRAME's workarea. + (parent (frame-parent frame)) + (parent-edges + (if parent + `(0 0 ,(frame-native-width parent) ,(frame-native-height parent)) + (let* ((attributes + (car (display-monitor-attributes-list))) + (workarea (assq 'workarea attributes))) + (and workarea + `(,(nth 1 workarea) ,(nth 2 workarea) + ,(+ (nth 1 workarea) (nth 3 workarea)) + ,(+ (nth 2 workarea) (nth 4 workarea))))))) + (parent-left (and parent-edges (nth 0 parent-edges))) + (parent-top (and parent-edges (nth 1 parent-edges))) + (parent-right (and parent-edges (nth 2 parent-edges))) + (parent-bottom (and parent-edges (nth 3 parent-edges))) + ;; `pos-x' and `pos-y' record the x- and y-coordinates of the + ;; last sampled mouse position. Note that we sample absolute + ;; mouse positions to avoid that moving the mouse from one + ;; frame into another gets into our way. `last-x' and `last-y' + ;; records the x- and y-coordinates of the previously sampled + ;; position. The differences between `last-x' and `pos-x' as + ;; well as `last-y' and `pos-y' determine the amount the mouse + ;; has been dragged between the last two samples. + pos-x-y pos-x pos-y + (last-x-y (mouse-absolute-pixel-position)) + (last-x (car last-x-y)) + (last-y (cdr last-x-y)) + ;; `snap-x' and `snap-y' record the x- and y-coordinates of the + ;; mouse position when FRAME snapped. As soon as the + ;; difference between `pos-x' and `snap-x' (or `pos-y' and + ;; `snap-y') exceeds the value of FRAME's `snap-width' + ;; parameter, unsnap FRAME (at the respective side). `snap-x' + ;; and `snap-y' nil mean FRAME is curerntly not snapped. + snap-x snap-y + (exitfun nil) + (move + (lambda (event) + (interactive "e") + (when (consp event) + (setq pos-x-y (mouse-absolute-pixel-position)) + (setq pos-x (car pos-x-y)) + (setq pos-y (cdr pos-x-y)) + (cond + ((eq part 'left) + (mouse-resize-frame frame (- last-x pos-x) 0 t)) + ((eq part 'top) + (mouse-resize-frame frame 0 (- last-y pos-y) nil t)) + ((eq part 'right) + (mouse-resize-frame frame (- pos-x last-x) 0)) + ((eq part 'bottom) + (mouse-resize-frame frame 0 (- pos-y last-y))) + ((eq part 'top-left) + (mouse-resize-frame + frame (- last-x pos-x) (- last-y pos-y) t t)) + ((eq part 'top-right) + (mouse-resize-frame + frame (- pos-x last-x) (- last-y pos-y) nil t)) + ((eq part 'bottom-left) + (mouse-resize-frame + frame (- last-x pos-x) (- pos-y last-y) t)) + ((eq part 'bottom-right) + (mouse-resize-frame + frame (- pos-x last-x) (- pos-y last-y))) + ((eq part 'move) + (let* ((old-position (frame-position frame)) + (old-left (car old-position)) + (old-top (cdr old-position)) + (left (+ old-left (- pos-x last-x))) + (top (+ old-top (- pos-y last-y))) + right bottom + ;; `snap-width' (maybe also a yet to be provided + ;; `snap-height') could become floats to handle + ;; proportionality wrt PARENT. We don't do any + ;; checks on this parameter so far. + (snap-width (frame-parameter frame 'snap-width))) + ;; Docking and constraining. + (when (and (numberp snap-width) parent-edges) + (cond + ;; Docking at the left parent edge. + ((< pos-x last-x) + (cond + ((and (> left parent-left) + (<= (- left parent-left) snap-width)) + ;; Snap when the mouse moved leftward and + ;; FRAME's left edge would end up within + ;; `snap-width' pixels from PARENT's left edge. + (setq snap-x pos-x) + (setq left parent-left)) + ((and (<= left parent-left) + (<= (- parent-left left) snap-width) + snap-x (<= (- snap-x pos-x) snap-width)) + ;; Stay snapped when the mouse moved leftward + ;; but not more than `snap-width' pixels from + ;; the time FRAME snapped. + (setq left parent-left)) + (t + ;; Unsnap when the mouse moved more than + ;; `snap-width' pixels leftward from the time + ;; FRAME snapped. + (setq snap-x nil)))) + ((> pos-x last-x) + (setq right (+ left width)) + (cond + ((and (< right parent-right) + (<= (- parent-right right) snap-width)) + ;; Snap when the mouse moved rightward and + ;; FRAME's right edge would end up within + ;; `snap-width' pixels from PARENT's right edge. + (setq snap-x pos-x) + (setq left (- parent-right width))) + ((and (>= right parent-right) + (<= (- right parent-right) snap-width) + snap-x (<= (- pos-x snap-x) snap-width)) + ;; Stay snapped when the mouse moved rightward + ;; but not more more than `snap-width' pixels + ;; from the time FRAME snapped. + (setq left (- parent-right width))) + (t + ;; Unsnap when the mouse moved rightward more + ;; than `snap-width' pixels from the time FRAME + ;; snapped. + (setq snap-x nil))))) + + (cond + ((< pos-y last-y) + (cond + ((and (> top parent-top) + (<= (- top parent-top) snap-width)) + ;; Snap when the mouse moved upward and FRAME's + ;; top edge would end up within `snap-width' + ;; pixels from PARENT's top edge. + (setq snap-y pos-y) + (setq top parent-top)) + ((and (<= top parent-top) + (<= (- parent-top top) snap-width) + snap-y (<= (- snap-y pos-y) snap-width)) + ;; Stay snapped when the mouse moved upward but + ;; not more more than `snap-width' pixels from + ;; the time FRAME snapped. + (setq top parent-top)) + (t + ;; Unsnap when the mouse moved upward more than + ;; `snap-width' pixels from the time FRAME + ;; snapped. + (setq snap-y nil)))) + ((> pos-y last-y) + (setq bottom (+ top height)) + (cond + ((and (< bottom parent-bottom) + (<= (- parent-bottom bottom) snap-width)) + ;; Snap when the mouse moved downward and + ;; FRAME's bottom edge would end up within + ;; `snap-width' pixels from PARENT's bottom + ;; edge. + (setq snap-y pos-y) + (setq top (- parent-bottom height))) + ((and (>= bottom parent-bottom) + (<= (- bottom parent-bottom) snap-width) + snap-y (<= (- pos-y snap-y) snap-width)) + ;; Stay snapped when the mouse moved downward + ;; but not more more than `snap-width' pixels + ;; from the time FRAME snapped. + (setq top (- parent-bottom height))) + (t + ;; Unsnap when the mouse moved downward more + ;; than `snap-width' pixels from the time FRAME + ;; snapped. + (setq snap-y nil)))))) + + ;; If requested, constrain FRAME's draggable areas to + ;; PARENT's edges. The `top-visible' parameter should + ;; be set when FRAME has a draggable header-line. If + ;; set to a number, it ascertains that the top of + ;; FRAME is always constrained to the top of PARENT + ;; and that at least as many pixels of FRAME as + ;; specified by that number are visible on each of the + ;; three remaining sides of PARENT. + ;; + ;; The `bottom-visible' parameter should be set when + ;; FRAME has a draggable mode-line. If set to a + ;; number, it ascertains that the bottom of FRAME is + ;; always constrained to the bottom of PARENT and that + ;; at least as many pixels of FRAME as specified by + ;; that number are visible on each of the three + ;; remaining sides of PARENT. + (let ((par (frame-parameter frame 'top-visible)) + bottom-visible) + (unless par + (setq par (frame-parameter frame 'bottom-visible)) + (setq bottom-visible t)) + (when (and (numberp par) parent-edges) + (setq left + (max (min (- parent-right par) left) + (+ (- parent-left width) par))) + (setq top + (if bottom-visible + (min (max top (- parent-top (- height par))) + (- parent-bottom height)) + (min (max top parent-top) + (- parent-bottom par)))))) + + ;; Use `modify-frame-parameters' since `left' and + ;; `top' may want to move FRAME out of its PARENT. + (modify-frame-parameters + frame + `((left . (+ ,left)) (top . (+ ,top))))))) + (setq last-x pos-x) + (setq last-y pos-y)))) + (old-track-mouse track-mouse)) + ;; Start tracking. The special value 'dragging' signals the + ;; display engine to freeze the mouse pointer shape for as long + ;; as we drag. + (setq track-mouse 'dragging) + ;; Loop reading events and sampling the position of the mouse. + (setq exitfun + (set-transient-map + (let ((map (make-sparse-keymap))) + (define-key map [switch-frame] #'ignore) + (define-key map [select-window] #'ignore) + (define-key map [scroll-bar-movement] #'ignore) + (define-key map [mouse-movement] move) + ;; Swallow drag-mouse-1 events to avoid selecting some other window. + (define-key map [drag-mouse-1] + (lambda () (interactive) (funcall exitfun))) + ;; Some of the events will of course end up looked up + ;; with a mode-line, header-line or vertical-line prefix ... + (define-key map [mode-line] map) + (define-key map [header-line] map) + (define-key map [vertical-line] map) + ;; ... and some maybe even with a right- or bottom-divider + ;; prefix. + (define-key map [right-divider] map) + (define-key map [bottom-divider] map) + map) + t (lambda () (setq track-mouse old-track-mouse)))))) + +(defun mouse-drag-left-edge (start-event) + "Drag left edge of a frame with the mouse. +START-EVENT is the starting mouse event of the drag action." + (interactive "e") + (mouse-drag-frame start-event 'left)) + +(defun mouse-drag-top-left-corner (start-event) + "Drag top left corner of a frame with the mouse. +START-EVENT is the starting mouse event of the drag action." + (interactive "e") + (mouse-drag-frame start-event 'top-left)) + +(defun mouse-drag-top-edge (start-event) + "Drag top edge of a frame with the mouse. +START-EVENT is the starting mouse event of the drag action." + (interactive "e") + (mouse-drag-frame start-event 'top)) + +(defun mouse-drag-top-right-corner (start-event) + "Drag top right corner of a frame with the mouse. +START-EVENT is the starting mouse event of the drag action." + (interactive "e") + (mouse-drag-frame start-event 'top-right)) + +(defun mouse-drag-right-edge (start-event) + "Drag right edge of a frame with the mouse. +START-EVENT is the starting mouse event of the drag action." + (interactive "e") + (mouse-drag-frame start-event 'right)) + +(defun mouse-drag-bottom-right-corner (start-event) + "Drag bottom right corner of a frame with the mouse. +START-EVENT is the starting mouse event of the drag action." + (interactive "e") + (mouse-drag-frame start-event 'bottom-right)) + +(defun mouse-drag-bottom-edge (start-event) + "Drag bottom edge of a frame with the mouse. +START-EVENT is the starting mouse event of the drag action." + (interactive "e") + (mouse-drag-frame start-event 'bottom)) + +(defun mouse-drag-bottom-left-corner (start-event) + "Drag bottom left corner of a frame with the mouse. +START-EVENT is the starting mouse event of the drag action." + (interactive "e") + (mouse-drag-frame start-event 'bottom-left)) + (defcustom mouse-select-region-move-to-beginning nil "Effect of selecting a region extending backward from double click. Nil means keep point at the position clicked (region end); @@ -2078,6 +2449,22 @@ function-key-map (global-set-key [bottom-divider down-mouse-1] 'mouse-drag-mode-line) (global-set-key [bottom-divider mouse-1] 'ignore) (global-set-key [bottom-divider C-mouse-2] 'mouse-split-window-horizontally) +(global-set-key [left-edge down-mouse-1] 'mouse-drag-left-edge) +(global-set-key [left-edge mouse-1] 'ignore) +(global-set-key [top-left-corner down-mouse-1] 'mouse-drag-top-left-corner) +(global-set-key [top-left-corner mouse-1] 'ignore) +(global-set-key [top-edge down-mouse-1] 'mouse-drag-top-edge) +(global-set-key [top-edge mouse-1] 'ignore) +(global-set-key [top-right-corner down-mouse-1] 'mouse-drag-top-right-corner) +(global-set-key [top-right-corner mouse-1] 'ignore) +(global-set-key [right-edge down-mouse-1] 'mouse-drag-right-edge) +(global-set-key [right-edge mouse-1] 'ignore) +(global-set-key [bottom-right-corner down-mouse-1] 'mouse-drag-bottom-right-corner) +(global-set-key [bottom-right-corner mouse-1] 'ignore) +(global-set-key [bottom-edge down-mouse-1] 'mouse-drag-bottom-edge) +(global-set-key [bottom-edge mouse-1] 'ignore) +(global-set-key [bottom-left-corner down-mouse-1] 'mouse-drag-bottom-left-corner) +(global-set-key [bottom-left-corner mouse-1] 'ignore) (provide 'mouse) diff --git a/lisp/tooltip.el b/lisp/tooltip.el index 367114b..c011f1b 100644 --- a/lisp/tooltip.el +++ b/lisp/tooltip.el @@ -119,7 +119,8 @@ tooltip-y-offset (defcustom tooltip-frame-parameters '((name . "tooltip") (internal-border-width . 2) - (border-width . 1)) + (border-width . 1) + (no-special-glyphs . t)) "Frame parameters used for tooltips. If `left' or `top' parameters are included, they specify the absolute @@ -130,7 +131,8 @@ tooltip-frame-parameters :type '(repeat (cons :format "%v" (symbol :tag "Parameter") (sexp :tag "Value"))) - :group 'tooltip) + :group 'tooltip + :version "26.1") (defface tooltip '((((class color)) diff --git a/lisp/window.el b/lisp/window.el index 8b07ed4..c933996 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -3703,7 +3703,7 @@ window-edges ABSOLUTE is non-nil, PIXELWISE is implicitly non-nil too." (let* ((window (window-normalize-window window body)) (frame (window-frame window)) - (border-width (frame-border-width frame)) + (border-width (frame-internal-border-width frame)) (char-width (frame-char-width frame)) (char-height (frame-char-height frame)) (left (if pixelwise @@ -4572,12 +4572,13 @@ frame-auto-hide-function Functions affected by this option are those that bury a buffer shown in a separate frame like `quit-window' and `bury-buffer'." :type '(choice (const :tag "Iconify" iconify-frame) + (const :tag "Make invisible" make-frame-invisible) (const :tag "Delete" delete-frame) (const :tag "Do nothing" ignore) function) :group 'windows :group 'frames - :version "24.1") + :version "26.1") (defun window--delete (&optional window dedicated-only kill) "Delete WINDOW if possible. @@ -4595,7 +4596,9 @@ window--delete (cond (kill (delete-frame frame)) - ((functionp frame-auto-hide-function) + ((functionp (frame-parameter frame 'auto-hide-function)) + (funcall (frame-parameter frame 'auto-hide-function))) + ((functionp frame-auto-hide-function) (funcall frame-auto-hide-function frame)))) 'frame) (deletable @@ -6734,15 +6737,17 @@ window--display-buffer window)) (defun window--maybe-raise-frame (frame) - (let ((visible (frame-visible-p frame))) - (unless (or (not visible) - ;; Assume the selected frame is already visible enough. - (eq frame (selected-frame)) - ;; Assume the frame from which we invoked the - ;; minibuffer is visible. - (and (minibuffer-window-active-p (selected-window)) - (eq frame (window-frame (minibuffer-selected-window))))) - (raise-frame frame)))) + (make-frame-visible frame) + (unless (or (frame-parameter frame 'no-focus-on-map) + ;; Don't raise frames that should not get focus. + (frame-parameter frame 'no-accept-focus) + ;; Assume the selected frame is already visible enough. + (eq frame (selected-frame)) + ;; Assume the frame from which we invoked the + ;; minibuffer is visible. + (and (minibuffer-window-active-p (selected-window)) + (eq frame (window-frame (minibuffer-selected-window))))) + (raise-frame frame))) ;; FIXME: Not implemented. ;; FIXME: By the way, there could be more levels of dedication: @@ -6762,6 +6767,7 @@ display-buffer--action-function-custom-type (const display-buffer-pop-up-window) (const display-buffer-same-window) (const display-buffer-pop-up-frame) + (const display-buffer-in-child-frame) (const display-buffer-below-selected) (const display-buffer-at-bottom) (const display-buffer-in-previous-window) @@ -6908,6 +6914,7 @@ display-buffer `display-buffer-same-window' `display-buffer-reuse-window' `display-buffer-pop-up-frame' + `display-buffer-in-child-frame' `display-buffer-pop-up-window' `display-buffer-in-previous-window' `display-buffer-use-some-window' @@ -7239,6 +7246,7 @@ display-buffer-pop-up-window (get-largest-window frame t) alist) (window--try-to-split-window (get-lru-window frame t) alist)))) + (prog1 (window--display-buffer buffer window 'window alist display-buffer-mark-dedicated) (unless (cdr (assq 'inhibit-switch-frame alist)) @@ -7258,6 +7266,47 @@ display-buffer--maybe-pop-up-frame-or-window (and pop-up-windows (display-buffer-pop-up-window buffer alist)))) +(defun display-buffer-in-child-frame (buffer alist) + "Display BUFFER in a child frame. +By default, this either reuses a child frame of the selected +frame or makes a new child frame of the selected frame. If +successful, return the window used; otherwise return nil. + +If ALIST has a non-nil 'child-frame-parameters' entry, the +corresponding value is an alist of frame parameters to give the +new frame. A 'parent-frame' parameter specifying the selected +frame is provided by default. If the child frame should be or +become the child of any other frame, a corresponding entry must +be added to ALIST." + (let* ((parameters + (append + (cdr (assq 'child-frame-parameters alist)) + `((parent-frame . ,(selected-frame))))) + (parent (or (assq 'parent-frame parameters) + (selected-frame))) + (share (assq 'share-child-frame parameters)) + share1 frame window) + (with-current-buffer buffer + (when (frame-live-p parent) + (catch 'frame + (dolist (frame1 (frame-list)) + (when (eq (frame-parent frame1) parent) + (setq share1 (assq 'share-child-frame + (frame-parameters frame1))) + (when (eq share share1) + (setq frame frame1) + (throw 'frame t)))))) + + (if frame + (setq window (frame-selected-window frame)) + (setq frame (make-frame parameters)) + (setq window (frame-selected-window frame)))) + + (prog1 (window--display-buffer + buffer window 'frame alist display-buffer-mark-dedicated) + (unless (cdr (assq 'inhibit-switch-frame alist)) + (window--maybe-raise-frame frame))))) + (defun display-buffer-below-selected (buffer alist) "Try displaying BUFFER in a window below the selected window. If there is a window below the selected one and that window @@ -7272,7 +7321,8 @@ display-buffer-below-selected (and (not (frame-parameter nil 'unsplittable)) (let ((split-height-threshold 0) split-width-threshold) - (setq window (window--try-to-split-window (selected-window) alist))) + (setq window (window--try-to-split-window + (selected-window) alist))) (window--display-buffer buffer window 'window alist display-buffer-mark-dedicated)) (and (setq window (window-in-direction 'below)) @@ -7885,10 +7935,12 @@ fit-frame-to-buffer-sizes (declare-function x-display-pixel-height "xfns.c" (&optional terminal)) (defun window--sanitize-margin (margin left right) - "Return MARGIN if it's a number between LEFT and RIGHT." - (when (and (numberp margin) - (<= left (- right margin)) (<= margin right)) - margin)) + "Return MARGIN if it's a number between LEFT and RIGHT. +Return 0 otherwise." + (if (and (numberp margin) + (<= left (- right margin)) (<= margin right)) + margin + 0)) (declare-function tool-bar-height "xdisp.c" (&optional frame pixelwise)) @@ -7906,190 +7958,197 @@ fit-frame-to-buffer The new position and size of FRAME can be additionally determined by customizing the options `fit-frame-to-buffer-sizes' and -`fit-frame-to-buffer-margins' or the corresponding parameters of -FRAME." +`fit-frame-to-buffer-margins' or setting the corresponding +parameters of FRAME." (interactive) - (unless (and (fboundp 'x-display-pixel-height) - ;; We need the respective sizes now. - (fboundp 'display-monitor-attributes-list)) + (unless (fboundp 'display-monitor-attributes-list) (user-error "Cannot resize frame in non-graphic Emacs")) (setq frame (window-normalize-frame frame)) (when (window-live-p (frame-root-window frame)) - (with-selected-window (frame-root-window frame) - (let* ((char-width (frame-char-width)) - (char-height (frame-char-height)) - (monitor-attributes (car (display-monitor-attributes-list - (frame-parameter frame 'display)))) - (geometry (cdr (assq 'geometry monitor-attributes))) - (display-width (- (nth 2 geometry) (nth 0 geometry))) - (display-height (- (nth 3 geometry) (nth 1 geometry))) - (workarea (cdr (assq 'workarea monitor-attributes))) - ;; Handle margins. - (margins (or (frame-parameter frame 'fit-frame-to-buffer-margins) - fit-frame-to-buffer-margins)) - (left-margin (if (nth 0 margins) - (or (window--sanitize-margin - (nth 0 margins) 0 display-width) - 0) - (nth 0 workarea))) - (top-margin (if (nth 1 margins) - (or (window--sanitize-margin - (nth 1 margins) 0 display-height) - 0) - (nth 1 workarea))) - (workarea-width (nth 2 workarea)) - (right-margin (if (nth 2 margins) - (- display-width - (or (window--sanitize-margin - (nth 2 margins) left-margin display-width) - 0)) - (nth 2 workarea))) - (workarea-height (nth 3 workarea)) - (bottom-margin (if (nth 3 margins) - (- display-height - (or (window--sanitize-margin - (nth 3 margins) top-margin display-height) - 0)) - (nth 3 workarea))) - ;; The pixel width of FRAME (which does not include the - ;; window manager's decorations). - (frame-width (frame-pixel-width)) - ;; The pixel width of the body of FRAME's root window. - (window-body-width (window-body-width nil t)) - ;; The difference in pixels between total and body width of - ;; FRAME's window. - (window-extra-width (- (window-pixel-width) window-body-width)) - ;; The difference in pixels between the frame's pixel width - ;; and the window's body width. This is the space we can't - ;; use for fitting. - (extra-width (- frame-width window-body-width)) - ;; The pixel position of FRAME's left border. We usually - ;; try to leave this alone. - (left - (let ((left (frame-parameter nil 'left))) - (if (consp left) - (funcall (car left) (cadr left)) - left))) - ;; The pixel height of FRAME (which does not include title - ;; line, decorations, and sometimes neither the menu nor - ;; the toolbar). - (frame-height (frame-pixel-height)) - ;; The pixel height of FRAME's root window (we don't care - ;; about the window's body height since the return value of - ;; `window-text-pixel-size' includes header and mode line). - (window-height (window-pixel-height)) - ;; The difference in pixels between the frame's pixel - ;; height and the window's height. - (extra-height (- frame-height window-height)) - ;; The pixel position of FRAME's top border. - (top - (let ((top (frame-parameter nil 'top))) - (if (consp top) - (funcall (car top) (cadr top)) - top))) - ;; Sanitize minimum and maximum sizes. - (sizes (or (frame-parameter frame 'fit-frame-to-buffer-sizes) - fit-frame-to-buffer-sizes)) - (max-height - (cond - ((numberp (nth 0 sizes)) (* (nth 0 sizes) char-height)) - ((numberp max-height) (* max-height char-height)) - (t display-height))) - (min-height - (cond - ((numberp (nth 1 sizes)) (* (nth 1 sizes) char-height)) - ((numberp min-height) (* min-height char-height)) - (t (* window-min-height char-height)))) - (max-width - (cond - ((numberp (nth 2 sizes)) - (- (* (nth 2 sizes) char-width) window-extra-width)) - ((numberp max-width) - (- (* max-width char-width) window-extra-width)) - (t display-width))) - (min-width - (cond - ((numberp (nth 3 sizes)) - (- (* (nth 3 sizes) char-width) window-extra-width)) - ((numberp min-width) - (- (* min-width char-width) window-extra-width)) - (t (* window-min-width char-width)))) - ;; Note: Currently, for a new frame the sizes of the header - ;; and mode line may be estimated incorrectly - (value (window-text-pixel-size - nil t t workarea-width workarea-height t)) - (width (+ (car value) (window-right-divider-width))) - (height - (+ (cdr value) - (window-bottom-divider-width) - (window-scroll-bar-height)))) - ;; Don't change height or width when the window's size is fixed - ;; in either direction or ONLY forbids it. - (cond - ((or (eq window-size-fixed 'width) (eq only 'vertically)) - (setq width nil)) - ((or (eq window-size-fixed 'height) (eq only 'horizontally)) - (setq height nil))) - ;; Fit width to constraints. - (when width - (unless frame-resize-pixelwise - ;; Round to character sizes. - (setq width (* (/ (+ width char-width -1) char-width) - char-width))) - ;; Fit to maximum and minimum widths. - (setq width (max (min width max-width) min-width)) - ;; Add extra width. - (setq width (+ width extra-width)) - ;; Preserve margins. - (let ((right (+ left width))) - (cond - ((> right right-margin) - ;; Move frame to left (we don't know its real width). - (setq left (max left-margin (- left (- right right-margin))))) - ((< left left-margin) - ;; Move frame to right. - (setq left left-margin))))) - ;; Fit height to constraints. - (when height - (unless frame-resize-pixelwise - (setq height (* (/ (+ height char-height -1) char-height) - char-height))) - ;; Fit to maximum and minimum heights. - (setq height (max (min height max-height) min-height)) - ;; Add extra height. - (setq height (+ height extra-height)) - ;; Preserve margins. - (let ((bottom (+ top height))) - (cond - ((> bottom bottom-margin) - ;; Move frame up (we don't know its real height). - (setq top (max top-margin (- top (- bottom bottom-margin))))) - ((< top top-margin) - ;; Move frame down. - (setq top top-margin))))) - ;; Apply changes. - (set-frame-position frame left top) - ;; Clumsily try to translate our calculations to what - ;; `set-frame-size' wants. - (when width - (setq width (- (+ (frame-text-width) width) - extra-width window-body-width))) - (when height - (setq height (- (+ (frame-text-height) height) - extra-height window-height))) - (set-frame-size - frame - (if width - (if frame-resize-pixelwise - width - (/ width char-width)) - (frame-text-width)) - (if height - (if frame-resize-pixelwise - height - (/ height char-height)) - (frame-text-height)) - frame-resize-pixelwise))))) + (let* ((char-width (frame-char-width frame)) + (char-height (frame-char-height frame)) + ;; WINDOW is FRAME's root window. + (window (frame-root-window frame)) + (parent (frame-parent frame)) + (monitor-attributes + (unless parent + (car (display-monitor-attributes-list + (frame-parameter frame 'display))))) + ;; FRAME'S parent or display sizes. Used in connection + ;; with margins. + (geometry + (unless parent + (cdr (assq 'geometry monitor-attributes)))) + (parent-or-display-width + (if parent + (frame-native-width parent) + (- (nth 2 geometry) (nth 0 geometry)))) + (parent-or-display-height + (if parent + (frame-native-height parent) + (- (nth 3 geometry) (nth 1 geometry)))) + ;; FRAME'S parent or workarea sizes. Used when no margins + ;; are specified. + (parent-or-workarea + (if parent + `(0 0 ,parent-or-display-width ,parent-or-display-height) + (cdr (assq 'workarea monitor-attributes)))) + ;; The outer size of FRAME. Needed to calculate the + ;; margins around the root window's body that have to + ;; remain untouched by fitting. + (outer-edges (frame-edges frame 'outer-edges)) + (outer-width (if outer-edges + (- (nth 2 outer-edges) (nth 0 outer-edges)) + ;; A poor guess. + (frame-pixel-width frame))) + (outer-height (if outer-edges + (- (nth 3 outer-edges) (nth 1 outer-edges)) + ;; Another poor guess. + (frame-pixel-height frame))) + ;; The text size of of FRAME. Needed to specify FRAME's + ;; text size after the root window's body's new sizes have + ;; been calculated. + (text-width (frame-text-width frame)) + (text-height (frame-text-height frame)) + ;; WINDOW's body size. + (body-width (window-body-width window t)) + (body-height (window-body-height window t)) + ;; The difference between FRAME's outer size and WINDOW's + ;; body size. + (outer-minus-body-width (- outer-width body-width)) + (outer-minus-body-height (- outer-height body-height)) + ;; The difference between FRAME's text size and WINDOW's + ;; body size (these values "should" be positive). + (text-minus-body-width (- text-width body-width)) + (text-minus-body-height (- text-height body-height)) + ;; The current position of FRAME. + (position (frame-position frame)) + (left (car position)) + (top (cdr position)) + ;; The margins specified for FRAME. These represent pixel + ;; offsets from the left, top, right and bottom edge of the + ;; display or FRAME's parent's native rectangle and have to + ;; take care of the display's taskbar and other obstacles. + ;; If they are unspecified, constrain the resulting frame + ;; to its workarea or the parent frame's native rectangle. + (margins (or (frame-parameter frame 'fit-frame-to-buffer-margins) + fit-frame-to-buffer-margins)) + ;; Convert margins intto pixel offsets from the left-top + ;; corner of FRAME's display or parent. + (left-margin (if (nth 0 margins) + (window--sanitize-margin + (nth 0 margins) 0 parent-or-display-width) + (nth 0 parent-or-workarea))) + (top-margin (if (nth 1 margins) + (window--sanitize-margin + (nth 1 margins) 0 parent-or-display-height) + (nth 1 parent-or-workarea))) + (right-margin (if (nth 2 margins) + (- parent-or-display-width + (window--sanitize-margin + (nth 2 margins) left-margin + parent-or-display-width)) + (nth 2 parent-or-workarea))) + (bottom-margin (if (nth 3 margins) + (- parent-or-display-height + (window--sanitize-margin + (nth 3 margins) top-margin + parent-or-display-height)) + (nth 3 parent-or-workarea))) + ;; Minimum and maximum sizes specified for FRAME. + (sizes (or (frame-parameter frame 'fit-frame-to-buffer-sizes) + fit-frame-to-buffer-sizes)) + ;; Calculate the minimum and maximum pixel sizes of FRAME + ;; from the values provided by the MAX-HEIGHT, MIN-HEIGHT, + ;; MAX-WIDTH and MIN-WIDTH arguments or, if these are nil, + ;; from those provided by `fit-frame-to-buffer-sizes'. + (max-height + (min + (cond + ((numberp max-height) (* max-height char-height)) + ((numberp (nth 0 sizes)) (* (nth 0 sizes) char-height)) + (t parent-or-display-height)) + ;; The following is the maximum height that fits into the + ;; top and bottom margins. + (max (- bottom-margin top-margin outer-minus-body-height)))) + (min-height + (cond + ((numberp min-height) (* min-height char-height)) + ((numberp (nth 1 sizes)) (* (nth 1 sizes) char-height)) + (t (window-min-size window nil nil t)))) + (max-width + (min + (cond + ((numberp max-width) (* max-width char-width)) + ((numberp (nth 2 sizes)) (* (nth 2 sizes) char-width)) + (t parent-or-display-width)) + ;; The following is the maximum width that fits into the + ;; left and right margins. + (max (- right-margin left-margin outer-minus-body-width)))) + (min-width + (cond + ((numberp min-width) (* min-width char-width)) + ((numberp (nth 3 sizes)) (nth 3 sizes)) + (t (window-min-size window t nil t)))) + ;; Note: Currently, for a new frame the sizes of the header + ;; and mode line may be estimated incorrectly + (size + (window-text-pixel-size window t t max-width max-height)) + (width (max (car size) min-width)) + (height (max (cdr size) min-height))) + ;; Don't change height or width when the window's size is fixed + ;; in either direction or ONLY forbids it. + (cond + ((or (eq window-size-fixed 'width) (eq only 'vertically)) + (setq width nil)) + ((or (eq window-size-fixed 'height) (eq only 'horizontally)) + (setq height nil))) + ;; Fit width to constraints. + (when width + (unless frame-resize-pixelwise + ;; Round to character sizes. + (setq width (* (/ (+ width char-width -1) char-width) + char-width))) + ;; The new outer width (in pixels). + (setq outer-width (+ width outer-minus-body-width)) + ;; Maybe move FRAME to preserve margins. + (let ((right (+ left outer-width))) + (cond + ((> right right-margin) + ;; Move frame to left. + (setq left (max left-margin (- left (- right right-margin))))) + ((< left left-margin) + ;; Move frame to right. + (setq left left-margin))))) + ;; Fit height to constraints. + (when height + (unless frame-resize-pixelwise + (setq height (* (/ (+ height char-height -1) char-height) + char-height))) + ;; The new outer height. + (setq outer-height (+ height outer-minus-body-height)) + ;; Preserve margins. + (let ((bottom (+ top outer-height))) + (cond + ((> bottom bottom-margin) + ;; Move frame up. + (setq top (max top-margin (- top (- bottom bottom-margin))))) + ((< top top-margin) + ;; Move frame down. + (setq top top-margin))))) + ;; Apply our changes. + (setq text-width + (if width + (+ width text-minus-body-width) + (frame-text-width frame))) + (setq text-height + (if height + (+ height text-minus-body-height) + (frame-text-height frame))) + (modify-frame-parameters + frame `((left . ,left) (top . ,top) + (width . (text-pixels . ,text-width)) + (height . (text-pixels . ,text-height))))))) (defun fit-window-to-buffer (&optional window max-height min-height max-width min-width preserve-size) "Adjust size of WINDOW to display its buffer's contents exactly. @@ -8286,6 +8345,168 @@ shrink-window-if-larger-than-buffer (when (and (window-combined-p window) (pos-visible-in-window-p (point-min) window)) (fit-window-to-buffer window (window-total-height window)))) + +(defun window-largest-empty-rectangle--maximums-1 (quad maximums) + "Support function for `window-largest-empty-rectangle'." + (cond + ((null maximums) + (list quad)) + ((> (car quad) (caar maximums)) + (cons quad maximums)) + (t + (cons (car maximums) + (window-largest-empty-rectangle--maximums-1 quad (cdr maximums)))))) + +(defun window-largest-empty-rectangle--maximums (quad maximums count) + "Support function for `window-largest-empty-rectangle'." + (setq maximums (window-largest-empty-rectangle--maximums-1 quad maximums)) + (if (> (length maximums) count) + (nbutlast maximums) + maximums)) + +(defun window-largest-empty-rectangle--disjoint-maximums (maximums count) + "Support function for `window-largest-empty-rectangle'." + (setq maximums (sort maximums (lambda (x y) (> (car x) (car y))))) + (let ((new-length 0) + new-maximums) + (while (and maximums (< new-length count)) + (let* ((maximum (car maximums)) + (at (nth 2 maximum)) + (to (nth 3 maximum))) + (catch 'drop + (dolist (new-maximum new-maximums) + (let ((new-at (nth 2 new-maximum)) + (new-to (nth 3 new-maximum))) + (when (if (< at new-at) (> to new-at) (< at new-to)) + ;; Intersection -> drop. + (throw 'drop nil)))) + (setq new-maximums (cons maximum new-maximums)) + (setq new-length (1+ new-length))) + (setq maximums (cdr maximums)))) + + (nreverse new-maximums))) + +(defun window-largest-empty-rectangle (&optional window count min-width min-height positions left) + "Return dimensions of largest empty rectangle in WINDOW. +WINDOW must be a live window and defaults to the selected one. + +The return value is a triple of the width and the start and end +Y-coordinates of the largest rectangle that can be inscribed into +the empty space (the space not displaying any text) of WINDOW's +text area. The return value is nil if the current glyph matrix +of WINDOW is not up-to-date. + +Optional argument COUNT, if non-nil, specifies the maximum number +of rectangles to return. This means that the return value is a +list of triples specifying rectangles with the largest rectangle +first. COUNT can be also a cons cell whose car specifies the +number of rectangles to return and whose cdr, if non-nil, states +that all rectangles returned must be disjoint. + +Note that the right edge of any rectangle returned by this +function is the right edge of WINDOW (the left edge if its buffer +displays RTL text). + +Optional arguments MIN-WIDTH and MIN-HEIGHT, if non-nil, specify +the minimum width and height of any rectangle returned. + +Optional argument POSITIONS, if non-nil, is a cons cell whose car +specifies the uppermost and whose cdr specifies the lowermost +pixel position that must be covered by any rectangle returned. +Note that positions are counted from the start of the text area +of WINDOW. + +Optional argument LEFT, if non-nil, means to return values suitable for +buffers displaying right to left text." + ;; Process lines as returned by ‘window-lines-pixel-dimensions’. + ;; STACK is a stack that contains rows that have to be processed yet. + (let* ((window (window-normalize-window window t)) + (disjoint (and (consp count) (cdr count))) + (count (or (and (numberp count) count) + (and (consp count) (numberp (car count)) (car count)))) + (rows (window-lines-pixel-dimensions window nil nil t t left)) + (rows-at 0) + (max-size 0) + row stack stack-at stack-to + top top-width top-at top-to top-size + max-width max-at max-to maximums) + ;; ROWS-AT is the position where the first element of ROWS starts. + ;; STACK-AT is the position where the first element of STACK starts. + (while rows + (setq row (car rows)) + (if (or (not stack) (>= (car row) (caar stack))) + (progn + (unless stack + (setq stack-at rows-at)) + (setq stack (cons row stack)) + ;; Set ROWS-AT to where the first element of ROWS ends + ;; which, after popping ROW, makes it the start position of + ;; the next ROW. + (setq rows-at (cdr row)) + (setq rows (cdr rows))) + (setq top (car stack)) + (setq stack (cdr stack)) + (setq top-width (car top)) + (setq top-at (if stack (cdar stack) stack-at)) + (setq top-to (cdr top)) + (setq top-size (* top-width (- top-to top-at))) + (unless (or (and min-width (< top-width min-width)) + (and min-height (< (- top-to top-at) min-height)) + (and positions + (or (> top-at (car positions)) + (< top-to (cdr positions))))) + (if count + (if disjoint + (setq maximums (cons (list top-size top-width top-at top-to) + maximums)) + (setq maximums (window-largest-empty-rectangle--maximums + (list top-size top-width top-at top-to) + maximums count))) + (when (> top-size max-size) + (setq max-size top-size) + (setq max-width top-width) + (setq max-at top-at) + (setq max-to top-to)))) + (if (and stack (> (caar stack) (car row))) + ;; Have new top element of stack include old top. + (setq stack (cons (cons (caar stack) (cdr top)) (cdr stack))) + ;; Move rows-at backwards to top-at. + (setq rows-at top-at)))) + + (when stack + ;; STACK-TO is the position where the stack ends. + (setq stack-to (cdar stack)) + (while stack + (setq top (car stack)) + (setq stack (cdr stack)) + (setq top-width (car top)) + (setq top-at (if stack (cdar stack) stack-at)) + (setq top-size (* top-width (- stack-to top-at))) + (unless (or (and min-width (< top-width min-width)) + (and min-height (< (- stack-to top-at) min-height)) + (and positions + (or (> top-at (car positions)) + (< stack-to (cdr positions))))) + (if count + (if disjoint + (setq maximums (cons (list top-size top-width top-at stack-to) + maximums)) + (setq maximums (window-largest-empty-rectangle--maximums + (list top-size top-width top-at stack-to) + maximums count))) + (when (> top-size max-size) + (setq max-size top-size) + (setq max-width top-width) + (setq max-at top-at) + (setq max-to stack-to)))))) + + (cond + (maximums + (if disjoint + (window-largest-empty-rectangle--disjoint-maximums maximums count) + maximums)) + ((> max-size 0) + (list max-width max-at max-to))))) \f (defun kill-buffer-and-window () "Kill the current buffer and delete the selected window." diff --git a/src/dispextern.h b/src/dispextern.h index d1e4715..8644ce2 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1106,7 +1106,7 @@ struct glyph_row #define MATRIX_BOTTOM_TEXT_ROW(MATRIX, W) \ ((MATRIX)->rows \ + (MATRIX)->nrows \ - - (WINDOW_WANTS_MODELINE_P ((W)) ? 1 : 0)) + - (window_wants_mode_line ((W)) ? 1 : 0)) /* Non-zero if the face of the last glyph in ROW's text area has to be drawn to the end of the text area. */ @@ -1469,40 +1469,6 @@ struct glyph_string #define DESIRED_HEADER_LINE_HEIGHT(W) \ MATRIX_HEADER_LINE_HEIGHT ((W)->desired_matrix) -/* PXW: The height checks below serve to show at least one text line - instead of a mode- and/or header line when a window gets very small. - But (1) the check fails when the mode- or header-line is taller than - the associated frame's line height and (2) we don't care much about - text visibility anyway when shrinking a frame containing a toolbar. - - So maybe these checks should be removed and any clipping left to the - window manager. */ - -/* Value is true if window W wants a mode line and is large enough - to accommodate it. */ -#define WINDOW_WANTS_MODELINE_P(W) \ - (BUFFERP ((W)->contents) \ - ? (!MINI_WINDOW_P (W) \ - && !(W)->pseudo_window_p \ - && FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (W))) \ - && !NILP (BVAR (XBUFFER ((W)->contents), mode_line_format)) \ - && WINDOW_PIXEL_HEIGHT (W) > WINDOW_FRAME_LINE_HEIGHT (W)) \ - : false) - -/* Value is true if window W wants a header line and is large enough - to accommodate it. */ -#define WINDOW_WANTS_HEADER_LINE_P(W) \ - (BUFFERP ((W)->contents) \ - ? (!MINI_WINDOW_P (W) \ - && !(W)->pseudo_window_p \ - && FRAME_WANTS_MODELINE_P (XFRAME (WINDOW_FRAME (W))) \ - && !NILP (BVAR (XBUFFER ((W)->contents), header_line_format)) \ - && (WINDOW_PIXEL_HEIGHT (W) \ - > (WINDOW_WANTS_MODELINE_P (W) \ - ? (2 * WINDOW_FRAME_LINE_HEIGHT (W)) \ - : WINDOW_FRAME_LINE_HEIGHT (W)))) \ - : false) - /* Return proper value to be used as baseline offset of font that has ASCENT and DESCENT to draw characters by the font at the vertical center of the line of frame F. diff --git a/src/dispnew.c b/src/dispnew.c index 27c69bd..0c1918f 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -377,7 +377,7 @@ struct redisplay_history { window_box (w, ANY_AREA, 0, 0, &window_width, &window_height); - header_line_p = WINDOW_WANTS_HEADER_LINE_P (w); + header_line_p = window_wants_header_line (w); header_line_changed_p = header_line_p != matrix->header_line_p; } matrix->header_line_p = header_line_p; @@ -446,7 +446,7 @@ struct redisplay_history if (w == NULL || (row == matrix->rows + dim.height - 1 - && WINDOW_WANTS_MODELINE_P (w)) + && window_wants_mode_line (w)) || (row == matrix->rows && matrix->header_line_p)) { row->glyphs[TEXT_AREA] @@ -491,7 +491,7 @@ struct redisplay_history /* The mode line, if displayed, never has marginal areas. */ if ((row == matrix->rows + dim.height - 1 - && !(w && WINDOW_WANTS_MODELINE_P (w))) + && !(w && window_wants_mode_line (w))) || (row == matrix->rows && matrix->header_line_p)) { row->glyphs[TEXT_AREA] @@ -570,7 +570,7 @@ struct redisplay_history the mode line, if any, since otherwise it will remain disabled in the current matrix, and expose events won't redraw it. */ - if (WINDOW_WANTS_MODELINE_P (w)) + if (window_wants_mode_line (w)) w->update_mode_line = 1; } else if (matrix == w->desired_matrix) @@ -5188,7 +5188,7 @@ struct row_entry start position, i.e. it excludes the header-line row, but MATRIX_ROW includes the header-line row. Adjust for a possible header-line row. */ - it_vpos = it.vpos + WINDOW_WANTS_HEADER_LINE_P (w); + it_vpos = it.vpos + window_wants_header_line (w); if (it_vpos < w->current_matrix->nrows && (row = MATRIX_ROW (w->current_matrix, it_vpos), row->enabled_p)) diff --git a/src/frame.c b/src/frame.c index 4d17a07..653e44f 100644 --- a/src/frame.c +++ b/src/frame.c @@ -328,8 +328,8 @@ struct frame * * 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. + * of FRAME. If PIXELWISE is non-nil, return the minimum inner height + * (width) of FRAME 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 @@ -341,7 +341,7 @@ struct frame * * 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. + * In either case, never return a value less than 1. */ static int frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal, @@ -373,46 +373,179 @@ struct frame * } -/* Make sure windows sizes of frame F are OK. new_width and new_height - are in pixels. A value of -1 means no change is requested for that - size (but the frame may still have to be resized to accommodate - windows with their minimum sizes). This can either issue a request - to resize the frame externally (via x_set_window_size), to resize the - frame internally (via resize_frame_windows) or do nothing at all. +#ifdef HAVE_WINDOW_SYSTEM +/** + * keep_ratio: + * + * Preserve ratios of frame F which usually happens after its parent + * frame got resized. OLD_WIDTH, OLD_HEIGHT specifies the old native + * size of F's parent, NEW_WIDTH and NEW_HEIGHT its new size. + * + * Adjust F's width if F's 'keep_ratio' parameter is non-nil and, if + * it is a cons, its car is not 'height-only'. Adjust F's height if F's + * 'keep_ratio' parameter is non-nil and, if it is a cons, its car + * is not 'width-only'. + * + * Adjust F's left position if F's 'keep_ratio' parameter is non-nil + * and, if its is a cons, its cdr is non-nil and not 'top-only'. Adjust + * F's top position if F's 'keep_ratio' parameter is non-nil and, if + * its is a cons, its cdr is non-nil and not 'left-only'. + * + * Note that when positional adjustment is requested but the size of F + * should remain unaltered in the corresponding direction, this routine + * tries to constrain F to its parent frame - something which usually + * happens when the parent frame shrinks. This means, however, that + * when the parent frame is re-enlarged later, the child's original + * position will not get restored to its pre-shrinking value. + * + * This routine is currently useful for child frames only. It might be + * eventually useful when moving non-child frames between monitors with + * different resolutions. + */ +static void +keep_ratio (struct frame *f, int old_width, int old_height, + int new_width, int new_height) +{ + Lisp_Object keep_ratio = get_frame_param (f, Qkeep_ratio); - The argument INHIBIT can assume the following values: - 0 means to unconditionally call x_set_window_size even if sizes - apparently do not change. Fx_create_frame uses this to pass the - initial size to the window manager. + if (!NILP (keep_ratio)) + { + double width_factor = (double)new_width / (double)old_width; + double height_factor = (double)new_height / (double)old_height; + int pixel_width, pixel_height, pos_x, pos_y; - 1 means to call x_set_window_size if the outer frame size really - changes. Fset_frame_size, Fset_frame_height, ... use this. + if (!CONSP (keep_ratio) || !NILP (Fcdr (keep_ratio))) + { + if (CONSP (keep_ratio) && EQ (Fcdr (keep_ratio), Qtop_only)) + pos_x = f->left_pos; + else + { + pos_x = (int)(f->left_pos * width_factor + 0.5); - 2 means to call x_set_window_size provided frame_inhibit_resize - allows it. The menu and tool bar code use this ("3" won't work - here in general because menu and tool bar are often not counted in - the frame's text height). + if (CONSP (keep_ratio) && + (NILP (Fcar (keep_ratio)) || EQ (Fcar (keep_ratio), Qheight_only))) + { + struct frame *p = FRAME_PARENT_FRAME (f); - 3 means call x_set_window_size if window minimum sizes must be - preserved or frame_inhibit_resize allows it. x_set_left_fringe, - x_set_scroll_bar_width, x_new_font ... use (or should use) this. + if (pos_x + f->pixel_width > p->pixel_width) + { + int p_f_width = p->pixel_width - f->pixel_width; - 4 means call x_set_window_size only if window minimum sizes must be - preserved. x_set_right_divider_width, x_set_border_width and the - code responsible for wrapping the tool bar use this. + if (p_f_width <= 0) + pos_x = 0; + else + pos_x = (int)(p_f_width * width_factor * 0.5 + 0.5); + } + } + + f->left_pos = pos_x; + } + + if (CONSP (keep_ratio) && EQ (Fcdr (keep_ratio), Qleft_only)) + pos_y = f->top_pos; + else + { + pos_y = (int)(f->top_pos * height_factor + 0.5); + + if (CONSP (keep_ratio) && + (NILP (Fcar (keep_ratio)) || EQ (Fcar (keep_ratio), Qwidth_only))) + /* When positional adjustment was requested and the + width of F should remain unaltered, try to constrain + F to its parent. This means that when the parent + frame is enlarged later the child's original position + won't get restored. */ + { + struct frame *p = FRAME_PARENT_FRAME (f); + + if (pos_y + f->pixel_height > p->pixel_height) + { + int p_f_height = p->pixel_height - f->pixel_height; + + if (p_f_height <= 0) + pos_y = 0; + else + pos_y = (int)(p_f_height * height_factor * 0.5 + 0.5); + } + } - 5 means to never call x_set_window_size. change_frame_size uses - this. + f->top_pos = pos_y; + } - Note that even when x_set_window_size is not called, individual - windows may have to be resized (via `window--sanitize-window-sizes') - in order to support minimum size constraints. + x_set_offset (f, pos_x, pos_y, -1); + } - PRETEND is as for change_frame_size. PARAMETER, if non-nil, is the - symbol of the parameter changed (like `menu-bar-lines', `font', ...). - This is passed on to frame_inhibit_resize to let the latter decide on - a case-by-case basis whether the frame may be resized externally. */ + if (!CONSP (keep_ratio) || !NILP (Fcar (keep_ratio))) + { + if (CONSP (keep_ratio) && EQ (Fcar (keep_ratio), Qheight_only)) + pixel_width = -1; + else + { + pixel_width = (int)(f->pixel_width * width_factor + 0.5); + pixel_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, pixel_width); + } + + if (CONSP (keep_ratio) && EQ (Fcar (keep_ratio), Qwidth_only)) + pixel_height = -1; + else + { + pixel_height = (int)(f->pixel_height * height_factor + 0.5); + pixel_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, pixel_height); + } + + adjust_frame_size (f, pixel_width, pixel_height, 1, 0, + Qkeep_ratio); + } + } +} +#endif + + +/** + * adjust_frame_size: + * + * Adjust size of frame F. NEW_WIDTH and NEW_HEIGHT specify the new + * text size of F in pixels. A value of -1 means no change is requested + * for that direction (but the frame may still have to be resized to + * accommodate windows with their minimum sizes). This can either issue + * a request to resize the frame externally (via x_set_window_size), to + * resize the frame internally (via resize_frame_windows) or do nothing + * at all. + * + * The argument INHIBIT can assume the following values: + * + * 0 means to unconditionally call x_set_window_size even if sizes + * apparently do not change. Fx_create_frame uses this to pass the + * initial size to the window manager. + * + * 1 means to call x_set_window_size if the native frame size really + * changes. Fset_frame_size, Fset_frame_height, ... use this. + * + * 2 means to call x_set_window_size provided frame_inhibit_resize + * allows it. The menu and tool bar code use this ("3" won't work + * here in general because menu and tool bar are often not counted in + * the frame's text height). + * + * 3 means call x_set_window_size if window minimum sizes must be + * preserved or frame_inhibit_resize allows it. x_set_left_fringe, + * x_set_scroll_bar_width, x_new_font ... use (or should use) this. + * + * 4 means call x_set_window_size only if window minimum sizes must be + * preserved. x_set_right_divider_width, x_set_border_width and the + * code responsible for wrapping the tool bar use this. + * + * 5 means to never call x_set_window_size. change_frame_size uses + * this. + * + * Note that even when x_set_window_size is not called, individual + * windows may have to be resized (via `window--sanitize-window-sizes') + * in order to support minimum size constraints. + * + * PRETEND is as for change_frame_size. PARAMETER, if non-nil, is the + * symbol of the parameter changed (like `menu-bar-lines', `font', ...). + * This is passed on to frame_inhibit_resize to let the latter decide on + * a case-by-case basis whether the frame may be resized externally. + */ void adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit, bool pretend, Lisp_Object parameter) @@ -636,6 +769,18 @@ struct frame * || new_pixel_height != old_pixel_height); unblock_input (); + +#ifdef HAVE_WINDOW_SYSTEM + { + /* Adjust size of F's child frames. */ + Lisp_Object frames, frame1; + + FOR_EACH_FRAME (frames, frame1) + if (FRAME_PARENT_FRAME (XFRAME (frame1)) == f) + keep_ratio (XFRAME (frame1), old_pixel_width, old_pixel_height, + new_pixel_width, new_pixel_height); + } +#endif } /* Allocate basically initialized frame. */ @@ -684,6 +829,7 @@ struct frame * f->horizontal_scroll_bars = false; f->want_fullscreen = FULLSCREEN_NONE; f->undecorated = false; + f->no_special_glyphs = false; #ifndef HAVE_NTGUI f->override_redirect = false; #endif @@ -2004,8 +2150,101 @@ of them (the selected terminal frame) is actually displayed. { return delete_frame (frame, !NILP (force) ? Qt : Qnil); } - \f +#ifdef HAVE_WINDOW_SYSTEM +/** + * frame_internal_border_part: + * + * Return part of internal border the coordinates X and Y relative to + * frame F are on. Return nil if the coordinates are not on the + * internal border of F. + * + * Return one of INTERNAL_BORDER_LEFT_EDGE, INTERNAL_BORDER_TOP_EDGE, + * INTERNAL_BORDER_RIGHT_EDGE or INTERNAL_BORDER_BOTTOM_EDGE when the + * mouse cursor is on the corresponding border with an offset of at + * least one canonical character height from that border's edges. + * + * If no border part could be found this way, return one of + * INTERNAL_BORDER_TOP_LEFT_CORNER, INTERNAL_BORDER_TOP_RIGHT_CORNER, + * INTERNAL_BORDER_BOTTOM_LEFT_CORNER or + * INTERNAL_BORDER_BOTTOM_RIGHT_CORNER to indicate that the mouse is in + * one of the corresponding corners. This means that for very small + * frames an `edge' return value is preferred. + */ +enum internal_border_part +frame_internal_border_part (struct frame *f, int x, int y) +{ + int border = FRAME_INTERNAL_BORDER_WIDTH (f); + int offset = FRAME_LINE_HEIGHT (f); + int width = FRAME_PIXEL_WIDTH (f); + int height = FRAME_PIXEL_HEIGHT (f); + enum internal_border_part part = INTERNAL_BORDER_NONE; + + if (offset < border) + /* For very wide borders make offset at least as large as + border. */ + offset = border; + + if (offset < x && x < width - offset) + /* Top or bottom border. */ + { + if (0 <= y && y <= border) + part = INTERNAL_BORDER_TOP_EDGE; + else if (height - border <= y && y <= height) + part = INTERNAL_BORDER_BOTTOM_EDGE; + } + else if (offset < y && y < height - offset) + /* Left or right border. */ + { + if (0 <= x && x <= border) + part = INTERNAL_BORDER_LEFT_EDGE; + else if (width - border <= x && x <= width) + part = INTERNAL_BORDER_RIGHT_EDGE; + } + else + { + /* An edge. */ + int half_width = width / 2; + int half_height = height / 2; + + if (0 <= x && x <= border) + { + /* A left edge. */ + if (0 <= y && y <= half_height) + part = INTERNAL_BORDER_TOP_LEFT_CORNER; + else if (half_height < y && y <= height) + part = INTERNAL_BORDER_BOTTOM_LEFT_CORNER; + } + else if (width - border <= x && x <= width) + { + /* A right edge. */ + if (0 <= y && y <= half_height) + part = INTERNAL_BORDER_TOP_RIGHT_CORNER; + else if (half_height < y && y <= height) + part = INTERNAL_BORDER_BOTTOM_RIGHT_CORNER; + } + else if (0 <= y && y <= border) + { + /* A top edge. */ + if (0 <= x && x <= half_width) + part = INTERNAL_BORDER_TOP_LEFT_CORNER; + else if (half_width < x && x <= width) + part = INTERNAL_BORDER_TOP_RIGHT_CORNER; + } + else if (height - border <= y && y <= height) + { + /* A bottom edge. */ + if (0 <= x && x <= half_width) + part = INTERNAL_BORDER_BOTTOM_LEFT_CORNER; + else if (half_width < x && x <= width) + part = INTERNAL_BORDER_BOTTOM_RIGHT_CORNER; + } + } + + return part; +} +#endif + /* Return mouse position in character cell units. */ DEFUN ("mouse-position", Fmouse_position, Smouse_position, 0, 0, 0, @@ -2962,49 +3201,47 @@ Each element of ALIST has the form (PARM . VALUE), where PARM is a symbol. return make_number (1); } -DEFUN ("frame-pixel-height", Fframe_pixel_height, - Sframe_pixel_height, 0, 1, 0, - doc: /* Return a FRAME's height in pixels. -If FRAME is omitted or nil, the selected frame is used. The exact value -of the result depends on the window-system and toolkit in use: - -In the Gtk+ version of Emacs, it includes only any window (including -the minibuffer or echo area), mode line, and header line. It does not -include the tool bar or menu bar. - -With other graphical versions, it also includes the tool bar and the -menu bar. - -For a text terminal, it includes the menu bar. In this case, the -result is really in characters rather than pixels (i.e., is identical -to `frame-height'). */) +DEFUN ("frame-native-width", Fframe_native_width, + Sframe_native_width, 0, 1, 0, + doc: /* Return FRAME's native width in pixels. +For a terminal frame, the result really gives the width in characters. +If FRAME is omitted or nil, the selected frame is used. */) (Lisp_Object frame) { struct frame *f = decode_any_frame (frame); #ifdef HAVE_WINDOW_SYSTEM if (FRAME_WINDOW_P (f)) - return make_number (FRAME_PIXEL_HEIGHT (f)); + return make_number (FRAME_PIXEL_WIDTH (f)); else #endif - return make_number (FRAME_TOTAL_LINES (f)); + return make_number (FRAME_TOTAL_COLS (f)); } -DEFUN ("frame-pixel-width", Fframe_pixel_width, - Sframe_pixel_width, 0, 1, 0, - doc: /* Return FRAME's width in pixels. -For a terminal frame, the result really gives the width in characters. -If FRAME is omitted or nil, the selected frame is used. */) +DEFUN ("frame-native-height", Fframe_native_height, + Sframe_native_height, 0, 1, 0, + doc: /* Return FRAME's native height in pixels. +If FRAME is omitted or nil, the selected frame is used. The exact value +of the result depends on the window-system and toolkit in use: + +In the Gtk+ and NS versions, it includes only any window (including the +minibuffer or echo area), mode line, and header line. It does not +include the tool bar or menu bar. With other graphical versions, it may +also include the tool bar and the menu bar. + +For a text terminal, it includes the menu bar. In this case, the +result is really in characters rather than pixels (i.e., is identical +to `frame-height'). */) (Lisp_Object frame) { struct frame *f = decode_any_frame (frame); #ifdef HAVE_WINDOW_SYSTEM if (FRAME_WINDOW_P (f)) - return make_number (FRAME_PIXEL_WIDTH (f)); + return make_number (FRAME_PIXEL_HEIGHT (f)); else #endif - return make_number (FRAME_TOTAL_COLS (f)); + return make_number (FRAME_TOTAL_LINES (f)); } DEFUN ("tool-bar-pixel-width", Ftool_bar_pixel_width, @@ -3087,8 +3324,8 @@ result is really in characters rather than pixels (i.e., is identical return make_number (FRAME_TOTAL_FRINGE_WIDTH (decode_any_frame (frame))); } -DEFUN ("frame-border-width", Fborder_width, Sborder_width, 0, 1, 0, - doc: /* Return border width of FRAME in pixels. */) +DEFUN ("frame-internal-border-width", Fframe_internal_border_width, Sframe_internal_border_width, 0, 1, 0, + doc: /* Return width of FRAME's internal border in pixels. */) (Lisp_Object frame) { return make_number (FRAME_INTERNAL_BORDER_WIDTH (decode_any_frame (frame))); @@ -3224,7 +3461,6 @@ outer frame in pixels relative to an origin (0, 0) of FRAME's display. return Qt; } - \f /*********************************************************************** Frame Parameters @@ -3289,10 +3525,193 @@ struct frame_parm_table { {"no-accept-focus", SYMBOL_INDEX (Qno_accept_focus)}, {"z-group", SYMBOL_INDEX (Qz_group)}, {"override-redirect", SYMBOL_INDEX (Qoverride_redirect)}, + {"no-special-glyphs", SYMBOL_INDEX (Qno_special_glyphs)}, }; #ifdef HAVE_WINDOW_SYSTEM +/* Enumeration type for switch in frame_float. */ +enum frame_float_type +{ + FRAME_FLOAT_WIDTH, + FRAME_FLOAT_HEIGHT, + FRAME_FLOAT_LEFT, + FRAME_FLOAT_TOP +}; + +/** + * frame_float: + * + * Process the value VAL of the float type frame parameter 'width', + * 'height', 'left', or 'top' specified via a frame_float_type + * enumeration type WHAT for frame F. Such parameters relate the outer + * size or position of F to the size of the F's display or parent frame + * which have to be both available in some way. + * + * The return value is a size or position value in pixels. VAL must be + * in the range 0.0 to 1.0 where a width/height of 0.0 means to return 0 + * and 1.0 means to return the full width/height of the display/parent. + * For positions, 0.0 means position in the left/top corner of the + * display/parent while 1.0 means to position at the right/bottom corner + * of the display/parent frame. + * + * Set PARENT_DONE and OUTER_DONE to avoid recalculation of the outer + * size or parent or display attributes when more float parameters are + * calculated in a row: -1 means not processed yet, 0 means processing + * failed, 1 means processing succeeded. + * + * Return DEFAULT_VALUE when processing fails for whatever reason with + * one exception: When calculating F's outer edges fails (probably + * because F has not been created yet) return the difference between F's + * native and text size. + */ +static int +frame_float (struct frame *f, Lisp_Object val, enum frame_float_type what, + int *parent_done, int *outer_done, int default_value) +{ + double d_val = XFLOAT_DATA (val); + + if (d_val < 0.0 || d_val > 1.0) + /* Invalid VAL. */ + return default_value; + else + { + static unsigned parent_width, parent_height; + static int parent_left, parent_top; + static unsigned outer_minus_text_width, outer_minus_text_height; + struct frame *p = FRAME_PARENT_FRAME (f); + + if (*parent_done == 1) + ; + else if (p) + { + parent_width = FRAME_PIXEL_WIDTH (p); + parent_height = FRAME_PIXEL_HEIGHT (p); + *parent_done = 1; + } + else + { + if (*parent_done == 0) + /* No workarea available. */ + return default_value; + else if (*parent_done == -1) + { + Lisp_Object monitor_attributes; + Lisp_Object workarea; + Lisp_Object frame; + + XSETFRAME (frame, f); + monitor_attributes = Fcar (call1 (Qdisplay_monitor_attributes_list, frame)); + if (NILP (monitor_attributes)) + { + /* No monitor attributes available. */ + *parent_done = 0; + + return default_value; + } + + workarea = Fcdr (Fassq (Qworkarea, monitor_attributes)); + if (NILP (workarea)) + { + /* No workarea available. */ + *parent_done = 0; + + return default_value; + } + + /* Workarea available. */ + parent_left = XINT (Fnth (make_number (0), workarea)); + parent_top = XINT (Fnth (make_number (1), workarea)); + parent_width = XINT (Fnth (make_number (2), workarea)); + parent_height = XINT (Fnth (make_number (3), workarea)); + *parent_done = 1; + } + } + + if (*outer_done == 1) + ; + else if (FRAME_UNDECORATED (f)) + { + outer_minus_text_width + = FRAME_PIXEL_WIDTH (f) - FRAME_TEXT_WIDTH (f); + outer_minus_text_height + = FRAME_PIXEL_HEIGHT (f) - FRAME_TEXT_HEIGHT (f); + *outer_done = 1; + } + else if (*outer_done == 0) + /* No outer size available. */ + return default_value; + else if (*outer_done == -1) + { + Lisp_Object frame, outer_edges; + + XSETFRAME (frame, f); + outer_edges = call2 (Qframe_edges, frame, Qouter_edges); + + if (!NILP (outer_edges)) + { + outer_minus_text_width + = (XINT (Fnth (make_number (2), outer_edges)) + - XINT (Fnth (make_number (0), outer_edges)) + - FRAME_TEXT_WIDTH (f)); + outer_minus_text_height + = (XINT (Fnth (make_number (3), outer_edges)) + - XINT (Fnth (make_number (1), outer_edges)) + - FRAME_TEXT_HEIGHT (f)); + } + else + { + /* If we can't get any outer edges, proceed as if the frame + were undecorated. */ + outer_minus_text_width + = FRAME_PIXEL_WIDTH (f) - FRAME_TEXT_WIDTH (f); + outer_minus_text_height + = FRAME_PIXEL_HEIGHT (f) - FRAME_TEXT_HEIGHT (f); + } + + *outer_done = 1; + } + + switch (what) + { + case FRAME_FLOAT_WIDTH: + return parent_width * d_val - outer_minus_text_width; + + case FRAME_FLOAT_HEIGHT: + return parent_height * d_val - outer_minus_text_height; + + case FRAME_FLOAT_LEFT: + { + int rest_width = (parent_width + - FRAME_TEXT_WIDTH (f) + - outer_minus_text_width); + + if (p) + return (rest_width <= 0 ? 0 : d_val * rest_width); + else + return (rest_width <= 0 + ? parent_left + : parent_left + d_val * rest_width); + } + case FRAME_FLOAT_TOP: + { + int rest_height = (parent_height + - FRAME_TEXT_HEIGHT (f) + - outer_minus_text_height); + + if (p) + return (rest_height <= 0 ? 0 : d_val * rest_height); + else + return (rest_height <= 0 + ? parent_top + : parent_top + d_val * rest_height); + } + default: + emacs_abort (); + } + } +} + /* Change the parameters of frame F as specified by ALIST. If a parameter is not specially recognized, do nothing special; otherwise call the `x_set_...' function for that parameter. @@ -3302,7 +3721,8 @@ struct frame_parm_table { void x_set_frame_parameters (struct frame *f, Lisp_Object alist) { - Lisp_Object tail; + Lisp_Object tail, frame; + /* If both of these parameters are present, it's more efficient to set them both at once. So we wait until we've looked at the @@ -3327,7 +3747,9 @@ struct frame_parm_table { #ifdef HAVE_X_WINDOWS bool icon_left_no_change = 0, icon_top_no_change = 0; #endif + int parent_done = -1, outer_done = -1; + XSETFRAME (frame, f); for (size = 0, tail = alist; CONSP (tail); tail = XCDR (tail)) size++; CHECK_LIST_END (tail, alist); @@ -3388,6 +3810,9 @@ struct frame_parm_table { else if (CONSP (val) && EQ (XCAR (val), Qtext_pixels) && RANGED_INTEGERP (0, XCDR (val), INT_MAX)) width = XFASTINT (XCDR (val)); + else if (FLOATP (val)) + width = frame_float (f, val, FRAME_FLOAT_WIDTH, &parent_done, + &outer_done, -1); } else if (EQ (prop, Qheight)) { @@ -3396,6 +3821,9 @@ struct frame_parm_table { else if (CONSP (val) && EQ (XCAR (val), Qtext_pixels) && RANGED_INTEGERP (0, XCDR (val), INT_MAX)) height = XFASTINT (XCDR (val)); + else if (FLOATP (val)) + height = frame_float (f, val, FRAME_FLOAT_HEIGHT, &parent_done, + &outer_done, -1); } else if (EQ (prop, Qtop)) top = val; @@ -3472,105 +3900,100 @@ struct frame_parm_table { Don't set these parameters unless they actually differ from the window's current parameters; the window may not actually exist yet. */ - { - Lisp_Object frame; - - XSETFRAME (frame, f); - - if ((width != -1 && width != FRAME_TEXT_WIDTH (f)) - || (height != -1 && height != FRAME_TEXT_HEIGHT (f))) - /* We could consider checking f->after_make_frame here, but I - don't have the faintest idea why the following is needed at - all. With the old setting it can get a Heisenbug when - EmacsFrameResize intermittently provokes a delayed - change_frame_size in the middle of adjust_frame_size. */ - /** || (f->can_x_set_window_size && (f->new_height || f->new_width))) **/ - adjust_frame_size (f, width, height, 1, 0, Qx_set_frame_parameters); - - if ((!NILP (left) || !NILP (top)) - && ! (left_no_change && top_no_change) - && ! (NUMBERP (left) && XINT (left) == f->left_pos - && NUMBERP (top) && XINT (top) == f->top_pos)) - { - int leftpos = 0; - int toppos = 0; + if ((width != -1 && width != FRAME_TEXT_WIDTH (f)) + || (height != -1 && height != FRAME_TEXT_HEIGHT (f))) + /* We could consider checking f->after_make_frame here, but I + don't have the faintest idea why the following is needed at + all. With the old setting it can get a Heisenbug when + EmacsFrameResize intermittently provokes a delayed + change_frame_size in the middle of adjust_frame_size. */ + /** || (f->can_x_set_window_size && (f->new_height || f->new_width))) **/ + adjust_frame_size (f, width, height, 1, 0, Qx_set_frame_parameters); + + if ((!NILP (left) || !NILP (top)) + && ! (left_no_change && top_no_change) + && ! (NUMBERP (left) && XINT (left) == f->left_pos + && NUMBERP (top) && XINT (top) == f->top_pos)) + { + int leftpos = 0; + int toppos = 0; - /* Record the signs. */ - f->size_hint_flags &= ~ (XNegative | YNegative); - if (EQ (left, Qminus)) - f->size_hint_flags |= XNegative; - else if (TYPE_RANGED_INTEGERP (int, left)) - { - leftpos = XINT (left); - if (leftpos < 0) - f->size_hint_flags |= XNegative; - } - else if (CONSP (left) && EQ (XCAR (left), Qminus) - && CONSP (XCDR (left)) - && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (left)), INT_MAX)) - { - leftpos = - XINT (XCAR (XCDR (left))); + /* Record the signs. */ + f->size_hint_flags &= ~ (XNegative | YNegative); + if (EQ (left, Qminus)) + f->size_hint_flags |= XNegative; + else if (TYPE_RANGED_INTEGERP (int, left)) + { + leftpos = XINT (left); + if (leftpos < 0) f->size_hint_flags |= XNegative; - } - else if (CONSP (left) && EQ (XCAR (left), Qplus) - && CONSP (XCDR (left)) - && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (left)))) - { - leftpos = XINT (XCAR (XCDR (left))); - } + } + else if (CONSP (left) && EQ (XCAR (left), Qminus) + && CONSP (XCDR (left)) + && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (left)), INT_MAX)) + { + leftpos = - XINT (XCAR (XCDR (left))); + f->size_hint_flags |= XNegative; + } + else if (CONSP (left) && EQ (XCAR (left), Qplus) + && CONSP (XCDR (left)) + && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (left)))) + leftpos = XINT (XCAR (XCDR (left))); + else if (FLOATP (left)) + leftpos = frame_float (f, left, FRAME_FLOAT_LEFT, &parent_done, + &outer_done, 0); - if (EQ (top, Qminus)) - f->size_hint_flags |= YNegative; - else if (TYPE_RANGED_INTEGERP (int, top)) - { - toppos = XINT (top); - if (toppos < 0) - f->size_hint_flags |= YNegative; - } - else if (CONSP (top) && EQ (XCAR (top), Qminus) - && CONSP (XCDR (top)) - && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (top)), INT_MAX)) - { - toppos = - XINT (XCAR (XCDR (top))); + if (EQ (top, Qminus)) + f->size_hint_flags |= YNegative; + else if (TYPE_RANGED_INTEGERP (int, top)) + { + toppos = XINT (top); + if (toppos < 0) f->size_hint_flags |= YNegative; - } - else if (CONSP (top) && EQ (XCAR (top), Qplus) - && CONSP (XCDR (top)) - && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (top)))) - { - toppos = XINT (XCAR (XCDR (top))); - } - + } + else if (CONSP (top) && EQ (XCAR (top), Qminus) + && CONSP (XCDR (top)) + && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (top)), INT_MAX)) + { + toppos = - XINT (XCAR (XCDR (top))); + f->size_hint_flags |= YNegative; + } + else if (CONSP (top) && EQ (XCAR (top), Qplus) + && CONSP (XCDR (top)) + && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (top)))) + toppos = XINT (XCAR (XCDR (top))); + else if (FLOATP (top)) + toppos = frame_float (f, top, FRAME_FLOAT_TOP, &parent_done, + &outer_done, 0); - /* Store the numeric value of the position. */ - f->top_pos = toppos; - f->left_pos = leftpos; + /* Store the numeric value of the position. */ + f->top_pos = toppos; + f->left_pos = leftpos; - f->win_gravity = NorthWestGravity; + f->win_gravity = NorthWestGravity; - /* Actually set that position, and convert to absolute. */ - x_set_offset (f, leftpos, toppos, -1); - } + /* Actually set that position, and convert to absolute. */ + x_set_offset (f, leftpos, toppos, -1); + } - if (fullscreen_change) - { - Lisp_Object old_value = get_frame_param (f, Qfullscreen); + if (fullscreen_change) + { + Lisp_Object old_value = get_frame_param (f, Qfullscreen); - frame_size_history_add - (f, Qx_set_fullscreen, 0, 0, list2 (old_value, fullscreen)); + frame_size_history_add + (f, Qx_set_fullscreen, 0, 0, list2 (old_value, fullscreen)); - store_frame_param (f, Qfullscreen, fullscreen); - if (!EQ (fullscreen, old_value)) - x_set_fullscreen (f, fullscreen, old_value); - } + store_frame_param (f, Qfullscreen, fullscreen); + if (!EQ (fullscreen, old_value)) + x_set_fullscreen (f, fullscreen, old_value); + } #ifdef HAVE_X_WINDOWS - if ((!NILP (icon_left) || !NILP (icon_top)) - && ! (icon_left_no_change && icon_top_no_change)) - x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top)); + if ((!NILP (icon_left) || !NILP (icon_top)) + && ! (icon_left_no_change && icon_top_no_change)) + x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top)); #endif /* HAVE_X_WINDOWS */ - } SAFE_FREE (); } @@ -3990,7 +4413,6 @@ struct frame_parm_table { adjust_frame_glyphs (f); SET_FRAME_GARBAGED (f); } - } void @@ -4204,6 +4626,22 @@ struct frame_parm_table { return; } + +/** + * x_set_no_special_glyphs: + * + * Set frame F's `no-special-glyphs' parameter which, if non-nil, + * suppresses the display of truncation and continuation glyphs + * outside fringes. + */ +void +x_set_no_special_glyphs (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) +{ + if (!EQ (new_value, old_value)) + FRAME_NO_SPECIAL_GLYPHS (f) = !NILP (new_value); +} + + #ifndef HAVE_NS /* Non-zero if mouse is grabbed on DPYINFO @@ -4759,6 +5197,7 @@ or a list (- N) meaning -N pixels relative to bottom/right corner. Lisp_Object height, width, user_size, top, left, user_position; long window_prompting = 0; Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f); + int parent_done = -1, outer_done = -1; /* Default values if we fall through. Actually, if that happens we should get @@ -4823,6 +5262,21 @@ or a list (- N) meaning -N pixels relative to bottom/right corner. f->inhibit_horizontal_resize = true; *x_width = XINT (XCDR (width)); } + else if (FLOATP (width)) + { + double d_width = XFLOAT_DATA (width); + + if (d_width < 0.0 || d_width > 1.0) + xsignal1 (Qargs_out_of_range, width); + else + { + int new_width = frame_float (f, width, FRAME_FLOAT_WIDTH, + &parent_done, &outer_done, -1); + + if (new_width > -1) + SET_FRAME_WIDTH (f, new_width); + } + } else { CHECK_NUMBER (width); @@ -4845,6 +5299,21 @@ or a list (- N) meaning -N pixels relative to bottom/right corner. f->inhibit_vertical_resize = true; *x_height = XINT (XCDR (height)); } + else if (FLOATP (height)) + { + double d_height = XFLOAT_DATA (height); + + if (d_height < 0.0 || d_height > 1.0) + xsignal1 (Qargs_out_of_range, height); + else + { + int new_height = frame_float (f, height, FRAME_FLOAT_HEIGHT, + &parent_done, &outer_done, -1); + + if (new_height > -1) + SET_FRAME_HEIGHT (f, new_height); + } + } else { CHECK_NUMBER (height); @@ -4885,6 +5354,9 @@ or a list (- N) meaning -N pixels relative to bottom/right corner. { f->top_pos = XINT (XCAR (XCDR (top))); } + else if (FLOATP (top)) + f->top_pos = frame_float (f, top, FRAME_FLOAT_TOP, &parent_done, + &outer_done, 0); else if (EQ (top, Qunbound)) f->top_pos = 0; else @@ -4913,6 +5385,9 @@ or a list (- N) meaning -N pixels relative to bottom/right corner. { f->left_pos = XINT (XCAR (XCDR (left))); } + else if (FLOATP (left)) + f->left_pos = frame_float (f, top, FRAME_FLOAT_LEFT, &parent_done, + &outer_done, 0); else if (EQ (left, Qunbound)) f->left_pos = 0; else @@ -5071,12 +5546,14 @@ or a list (- N) meaning -N pixels relative to bottom/right corner. DEFSYM (Qframep, "framep"); DEFSYM (Qframe_live_p, "frame-live-p"); DEFSYM (Qframe_windows_min_size, "frame-windows-min-size"); + DEFSYM (Qdisplay_monitor_attributes_list, "display-monitor-attributes-list"); DEFSYM (Qwindow__pixel_to_total, "window--pixel-to-total"); DEFSYM (Qexplicit_name, "explicit-name"); DEFSYM (Qheight, "height"); DEFSYM (Qicon, "icon"); DEFSYM (Qminibuffer, "minibuffer"); DEFSYM (Qundecorated, "undecorated"); + DEFSYM (Qno_special_glyphs, "no-special-glyphs"); DEFSYM (Qparent_frame, "parent-frame"); DEFSYM (Qskip_taskbar, "skip-taskbar"); DEFSYM (Qno_focus_on_map, "no-focus-on-map"); @@ -5129,6 +5606,7 @@ or a list (- N) meaning -N pixels relative to bottom/right corner. DEFSYM (Qframes, "frames"); DEFSYM (Qsource, "source"); + DEFSYM (Qframe_edges, "frame-edges"); DEFSYM (Qouter_edges, "outer-edges"); DEFSYM (Qouter_position, "outer-position"); DEFSYM (Qouter_size, "outer-size"); @@ -5220,6 +5698,11 @@ or a list (- N) meaning -N pixels relative to bottom/right corner. DEFSYM (Qmin_width, "min-width"); DEFSYM (Qmin_height, "min-height"); DEFSYM (Qmouse_wheel_frame, "mouse-wheel-frame"); + DEFSYM (Qkeep_ratio, "keep-ratio"); + DEFSYM (Qwidth_only, "width-only"); + DEFSYM (Qheight_only, "height-only"); + DEFSYM (Qleft_only, "left-only"); + DEFSYM (Qtop_only, "top-only"); { int i; @@ -5564,8 +6047,8 @@ This variable is effective only with the X toolkit (and there only when defsubr (&Smodify_frame_parameters); defsubr (&Sframe_char_height); defsubr (&Sframe_char_width); - defsubr (&Sframe_pixel_height); - defsubr (&Sframe_pixel_width); + defsubr (&Sframe_native_height); + defsubr (&Sframe_native_width); defsubr (&Sframe_text_cols); defsubr (&Sframe_text_lines); defsubr (&Sframe_total_cols); @@ -5575,7 +6058,7 @@ This variable is effective only with the X toolkit (and there only when defsubr (&Sscroll_bar_width); defsubr (&Sscroll_bar_height); defsubr (&Sfringe_width); - defsubr (&Sborder_width); + defsubr (&Sframe_internal_border_width); defsubr (&Sright_divider_width); defsubr (&Sbottom_divider_width); defsubr (&Stool_bar_pixel_width); diff --git a/src/frame.h b/src/frame.h index 4aa7c34..2feb09b 100644 --- a/src/frame.h +++ b/src/frame.h @@ -52,6 +52,19 @@ enum z_group z_group_below, z_group_above_suspended, }; + +enum internal_border_part + { + INTERNAL_BORDER_NONE, + INTERNAL_BORDER_LEFT_EDGE, + INTERNAL_BORDER_TOP_LEFT_CORNER, + INTERNAL_BORDER_TOP_EDGE, + INTERNAL_BORDER_TOP_RIGHT_CORNER, + INTERNAL_BORDER_RIGHT_EDGE, + INTERNAL_BORDER_BOTTOM_RIGHT_CORNER, + INTERNAL_BORDER_BOTTOM_EDGE, + INTERNAL_BORDER_BOTTOM_LEFT_CORNER, + }; #endif /* HAVE_WINDOW_SYSTEM */ /* The structure representing a frame. */ @@ -354,7 +367,11 @@ struct frame /* The z-group this frame's window belongs to. */ ENUM_BF (z_group) z_group : 2; -#endif /* HAVE_WINDOW_SYSTEM and not HAVE_NS */ + + /* Non-zero if display of truncation and continuation glyphs outside + the fringes is suppressed. */ + bool_bf no_special_glyphs : 1; +#endif /* HAVE_WINDOW_SYSTEM */ /* Whether new_height and new_width shall be interpreted in pixels. */ @@ -928,6 +945,7 @@ struct 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_NO_SPECIAL_GLYPHS(f) ((f)->no_special_glyphs) #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) @@ -941,6 +959,7 @@ struct frame #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_NO_SPECIAL_GLYPHS(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) @@ -1288,19 +1307,20 @@ extern void frame_size_history_add (struct frame *f, Lisp_Object fun_symbol, return FRAME_LEFT_FRINGE_WIDTH (f) + FRAME_RIGHT_FRINGE_WIDTH (f); } -/* Pixel-width of internal border lines */ +/* Pixel-width of internal border lines. */ INLINE int FRAME_INTERNAL_BORDER_WIDTH (struct frame *f) { return frame_dimension (f->internal_border_width); } -/* Pixel-size of window divider lines */ +/* Pixel-size of window divider lines. */ INLINE int FRAME_RIGHT_DIVIDER_WIDTH (struct frame *f) { return frame_dimension (f->right_divider_width); } + INLINE int FRAME_BOTTOM_DIVIDER_WIDTH (struct frame *f) { @@ -1498,6 +1518,7 @@ extern void x_set_bottom_divider_width (struct frame *, Lisp_Object, extern long x_figure_window_size (struct frame *, Lisp_Object, bool, int *, int *); extern void x_set_alpha (struct frame *, Lisp_Object, Lisp_Object); +extern void x_set_no_special_glyphs (struct frame *, Lisp_Object, Lisp_Object); extern void validate_x_resource_name (void); @@ -1521,6 +1542,7 @@ extern void x_set_window_size (struct frame *f, bool change_gravity, 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); +extern enum internal_border_part frame_internal_border_part (struct frame *f, int x, int y); #if defined HAVE_X_WINDOWS extern void x_wm_set_icon_position (struct frame *, int, int); diff --git a/src/keyboard.c b/src/keyboard.c index 55486c6..b202d9b 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -5126,6 +5126,17 @@ in the same style as (current-time). SYMBOL_INDEX (Qrightmost), SYMBOL_INDEX (Qend_scroll), SYMBOL_INDEX (Qratio) }; +/* An array of symbol indexes of internal border parts, indexed by an enum + internal_border_part value. Note that Qnil corresponds to + internal_border_part_none and should not appear in Lisp events. */ +static short const internal_border_parts[] = { + SYMBOL_INDEX (Qnil), SYMBOL_INDEX (Qleft_edge), + SYMBOL_INDEX (Qtop_left_corner), SYMBOL_INDEX (Qtop_edge), + SYMBOL_INDEX (Qtop_right_corner), SYMBOL_INDEX (Qright_edge), + SYMBOL_INDEX (Qbottom_right_corner), SYMBOL_INDEX (Qbottom_edge), + SYMBOL_INDEX (Qbottom_left_corner) +}; + /* A vector, indexed by button number, giving the down-going location of currently depressed buttons, both scroll bar and non-scroll bar. @@ -5163,15 +5174,15 @@ in the same style as (current-time). Lisp_Object extra_info = Qnil; /* Coordinate pixel positions to return. */ int xret = 0, yret = 0; - /* The window under frame pixel coordinates (x,y) */ - Lisp_Object window = f + /* The window or frame under frame pixel coordinates (x,y) */ + Lisp_Object window_or_frame = f ? window_from_coordinates (f, XINT (x), XINT (y), &part, 0) : Qnil; - if (WINDOWP (window)) + if (WINDOWP (window_or_frame)) { /* It's a click in window WINDOW at frame coordinates (X,Y) */ - struct window *w = XWINDOW (window); + struct window *w = XWINDOW (window_or_frame); Lisp_Object string_info = Qnil; ptrdiff_t textpos = 0; int col = -1, row = -1; @@ -5360,17 +5371,31 @@ in the same style as (current-time). make_number (row)), extra_info))); } - else if (f != 0) + +#ifdef HAVE_WINDOW_SYSTEM + else if (f) { /* Return mouse pixel coordinates here. */ - XSETFRAME (window, f); + XSETFRAME (window_or_frame, f); xret = XINT (x); yret = XINT (y); + + if (FRAME_LIVE_P (f) + && FRAME_INTERNAL_BORDER_WIDTH (f) > 0 + && !NILP (get_frame_param (f, Qdrag_internal_border))) + { + enum internal_border_part part + = frame_internal_border_part (f, xret, yret); + + posn = builtin_lisp_symbol (internal_border_parts[part]); + } } +#endif + else - window = Qnil; + window_or_frame = Qnil; - return Fcons (window, + return Fcons (window_or_frame, Fcons (posn, Fcons (Fcons (make_number (xret), make_number (yret)), @@ -11158,6 +11183,17 @@ struct event_head Fset (Qinput_method_exit_on_first_char, Qnil); Fset (Qinput_method_use_echo_area, Qnil); + /* Symbols for dragging internal borders. */ + DEFSYM (Qdrag_internal_border, "drag-internal-border"); + DEFSYM (Qleft_edge, "left-edge"); + DEFSYM (Qtop_left_corner, "top-left-corner"); + DEFSYM (Qtop_edge, "top-edge"); + DEFSYM (Qtop_right_corner, "top-right-corner"); + DEFSYM (Qright_edge, "right-edge"); + DEFSYM (Qbottom_right_corner, "bottom-right-corner"); + DEFSYM (Qbottom_edge, "bottom-edge"); + DEFSYM (Qbottom_left_corner, "bottom-left-corner"); + /* Symbols to head events. */ DEFSYM (Qmouse_movement, "mouse-movement"); DEFSYM (Qscroll_bar_movement, "scroll-bar-movement"); diff --git a/src/minibuf.c b/src/minibuf.c index 1bbe276..4d91b48 100644 --- a/src/minibuf.c +++ b/src/minibuf.c @@ -874,6 +874,30 @@ if (minibuf_level == 0) resize_mini_window (XWINDOW (window), 0); + /* Deal with frames that should be removed when exiting the + minibuffer. */ + { + Lisp_Object frames, frame1, val; + struct frame *f1; + + FOR_EACH_FRAME (frames, frame1) + { + f1 = XFRAME (frame1); + + if ((FRAME_PARENT_FRAME (f1) + || !NILP (get_frame_param (f1, Qdelete_before))) + && !NILP (val = (get_frame_param (f1, Qminibuffer_exit)))) + { + if (EQ (val, Qiconify_frame)) + Ficonify_frame (frame1); + else if (EQ (val, Qdelete_frame)) + Fdelete_frame (frame1, Qnil); + else + Fmake_frame_invisible (frame1, Qnil); + } + } + } + /* In case the previous minibuffer displayed in this miniwindow is dead, we may keep displaying this buffer (tho it's inactive), so reset it, to make sure we don't leave around bindings and stuff which only @@ -1930,6 +1954,8 @@ DEFSYM (Qactivate_input_method, "activate-input-method"); DEFSYM (Qcase_fold_search, "case-fold-search"); DEFSYM (Qmetadata, "metadata"); + /* A frame parameter. */ + DEFSYM (Qminibuffer_exit, "minibuffer-exit"); DEFVAR_LISP ("read-expression-history", Vread_expression_history, doc: /* A history list for arguments that are Lisp expressions to evaluate. diff --git a/src/nsfns.m b/src/nsfns.m index dbce279..68eba8b 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -984,6 +984,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side x_set_no_accept_focus, x_set_z_group, /* x_set_z_group */ 0, /* x_set_override_redirect */ + x_set_no_special_glyphs, }; @@ -1256,6 +1257,8 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side "leftFringe", "LeftFringe", RES_TYPE_NUMBER); x_default_parameter (f, parms, Qright_fringe, Qnil, "rightFringe", "RightFringe", RES_TYPE_NUMBER); + x_default_parameter (f, parms, Qno_special_glyphs, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); init_frame_faces (f); @@ -1325,6 +1328,15 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side f->output_data.ns->hourglass_cursor = [NSCursor disappearingItemCursor]; f->output_data.ns->horizontal_drag_cursor = [NSCursor resizeLeftRightCursor]; f->output_data.ns->vertical_drag_cursor = [NSCursor resizeUpDownCursor]; + f->output_data.ns->left_edge_cursor = [NSCursor resizeLeftRightCursor]; + f->output_data.ns->top_left_corner_cursor = [NSCursor arrowCursor]; + f->output_data.ns->top_edge_cursor = [NSCursor resizeUpDownCursor]; + f->output_data.ns->top_right_corner_cursor = [NSCursor arrowCursor]; + f->output_data.ns->right_edge_cursor = [NSCursor resizeLeftRightCursor]; + f->output_data.ns->bottom_right_corner_cursor = [NSCursor arrowCursor]; + f->output_data.ns->bottom_edge_cursor = [NSCursor resizeUpDownCursor]; + f->output_data.ns->bottom_left_corner_cursor = [NSCursor arrowCursor]; + FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor = [NSCursor arrowCursor]; FRAME_DISPLAY_INFO (f)->horizontal_scroll_bar_cursor diff --git a/src/nsterm.h b/src/nsterm.h index bed0b92..84f7f0a 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -957,6 +957,14 @@ struct ns_output Cursor hourglass_cursor; Cursor horizontal_drag_cursor; Cursor vertical_drag_cursor; + Cursor left_edge_cursor; + Cursor top_left_corner_cursor; + Cursor top_edge_cursor; + Cursor top_right_corner_cursor; + Cursor right_edge_cursor; + Cursor bottom_right_corner_cursor; + Cursor bottom_edge_cursor; + Cursor bottom_left_corner_cursor; /* NS-specific */ Cursor current_pointer; diff --git a/src/w32fns.c b/src/w32fns.c index e490588..b0842b5 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -5889,6 +5889,8 @@ struct frame * NULL, NULL, RES_TYPE_BOOLEAN); x_default_parameter (f, parameters, Qno_accept_focus, Qnil, NULL, NULL, RES_TYPE_BOOLEAN); + x_default_parameter (f, parameters, Qno_special_glyphs, 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 @@ -5957,6 +5959,14 @@ struct frame * f->output_data.w32->hourglass_cursor = w32_load_cursor (IDC_WAIT); f->output_data.w32->horizontal_drag_cursor = w32_load_cursor (IDC_SIZEWE); f->output_data.w32->vertical_drag_cursor = w32_load_cursor (IDC_SIZENS); + f->output_data.w32->left_edge_cursor = w32_load_cursor (IDC_SIZEWE); + f->output_data.w32->top_left_corner_cursor = w32_load_cursor (IDC_SIZENWSE); + f->output_data.w32->top_edge_cursor = w32_load_cursor (IDC_SIZENS); + f->output_data.w32->top_right_corner_cursor = w32_load_cursor (IDC_SIZENESW); + f->output_data.w32->right_edge_cursor = w32_load_cursor (IDC_SIZEWE); + f->output_data.w32->bottom_right_corner_cursor = w32_load_cursor (IDC_SIZENWSE); + f->output_data.w32->bottom_edge_cursor = w32_load_cursor (IDC_SIZENS); + f->output_data.w32->bottom_left_corner_cursor = w32_load_cursor (IDC_SIZENESW); f->output_data.w32->current_cursor = f->output_data.w32->nontext_cursor; @@ -7049,6 +7059,8 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, "cursorColor", "Foreground", RES_TYPE_STRING); x_default_parameter (f, parms, Qborder_color, build_string ("black"), "borderColor", "BorderColor", RES_TYPE_STRING); + x_default_parameter (f, parms, Qno_special_glyphs, Qt, + NULL, NULL, RES_TYPE_BOOLEAN); /* Init faces before x_default_parameter is called for the scroll-bar-width parameter because otherwise we end up in @@ -8950,33 +8962,47 @@ value is a list of the form (LEFT, TOP, RIGHT, BOTTOM). All values are if (EQ (type, Qouter_edges)) { RECT rectangle; + BOOL success = false; block_input (); /* Outer frame rectangle, including outer borders and title bar. */ - GetWindowRect (FRAME_W32_WINDOW (f), &rectangle); + success = GetWindowRect (FRAME_W32_WINDOW (f), &rectangle); unblock_input (); - return list4 (make_number (rectangle.left), - make_number (rectangle.top), - make_number (rectangle.right), - make_number (rectangle.bottom)); + if (success) + return list4 (make_number (rectangle.left), + make_number (rectangle.top), + make_number (rectangle.right), + make_number (rectangle.bottom)); + else + return Qnil; } else { RECT rectangle; POINT pt; int left, top, right, bottom; + BOOL success; block_input (); /* Inner frame rectangle, excluding borders and title bar. */ - GetClientRect (FRAME_W32_WINDOW (f), &rectangle); + success = GetClientRect (FRAME_W32_WINDOW (f), &rectangle); /* Get top-left corner of native rectangle in screen coordinates. */ + if (!success) + { + unblock_input (); + return Qnil; + } + pt.x = 0; pt.y = 0; - ClientToScreen (FRAME_W32_WINDOW (f), &pt); + success = ClientToScreen (FRAME_W32_WINDOW (f), &pt); unblock_input (); + if (!success) + return Qnil; + left = pt.x; top = pt.y; right = left + rectangle.right; @@ -10330,6 +10356,7 @@ enum NI_Severity { x_set_no_accept_focus, x_set_z_group, 0, /* x_set_override_redirect */ + x_set_no_special_glyphs, }; void diff --git a/src/w32term.c b/src/w32term.c index 712bdae..c37805c 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -5086,6 +5086,51 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object } case WM_WINDOWPOSCHANGED: + f = x_window_to_frame (dpyinfo, msg.msg.hwnd); + + if (f) + { + RECT rect; + int /* rows, columns, */ width, height, text_width, text_height; + + if (GetClientRect (msg.msg.hwnd, &rect) + /* GetClientRect evidently returns (0, 0, 0, 0) if + called on a minimized frame. Such "dimensions" + aren't useful anyway. */ + && !(rect.bottom == 0 + && rect.top == 0 + && rect.left == 0 + && rect.right == 0)) + { + height = rect.bottom - rect.top; + width = rect.right - rect.left; + text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, width); + text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, height); + /* rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, height); */ + /* columns = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, width); */ + + /* TODO: Clip size to the screen dimensions. */ + + /* Even if the number of character rows and columns + has not changed, the font size may have changed, + so we need to check the pixel dimensions as well. */ + + if (width != FRAME_PIXEL_WIDTH (f) + || height != FRAME_PIXEL_HEIGHT (f) + || text_width != FRAME_TEXT_WIDTH (f) + || text_height != FRAME_TEXT_HEIGHT (f)) + { + change_frame_size (f, text_width, text_height, 0, 1, 0, 1); + SET_FRAME_GARBAGED (f); + cancel_mouse_face (f); + f->win_gravity = NorthWestGravity; + } + } + } + + check_visibility = 1; + break; + case WM_ACTIVATE: case WM_ACTIVATEAPP: f = x_window_to_frame (dpyinfo, msg.msg.hwnd); @@ -6052,7 +6097,7 @@ struct xim_inst_t int display_top = 0; struct frame *p = FRAME_PARENT_FRAME (f); - if (flags & (XNegative | YNegative)) + if (!p && flags & (XNegative | YNegative)) { Lisp_Object list; @@ -6078,20 +6123,26 @@ struct xim_inst_t } /* Treat negative positions as relative to the rightmost bottommost - position that fits on the screen. */ + position that fits on the screen or parent frame. + + I see no need for subtracting 1 from the border widths - is there + any on the remaining platforms? Here these subtractions did put + the last pixel line/column of a frame off-display when, for + example, a (set-frame-parameter nil 'left '(- 0)) specification was + used - martin 20017-05-05. */ if (flags & XNegative) { if (p) f->left_pos = (FRAME_PIXEL_WIDTH (p) - FRAME_PIXEL_WIDTH (f) + f->left_pos - - (left_right_borders_width - 1)); + - left_right_borders_width); 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)); + - left_right_borders_width); } if (flags & YNegative) @@ -6100,13 +6151,13 @@ struct xim_inst_t f->top_pos = (FRAME_PIXEL_HEIGHT (p) - FRAME_PIXEL_HEIGHT (f) + f->top_pos - - (top_bottom_borders_height - 1)); + - top_bottom_borders_height); 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)); + - top_bottom_borders_height); } /* The left_pos and top_pos are now relative to the top and left diff --git a/src/w32term.h b/src/w32term.h index 371cf90..9956682 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -345,6 +345,14 @@ struct w32_output Cursor hourglass_cursor; Cursor horizontal_drag_cursor; Cursor vertical_drag_cursor; + Cursor left_edge_cursor; + Cursor top_left_corner_cursor; + Cursor top_edge_cursor; + Cursor top_right_corner_cursor; + Cursor right_edge_cursor; + Cursor bottom_right_corner_cursor; + Cursor bottom_edge_cursor; + Cursor bottom_left_corner_cursor; /* Non-zero means hourglass cursor is currently displayed. */ unsigned hourglass_p : 1; diff --git a/src/window.c b/src/window.c index bf89f0e..4816bd6 100644 --- a/src/window.c +++ b/src/window.c @@ -1208,13 +1208,13 @@ should be a buffer position (typically a marker) or nil. If it is a - WINDOW_BOTTOM_DIVIDER_WIDTH (w)))) return ON_HORIZONTAL_SCROLL_BAR; /* On the mode or header line? */ - else if ((WINDOW_WANTS_MODELINE_P (w) + else if ((window_wants_mode_line (w) && y >= (bottom_y - CURRENT_MODE_LINE_HEIGHT (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w)) && y <= bottom_y - WINDOW_BOTTOM_DIVIDER_WIDTH (w) && (part = ON_MODE_LINE)) - || (WINDOW_WANTS_HEADER_LINE_P (w) + || (window_wants_header_line (w) && y < top_y + CURRENT_HEADER_LINE_HEIGHT (w) && (part = ON_HEADER_LINE))) { @@ -1851,7 +1851,7 @@ of the (first) text line, YPOS is negative. if (EQ (line, Qheader_line)) { - if (!WINDOW_WANTS_HEADER_LINE_P (w)) + if (!window_wants_header_line (w)) return Qnil; row = MATRIX_HEADER_LINE_ROW (w->current_matrix); return row->enabled_p ? list4i (row->height, 0, 0, 0) : Qnil; @@ -1898,6 +1898,129 @@ of the (first) text line, YPOS is negative. return list4i (row->height + min (0, row->y) - crop, i, row->y, crop); } +DEFUN ("window-lines-pixel-dimensions", Fwindow_lines_pixel_dimensions, Swindow_lines_pixel_dimensions, 0, 6, 0, + doc: /* Return pixel dimensions of WINDOW's lines. +The return value is a list of the x- and y-coordinates of the lower +right corner of the last character of each line. Return nil if the +current glyph matrix of WINDOW is not up-to-date. + +Optional argument WINDOW specifies the window whose lines' dimensions +shall be returned. Nil or omitted means to return the dimensions for +the selected window. + +FIRST, if non-nil, specifies the index of the first line whose +dimensions shall be returned. If FIRST is nil and BODY is non-nil, +start with the first text line of WINDOW. Otherwise, start with the +first line of WINDOW. + +LAST, if non-nil, specifies the last line whose dimensions shall be +returned. If LAST is nil and BODY is non-nil, the last line is the last +line of the body (text area) of WINDOW. Otherwise, last is the last +line of WINDOW. + +INVERSE, if nil, means that the y-pixel value returned for a specific +line specifies the distance in pixels from the left edge (body edge if +BODY is non-nil) of WINDOW to the right edge of the last glyph of that +line. INVERSE non-nil means that the y-pixel value returned for a +specific line specifies the distance in pixels from the right edge of +the last glyph of that line to the right edge (body edge if BODY is +non-nil) of WINDOW. + +LEFT non-nil means to return the x- and y-coordinates of the lower left +corner of the leftmost character on each line. This is the value that +should be used for buffers that mostly display text from right to left. + +If LEFT is non-nil and INVERSE is nil, this means that the y-pixel value +returned for a specific line specifies the distance in pixels from the +left edge of the last (leftmost) glyph of that line to the right edge +(body edge if BODY is non-nil) of WINDOW. If LEFT and INVERSE are both +non-nil, the y-pixel value returned for a specific line specifies the +distance in pixels from the left edge (body edge if BODY is non-nil) of +WINDOW to the left edge of the last (leftmost) glyph of that line. + +Normally, the value of this function is not available while Emacs is +busy, for example, when processing a command. It should be retrievable +though when run from an idle timer with a delay of zero seconds. */) + (Lisp_Object window, Lisp_Object first, Lisp_Object last, Lisp_Object body, Lisp_Object inverse, Lisp_Object left) +{ + struct window *w = decode_live_window (window); + struct buffer *b; + struct glyph_row *row, *end_row; + int max_y = NILP (body) ? WINDOW_PIXEL_HEIGHT (w) : window_text_bottom_y (w); + Lisp_Object rows = Qnil; + int window_width = NILP (body) ? w->pixel_width : window_body_width (w, true); + int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w); + int subtract = NILP (body) ? 0 : header_line_height; + bool invert = !NILP (inverse); + bool left_flag = !NILP (left); + + if (noninteractive || w->pseudo_window_p) + return Qnil; + + CHECK_BUFFER (w->contents); + b = XBUFFER (w->contents); + + /* Fail if current matrix is not up-to-date. */ + if (!w->window_end_valid + || windows_or_buffers_changed + || b->clip_changed + || b->prevent_redisplay_optimizations_p + || window_outdated (w)) + return Qnil; + + if (NILP (first)) + row = (NILP (body) + ? MATRIX_ROW (w->current_matrix, 0) + : MATRIX_FIRST_TEXT_ROW (w->current_matrix)); + else if (NUMBERP (first)) + { + CHECK_RANGED_INTEGER (first, 0, w->current_matrix->nrows); + row = MATRIX_ROW (w->current_matrix, XINT (first)); + } + else + error ("Invalid specification of first line"); + + if (NILP (last)) + + end_row = (NILP (body) + ? MATRIX_ROW (w->current_matrix, w->current_matrix->nrows) + : MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w)); + else if (NUMBERP (last)) + { + CHECK_RANGED_INTEGER (last, 0, w->current_matrix->nrows); + end_row = MATRIX_ROW (w->current_matrix, XINT (last)); + } + else + error ("Invalid specification of last line"); + + while (row <= end_row && row->enabled_p + && row->y + row->height < max_y) + { + + if (left_flag) + { + struct glyph *glyph = row->glyphs[TEXT_AREA]; + + rows = Fcons (Fcons (make_number + (invert + ? glyph->pixel_width + : window_width - glyph->pixel_width), + make_number (row->y + row->height - subtract)), + rows); + } + else + rows = Fcons (Fcons (make_number + (invert + ? window_width - row->pixel_width + : row->pixel_width), + make_number (row->y + row->height - subtract)), + rows); + row++; + } + + return Fnreverse (rows); +} + DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p, 0, 1, 0, doc: /* Return non-nil when WINDOW is dedicated to its buffer. @@ -2003,16 +2126,24 @@ return value is a list of elements of the form (PARAMETER . VALUE). */) return Fcopy_alist (decode_valid_window (window)->window_parameters); } +Lisp_Object +window_parameter (struct window *w, Lisp_Object parameter) +{ + Lisp_Object result = Fassq (parameter, w->window_parameters); + + return CDR_SAFE (result); +} + + DEFUN ("window-parameter", Fwindow_parameter, Swindow_parameter, 2, 2, 0, doc: /* Return WINDOW's value for PARAMETER. WINDOW can be any window and defaults to the selected one. */) (Lisp_Object window, Lisp_Object parameter) { - Lisp_Object result; + struct window *w = decode_any_window (window); - result = Fassq (parameter, decode_any_window (window)->window_parameters); - return CDR_SAFE (result); + return window_parameter (w, parameter); } DEFUN ("set-window-parameter", Fset_window_parameter, @@ -4740,6 +4871,69 @@ SIDE t (or `right') specifies that the new window shall be located on } +/** + * window_wants_mode_line: + * + * Return 1 if window W wants a mode line and is high enough to + * accomodate it, 0 otherwise. + * + * W wants a mode line if it's a leaf window and neither a minibuffer + * nor a pseudo window. Moreover, its 'window-mode-line-format' + * parameter must not be 'none' and either that parameter or W's + * buffer's 'mode-line-format' value must be non-nil. Finally, W must + * be higher than its frame's canonical character height. + */ +bool +window_wants_mode_line (struct window *w) +{ + Lisp_Object window_mode_line_format = + window_parameter (w, Qmode_line_format); + + return ((WINDOW_LEAF_P (w) + && !MINI_WINDOW_P (w) + && !WINDOW_PSEUDO_P (w) + && !EQ (window_mode_line_format, Qnone) + && (!NILP (window_mode_line_format) + || !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), mode_line_format))) + && WINDOW_PIXEL_HEIGHT (w) > WINDOW_FRAME_LINE_HEIGHT (w)) + ? 1 + : 0); +} + + +/** + * window_wants_header_line: + * + * Return 1 if window W wants a header line and is high enough to + * accomodate it, 0 otherwise. + * + * W wants a header line if it's a leaf window and neither a minibuffer + * nor a pseudo window. Moreover, its 'window-mode-line-format' + * parameter must not be 'none' and either that parameter or W's + * buffer's 'mode-line-format' value must be non-nil. Finally, W must + * be higher than its frame's canonical character height and be able to + * accomodate a mode line too if necessary (the mode line prevails). + */ +bool +window_wants_header_line (struct window *w) +{ + Lisp_Object window_header_line_format = + window_parameter (w, Qheader_line_format); + + return ((WINDOW_LEAF_P (w) + && !MINI_WINDOW_P (w) + && !WINDOW_PSEUDO_P (w) + && !EQ (window_header_line_format, Qnone) + && (!NILP (window_header_line_format) + || !NILP (BVAR (XBUFFER (WINDOW_BUFFER (w)), header_line_format))) + && (WINDOW_PIXEL_HEIGHT (w) + > (window_wants_mode_line (w) + ? 2 * WINDOW_FRAME_LINE_HEIGHT (w) + : WINDOW_FRAME_LINE_HEIGHT (w)))) + ? 1 + : 0); +} + /* Return number of lines of text (not counting mode lines) in W. */ int @@ -4753,10 +4947,10 @@ SIDE t (or `right') specifies that the new window shall be located on || WINDOWP (w->contents) || !NILP (w->next) || !NILP (w->prev) - || WINDOW_WANTS_MODELINE_P (w)) + || window_wants_mode_line (w)) --ht; - if (WINDOW_WANTS_HEADER_LINE_P (w)) + if (window_wants_header_line (w)) --ht; } @@ -7354,6 +7548,8 @@ Value is a list of the form (WIDTH COLUMNS VERTICAL-TYPE HEIGHT LINES DEFSYM (Qfloor, "floor"); DEFSYM (Qceiling, "ceiling"); DEFSYM (Qmark_for_redisplay, "mark-for-redisplay"); + DEFSYM (Qmode_line_format, "mode-line-format"); + DEFSYM (Qheader_line_format, "header-line-format"); staticpro (&Vwindow_list); @@ -7603,6 +7799,7 @@ this value for parameters without read syntax (like windows or frames). defsubr (&Sset_window_point); defsubr (&Sset_window_start); defsubr (&Swindow_dedicated_p); + defsubr (&Swindow_lines_pixel_dimensions); defsubr (&Sset_window_dedicated_p); defsubr (&Swindow_display_table); defsubr (&Sset_window_display_table); diff --git a/src/window.h b/src/window.h index acb8a5c..e9040f816 100644 --- a/src/window.h +++ b/src/window.h @@ -328,8 +328,9 @@ struct window /* True if this window is a minibuffer window. */ bool_bf mini : 1; - /* Meaningful only if contents is a window, true if this - internal window is used in horizontal combination. */ + /* Meaningful for internal windows only: true if this window is a + horizontal combination, false if it is a vertical + combination. */ bool_bf horizontal : 1; /* True means must regenerate mode line of this window. */ @@ -481,15 +482,14 @@ struct window /* True if W is a minibuffer window. */ #define MINI_WINDOW_P(W) ((W)->mini) -/* 1 if W is a non-only minibuffer window. */ -/* The first check is redundant and the second overly complicated. */ -#define MINI_NON_ONLY_WINDOW_P(W) \ - (MINI_WINDOW_P (W) \ - && (EQ (W->prev, FRAME_ROOT_WINDOW (WINDOW_XFRAME (W))))) +/* True if W is a minibuffer window on a frame that contains at least + one other window. */ +#define MINI_NON_ONLY_WINDOW_P(W) \ + (MINI_WINDOW_P (W) && !NILP ((W)->prev)) -/* 1 if W is a minibuffer-only window. */ -#define MINI_ONLY_WINDOW_P(W) \ - (MINI_WINDOW_P (W) && NILP (W->prev)) +/* True if W is a minibuffer window that is alone on its frame. */ +#define MINI_ONLY_WINDOW_P(W) \ + (MINI_WINDOW_P (W) && NILP ((W)->prev)) /* General window layout: @@ -518,29 +518,34 @@ struct window /* A handy macro. */ -/* Non-nil if W is leaf (carry the buffer). */ - +/* Non-nil if window W is leaf window (has a buffer). */ #define WINDOW_LEAF_P(W) \ (BUFFERP ((W)->contents)) -/* Non-nil if W is internal. */ +/* Non-nil if window W is internal (is a parent window). */ #define WINDOW_INTERNAL_P(W) \ (WINDOWP ((W)->contents)) -/* True if W is a member of horizontal combination. */ +/* True if window W is a horizontal combination of windows. */ #define WINDOW_HORIZONTAL_COMBINATION_P(W) \ (WINDOW_INTERNAL_P (W) && (W)->horizontal) -/* True if W is a member of vertical combination. */ +/* True if window W is a vertical combination of windows. */ #define WINDOW_VERTICAL_COMBINATION_P(W) \ (WINDOW_INTERNAL_P (W) && !(W)->horizontal) -/* WINDOW's XFRAME. */ +/* Window W's XFRAME. */ #define WINDOW_XFRAME(W) (XFRAME (WINDOW_FRAME ((W)))) -/* Whether WINDOW is a pseudo window. */ +/* Whether window W is a pseudo window. */ #define WINDOW_PSEUDO_P(W) ((W)->pseudo_window_p) +/* Window W's buffer. */ +#define WINDOW_BUFFER(W) \ + (WINDOW_LEAF_P(W) \ + ? (W)->contents \ + : Qnil) \ + /* Return the canonical column width of the frame of window W. */ #define WINDOW_FRAME_COLUMN_WIDTH(W) \ (FRAME_COLUMN_WIDTH (WINDOW_XFRAME ((W)))) @@ -549,24 +554,24 @@ struct window #define WINDOW_FRAME_LINE_HEIGHT(W) \ (FRAME_LINE_HEIGHT (WINDOW_XFRAME ((W)))) -/* Return the pixel width of window W. - This includes scroll bars and fringes. */ +/* Return the pixel width of window W. This includes dividers, scroll + bars, fringes and margins, if any. */ #define WINDOW_PIXEL_WIDTH(W) (W)->pixel_width -/* Return the pixel height of window W. - This includes header and mode lines, if any. */ +/* Return the pixel height of window W. This includes dividers, scroll + bars, header and mode lines, if any. */ #define WINDOW_PIXEL_HEIGHT(W) (W)->pixel_height -/* Return the width of window W in canonical column units. - This includes scroll bars and fringes. - This value is adjusted such that the sum of the widths of all child +/* Return the width of window W in canonical column units. This + includes dividers, scroll bars, fringes and margins, if any. The + value is adjusted such that the sum of the widths of all child windows equals the width of their parent window. */ #define WINDOW_TOTAL_COLS(W) (W)->total_cols -/* Return the height of window W in canonical line units. - This includes header and mode lines, if any. - This value is adjusted such that the sum of the heights of all child - windows equals the height of their parent window. */ +/* Return the height of window W in canonical line units. This includes + dividers, scroll bars, header and mode lines, if any. The value is + adjusted such that the sum of the heights of all child windows equals + the height of their parent window. */ #define WINDOW_TOTAL_LINES(W) (W)->total_lines /* The smallest acceptable dimensions for a window. Anything smaller @@ -581,31 +586,63 @@ struct window #define MIN_SAFE_WINDOW_PIXEL_HEIGHT(W) \ (WINDOW_FRAME_LINE_HEIGHT (W)) +/* True if window W has no other windows to its left on its frame. */ +#define WINDOW_LEFTMOST_P(W) \ + (WINDOW_LEFT_PIXEL_EDGE (W) == 0) + +/* True if window W has no other windows above it on its frame. */ +#define WINDOW_TOPMOST_P(W) \ + (WINDOW_TOP_PIXEL_EDGE (W) == 0) + +/* True if window W has no other windows to its right on its frame. */ +#define WINDOW_RIGHTMOST_P(W) \ + (WINDOW_RIGHT_PIXEL_EDGE (W) \ + == (WINDOW_RIGHT_PIXEL_EDGE \ + (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))))) \ + +/* True if window W has no other windows below it on its frame (the + minibuffer window is not counted in this respect unless W itself is a + minibuffer window). */ +#define WINDOW_BOTTOMMOST_P(W) \ + (WINDOW_BOTTOM_PIXEL_EDGE (W) \ + == (WINDOW_BOTTOM_PIXEL_EDGE \ + (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))))) \ + +/* True if window W takes up the full width of its frame. */ +#define WINDOW_FULL_WIDTH_P(W) \ + (WINDOW_PIXEL_WIDTH (W) \ + == (WINDOW_PIXEL_WIDTH \ + (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))))) \ + /* Width of right divider of window W. */ #define WINDOW_RIGHT_DIVIDER_WIDTH(W) \ - ((WINDOW_RIGHTMOST_P (W) || MINI_WINDOW_P (W)) \ - ? 0 \ - : FRAME_RIGHT_DIVIDER_WIDTH (WINDOW_XFRAME (W))) + (WINDOW_RIGHTMOST_P (W) \ + ? 0 : FRAME_RIGHT_DIVIDER_WIDTH (WINDOW_XFRAME (W))) + +/* Width of bottom divider of window W. */ +#define WINDOW_BOTTOM_DIVIDER_WIDTH(W) \ + (((WINDOW_BOTTOMMOST_P (W) \ + && NILP ((XWINDOW (FRAME_ROOT_WINDOW \ + (WINDOW_XFRAME (W))))->next)) \ + || EQ ((W)->prev, FRAME_ROOT_WINDOW (WINDOW_XFRAME (W))) \ + || (W)->pseudo_window_p) \ + ? 0 : FRAME_BOTTOM_DIVIDER_WIDTH (WINDOW_XFRAME (W))) /* Return the canonical frame column at which window W starts. This includes a left-hand scroll bar, if any. */ - #define WINDOW_LEFT_EDGE_COL(W) (W)->left_col /* Return the canonical frame column before which window W ends. This includes a right-hand scroll bar, if any. */ - #define WINDOW_RIGHT_EDGE_COL(W) \ (WINDOW_LEFT_EDGE_COL (W) + WINDOW_TOTAL_COLS (W)) /* Return the canonical frame line at which window W starts. This includes a header line, if any. */ - #define WINDOW_TOP_EDGE_LINE(W) (W)->top_line /* Return the canonical frame line before which window W ends. This includes a mode line, if any. */ - #define WINDOW_BOTTOM_EDGE_LINE(W) \ (WINDOW_TOP_EDGE_LINE (W) + WINDOW_TOTAL_LINES (W)) @@ -629,20 +666,17 @@ struct window /* Return the frame x-position at which window W starts. This includes a left-hand scroll bar, if any. */ - #define WINDOW_LEFT_EDGE_X(W) \ (FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W)) \ + WINDOW_LEFT_PIXEL_EDGE (W)) /* Return the frame x- position before which window W ends. This includes a right-hand scroll bar, if any. */ - #define WINDOW_RIGHT_EDGE_X(W) \ (FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W)) \ + WINDOW_RIGHT_PIXEL_EDGE (W)) /* True if W is a menu bar window. */ - #if defined (HAVE_X_WINDOWS) && ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) #define WINDOW_MENU_BAR_P(W) \ (WINDOWP (WINDOW_XFRAME (W)->menu_bar_window) \ @@ -661,72 +695,24 @@ struct window #define WINDOW_TOOL_BAR_P(W) false #endif -/* Return the frame y-position at which window W starts. - This includes a header line, if any. - - PXW: With a menu or tool bar this is not symmetric to the _X values - since it _does_ include the internal border width. */ +/* Return the frame y-position at which window W starts. */ #define WINDOW_TOP_EDGE_Y(W) \ (((WINDOW_MENU_BAR_P (W) || WINDOW_TOOL_BAR_P (W)) \ ? 0 : FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W))) \ + WINDOW_TOP_PIXEL_EDGE (W)) -/* Return the frame y-position before which window W ends. - This includes a mode line, if any. */ +/* Return the frame y-position before which window W ends. */ #define WINDOW_BOTTOM_EDGE_Y(W) \ (((WINDOW_MENU_BAR_P (W) || WINDOW_TOOL_BAR_P (W)) \ ? 0 : FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W))) \ + WINDOW_BOTTOM_PIXEL_EDGE (W)) -/* True if window W takes up the full width of its frame. */ -#define WINDOW_FULL_WIDTH_P(W) \ - (WINDOW_PIXEL_WIDTH (W) \ - == (WINDOW_PIXEL_WIDTH \ - (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))))) \ - -/* True if window W's has no other windows to its left in its frame. */ - -#define WINDOW_LEFTMOST_P(W) \ - (WINDOW_LEFT_PIXEL_EDGE (W) == 0) - -/* True if window W's has no other windows above in its frame. */ -#define WINDOW_TOPMOST_P(W) \ - (WINDOW_TOP_PIXEL_EDGE (W) == 0) - -/* True if window W's has no other windows to its right in its frame. */ -#define WINDOW_RIGHTMOST_P(W) \ - (WINDOW_RIGHT_PIXEL_EDGE (W) \ - == (WINDOW_RIGHT_PIXEL_EDGE \ - (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))))) \ - -/* True if window W's has no other windows below it in its frame - (the minibuffer window is not counted in this respect). */ -#define WINDOW_BOTTOMMOST_P(W) \ - (WINDOW_BOTTOM_PIXEL_EDGE (W) \ - == (WINDOW_BOTTOM_PIXEL_EDGE \ - (XWINDOW (FRAME_ROOT_WINDOW (WINDOW_XFRAME (W)))))) \ - -/* Return the frame column at which the text (or left fringe) in - window W starts. This is different from the `LEFT_EDGE' because it - does not include a left-hand scroll bar if any. */ -#define WINDOW_BOX_LEFT_EDGE_COL(W) \ - (WINDOW_LEFT_EDGE_COL (W) \ - + WINDOW_LEFT_SCROLL_BAR_COLS (W)) - -/* Return the pixel value where the text (or left fringe) in - window W starts. This is different from the `LEFT_EDGE' because it - does not include a left-hand scroll bar if any. */ +/* Return the pixel value where the text (or left fringe) in window W + starts. */ #define WINDOW_BOX_LEFT_PIXEL_EDGE(W) \ (WINDOW_LEFT_PIXEL_EDGE (W) \ + WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (W)) -/* Return the window column before which the text in window W ends. - This is different from WINDOW_RIGHT_EDGE_COL because it does not - include a scroll bar or window-separating line on the right edge. */ -#define WINDOW_BOX_RIGHT_EDGE_COL(W) \ - (WINDOW_RIGHT_EDGE_COL (W) \ - - WINDOW_RIGHT_SCROLL_BAR_COLS (W)) - /* Return the pixel value before which the text in window W ends. This is different from the `RIGHT_EDGE' because it does not include a right-hand scroll bar or window-separating line on the right @@ -736,16 +722,16 @@ struct window - WINDOW_RIGHT_DIVIDER_WIDTH (W) \ - WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH (W)) -/* Return the frame position at which the text (or left fringe) in - window W starts. This is different from the `LEFT_EDGE' because it - does not include a left-hand scroll bar if any. */ +/* Return the frame x-position at which the text (or left fringe) in + window W starts. This does not include a left-hand scroll bar if + any. */ #define WINDOW_BOX_LEFT_EDGE_X(W) \ (FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W)) \ + WINDOW_BOX_LEFT_PIXEL_EDGE (W)) -/* Return the window column before which the text in window W ends. - This is different from WINDOW_RIGHT_EDGE_COL because it does not - include a scroll bar or window-separating line on the right edge. */ +/* Return the frame x-position before which the text in window W ends. + This does not include a scroll bar, divider or window-separating line + on the right edge. */ #define WINDOW_BOX_RIGHT_EDGE_X(W) \ (FRAME_INTERNAL_BORDER_WIDTH (WINDOW_XFRAME (W)) \ + WINDOW_BOX_RIGHT_PIXEL_EDGE (W)) @@ -899,16 +885,6 @@ struct window ? WINDOW_BOX_RIGHT_EDGE_X (W) \ : WINDOW_LEFT_EDGE_X (W)) -/* Width of bottom divider of window W. */ -#define WINDOW_BOTTOM_DIVIDER_WIDTH(W) \ - (((WINDOW_BOTTOMMOST_P (W) \ - && NILP ((XWINDOW (FRAME_ROOT_WINDOW \ - (WINDOW_XFRAME (W))))->next)) \ - || EQ ((W)->prev, FRAME_ROOT_WINDOW (WINDOW_XFRAME (W))) \ - || (W)->pseudo_window_p) \ - ? 0 \ - : FRAME_BOTTOM_DIVIDER_WIDTH (WINDOW_XFRAME (W))) - /* Height that a scroll bar in window W should have, if there is one. Measured in pixels. If scroll bars are turned off, this is still nonzero. */ @@ -942,22 +918,22 @@ struct window /* Height in pixels of the mode line. May be zero if W doesn't have a mode line. */ #define WINDOW_MODE_LINE_HEIGHT(W) \ - (WINDOW_WANTS_MODELINE_P ((W)) \ + (window_wants_mode_line ((W)) \ ? CURRENT_MODE_LINE_HEIGHT (W) \ : 0) #define WINDOW_MODE_LINE_LINES(W) \ - WINDOW_WANTS_MODELINE_P (W) + window_wants_mode_line (W) /* Height in pixels of the header line. Zero if W doesn't have a header line. */ #define WINDOW_HEADER_LINE_HEIGHT(W) \ - (WINDOW_WANTS_HEADER_LINE_P (W) \ + (window_wants_header_line (W) \ ? CURRENT_HEADER_LINE_HEIGHT (W) \ : 0) #define WINDOW_HEADER_LINE_LINES(W) \ - WINDOW_WANTS_HEADER_LINE_P (W) + window_wants_header_line (W) /* Pixel height of window W without mode line, bottom scroll bar and bottom divider. */ @@ -1114,10 +1090,13 @@ void set_window_buffer (Lisp_Object window, Lisp_Object buffer, extern Lisp_Object Vwindow_list; extern Lisp_Object window_list (void); +extern Lisp_Object window_parameter (struct window *, Lisp_Object parameter); extern struct window *decode_live_window (Lisp_Object); extern struct window *decode_any_window (Lisp_Object); extern bool compare_window_configurations (Lisp_Object, Lisp_Object, bool); extern void mark_window_cursors_off (struct window *); +extern bool window_wants_mode_line (struct window *); +extern bool window_wants_header_line (struct window *); extern int window_internal_height (struct window *); extern int window_body_width (struct window *w, bool); enum margin_unit { MARGIN_IN_LINES, MARGIN_IN_PIXELS }; @@ -1133,7 +1112,6 @@ void set_window_buffer (Lisp_Object window, Lisp_Object buffer, extern void init_window (void); extern void syms_of_window (void); extern void keys_of_window (void); - /* Move cursor to row/column position VPOS/HPOS, pixel coordinates Y/X. HPOS/VPOS are window-relative row and column numbers and X/Y are window-relative pixel positions. This is always done during diff --git a/src/xdisp.c b/src/xdisp.c index 34ee877..7848489 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -921,7 +921,7 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object, height -= WINDOW_BOTTOM_DIVIDER_WIDTH (w); - if (WINDOW_WANTS_MODELINE_P (w)) + if (window_wants_mode_line (w)) height -= CURRENT_MODE_LINE_HEIGHT (w); height -= WINDOW_SCROLL_BAR_AREA_HEIGHT (w); @@ -978,7 +978,7 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object, the appropriate glyph row has its `mode_line_p' flag set, and if it doesn't, uses estimate_mode_line_height instead. */ - if (WINDOW_WANTS_MODELINE_P (w)) + if (window_wants_mode_line (w)) { struct glyph_row *ml_row = (w->current_matrix && w->current_matrix->rows @@ -990,7 +990,7 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object, height -= estimate_mode_line_height (f, CURRENT_MODE_LINE_FACE_ID (w)); } - if (WINDOW_WANTS_HEADER_LINE_P (w)) + if (window_wants_header_line (w)) { struct glyph_row *hl_row = (w->current_matrix && w->current_matrix->rows @@ -1102,7 +1102,7 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object, if (box_y) { *box_y = WINDOW_TOP_EDGE_Y (w); - if (WINDOW_WANTS_HEADER_LINE_P (w)) + if (window_wants_header_line (w)) *box_y += CURRENT_HEADER_LINE_HEIGHT (w); } } @@ -1322,15 +1322,29 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object, return visible_p; /* Compute exact mode line heights. */ - if (WINDOW_WANTS_MODELINE_P (w)) - w->mode_line_height - = display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w), - BVAR (current_buffer, mode_line_format)); + if (window_wants_mode_line (w)) + { + Lisp_Object window_mode_line_format + = window_parameter (w, Qmode_line_format); + + w->mode_line_height + = display_mode_line (w, CURRENT_MODE_LINE_FACE_ID (w), + NILP (window_mode_line_format) + ? BVAR (current_buffer, mode_line_format) + : window_mode_line_format); + } - if (WINDOW_WANTS_HEADER_LINE_P (w)) - w->header_line_height - = display_mode_line (w, HEADER_LINE_FACE_ID, - BVAR (current_buffer, header_line_format)); + if (window_wants_header_line (w)) + { + Lisp_Object window_header_line_format + = window_parameter (w, Qheader_line_format); + + w->header_line_height + = display_mode_line (w, HEADER_LINE_FACE_ID, + NILP (window_header_line_format) + ? BVAR (current_buffer, header_line_format) + : window_header_line_format); + } start_display (&it, w, top); move_it_to (&it, charpos, -1, it.last_visible_y - 1, -1, @@ -2842,13 +2856,12 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object, /* Get dimensions of truncation and continuation glyphs. These are displayed as fringe bitmaps under X, but we need them for such - frames when the fringes are turned off. But leave the dimensions - zero for tooltip frames, as these glyphs look ugly there and also - sabotage calculations of tooltip dimensions in x-show-tip. */ + frames when the fringes are turned off. The no_special_glyphs slot + of the iterator's frame, when set, suppresses their display - by + default for tooltip frames and when set via the 'no-special-glyphs' + frame parameter. */ #ifdef HAVE_WINDOW_SYSTEM - if (!(FRAME_WINDOW_P (it->f) - && FRAMEP (tip_frame) - && it->f == XFRAME (tip_frame))) + if (!(FRAME_WINDOW_P (it->f) && it->f->no_special_glyphs)) #endif { if (it->line_wrap == TRUNCATE) @@ -2920,7 +2933,7 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object, it->last_visible_x -= it->continuation_pixel_width; } - it->header_line_p = WINDOW_WANTS_HEADER_LINE_P (w); + it->header_line_p = window_wants_header_line (w); it->current_y = WINDOW_HEADER_LINE_HEIGHT (w) + w->vscroll; } @@ -3019,7 +3032,7 @@ static Lisp_Object calc_line_height_property (struct it *, Lisp_Object, start_display (struct it *it, struct window *w, struct text_pos pos) { struct glyph_row *row; - bool first_vpos = WINDOW_WANTS_HEADER_LINE_P (w); + bool first_vpos = window_wants_header_line (w); row = w->desired_matrix->rows + first_vpos; init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID); @@ -15799,7 +15812,7 @@ enum /* Find the start of the continued line. This should be fast because find_newline is fast (newline cache). */ - row = w->desired_matrix->rows + WINDOW_WANTS_HEADER_LINE_P (w); + row = w->desired_matrix->rows + window_wants_header_line (w); init_iterator (&it, w, CHARPOS (start_pos), BYTEPOS (start_pos), row, DEFAULT_FACE_ID); reseat_at_previous_visible_line_start (&it); @@ -15949,7 +15962,7 @@ enum this_scroll_margin = window_scroll_margin (w, MARGIN_IN_PIXELS); top_scroll_margin = this_scroll_margin; - if (WINDOW_WANTS_HEADER_LINE_P (w)) + if (window_wants_header_line (w)) top_scroll_margin += CURRENT_HEADER_LINE_HEIGHT (w); /* Start with the row the cursor was displayed during the last @@ -16732,7 +16745,7 @@ enum margin, even though this part handles windows that didn't scroll at all. */ int pixel_margin = margin * frame_line_height; - bool header_line = WINDOW_WANTS_HEADER_LINE_P (w); + bool header_line = window_wants_header_line (w); /* Note: We add an extra FRAME_LINE_HEIGHT, because the loop below, which finds the row to move point to, advances by @@ -17299,15 +17312,15 @@ enum || (w->column_number_displayed != -1 && (w->column_number_displayed != current_column ()))) /* This means that the window has a mode line. */ - && (WINDOW_WANTS_MODELINE_P (w) - || WINDOW_WANTS_HEADER_LINE_P (w))) + && (window_wants_mode_line (w) + || window_wants_header_line (w))) { display_mode_lines (w); /* If mode line height has changed, arrange for a thorough immediate redisplay using the correct mode line height. */ - if (WINDOW_WANTS_MODELINE_P (w) + if (window_wants_mode_line (w) && CURRENT_MODE_LINE_HEIGHT (w) != DESIRED_MODE_LINE_HEIGHT (w)) { f->fonts_changed = true; @@ -17318,7 +17331,7 @@ enum /* If header line height has changed, arrange for a thorough immediate redisplay using the correct header line height. */ - if (WINDOW_WANTS_HEADER_LINE_P (w) + if (window_wants_header_line (w) && CURRENT_HEADER_LINE_HEIGHT (w) != DESIRED_HEADER_LINE_HEIGHT (w)) { f->fonts_changed = true; @@ -17583,7 +17596,7 @@ enum return false; /* If top-line visibility has changed, give up. */ - if (WINDOW_WANTS_HEADER_LINE_P (w) + if (window_wants_header_line (w) != MATRIX_HEADER_LINE_ROW (w->current_matrix)->mode_line_p) return false; @@ -18818,7 +18831,7 @@ struct glyph_row * = MATRIX_ROW_VPOS (first_unchanged_at_end_row, w->current_matrix); int from = WINDOW_TOP_EDGE_LINE (w) + from_vpos; int end = (WINDOW_TOP_EDGE_LINE (w) - + WINDOW_WANTS_HEADER_LINE_P (w) + + window_wants_header_line (w) + window_internal_height (w)); #if defined (HAVE_GPM) || defined (MSDOS) @@ -18996,7 +19009,7 @@ struct glyph_row * { /* Displayed to end of window, but no line containing text was displayed. Lines were deleted at the end of the window. */ - bool first_vpos = WINDOW_WANTS_HEADER_LINE_P (w); + bool first_vpos = window_wants_header_line (w); int vpos = w->window_end_vpos; struct glyph_row *current_row = current_matrix->rows + vpos; struct glyph_row *desired_row = desired_matrix->rows + vpos; @@ -20696,7 +20709,7 @@ struct glyph_row * ptrdiff_t min_pos = ZV + 1, max_pos = 0; ptrdiff_t min_bpos UNINIT, max_bpos UNINIT; bool pending_handle_line_prefix = false; - int header_line = WINDOW_WANTS_HEADER_LINE_P (it->w); + int header_line = window_wants_header_line (it->w); bool hscroll_this_line = (cursor_vpos >= 0 && it->vpos == cursor_vpos - header_line && hscrolling_current_line_p (it->w)); @@ -22649,20 +22662,30 @@ control characters RLO (u+202e) and LRO (u+202d). See the line_number_displayed = false; w->column_number_displayed = -1; - if (WINDOW_WANTS_MODELINE_P (w)) + if (window_wants_mode_line (w)) { + Lisp_Object window_mode_line_format + = window_parameter (w, Qmode_line_format); + struct window *sel_w = XWINDOW (old_selected_window); /* Select mode line face based on the real selected window. */ display_mode_line (w, CURRENT_MODE_LINE_FACE_ID_3 (sel_w, sel_w, w), - BVAR (current_buffer, mode_line_format)); + NILP (window_mode_line_format) + ? BVAR (current_buffer, mode_line_format) + : window_mode_line_format); ++n; } - if (WINDOW_WANTS_HEADER_LINE_P (w)) + if (window_wants_header_line (w)) { + Lisp_Object window_header_line_format + = window_parameter (w, Qheader_line_format); + display_mode_line (w, HEADER_LINE_FACE_ID, - BVAR (current_buffer, header_line_format)); + NILP (window_header_line_format) + ? BVAR (current_buffer, header_line_format) + : window_header_line_format); ++n; } @@ -30442,13 +30465,67 @@ A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the && part != ON_HEADER_LINE)) clear_mouse_face (hlinfo); + /* Reset help_echo_string. It will get recomputed below. */ + help_echo_string = Qnil; + +#ifdef HAVE_WINDOW_SYSTEM + /* If the cursor is on the internal border of FRAME and FRAME's + internal border is draggable, provide some visual feedback. */ + if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0 + && !NILP (get_frame_param (f, Qdrag_internal_border))) + { + enum internal_border_part part = frame_internal_border_part (f, x, y); + + switch (part) + { + case INTERNAL_BORDER_NONE: + if (cursor != FRAME_X_OUTPUT (f)->nontext_cursor) + /* Reset cursor. */ + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + break; + case INTERNAL_BORDER_LEFT_EDGE: + cursor = FRAME_X_OUTPUT (f)->left_edge_cursor; + break; + case INTERNAL_BORDER_TOP_LEFT_CORNER: + cursor = FRAME_X_OUTPUT (f)->top_left_corner_cursor; + break; + case INTERNAL_BORDER_TOP_EDGE: + cursor = FRAME_X_OUTPUT (f)->top_edge_cursor; + break; + case INTERNAL_BORDER_TOP_RIGHT_CORNER: + cursor = FRAME_X_OUTPUT (f)->top_right_corner_cursor; + break; + case INTERNAL_BORDER_RIGHT_EDGE: + cursor = FRAME_X_OUTPUT (f)->right_edge_cursor; + break; + case INTERNAL_BORDER_BOTTOM_RIGHT_CORNER: + cursor = FRAME_X_OUTPUT (f)->bottom_right_corner_cursor; + break; + case INTERNAL_BORDER_BOTTOM_EDGE: + cursor = FRAME_X_OUTPUT (f)->bottom_edge_cursor; + break; + case INTERNAL_BORDER_BOTTOM_LEFT_CORNER: + cursor = FRAME_X_OUTPUT (f)->bottom_left_corner_cursor; + break; + default: + /* This should not happen. */ + if (cursor != FRAME_X_OUTPUT (f)->nontext_cursor) + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; + } + + if (cursor != FRAME_X_OUTPUT (f)->nontext_cursor) + { + /* Do we really want a help echo here? */ + help_echo_string = build_string ("drag-mouse-1: resize frame"); + goto set_cursor; + } + } +#endif /* HAVE_WINDOW_SYSTEM */ + /* Not on a window -> return. */ if (!WINDOWP (window)) return; - /* Reset help_echo_string. It will get recomputed below. */ - help_echo_string = Qnil; - /* Convert to window-relative pixel coordinates. */ w = XWINDOW (window); frame_to_window_pixel_xy (w, &x, &y); @@ -30486,11 +30563,13 @@ A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the { cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; help_echo_string = build_string ("drag-mouse-1: resize"); + goto set_cursor; } else if (part == ON_RIGHT_DIVIDER) { cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor; help_echo_string = build_string ("drag-mouse-1: resize"); + goto set_cursor; } else if (part == ON_BOTTOM_DIVIDER) if (! WINDOW_BOTTOMMOST_P (w) @@ -30499,6 +30578,7 @@ A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the { cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor; help_echo_string = build_string ("drag-mouse-1: resize"); + goto set_cursor; } else cursor = FRAME_X_OUTPUT (f)->nontext_cursor; @@ -31193,8 +31273,15 @@ A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the int x0 = WINDOW_RIGHT_EDGE_X (w) - WINDOW_RIGHT_DIVIDER_WIDTH (w); int x1 = WINDOW_RIGHT_EDGE_X (w); int y0 = WINDOW_TOP_EDGE_Y (w); - /* The bottom divider prevails. */ - int y1 = WINDOW_BOTTOM_EDGE_Y (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w); + int y1 = WINDOW_BOTTOM_EDGE_Y (w); + + /* If W is horizontally combined and has a right sibling, don't + draw over any bottom divider. */ + if (WINDOW_BOTTOM_DIVIDER_WIDTH (w) + && !NILP (w->parent) + && WINDOW_HORIZONTAL_COMBINATION_P (XWINDOW (w->parent)) + && !NILP (w->next)) + y1 -= WINDOW_BOTTOM_DIVIDER_WIDTH (w); FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1); } @@ -31213,8 +31300,22 @@ A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the int x1 = WINDOW_RIGHT_EDGE_X (w); int y0 = WINDOW_BOTTOM_EDGE_Y (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w); int y1 = WINDOW_BOTTOM_EDGE_Y (w); + struct window *p = !NILP (w->parent) ? XWINDOW (w->parent) : false; - FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1); + /* If W is vertically combined and has a sibling below, don't draw + over any right divider. */ + if (WINDOW_RIGHT_DIVIDER_WIDTH (w) + && p + && ((WINDOW_VERTICAL_COMBINATION_P (p) + && !NILP (w->next)) + || (WINDOW_HORIZONTAL_COMBINATION_P (p) + && NILP (w->next) + && !NILP (p->parent) + && WINDOW_VERTICAL_COMBINATION_P (XWINDOW (p->parent)) + && !NILP (XWINDOW (p->parent)->next)))) + x1 -= WINDOW_RIGHT_DIVIDER_WIDTH (w); + + FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1); } } @@ -31329,7 +31430,7 @@ A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the } /* Display the mode line if there is one. */ - if (WINDOW_WANTS_MODELINE_P (w) + if (window_wants_mode_line (w) && (row = MATRIX_MODE_LINE_ROW (w->current_matrix), row->enabled_p) && row->y < r_bottom) diff --git a/src/xfns.c b/src/xfns.c index 7be2253..3dd1970 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -1120,6 +1120,14 @@ enum mouse_cursor { mouse_cursor_hand, mouse_cursor_horizontal_drag, mouse_cursor_vertical_drag, + mouse_cursor_left_edge, + mouse_cursor_top_left_corner, + mouse_cursor_top_edge, + mouse_cursor_top_right_corner, + mouse_cursor_right_edge, + mouse_cursor_bottom_right_corner, + mouse_cursor_bottom_edge, + mouse_cursor_bottom_left_corner, mouse_cursor_max }; @@ -1139,13 +1147,21 @@ struct mouse_cursor_types { /* This array must stay in sync with enum mouse_cursor above! */ static const struct mouse_cursor_types mouse_cursor_types[] = { - { "text", &Vx_pointer_shape, XC_xterm }, - { "nontext", &Vx_nontext_pointer_shape, XC_left_ptr }, - { "hourglass", &Vx_hourglass_pointer_shape, XC_watch }, - { "modeline", &Vx_mode_pointer_shape, XC_xterm }, - { NULL, &Vx_sensitive_text_pointer_shape, XC_hand2 }, - { NULL, &Vx_window_horizontal_drag_shape, XC_sb_h_double_arrow }, - { NULL, &Vx_window_vertical_drag_shape, XC_sb_v_double_arrow }, + { "text", &Vx_pointer_shape, XC_xterm }, + { "nontext", &Vx_nontext_pointer_shape, XC_left_ptr }, + { "hourglass", &Vx_hourglass_pointer_shape, XC_watch }, + { "modeline", &Vx_mode_pointer_shape, XC_xterm }, + { NULL, &Vx_sensitive_text_pointer_shape, XC_hand2 }, + { NULL, &Vx_window_horizontal_drag_shape, XC_sb_h_double_arrow }, + { NULL, &Vx_window_vertical_drag_shape, XC_sb_v_double_arrow }, + { NULL, &Vx_window_left_edge_shape, XC_left_side }, + { NULL, &Vx_window_top_left_corner_shape, XC_top_left_corner }, + { NULL, &Vx_window_top_edge_shape, XC_top_side }, + { NULL, &Vx_window_top_right_corner_shape, XC_top_right_corner }, + { NULL, &Vx_window_right_edge_shape, XC_right_side }, + { NULL, &Vx_window_bottom_right_corner_shape, XC_bottom_right_corner }, + { NULL, &Vx_window_bottom_edge_shape, XC_bottom_side }, + { NULL, &Vx_window_bottom_left_corner_shape, XC_bottom_left_corner }, }; struct mouse_cursor_data { @@ -1296,6 +1312,14 @@ struct mouse_cursor_data { INSTALL_CURSOR (hand_cursor, hand); INSTALL_CURSOR (horizontal_drag_cursor, horizontal_drag); INSTALL_CURSOR (vertical_drag_cursor, vertical_drag); + INSTALL_CURSOR (left_edge_cursor, left_edge); + INSTALL_CURSOR (top_left_corner_cursor, top_left_corner); + INSTALL_CURSOR (top_edge_cursor, top_edge); + INSTALL_CURSOR (top_right_corner_cursor, top_right_corner); + INSTALL_CURSOR (right_edge_cursor, right_edge); + INSTALL_CURSOR (bottom_right_corner_cursor, bottom_right_corner); + INSTALL_CURSOR (bottom_edge_cursor, bottom_edge); + INSTALL_CURSOR (bottom_left_corner_cursor, bottom_left_corner); #undef INSTALL_CURSOR @@ -3814,6 +3838,8 @@ struct mouse_cursor_data { "leftFringe", "LeftFringe", RES_TYPE_NUMBER); x_default_parameter (f, parms, Qright_fringe, Qnil, "rightFringe", "RightFringe", RES_TYPE_NUMBER); + x_default_parameter (f, parms, Qno_special_glyphs, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground, "scrollBarForeground", @@ -6196,6 +6222,8 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, "cursorColor", "Foreground", RES_TYPE_STRING); x_default_parameter (f, parms, Qborder_color, build_string ("black"), "borderColor", "BorderColor", RES_TYPE_STRING); + x_default_parameter (f, parms, Qno_special_glyphs, Qnil, + NULL, NULL, RES_TYPE_BOOLEAN); /* Init faces before x_default_parameter is called for the scroll-bar-width parameter because otherwise we end up in @@ -7486,6 +7514,7 @@ FRAMES should be nil (the selected frame), a frame, or a list of x_set_no_accept_focus, x_set_z_group, x_set_override_redirect, + x_set_no_special_glyphs, }; void @@ -7564,6 +7593,62 @@ FRAMES should be nil (the selected frame), a frame, or a list of or when you set the mouse color. */); Vx_window_vertical_drag_shape = Qnil; + DEFVAR_LISP ("x-window-left-edge-cursor", + Vx_window_left_edge_shape, + doc: /* Pointer shape indicating a left x-window edge can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_left_edge_shape = Qnil; + + DEFVAR_LISP ("x-window-top-left-corner-cursor", + Vx_window_top_left_corner_shape, + doc: /* Pointer shape indicating a top left x-window corner can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_top_left_corner_shape = Qnil; + + DEFVAR_LISP ("x-window-top-edge-cursor", + Vx_window_top_edge_shape, + doc: /* Pointer shape indicating a top x-window edge can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_top_edge_shape = Qnil; + + DEFVAR_LISP ("x-window-top-right-corner-cursor", + Vx_window_top_right_corner_shape, + doc: /* Pointer shape indicating a top right x-window corner can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_top_right_corner_shape = Qnil; + + DEFVAR_LISP ("x-window-right-edge-cursor", + Vx_window_right_edge_shape, + doc: /* Pointer shape indicating a right x-window edge can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_right_edge_shape = Qnil; + + DEFVAR_LISP ("x-window-bottom-right-corner-cursor", + Vx_window_bottom_right_corner_shape, + doc: /* Pointer shape indicating a bottom right x-window corner can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_bottom_right_corner_shape = Qnil; + + DEFVAR_LISP ("x-window-bottom-edge-cursor", + Vx_window_bottom_edge_shape, + doc: /* Pointer shape indicating a bottom x-window edge can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_bottom_edge_shape = Qnil; + + DEFVAR_LISP ("x-window-bottom-left-corner-cursor", + Vx_window_bottom_left_corner_shape, + doc: /* Pointer shape indicating a bottom left x-window corner can be dragged. +This variable takes effect when you create a new frame +or when you set the mouse color. */); + Vx_window_bottom_left_corner_shape = Qnil; + DEFVAR_LISP ("x-cursor-fore-pixel", Vx_cursor_fore_pixel, doc: /* A string indicating the foreground color of the cursor box. */); Vx_cursor_fore_pixel = Qnil; diff --git a/src/xterm.c b/src/xterm.c index c8836b7..a214cd8 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -11757,6 +11757,22 @@ struct x_error_message_stack { XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->horizontal_drag_cursor); if (f->output_data.x->vertical_drag_cursor != 0) XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->vertical_drag_cursor); + if (f->output_data.x->left_edge_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->left_edge_cursor); + if (f->output_data.x->top_left_corner_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->top_left_corner_cursor); + if (f->output_data.x->top_edge_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->top_edge_cursor); + if (f->output_data.x->top_right_corner_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->top_right_corner_cursor); + if (f->output_data.x->right_edge_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->right_edge_cursor); + if (f->output_data.x->bottom_right_corner_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_right_corner_cursor); + if (f->output_data.x->bottom_edge_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_edge_cursor); + if (f->output_data.x->bottom_left_corner_cursor != 0) + XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->bottom_left_corner_cursor); XFlush (FRAME_X_DISPLAY (f)); } diff --git a/src/xterm.h b/src/xterm.h index a752570..803feda 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -637,6 +637,14 @@ struct x_output Cursor horizontal_drag_cursor; Cursor vertical_drag_cursor; Cursor current_cursor; + Cursor left_edge_cursor; + Cursor top_left_corner_cursor; + Cursor top_edge_cursor; + Cursor top_right_corner_cursor; + Cursor right_edge_cursor; + Cursor bottom_right_corner_cursor; + Cursor bottom_edge_cursor; + Cursor bottom_left_corner_cursor; /* Window whose cursor is hourglass_cursor. This window is temporarily mapped to display an hourglass cursor. */ [-- Attachment #3: ChangeLog --] [-- Type: text/plain, Size: 8973 bytes --] Provide mouse dragging and resizing of frames. Allow resizing frames proportionally. Provide additional functionality for child frames. * lisp/frame.el (frame-border-width, frame-pixel-width) (frame-pixel-height): Alias to `frame-internal-border-width', `frame-native-width' and `frame-native-height'. (frame-inner-width, frame-inner-height, frame-outer-width) (frame-outer-height): New functions. * lisp/minibuffer.el (completion-auto-help): Fix typo. * lisp/mouse.el (mouse-drag-line, mouse-drag-mode-line) (mouse-drag-header-line): Allow moving a frame by dragging the mode line of its bottommost window (on a minibuffer-less frame) or the header line of its topmost window. (mouse-drag-vertical-line): Mention argument in doc-string. (mouse-resize-frame, mouse-drag-frame, mouse-drag-left-edge) (mouse-drag-top-left-corner, mouse-drag-top-edge) (mouse-drag-top-right-corner, mouse-drag-right-edge) (mouse-drag-bottom-right-corner, mouse-drag-bottom-edge) (mouse-drag-bottom-left-corner): New functions for resizing a frame by dragging its internal border together with corresponding key bindings. * lisp/tooltip.el (tooltip-frame-parameters): Add 'no-special-glyphs' to default parameters and update version tag. * lisp/window.el (frame-auto-hide-function): Add choice to make frame invisible and update version tag. (window--delete): Handle 'auto-hide-function' frame parameter. (window--maybe-raise-frame): Respect 'no-focus-on-map' and 'no-accept-focus' frame parameters. (display-buffer--action-function-custom-type): Add `display-buffer-in-child-frame'. (display-buffer): Mention `display-buffer-in-child-frame' in doc-string. (display-buffer-in-child-frame): New action function for `display-buffer'. (window--sanitize-margin): Return zero when MARGIN cannot be sanitized. (fit-frame-to-buffer): Major rewrite to handle child frames and 'fit-frame-to-buffer-sizes' and 'fit-frame-to-buffer-margins' frame parameters. (window-largest-empty-rectangle--maximums-1) (window-largest-empty-rectangle--maximums) (window-largest-empty-rectangle--disjoint-maximums) (window-largest-empty-rectangle): New functions. * src/dispextern.h (WINDOW_WANTS_MODELINE_P) (WINDOW_WANTS_HEADER_LINE_P): Remove. Functionality is now provided by corresponding functions window_wants_modeline and window_wants_header_line in window.c. Adjust users. * src/dispnew.c (adjust_glyph_matrix) (buffer_posn_from_coords): Use window_wants_modeline and window_wants_header_line instead of WINDOW_WANTS_MODELINE_P and WINDOW_WANTS_HEADER_LINE_P. * src/frame.c (keep_ratio): New function. (adjust_frame_size): Call keep_ratio for each of F's child frames. (make_frame): Initialize no_special_glyphs slot. (frame_internal_border_part): New function. (Fframe_pixel_width, Fframe_pixel_height, Fborder_width): Rename to Fframe_native_width, Fframe_native_height mand Fframe_internal_border_width. (frame_parm_table): Add Qno_special_glyphs entry. (frame_float_type): New enumeration type. (frame_float): New function to handle frame size and position ratios. (x_set_frame_parameters): Handle size and position ratios. (x_set_no_special_glyphs): New function (x_figure_window_size): Handle size and position ratios. (syms_of_frame): Add Qdisplay_monitor_attributes_list, Qno_special_glyphs, Qframe_edges, Qkeep_ratio, Qwidth_only, Qheight_only, Qleft_only and Qtop_only. * src/frame.h (internal_border_part): New enumeration type. (struct frame): New slot no_special_glyphs. (FRAME_NO_SPECIAL_GLYPHS): New macro. * src/keyboard.c (internal_border_parts): New array constant. (make_lispy_position): For frames with border dragging enabled return internal border part. (syms_of_keyboard): New symbols Qdrag_internal_border, Qleft_edge, Qtop_left_corner, Qtop_edge, Qtop_right_corner, Qright_edge, Qbottom_right_corner, Qbottom_edge and Qbottom_left_corner. * src/minibuf.c (read_minibuf_unwind): When exiting the minibuffer deal with frames that have the 'minibuffer-exit' parameter set. (syms_of_minibuf): New symbol Qminibuffer_exit. * src/nsfns.m (frame_parm_handler): Add entry for x_set_no_special_glyphs. (Fx_create_frame): Handle 'no-special-glyphs' parameter. Intitialize new cursor types for dragging frame borders. * src/nsterm.h (struct ns_output): Add new cursor types for dragging frame borders. * src/w32fns.c (w32_frame_parm_handlers): Add entry for x_set_no_special_glyphs. (Fx_create_frame): Handle 'no-special-glyphs' parameter. Intitialize new cursor types for dragging frame borders. * src/w32term.h (struct w32_output): Add new cursor types for dragging frame borders. * src/window.c (coordinates_in_window) (Fwindow_line_height, window_internal_height): Use window_wants_modeline and window_wants_header_line instead of WINDOW_WANTS_MODELINE_P and WINDOW_WANTS_HEADER_LINE_P. (Fwindow_lines_pixel_dimensions): New function. (window_parameter): New function. (Fwindow_parameter): Call window_parameter. (window_wants_mode_line, window_wants_header_line): New functions replacing the macros WINDOW_WANTS_MODELINE_P and WINDOW_WANTS_HEADER_LINE_P from dispextern.h. (syms_of_window): New symbols Qmode_line_format and Qheader_line_format. * src/window.h: Reorganize and re-comment macros. Use window_wants_modeline and window_wants_header_line instead of WINDOW_WANTS_MODELINE_P and WINDOW_WANTS_HEADER_LINE_P. (MINI_NON_ONLY_WINDOW_P, MINI_ONLY_WINDOW_P): Minor rewrite. (WINDOW_BUFFER): New macro. (WINDOW_BOX_LEFT_EDGE_COL, WINDOW_BOX_RIGHT_EDGE_COL): Remove. * src/xdisp.c (window_text_bottom_y, window_box_height) (window_box, start_display) (compute_window_start_on_continuation_line) (try_cursor_movement, redisplay_window) (try_window_reusing_current_matrix, try_window_id) (display_line, expose_window): Use window_wants_modeline and window_wants_header_line instead of WINDOW_WANTS_MODELINE_P and WINDOW_WANTS_HEADER_LINE_P. (pos_visible_p, display_mode_lines): Respect W's 'mode-line-format' and 'header-line-format' window parameters. (init_iterator): Use window_wants_modeline and window_wants_header_line instead of WINDOW_WANTS_MODELINE_P and WINDOW_WANTS_HEADER_LINE_P. For tip frames respect no_special_glyphs value. (note_mouse_highlight): Set frame border cursors when on internal border. (x_draw_right_divider, x_draw_bottom_divider): Try to improve drawing of window dividers. * src/xfns.c (mouse_cursor): Add entries for border parts. (mouse_cursor_types): Add entries for cursor types to drag frame borders. (INSTALL_CURSOR): Add entries for new cursor types to drag frame borders. (Fx_create_frame): Handle 'no-special-glyphs' parameter. (x_frame_parm_handlers): Add entry for x_set_no_special_glyphs. (Vx_window_left_edge_shape, Vx_window_top_left_corner_shape) (Vx_window_top_edge_shape, Vx_window_top_right_corner_shape) (Vx_window_right_edge_shape) (Vx_window_bottom_right_corner_shape) (Vx_window_bottom_edge_shape) (Vx_window_bottom_left_corner_shape): New variables. * src/xterm.c (x_free_frame_resources): Remove new cursors for dragging frame borders. * src/xterm.h (struct x_output): Add new cursor types for dragging frame borders. * doc/lispref/display.texi (Size of Displayed Text): Document `window-lines-pixel-dimensions'. * doc/lispref/elisp.texi (Top): Add entry for "Mouse Dragging Parameters". * doc/lispref/frames.texi (Frame Size): Replace frame-pixel-width/-height by frame-native-width/-height. Add frame-inner-width/-height and frame-outer-width/-height docs. (Position Parameters): Describe specifying position as ratios. Clarify remark about positions relative to bottom/ridge display edge. (Size Parameters): Describe specifying sizes as ratios. Describe 'fit-frame-to-buffer-margins' and 'fit-frame-to-buffer-sizes' parameters. (Layout Parameters): Describe 'no-special-glyphs' parameter. (Frame Interaction Parameters): Describe 'auto-hide-function', 'minibuffer-exit' and 'keep-ratio' parameters. (Mouse Dragging Parameters): New section describing 'drag-internal-border', 'drag-with-header-line', 'drag-with-mode-line', 'snap-width', 'top-visible' and 'bottom-visible' parameters. (Management Parameters): Mention that `override-redirect' has no effect on MS Windows. (Font and Color Parameters): Mention child frames for `alpha' parameter. (Child Frames): Rewrite section with description and cross references to new frame parameters added. * doc/lispref/modes.texi (Mode Line Basics): Mention 'mode-line-format' and 'header-line-format' window parameters. * doc/lispref/windows.texi (Resizing Windows): Mention effect of `fit-frame-to-buffer-margins' for child frames. (Display Action Functions): New action function `display-buffer-in-child-frame'. (Quitting Windows): Mention `make-frame-invisible' as optional value of `frame-auto-hide-function' and `auto-hide-function' frame paameter. (Coordinates and Windows): Describe new function `window-largest-empty-rectangle'. (Window Parameters): Describe new parameters 'mode-line-format' and 'header-line-format'. Index all window parameters described in this section. [-- Attachment #4: my-child-frame.el --] [-- Type: application/emacs-lisp, Size: 3095 bytes --] ^ permalink raw reply related [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-06-22 9:10 ` martin rudalics @ 2017-06-25 14:22 ` Alan Third 2017-06-25 15:58 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Alan Third @ 2017-06-25 14:22 UTC (permalink / raw) To: martin rudalics Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren On Thu, Jun 22, 2017 at 11:10:54AM +0200, martin rudalics wrote: > > Anything else you’d like me to look at here? > > Attached find the changes I intend to push in the next few days plus a > ChangeLog. You will find this particular change there: > > + f->output_data.ns->left_edge_cursor = [NSCursor resizeLeftRightCursor]; > + f->output_data.ns->top_left_corner_cursor = [NSCursor arrowCursor]; > + f->output_data.ns->top_edge_cursor = [NSCursor resizeUpDownCursor]; > + f->output_data.ns->top_right_corner_cursor = [NSCursor arrowCursor]; > + f->output_data.ns->right_edge_cursor = [NSCursor resizeLeftRightCursor]; > + f->output_data.ns->bottom_right_corner_cursor = [NSCursor arrowCursor]; > + f->output_data.ns->bottom_edge_cursor = [NSCursor resizeUpDownCursor]; > + f->output_data.ns->bottom_left_corner_cursor = [NSCursor arrowCursor]; > > It would be nice to have something better on NS for the > top_left_corner_cursor, top_right_corner_cursor, > bottom_right_corner_cursor and bottom_left_corner_cursor cases. Maybe we could add a couple of custom cursors, it looks like there’s a way to do that. Do we have a standard set of cursor images to use? > If you want to play around with child frames, try the attached file > my-child-frame.el. Any feedback welcome. I’ve just been playing about with your child frame script and I think I’ve found a few bugs in the NS port: It appears that making the child frame invisible ‘disconnects’ it from the parent frame, so the next time it’s made visible it no longer moves with the parent. I guess I’ll have to make sure that when a frame is made visible it’s reconnected with it’s parent. Or find a way to prevent it disconnecting. It seems a really odd thing for it to do. Resizing the child frame with the mouse doesn’t work, is it supposed to? (set-face-background 'internal-border "blue" my-child-frame) makes me think the child frame should have a blue border, but it doesn’t. Is that a bug? Thanks! -- Alan Third ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-06-25 14:22 ` Alan Third @ 2017-06-25 15:58 ` martin rudalics 2017-07-15 21:27 ` Alan Third 0 siblings, 1 reply; 85+ messages in thread From: martin rudalics @ 2017-06-25 15:58 UTC (permalink / raw) To: Alan Third Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren > Maybe we could add a couple of custom cursors, it looks like there’s a > way to do that. Do we have a standard set of cursor images to use? No idea. IIUC there's no consensus on what is available on the various OS. > It appears that making the child frame invisible ‘disconnects’ it from > the parent frame, so the next time it’s made visible it no longer > moves with the parent. I guess I’ll have to make sure that when a > frame is made visible it’s reconnected with it’s parent. Or find a way > to prevent it disconnecting. It seems a really odd thing for it to do. Annoying. A similar thing happens with the z-group property on X where I reinstall it from its stored value whenever the frame becomes visible (see lines 8108--8111 in xterm.c). I suppose we should do something similar on NS. And maybe that's not the only property that gets reset here or there ... > Resizing the child frame with the mouse doesn’t work, is it supposed > to? Definitely. Do you see an internal border? Do you see a changing cursor at that border when the mouse is over it? And can you move the frame by dragging its mode or header line? > (set-face-background 'internal-border "blue" my-child-frame) > > makes me think the child frame should have a blue border, but it > doesn’t. Is that a bug? It doesn't get the border on Windows right away either. IMHO the face remapping code is not up to this everywhere, it might even work with GTK only. Try to set the 'internal-border' face via defcustom and tell me whether it works. Thanks, martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-06-25 15:58 ` martin rudalics @ 2017-07-15 21:27 ` Alan Third 2017-07-16 8:28 ` martin rudalics 0 siblings, 1 reply; 85+ messages in thread From: Alan Third @ 2017-07-15 21:27 UTC (permalink / raw) To: martin rudalics Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren On Sun, Jun 25, 2017 at 05:58:49PM +0200, martin rudalics wrote: > > It appears that making the child frame invisible ‘disconnects’ it from > > the parent frame, so the next time it’s made visible it no longer > > moves with the parent. I guess I’ll have to make sure that when a > > frame is made visible it’s reconnected with it’s parent. Or find a way > > to prevent it disconnecting. It seems a really odd thing for it to do. I’ve pushed a fix for this now. > > Resizing the child frame with the mouse doesn’t work, is it supposed > > to? > > Definitely. Do you see an internal border? Do you see a changing > cursor at that border when the mouse is over it? And can you move the > frame by dragging its mode or header line? It turned out that there was no NS version of mouse-absolute-pixel-position, so I’ve created one and suddenly all of the above things work. :) I’m slightly worried that there may be issues if the frame is resized across a screen edge, as it treats each screen as it’s own ‘space’, starting at (0, 0) at the top left. This is how the existing set-mouse-absolute-pixel-position works so it makes sense to me to keep them the same. It might make more sense to treat multiple screens as one ‘space’, though. I’m not sure. -- Alan Third ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-07-15 21:27 ` Alan Third @ 2017-07-16 8:28 ` martin rudalics 0 siblings, 0 replies; 85+ messages in thread From: martin rudalics @ 2017-07-16 8:28 UTC (permalink / raw) To: Alan Third Cc: Arthur Miller, 25408, Clément Pit--Claudel, Anders Lindgren >>> It appears that making the child frame invisible ‘disconnects’ it from >>> the parent frame, so the next time it’s made visible it no longer >>> moves with the parent. I guess I’ll have to make sure that when a >>> frame is made visible it’s reconnected with it’s parent. Or find a way >>> to prevent it disconnecting. It seems a really odd thing for it to do. > > I’ve pushed a fix for this now. Thanks. One of the largely untested behaviors with frames is what a frame looks like when it was invisible/iconified for a while, in that period operations (resizing, moving, reparenting) have been applied to it and the frame is made normally visible again. I've been struggling a while with the similar problem how to set a frame's size when it was fullscreen for a while and in that period a resize request was posted for it. > It turned out that there was no NS version of > mouse-absolute-pixel-position, so I’ve created one and suddenly all of > the above things work. :) Fine. Please add a (declare-function ns-mouse-absolute-pixel-position "nsfns.c") to frame.el. > I’m slightly worried that there may be issues if the frame is resized > across a screen edge, as it treats each screen as it’s own ‘space’, > starting at (0, 0) at the top left. This is how the existing > set-mouse-absolute-pixel-position works so it makes sense to me to > keep them the same. > > It might make more sense to treat multiple screens as one ‘space’, > though. I’m not sure. Can you give me an example? I never use multiple screens so my ability to imagine how a mouse behaves there is very limited. There's also the problem that some systems (Windows, IIRC) consider (0, 0) the top-left corner of some sort of "primary" screen and allow negative coordinates while others consider (0, 0) an abstract location at the top-left corner of all screens. Thanks, martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-17 14:56 ` bug#25408: Remove Decorations Around Emacs Frame (NS port) Alan Third 2017-04-17 15:43 ` martin rudalics @ 2017-04-19 11:24 ` Anders Lindgren 2017-04-19 12:50 ` martin rudalics 2017-04-19 13:51 ` Alan Third 1 sibling, 2 replies; 85+ messages in thread From: Anders Lindgren @ 2017-04-19 11:24 UTC (permalink / raw) To: Alan Third; +Cc: 25408, Clément Pit--Claudel, Arthur Miller [-- Attachment #1: Type: text/plain, Size: 1506 bytes --] Hi! > Anders, I hope it’s OK CCing you in. I think you might appreciate the > following (after applying the patch): > I really appreciate that you are keeping me in the loop! emacs -Q > > (set-frame-parameter nil 'undecorated t) > (setq ns-auto-hide-menu-bar t) > (toggle-frame-maximized) > This looks very promising! It's a cleaner solution than the one I use today -- placing the title bar above the top of the screen. The only issue I've came across was when the bottom edge of a frame was close to the bottom of the display (or when maximized). When `undocorated' goes from t to nil, the window shrinks. When positioned in the middle of the screen, it looks like the frame, for a fraction of a second, increases its size before returning to it's original shape. My guess is that, when at the bottom of the screen, the frame gets truncated when the frame is temporarily increased, and when it tries to return to it's original size, it shrinks. I made an attempt at adapting/modernizing my "multicolumn" ( https://github.com/Lindydancer/multicolumn) package (which, among else, can resize and reposition a frame). Currently, I have hardcoded the title size for various systems -- on macOS I use "24". However, `frame-geometry' says that the title height is 22 pixels. I'm not sure how to account for the missing 2 pixels, any thoughts? Martin, I also notices that `menu-bar-external' says `nil', but I guess is should say non-nil, right? -- Anders [-- Attachment #2: Type: text/html, Size: 2159 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-19 11:24 ` Anders Lindgren @ 2017-04-19 12:50 ` martin rudalics 2017-04-19 13:51 ` Alan Third 1 sibling, 0 replies; 85+ messages in thread From: martin rudalics @ 2017-04-19 12:50 UTC (permalink / raw) To: Anders Lindgren, Alan Third Cc: Arthur Miller, 25408, Clément Pit--Claudel > I made an attempt at adapting/modernizing my "multicolumn" ( > https://github.com/Lindydancer/multicolumn) package (which, among else, can > resize and reposition a frame). Currently, I have hardcoded the title size > for various systems -- on macOS I use "24". However, `frame-geometry' says > that the title height is 22 pixels. I'm not sure how to account for the > missing 2 pixels, any thoughts? The value returned by ‘frame-geometry’ should be correct. Look at all the occurrences of FRAME_NS_TITLEBAR_HEIGHT in nsterm.m. In contrast with other platforms, NS uses that value internally all the time. > Martin, I also notices that `menu-bar-external' says `nil', but I guess is > should say non-nil, right? Right. It should say non-nil. If possible, however, please check the function ‘ns-frame-edges’ for all values of TYPE whether it handles the menu bar height correctly, i.e., ignores it. Thanks, martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (NS port) 2017-04-19 11:24 ` Anders Lindgren 2017-04-19 12:50 ` martin rudalics @ 2017-04-19 13:51 ` Alan Third 1 sibling, 0 replies; 85+ messages in thread From: Alan Third @ 2017-04-19 13:51 UTC (permalink / raw) To: Anders Lindgren; +Cc: 25408, Clément Pit--Claudel, Arthur Miller On Wed, Apr 19, 2017 at 01:24:00PM +0200, Anders Lindgren wrote: > The only issue I've came across was when the bottom edge of a frame was > close to the bottom of the display (or when maximized). When `undocorated' > goes from t to nil, the window shrinks. When positioned in the middle of > the screen, it looks like the frame, for a fraction of a second, increases > its size before returning to it's original shape. My guess is that, when at > the bottom of the screen, the frame gets truncated when the frame is > temporarily increased, and when it tries to return to it's original size, > it shrinks. It appears this was being caused by the recreation of the toolbar when switching from undecorated to decorated. The toolbar was being added to the window, then made invisible, but I guess not before the new toolbar animation kicked in. I’ve swapped the two lines around and it seems much smoother now. > I made an attempt at adapting/modernizing my "multicolumn" ( > https://github.com/Lindydancer/multicolumn) package (which, among else, can > resize and reposition a frame). Currently, I have hardcoded the title size > for various systems -- on macOS I use "24". However, `frame-geometry' says > that the title height is 22 pixels. I'm not sure how to account for the > missing 2 pixels, any thoughts? I’m sure that 22 pixels is correct. I notice that internal-border-width defaults to two pixels, could that explain it? I’ve got an updated patch, but I’ll reply to Martin’s email and attach it there. -- Alan Third ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-11 7:08 ` Arthur Miller 2017-01-11 7:24 ` Arthur Miller @ 2017-01-11 8:38 ` martin rudalics 2017-01-11 16:39 ` Richard Stallman 2 siblings, 0 replies; 85+ messages in thread From: martin rudalics @ 2017-01-11 8:38 UTC (permalink / raw) To: Arthur Miller, Clément Pit--Claudel; +Cc: 25408 > added an > INLINE void fset_undecorated( ... ) to frame.h (not sure if it is > needed It's only needed for Lisp_Object components. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-11 7:08 ` Arthur Miller 2017-01-11 7:24 ` Arthur Miller 2017-01-11 8:38 ` bug#25408: Remove Decorations Around Emacs Frame (Windows OS) martin rudalics @ 2017-01-11 16:39 ` Richard Stallman 2 siblings, 0 replies; 85+ messages in thread From: Richard Stallman @ 2017-01-11 16:39 UTC (permalink / raw) To: Arthur Miller; +Cc: 25408, clement.pit [[[ To any NSA and FBI agents reading my email: please consider ]]] [[[ whether defending the US Constitution against all enemies, ]]] [[[ foreign or domestic, requires you to follow Snowden's example. ]]] > I do run Arch Linux otherwise, but I do some consulting with programming > databases and GUIs in access & spss and I also play some games > occasionally, so I still need losedows. 1. If I were you, I would stop doing those jobs and stop running those games, for my freedom's sake. Not only is Losedows proprietary, but also Access, SPSS and those games. Each one of them does injustice to whoever runs it. See https://gnu.org/philosophy/free-software-even-more-important.html. 2. The name "Arch Linux" is a misnomer. It is a variant of the GNU/Linux system, so in fairness it should be called "Arch GNU/Linux". We can't make them fix that mistake, but we can choose to not to repeat it -- so let's call it "Arch GNU/Linux". 3. That distro is not entirely free software. See https://gnu.org/distros. 4. Thanks for helping development of GNU Emacs. -- Dr Richard Stallman President, Free Software Foundation (gnu.org, fsf.org) Internet Hall-of-Famer (internethalloffame.org) Skype: No way! See stallman.org/skype.html. ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-09 22:20 bug#25408: Remove Decorations Around Emacs Frame (Windows OS) Arthur Miller 2017-01-10 8:23 ` martin rudalics @ 2017-01-10 19:36 ` Richard Stallman 2017-01-11 13:50 ` bug#25408: SV: " arthur.miller.no1 2017-01-11 14:59 ` arthur.miller.no1 3 siblings, 0 replies; 85+ messages in thread From: Richard Stallman @ 2017-01-10 19:36 UTC (permalink / raw) To: Arthur Miller; +Cc: 25408 [[[ To any NSA and FBI agents reading my email: please consider ]]] [[[ whether defending the US Constitution against all enemies, ]]] [[[ foreign or domestic, requires you to follow Snowden's example. ]]] > I would like to be able to run Emacs without frame decorations on Win > OS. We call it "Losedows" or "Lose OS", because if you use it, you lose your freedom. We're glad if Emacs gives you a taste of freedom, but a taste is all it can give you. To escape from Microsoft's power, you need to stop using Losedows. Here's what Microsoft does with its unjust power: http://gnu.org/proprietary/malware-microsoft.html. Here's explaining what gives Microsoft that unjust power: http://gnu.org/philosophy/free-software-even-more-important.html. -- Dr Richard Stallman President, Free Software Foundation (gnu.org, fsf.org) Internet Hall-of-Famer (internethalloffame.org) Skype: No way! See stallman.org/skype.html. ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: SV: Re: bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-09 22:20 bug#25408: Remove Decorations Around Emacs Frame (Windows OS) Arthur Miller 2017-01-10 8:23 ` martin rudalics 2017-01-10 19:36 ` Richard Stallman @ 2017-01-11 13:50 ` arthur.miller.no1 2017-01-11 13:57 ` martin rudalics 2017-01-11 14:59 ` arthur.miller.no1 3 siblings, 1 reply; 85+ messages in thread From: arthur.miller.no1 @ 2017-01-11 13:50 UTC (permalink / raw) To: martin rudalics, Clément Pit--Claudel; +Cc: 25408 [-- Attachment #1: Type: text/plain, Size: 1394 bytes --] By fthe way, if you want me I can send patch with my changes, but I guess Martin will provide better working code than I, and I have slightly different opinion about borders (I don't care abiut them at all). Skickat från min Samsung-enhet -------- Originalmeddelande -------- Från: martin rudalics <rudalics@gmx.at> Datum: 2017-01-11 09:39 (GMT+01:00) Till: Arthur Miller <arthur.miller.no1@gmail.com>, Clément Pit--Claudel <clement.pit@gmail.com> Kopia: Eli Zaretskii <eliz@gnu.org>, 25408@debbugs.gnu.org Rubrik: Re: bug#25408: Remove Decorations Around Emacs Frame (Windows OS) > There is a slightly cosmetic issue with above function. When one switches > back on decorations, > the frame will not resize properly and minibuffer will be not visible. It's > there but just > covered by frame. Just resizing emacs framefixes it. > > Adding call to PostMessage(hwnd, WM_SIZE,0,0) in Martins function fixes it. This is not necessary here. And it would be strange since the idea is that the outer frame size remains unchanged. Hence, any problem would manifest itself already when you remove the borders by leaving parts of the display area reserved for the frame not redrawn. The image you posted in the message you sent just now seems to confirm that. But I'm testing this on Windows XP and have not yet pulled the recent multi-thread Emacs changes. martin [-- Attachment #2: Type: text/html, Size: 1790 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: SV: Re: bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-11 13:50 ` bug#25408: SV: " arthur.miller.no1 @ 2017-01-11 13:57 ` martin rudalics 0 siblings, 0 replies; 85+ messages in thread From: martin rudalics @ 2017-01-11 13:57 UTC (permalink / raw) To: arthur.miller.no1, Clément Pit--Claudel; +Cc: 25408 > By fthe way, if you want me I can send patch with my changes, but I > guess Martin will provide better working code than I, and I have > slightly different opinion about borders (I don't care abiut them at > all). To not get a border, set the frame parameter `border-width' to zero. martin ^ permalink raw reply [flat|nested] 85+ messages in thread
* bug#25408: SV: Re: bug#25408: Remove Decorations Around Emacs Frame (Windows OS) 2017-01-09 22:20 bug#25408: Remove Decorations Around Emacs Frame (Windows OS) Arthur Miller ` (2 preceding siblings ...) 2017-01-11 13:50 ` bug#25408: SV: " arthur.miller.no1 @ 2017-01-11 14:59 ` arthur.miller.no1 3 siblings, 0 replies; 85+ messages in thread From: arthur.miller.no1 @ 2017-01-11 14:59 UTC (permalink / raw) To: martin rudalics; +Cc: 25408, Clément Pit--Claudel [-- Attachment #1: Type: text/plain, Size: 3521 bytes --] Aha thanks for clarifications. I didn't dive enough into src so I missed those other funcrions called before a frame is made. I had from beginnig nil and t as values for my decor var, but I realized I could use 1 and 0 too so I did :). It works fine to switch it off/on manually. I am away from home untill friday so it will have to wait before I can play more with emacs. Also if you going to merge your code into master on git soon, then I will probably abandon my changes and use yours :). Skickat från min Samsung-enhet -------- Originalmeddelande -------- Från: martin rudalics <rudalics@gmx.at> Datum: 2017-01-11 14:55 (GMT+01:00) Till: Arthur Miller <arthur.miller.no1@gmail.com> Kopia: Clément Pit--Claudel <clement.pit@gmail.com>, Eli Zaretskii <eliz@gnu.org>, 25408@debbugs.gnu.org Rubrik: Re: bug#25408: Remove Decorations Around Emacs Frame (Windows OS) > (add-to-list 'default-frame-alist '(undecorated . 0)) > (setq default-frame-alist '((undecorated . 0))) > (setq initial-frame-alist '((undecorated . 0))) > > But that does not give any effect at all. "0" is a quite misleading value ;-) See below. But I think I understand what happens. In fact, I haven't told you the whole story: In Fx_create_frame I do additionally 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); somewhere _before_ w32_window (f, window_prompting, minibuffer_only) gets called. And in w32_createwindow I have else if (FRAME_UNDECORATED (f)) { f->output_data.w32->dwStyle = ~WS_THICKFRAME & ~WS_CAPTION; /* 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; } before any other f->output_data.w32->dwStyle assignment and certainly before the FRAME_W32_WINDOW (f) = hwnd = CreateWindow (EMACS_CLASS, f->namebuf, f->output_data.w32->dwStyle, ... call. Just make sure that any time you set f->output_data.w32->dwStyle you don't overrule a previous assignment. (I haven't sent you a patch because I have completely redesigned the assignments to this component and it probably would distract more than provide any help.) This way (add-to-list 'default-frame-alist '(undecorated . t)) (setq default-frame-alist '((undecorated . t))) (setq initial-frame-alist '((undecorated . t))) should all work. BTW, you can also do f->output_data.w32->dwStyle = WS_POPUP; because the only thing Windows forbids in this context is to set WS_POPUP for an existing overlapped window (IIRC). > (defvar decor 0) > (defun toggle-frame-decor () > (interactive) > (progn > (modify-frame-parameters (selected-frame) `((undecorated . ,'decor))) You likely mean (modify-frame-parameters (selected-frame) `((undecorated . ,decor))) here. And probably you want to do the following calculation > (if (= decor 0) > (setq decor 1) > (setq decor 0)))) before calling ‘modify-frame-parameters’ so the latter will see the new value. But even this won't work because you want to toggle beween nil and non-nil so (devfar decor nil) and (setq decor (not decor)) are more appropriate. martin [-- Attachment #2: Type: text/html, Size: 4623 bytes --] ^ permalink raw reply [flat|nested] 85+ messages in thread
end of thread, other threads:[~2017-07-16 8:28 UTC | newest] Thread overview: 85+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-01-09 22:20 bug#25408: Remove Decorations Around Emacs Frame (Windows OS) Arthur Miller 2017-01-10 8:23 ` martin rudalics 2017-01-10 17:07 ` Eli Zaretskii 2017-01-10 18:07 ` martin rudalics 2017-01-10 18:27 ` Eli Zaretskii 2017-01-10 20:39 ` Clément Pit--Claudel 2017-01-11 7:08 ` Arthur Miller 2017-01-11 7:24 ` Arthur Miller 2017-01-11 7:48 ` Arthur Miller 2017-01-11 7:50 ` Arthur Miller 2017-01-11 8:15 ` Arthur Miller 2017-01-11 8:39 ` martin rudalics 2017-01-11 9:17 ` Arthur Miller 2017-01-11 10:20 ` Arthur Miller 2017-01-11 13:55 ` martin rudalics 2017-02-07 5:28 ` Clément Pit--Claudel 2017-02-07 6:53 ` martin rudalics 2017-02-07 13:05 ` Clément Pit--Claudel 2017-02-11 14:27 ` martin rudalics 2017-02-11 21:02 ` Clément Pit--Claudel 2017-02-11 21:10 ` Clément Pit--Claudel 2017-02-12 11:13 ` martin rudalics 2017-02-15 19:49 ` Arthur Miller 2017-02-16 8:04 ` martin rudalics 2017-02-16 13:22 ` Arthur Miller 2017-02-16 14:06 ` Arthur Miller 2017-02-17 7:03 ` martin rudalics 2017-02-17 7:03 ` martin rudalics 2017-04-12 9:27 ` martin rudalics 2017-05-06 0:06 ` Clément Pit-Claudel 2017-05-06 7:13 ` Eli Zaretskii 2017-05-06 13:26 ` Clément Pit-Claudel 2017-05-06 7:40 ` martin rudalics 2017-05-06 9:41 ` martin rudalics 2017-05-06 13:28 ` Clément Pit-Claudel 2017-05-06 14:20 ` Eli Zaretskii 2017-05-06 21:01 ` Clément Pit-Claudel 2017-05-07 2:30 ` Eli Zaretskii 2017-05-07 8:41 ` martin rudalics 2017-05-07 8:40 ` martin rudalics 2017-05-07 17:19 ` Eli Zaretskii 2017-05-07 18:07 ` martin rudalics 2017-05-07 18:33 ` Eli Zaretskii 2017-05-08 6:48 ` martin rudalics 2017-05-08 14:41 ` Eli Zaretskii 2017-06-25 11:02 ` martin rudalics 2017-06-25 16:23 ` Clément Pit-Claudel 2017-04-12 17:38 ` Alan Third 2017-04-12 19:13 ` martin rudalics 2017-04-12 19:51 ` Alan Third 2017-04-13 7:10 ` martin rudalics 2017-04-13 10:30 ` Alan Third 2017-04-13 11:56 ` martin rudalics 2017-04-15 16:29 ` Alan Third 2017-04-15 19:39 ` martin rudalics 2017-04-17 14:56 ` bug#25408: Remove Decorations Around Emacs Frame (NS port) Alan Third 2017-04-17 15:43 ` martin rudalics 2017-04-17 16:21 ` Alan Third 2017-04-17 17:20 ` martin rudalics 2017-04-17 18:55 ` Alan Third 2017-04-19 7:26 ` martin rudalics 2017-04-19 14:33 ` Alan Third 2017-04-19 16:01 ` martin rudalics 2017-04-19 17:04 ` Alan Third 2017-04-19 18:07 ` martin rudalics 2017-06-10 15:38 ` Alan Third 2017-06-11 8:10 ` martin rudalics 2017-06-11 16:35 ` Alan Third 2017-06-12 6:09 ` martin rudalics 2017-06-12 17:59 ` Alan Third 2017-06-13 7:24 ` martin rudalics 2017-06-22 9:10 ` martin rudalics 2017-06-25 14:22 ` Alan Third 2017-06-25 15:58 ` martin rudalics 2017-07-15 21:27 ` Alan Third 2017-07-16 8:28 ` martin rudalics 2017-04-19 11:24 ` Anders Lindgren 2017-04-19 12:50 ` martin rudalics 2017-04-19 13:51 ` Alan Third 2017-01-11 8:38 ` bug#25408: Remove Decorations Around Emacs Frame (Windows OS) martin rudalics 2017-01-11 16:39 ` Richard Stallman 2017-01-10 19:36 ` Richard Stallman 2017-01-11 13:50 ` bug#25408: SV: " arthur.miller.no1 2017-01-11 13:57 ` martin rudalics 2017-01-11 14:59 ` arthur.miller.no1
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.