Commit 4465bfb4 authored by Jan Djärv's avatar Jan Djärv

Implement display-monitor-attributes-list for NS.

* lisp/frame.el (display-monitor-attributes-list): Add NS case.
(ns-display-monitor-attributes-list): Declare.

* src/nsfns.m: Include IOGraphicsLib.h if Cocoa.
(Qgeometry, Qworkarea, Qmm_size, Qframes, Qsource): Declare.
(MonitorInfo): New struct.
(free_monitors, ns_screen_name, ns_make_monitor_attribute_list)
(Fns_display_monitor_attributes_list): New functions.
(display-usable-bounds): Remove.
(syms_of_nsfns): DEFSYM Qgeometry, Qworkarea, Qmm_size, Qframes and
parent 7583e2a0
......@@ -4247,6 +4247,9 @@ case "$opsys" in
## each); under Cocoa 31 commands are required.
if test "$HAVE_NS" = "yes"; then
libs_nsgui="-framework AppKit"
if test "$NS_IMPL_COCOA" = "yes"; then
libs_nsgui="$libs_nsgui -framework IOKit"
2013-05-09 Jan Djärv <>
* frame.el (display-monitor-attributes-list): Add NS case.
(ns-display-monitor-attributes-list): Declare.
2013-05-09 Ulrich Mueller <>
* descr-text.el (describe-char): Fix %d/%x typo. (Bug#14360)
......@@ -1495,6 +1495,8 @@ The value is one of the symbols `static-gray', `gray-scale',
(declare-function x-display-monitor-attributes-list "xfns.c"
(&optional terminal))
(declare-function ns-display-monitor-attributes-list "nsfns.c"
(&optional terminal))
(defun display-monitor-attributes-list (&optional display)
"Return a list of physical monitor attributes on DISPLAY.
......@@ -1528,6 +1530,8 @@ monitors."
((eq frame-type 'x)
(x-display-monitor-attributes-list display))
((eq frame-type 'ns)
(ns-display-monitor-attributes-list display))
(let ((geometry (list 0 0 (display-pixel-width display)
(display-pixel-height display))))
2013-05-09 Jan Djärv <>
* nsfns.m: Include IOGraphicsLib.h if Cocoa.
(Qgeometry, Qworkarea, Qmm_size, Qframes, Qsource): Declare.
(MonitorInfo): New struct.
(free_monitors, ns_screen_name, ns_make_monitor_attribute_list)
(Fns_display_monitor_attributes_list): New functions.
(display-usable-bounds): Remove.
(syms_of_nsfns): DEFSYM Qgeometry, Qworkarea, Qmm_size, Qframes and
2013-05-09 Paul Eggert <>
* xterm.h (GTK_PREREQ): Remove, replacing with GTK_CHECK_VERSION.
......@@ -44,6 +44,10 @@ Updated by Christian Limpach (
#include "fontset.h"
#include "font.h"
#include <IOKit/graphics/IOGraphicsLib.h>
#if 0
int fns_trace_num = 1;
#define NSTRACE(x) fprintf (stderr, "%s:%d: [%d] " #x "\n", \
......@@ -101,6 +105,8 @@ Updated by Christian Limpach (
static ptrdiff_t image_cache_refcount;
static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes, Qsource;
/* ==========================================================================
Internal utility functions
......@@ -2321,35 +2327,221 @@ and GNUstep implementations ("distributor-specific release
return make_number ((int) [ns_get_screen (display) frame].size.height);
struct MonitorInfo {
XRectangle geom, work;
int mm_width, mm_height;
char *name;
static void
free_monitors (struct MonitorInfo *monitors, int n_monitors)
int i;
for (i = 0; i < n_monitors; ++i)
xfree (monitors[i].name);
xfree (monitors);
/* Returns the name for the screen that DICT came from, or NULL.
Caller must free return value.
DEFUN ("display-usable-bounds", Fns_display_usable_bounds,
Sns_display_usable_bounds, 0, 1, 0,
doc: /* Return the bounds of the usable part of the screen.
The return value is a list of integers (LEFT TOP WIDTH HEIGHT), which
are the boundaries of the usable part of the screen, excluding areas
reserved for the Mac menu, dock, and so forth.
char *
ns_screen_name (CGDirectDisplayID did)
char *name = NULL;
NSDictionary *info = (NSDictionary *)
IODisplayCreateInfoDictionary (CGDisplayIOServicePort (did),
NSDictionary *names
= [info objectForKey:
[NSString stringWithUTF8String:kDisplayProductName]];
if ([names count] > 0) {
NSString *n = [names objectForKey: [[names allKeys] objectAtIndex:0]];
if (n != nil)
name = xstrdup ([n UTF8String]);
The screen queried corresponds to DISPLAY, which should be either a
frame, a display name (a string), or terminal ID. If omitted or nil,
that stands for the selected frame's display. */)
(Lisp_Object display)
[info release];
return name;
static Lisp_Object
ns_make_monitor_attribute_list (struct MonitorInfo *monitors,
int n_monitors,
int primary_monitor,
const char *source)
Lisp_Object monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
Lisp_Object frame, rest, attributes_list = Qnil;
Lisp_Object primary_monitor_attributes = Qnil;
NSArray *screens = [NSScreen screens];
int i;
FOR_EACH_FRAME (rest, frame)
struct frame *f = XFRAME (frame);
if (FRAME_NS_P (f))
NSView *view = FRAME_NS_VIEW (f);
NSScreen *screen = [[view window] screen];
NSUInteger k;
i = -1;
for (k = 0; i == -1 && k < [screens count]; ++k)
if ([screens objectAtIndex: k] == screen)
i = (int)k;
if (i > -1)
ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
for (i = 0; i < n_monitors; ++i)
Lisp_Object geometry, workarea, attributes = Qnil;
struct MonitorInfo *mi = &monitors[i];
if (mi->geom.width == 0) continue;
workarea = list4i (mi->work.x, mi->work.y,
mi->work.width, mi->work.height);
geometry = list4i (mi->geom.x, mi->geom.y,
mi->geom.width, mi->geom.height);
attributes = Fcons (Fcons (Qsource,
make_string (source, strlen (source))),
attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)),
attributes = Fcons (Fcons (Qmm_size,
list2i (mi->mm_width, mi->mm_height)),
attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
if (mi->name)
attributes = Fcons (Fcons (Qname, make_string (mi->name,
strlen (mi->name))),
if (i == primary_monitor)
primary_monitor_attributes = attributes;
attributes_list = Fcons (attributes, attributes_list);
if (!NILP (primary_monitor_attributes))
attributes_list = Fcons (primary_monitor_attributes, attributes_list);
return attributes_list;
DEFUN ("ns-display-monitor-attributes-list",
0, 1, 0,
doc: /* Return a list of physical monitor attributes on the X display TERMINAL.
The optional argument TERMINAL specifies which display to ask about.
TERMINAL should be a terminal object, a frame or a display name (a string).
If omitted or nil, that stands for the selected frame's display.
In addition to the standard attribute keys listed in
`display-monitor-attributes-list', the following keys are contained in
the attributes:
source -- String describing the source from which multi-monitor
information is obtained, \"NS\" is always the source."
Internal use only, use `display-monitor-attributes-list' instead. */)
(Lisp_Object terminal)
NSScreen *screen;
NSRect vScreen;
struct terminal *term = get_terminal (terminal, 1);
NSArray *screens;
NSUInteger i, n_monitors;
struct MonitorInfo *monitors;
Lisp_Object attributes_list = Qnil;
CGFloat primary_display_height = 0;
check_ns_display_info (display);
screen = ns_get_screen (display);
if (!screen)
if (term->type != output_ns)
return Qnil;
screens = [NSScreen screens];
n_monitors = [screens count];
if (n_monitors == 0)
return Qnil;
vScreen = [screen visibleFrame];
monitors = (struct MonitorInfo *) xzalloc (n_monitors * sizeof (*monitors));
for (i = 0; i < [screens count]; ++i)
NSScreen *s = [screens objectAtIndex:i];
struct MonitorInfo *m = &monitors[i];
NSRect fr = [s frame];
NSRect vfr = [s visibleFrame];
NSDictionary *dict = [s deviceDescription];
NSValue *resval = [dict valueForKey:NSDeviceResolution];
short y, vy;
NSNumber *nid = [dict objectForKey:@"NSScreenNumber"];
CGDirectDisplayID did = [nid unsignedIntValue];
if (i == 0)
primary_display_height = fr.size.height;
y = (short) fr.origin.y;
vy = (short) vfr.origin.y;
// Flip y coordinate as NS has y starting from the bottom.
y = (short) (primary_display_height - fr.size.height - fr.origin.y);
vy = (short) (primary_display_height -
vfr.size.height - vfr.origin.y);
m->geom.x = (short) fr.origin.x;
m->geom.y = y;
m->geom.width = (unsigned short) fr.size.width;
m->geom.height = (unsigned short) fr.size.height;
m->work.x = (short) vfr.origin.x;
// y is flipped on NS, so vy - y are pixels missing at the bottom,
// and fr.size.height - vfr.size.height are pixels missing in total.
// Pixels missing at top are
// fr.size.height - vfr.size.height - vy + y.
// work.y is then pixels missing at top + y.
m->work.y = (short) (fr.size.height - vfr.size.height) - vy + y + y;
m->work.width = (unsigned short) vfr.size.width;
m->work.height = (unsigned short) vfr.size.height;
m->name = ns_screen_name (did);
CGSize mms = CGDisplayScreenSize (did);
m->mm_width = (int) mms.width;
m->mm_height = (int) mms.height;
// Assume 92 dpi as x-display-mm-height/x-display-mm-width does.
m->mm_width = (int) (25.4 * fr.size.width / 92.0);
m->mm_height = (int) (25.4 * fr.size.height / 92.0);
// Primary monitor is always first for NS.
attributes_list = ns_make_monitor_attribute_list (monitors, n_monitors,
0, "NS");
/* NS coordinate system is upside-down.
Transform to screen-specific coordinates. */
return list4i (vScreen.origin.x,
[screen frame].size.height
- vScreen.size.height - vScreen.origin.y,
vScreen.size.width, vScreen.size.height);
free_monitors (monitors, n_monitors);
return attributes_list;
......@@ -2729,6 +2921,11 @@ - (NSString *)panel: (id)sender userEnteredFilename: (NSString *)filename
syms_of_nsfns (void)
DEFSYM (Qgeometry, "geometry");
DEFSYM (Qworkarea, "workarea");
DEFSYM (Qmm_size, "mm-size");
DEFSYM (Qframes, "frames");
DEFSYM (Qsource, "source");
Qfontsize = intern_c_string ("fontsize");
staticpro (&Qfontsize);
......@@ -2774,7 +2971,7 @@ - (NSString *)panel: (id)sender userEnteredFilename: (NSString *)filename
defsubr (&Sx_server_version);
defsubr (&Sx_display_pixel_width);
defsubr (&Sx_display_pixel_height);
defsubr (&Sns_display_usable_bounds);
defsubr (&Sns_display_monitor_attributes_list);
defsubr (&Sx_display_mm_width);
defsubr (&Sx_display_mm_height);
defsubr (&Sx_display_screens);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment