Within emacs, how do I reference the physical screens? - emacs

I have a multi-screen display. Within emacs (GNU Emacs 24.2.1 (i386-mingw-nt6.1.7601) on Windows 7), how can I determine the number of physical screens, and cause things to happen on different screens? For example, I might want to open a new frame in a different screen, or I might want to move the frame in which Emacs is starting to another screen.

I'm not sure if these functions work on Windows, but on Linux and Mac OS X you can use:
x-display-screens: Number of monitors
x-display-pixel-width: Current screen (screen that contains Emacs windows) width
x-display-pixel-height: Current screen height
set-frame-width and set-frame-height: resize
set-frame-position: Move frame
For example if you want to create a new frame in another screen, you can do:
(when (and (display-graphic-p) (= (display-screens) 2))
(make-frame)
(set-frame-position (selected-frame) 1280 0))
Where 1280 is the width of your first screen.

Checkout pos-tip.el code (http://www.emacswiki.org/emacs/pos-tip.el)
It says it works in X and Windows so probably you could find some compatible layer in it.

Related

Resizing EchoArea of Emacsclient

I am facing a strange problem. After I change the KDE window rules for emacs according to http://www.emacswiki.org/emacs/KdeMaximized, that is, I created a special window setting:
the size of echoarea (the area shared with minibuffer) is doubled by default whenever the font size is larger than 115 (1/10 pt):
,
while normally it should be like this:
Moreover, this only occurs when emacsclient is maximized and without menubar (it is fine when fullscreened or not maximized or with menubar). Maybe it is just a problem with KDE? But I couldn't find other way to fully maximize KDE without creating special window settings.
Surely a workaround is to set font size to be at most 115, but that looks too small on my 13.3 ultrabook and I usually set it to 125.
So I am just wondering if there is a way to resize the EchoArea (or change the font size of EchoArea.) by emacs settings? I tried adjusting the font size of the minibuffer, but it does not work since only the minibuffer font is changed while the Echoarea is not affected.
I am using emacs 24.3.
Thanks!
Explanation
Emacs cannot fully use arbitrary screen sizes because it (for the most part) displays a grid of characters.
As a simple example, consider characters that are each 10 by 10 pixels, and screen real estate of 1024 by 768. You'll have four pixels of width and eight pixels of height that cannot be used by Emacs.
The article you linked to is about forcing Emacs into a particular screen size. From the page:
Once you try to maximize the window, emacs resizes itself to a slightly smaller portion of the screen. This is because emacs rejects the geometry given to it by KWin, because it’s not an integral multiple of the width/height of one character.
When you tell KDE to force a particular size, the Emacs frame ("window" in non-Emacs terminology) will be the size you want, but the windows inside it ("splits" in non-Emacs terminology) may not fit properly. This usually leads to "wasted space" at the bottom of the screen like you are seeing.
As you noticed, changing your font size can give different results. If your character width is 8 pixels, for instance, you won't have any wasted horizontal space since 1024 divides by 8 evenly (128 times).
Similarly, going fullscreen and enabling the menubar both alter the amount of vertical space that Emacs has available for its windows.
Workaround
One workaround might be to adjust the size of your KDE taskbar. I believe it can be adjusted with single pixel granularity. If you adjust it smaller by a few pixels one at a time you should find a small adjustment that will make Emacs use its space more efficiently.
A you suggested, you might try to alter the font size of the minibuffer:
(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup)
(defun my-minibuffer-setup ()
(set (make-local-variable 'face-remapping-alist)
'((default :height 0.9))))
(via Altering the font size for the Emacs minibuffer separately from default emacs?)
This will make the font size just a bit smaller. Try playing with the height and see if it can resolve the issue...

Setting Both `fullheight` and `width` in Emacs on OS X

I find the default size of the Emacs frame a little too small. From reading around I know that I can set the height and width quite easily with something like the following:
;;; 140 x 60 window size
(setq default-frame-alist '((width . 140) (height . 60)))
Which works great on my external monitor, however it is a litte too big for the laptop display. I can solve the height problem by changing to the follwing:
;;; automatically set the height
(setq default-frame-alist '((fullscreen . fullheight)))
Which sets the frame to be as tall as possible for the current screen. I can't however set the width of the frame if I use this method. Adding (width . 140) to the above alist sets the width to the right value but also sets the height to the default height again.
When I see the frame appear it sets itself to the full height, and then sets the width to the value I requested, and shrinks in height.
I can overcome this problem with the following code:
;;; Full height for the default window
(setq default-frame-alist
'((fullscreen . fullheight)))
;; Set the width in a hook and have all windows inherit
(setq frame-inherited-parameters
'(width height))
(add-hook 'after-init-hook
(lambda ()
(set-frame-parameter nil 'width 140)))
Which uses a hook to set the width of the first frame to the value I want, and then sets all other windows to inherit this value.
This isn't very elegant however, so the question is "how can I accomplish this in a simpler (or less hackish) way?".
If you want to see my exact init.el script, take a look at this gist
TL;DR
How can I set both the width of a frame, and set the frame to be as tall as possible on the current monitor, on OS X? It seems you can't specify (width . 140) and (fullscreen . fullheight) in the default-frame-alist.
I have come up with a solution to this. I explicitly calculate the height of the window rather than relying on (fullscreen . fullheight) to do it for me.
The updated code to set the values for the height and width is quite simple:
;;; Nice size for the default window
(defun get-default-height ()
(/ (- (display-pixel-height) 120)
(frame-char-height)))
(add-to-list 'default-frame-alist '(width . 140))
(add-to-list 'default-frame-alist (cons 'height (get-default-height)))
In this code the subtraction of 120 from the height of the screen makes sure that the height of the window takes into account the height of the dock and the menubar. For correct results you will have to make sure that this code is executed after you have chosen the font face to use, otherwise the computed height value will not be valid.
Placing the height calculation in its own function should allow special casing certain operating systems and versions. This method also has the added advantage that is faster to open the window as it doesn't "animate" the height to the full height value.
The last paragraph of the help text for display-pixel-height is:
For graphical terminals, note that on "multi-monitor" setups this
refers to the pixel height for all physical monitors associated
with DISPLAY. To get information for each physical monitor, use
‘display-monitor-attributes-list’.
What got me to this page is what looks like a bug in the X11 implementation but I'm not sure yet. In any case, display-pixel-height works only often but not always.
Sample output from display-monitor-attributes-list is:
(
(
(geometry 0 0 1920 1080)
(workarea 0 25 1920 1055)
(mm-size 478 268)
(frames #<frame *scratch* 0x14489a030>)
(source . "NS")
)
(
(geometry 192 1080 1512 982)
(workarea 192 1080 1512 950)
(mm-size 301 195)
(frames)
(source . "NS")
)
)
In my case, I have a laptop (bottom entry) and a monitor connected to it (the top entry).
One possible solution would be to go through the list, find the monitor with the largest height and do the computations based upon that height and then at the end also do something like (set-frame-position nil 192 1080) where the two coordinates come from the top and left coordinates (the first two values of geometry and work area of the monitor that has the greatest height.
It appears that the workarea is the more prudent set of values to use.
And to further make a robust solution, a hook should be added to window-configuration-change-hook so that when a monitor is added or removed, things will get updated.
I am currently asking some questions on the Emacs developers mailing list and working on a solution for myself. I plan to return and update this entry when I have a solution that I'm happy with but thought this information may be of use to others as is.
Update:
There is no bug. x-display-pixel-height has various X11 rude facts of life. For more details, see this reply.
The "Frame Layout" node in the info documentation for ELisp as a description of the Inner and Outer Frame along with many other concepts that are pertinent to this question.
Here is my current solution. I have not done the hook yet. I don't claim to know how to program in lisp but this code is working for me.
(defun workarea-height ( monitor )
"MONITOR is an entry from `display-monitor-attributes-list' The
height entry (4th value) of the 'workarea' is returned"
(nth 4 (assoc 'workarea monitor)))
(defun monitor-with-largest-height-helper ( a b )
"Compares the height of the workarea of two monitor entries such as
those contained in the output of `display-monitor-attributes-list'"
(let* ((a-height (workarea-height a))
(b-height (workarea-height b)))
(if (> a-height b-height)
a
b)))
(defun monitor-with-largest-height ()
"Returns the monitor entry from `display-monitor-attributes-list'
with the largest 'workarea' height"
(cl-reduce #'monitor-with-largest-height-helper
(display-monitor-attributes-list)))
(defun largest-monitor-height ()
"Returns the usable height in lines of the largest monitor currently
attached"
(let* ((largest-monitor (monitor-with-largest-height)))
(/ (- (workarea-height largest-monitor)
(- (frame-outer-height)
(frame-inner-height)))
(frame-char-height))))
(defun my-resize-frame-height ()
"Resizes the current frame to the full height of the largest monitor
currently attached."
(interactive)
(set-frame-height nil (largest-monitor-height)))
The other work left to do is to make sure the left and top of the frame are within the area of the largest monitor to the frame will be displayed on that monitor.

Emacs Scrolling Bug on OS X

Update
This problem disappeared after upgrading from Mountain Lion to Mavericks, while also updating Emacs from 23.4 to 24.3.
End-update
With a .emacs file containing
(set-foreground-color "white")
(set-background-color "black")
(setq mouse-wheel-scroll-amount '(1 ((shift) . 1) ((control) . nil)))
(setq mouse-wheel-progressive-speed nil)
as I scroll up or down with the reduced step, I see the strange patterns
Magnifying one of the patterns reveals
This problem has been present in Emacs 22, 23, and now 24 for several versions of OSX—up to and including Mountain Lion. Is it a known rendering bug? Is there a fix?
Neither the suggestion to modify fringes nor linum works for me. Where else can I look?
If I use the default white background and black foreground, these lines either do not appear or are imperceptible (to me).
What is most pesky about this problem is that redrawing (C-l) does not result in clean text.
The problem is related to the interaction between OS X's LCD Font Smoothing algorithm and the algorithm that emacs uses to implement scrolling.
The figure below shows font smoothing turned off (left) and on (right). You will find this setting in System Preferences \ general. In both cases I scrolled the program by one line. When OS X draws the "#" with font smoothing turned on, it does not only use the pixels dedicated to the "#" but also uses the blue pixels of the adjacent (blank) character.
When emacs scrolls, it only modifies the characters that it believes need to be modified. If the character is blank and will remain blank after scrolling, it does not modify it. This optimization remains valid in 2013. In other words, testing that two characters are blank is still cheaper than drawing one character. But this optimization is hardly necessary today, and it results in the buggy display.
If the hypothesis above holds, the sequel question becomes whether one can turn off the optimization. Is it possible to ask emacs to redraw the full screen at each scroll or to at least redraw characters that remain blank if they were adjacent to a non-blank character.
One could of course simply turn off font smoothing. The magnified image may even suggest that the non-smoothed image is better. In practice, when the fonts appear in their natural (unmagnified) size, smoothing makes the characters far more legible, eliminating the need to use larger fonts.
The pattern on either side of "c();" in the image below is consistent with the bug. OS X uses blue pixels on the left side and red/tan pixels on the right (possibly this is related to the RGB pattern on the display). The vertical lines left over when scrolling are either blue or red/tan/brick, depending on whether they have dropped out of the left or right side of scrolled characters.
Update
The problem is now solved in this nightly. The magnified c(); produced by Emacs 24.3.50.1 shows that the font smoothing remains identical to that produced by Emacs 24.3.1. But the output is not identical. There is at least one extra horizontal line of pixels between each two lines of text.

Get width of current monitor in Emacs Lisp

I have a two-monitor setup (running Ubuntu).
The Emacs Lisp function display-pixel-width gives me the combined width of the two monitors. How can I get the width of the current monitor (i.e., the monitor displaying the current frame)?
If you are using 24.3 or earlier:
display-pixel-width is a compiled Lisp function in `frame.el'.
(display-pixel-width &optional DISPLAY)
Return the width of DISPLAY's screen in pixels. For character
terminals, each character counts as a single pixel.
Additionally, if you are using 24.4 or later:
** Multi-monitor support has been added.
*** New functions display-monitor-attributes-list and frame-monitor-attributes
can be used to obtain information about
each physical monitor on multi-monitor setups.
Use an external process
You can also parse the output of xwininfo or xrandr (use call-process).
Maximize emacs
Finally, you can maximize emacs (either interactively or using modify-frame-parameters; version 24.4 also has toggle-frame-fullscreen and toggle-frame-maximized) and query its frame size using frame-pixel-height and frame-pixel-width.
See also
How do I find the display size of my system in Emacs?
Can I detect the display size/resolution in Emacs?
display-pixel-width takes an argument to let you specify the display. From its documentation (C-h f display-pixel-width RET):
(display-pixel-width &optional DISPLAY)
Return the width of DISPLAY's screen in pixels. For character
terminals, each character counts as a single pixel.
There's also the similar x-display-pixel-width, which may work if the above doesn't.

Maximizing an Emacs frame to just one monitor with elisp

I use maxframe.el to maximize my Emacs frames.
It works great on all three major platforms, except on my dual-head Mac setup (Macbook Pro 15-inch laptop with 23-inch monitor).
When maximizing an Emacs frame, the frame expands to fill the width of both monitors and the height of the larger monitor.
Obviously, I would like the frame to maximize to fill only the monitor it's on. How can I detect the resolutions of the two individual monitors using elisp?
Thanks,
Jacob
EDIT: As Denis points out, setting mf-max-width is a reasonable workaround. But (as I should have mentioned) I was hoping for a solution that works on both monitors and with any resolution. Maybe something OSX-specific in the style of the Windows-specific w32-send-sys-command.
I quickly scanned the reference that you provided to maxframe.el and I don't think that you're using the same technique that I use. Does the following code snippet help you?
(defun toggle-fullscreen ()
"toggles whether the currently selected frame consumes the entire display or is decorated with a window border"
(interactive)
(let ((f (selected-frame)))
(modify-frame-parameters f `((fullscreen . ,(if (eq nil (frame-parameter f 'fullscreen)) 'fullboth nil))))))
Does customising `mf-max-width' work? Its documentation:
"*The maximum display width to support. This helps better support the true
nature of display-pixel-width. Since multiple monitors will result in a
very large display pixel width, this value is used to set the stop point for
maximizing the frame. This could also be used to set a fixed frame size
without going over the display dimensions."
This sort of thing is the job of your window manager, not the job of emacs. (For example, Xmonad handles full-screen emacs just fine.)