From 4465bfb465ffdecc9422bd2f3cd34440c7710dfa Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jan=20Dj=C3=A4rv?= Date: Thu, 9 May 2013 17:17:38 +0200 Subject: [PATCH] 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 Qsource. --- configure.ac | 3 + lisp/ChangeLog | 5 + lisp/frame.el | 4 + src/ChangeLog | 11 +++ src/nsfns.m | 243 ++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 243 insertions(+), 23 deletions(-) diff --git a/configure.ac b/configure.ac index fe70676f75..de3bf9d50d 100644 --- a/configure.ac +++ b/configure.ac @@ -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" + fi headerpad_extra=6C8 else libs_nsgui= diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 5bbfe1a6ff..3839375c6d 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,8 @@ +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) diff --git a/lisp/frame.el b/lisp/frame.el index 94a4842fc4..e1a55bdffc 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -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." (cond ((eq frame-type 'x) (x-display-monitor-attributes-list display)) + ((eq frame-type 'ns) + (ns-display-monitor-attributes-list display)) (t (let ((geometry (list 0 0 (display-pixel-width display) (display-pixel-height display)))) diff --git a/src/ChangeLog b/src/ChangeLog index e152d8de95..95b15a0f5a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,14 @@ +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 + Qsource. + 2013-05-09 Paul Eggert * xterm.h (GTK_PREREQ): Remove, replacing with GTK_CHECK_VERSION. diff --git a/src/nsfns.m b/src/nsfns.m index 95fdd516b9..497a856aa1 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -44,6 +44,10 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu) #include "fontset.h" #include "font.h" +#ifdef NS_IMPL_COCOA +#include +#endif + #if 0 int fns_trace_num = 1; #define NSTRACE(x) fprintf (stderr, "%s:%d: [%d] " #x "\n", \ @@ -101,6 +105,8 @@ static int as_status; static ptrdiff_t image_cache_refcount; #endif +static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes, Qsource; + /* ========================================================================== Internal utility functions @@ -2321,35 +2327,221 @@ If omitted or nil, that stands for the selected frame's display. */) 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); +} + +#ifdef NS_IMPL_COCOA +/* 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), + kIODisplayOnlyPreferredName); + 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; +} +#endif + +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); + attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)), + attributes); + attributes = Fcons (Fcons (Qmm_size, + list2i (mi->mm_width, mi->mm_height)), + attributes); + 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))), + attributes); + + if (i == primary_monitor) + primary_monitor_attributes = attributes; + else + 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", + Fns_display_monitor_attributes_list, + Sns_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; + +#ifdef NS_IMPL_COCOA + NSNumber *nid = [dict objectForKey:@"NSScreenNumber"]; + CGDirectDisplayID did = [nid unsignedIntValue]; +#endif + if (i == 0) + { + primary_display_height = fr.size.height; + y = (short) fr.origin.y; + vy = (short) vfr.origin.y; + } + else + { + // 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; + +#ifdef NS_IMPL_COCOA + m->name = ns_screen_name (did); + + { + CGSize mms = CGDisplayScreenSize (did); + m->mm_width = (int) mms.width; + m->mm_height = (int) mms.height; + } + +#else + // 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); +#endif + } + + // 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 @@ handlePanelKeys (NSSavePanel *panel, NSEvent *theEvent) void 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 @@ be used as the image of the icon representing the frame. */); 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); -- 2.20.1