* lisp/emacs-lisp/gv.el (gv-define-setter): Silence compiler warning
[emacs.git] / src / nsfns.m
blob7cf45a54f90fb17072c1d2d980dc26cb814b76bb
1 /* Functions for the NeXT/Open/GNUstep and macOS window system.
3 Copyright (C) 1989, 1992-1994, 2005-2006, 2008-2018 Free Software
4 Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or (at
11 your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes.  */
31 #include <config.h>
33 #include <math.h>
34 #include <c-strcase.h>
36 #include "lisp.h"
37 #include "blockinput.h"
38 #include "nsterm.h"
39 #include "window.h"
40 #include "character.h"
41 #include "buffer.h"
42 #include "keyboard.h"
43 #include "termhooks.h"
44 #include "fontset.h"
45 #include "font.h"
47 #ifdef NS_IMPL_COCOA
48 #include <IOKit/graphics/IOGraphicsLib.h>
49 #include "macfont.h"
50 #endif
53 #ifdef HAVE_NS
55 static EmacsTooltip *ns_tooltip = nil;
57 /* Static variables to handle AppleScript execution.  */
58 static Lisp_Object as_script, *as_result;
59 static int as_status;
61 static ptrdiff_t image_cache_refcount;
63 static struct ns_display_info *ns_display_info_for_name (Lisp_Object);
65 /* ==========================================================================
67     Internal utility functions
69    ========================================================================== */
71 /* Let the user specify a Nextstep display with a Lisp object.
72    OBJECT may be nil, a frame or a terminal object.
73    nil stands for the selected frame--or, if that is not a Nextstep frame,
74    the first Nextstep display on the list.  */
76 static struct ns_display_info *
77 check_ns_display_info (Lisp_Object object)
79   struct ns_display_info *dpyinfo = NULL;
81   if (NILP (object))
82     {
83       struct frame *sf = XFRAME (selected_frame);
85       if (FRAME_NS_P (sf) && FRAME_LIVE_P (sf))
86         dpyinfo = FRAME_DISPLAY_INFO (sf);
87       else if (x_display_list != 0)
88         dpyinfo = x_display_list;
89       else
90         error ("Nextstep windows are not in use or not initialized");
91     }
92   else if (TERMINALP (object))
93     {
94       struct terminal *t = decode_live_terminal (object);
96       if (t->type != output_ns)
97         error ("Terminal %d is not a Nextstep display", t->id);
99       dpyinfo = t->display_info.ns;
100     }
101   else if (STRINGP (object))
102     dpyinfo = ns_display_info_for_name (object);
103   else
104     {
105       struct frame *f = decode_window_system_frame (object);
106       dpyinfo = FRAME_DISPLAY_INFO (f);
107     }
109   return dpyinfo;
113 static id
114 ns_get_window (Lisp_Object maybeFrame)
116   id view =nil, window =nil;
118   if (!FRAMEP (maybeFrame) || !FRAME_NS_P (XFRAME (maybeFrame)))
119     maybeFrame = selected_frame; /* wrong_type_argument (Qframep, maybeFrame); */
121   if (!NILP (maybeFrame))
122     view = FRAME_NS_VIEW (XFRAME (maybeFrame));
123   if (view) window =[view window];
125   return window;
129 /* Return the X display structure for the display named NAME.
130    Open a new connection if necessary.  */
131 static struct ns_display_info *
132 ns_display_info_for_name (Lisp_Object name)
134   struct ns_display_info *dpyinfo;
136   CHECK_STRING (name);
138   for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
139     if (!NILP (Fstring_equal (XCAR (dpyinfo->name_list_element), name)))
140       return dpyinfo;
142   error ("Emacs for Nextstep does not yet support multi-display");
144   Fx_open_connection (name, Qnil, Qnil);
145   dpyinfo = x_display_list;
147   if (dpyinfo == 0)
148     error ("Display on %s not responding.\n", SDATA (name));
150   return dpyinfo;
153 static NSString *
154 ns_filename_from_panel (NSSavePanel *panel)
156 #ifdef NS_IMPL_COCOA
157   NSURL *url = [panel URL];
158   NSString *str = [url path];
159   return str;
160 #else
161   return [panel filename];
162 #endif
165 static NSString *
166 ns_directory_from_panel (NSSavePanel *panel)
168 #ifdef NS_IMPL_COCOA
169   NSURL *url = [panel directoryURL];
170   NSString *str = [url path];
171   return str;
172 #else
173   return [panel directory];
174 #endif
177 #ifndef NS_IMPL_COCOA
178 static Lisp_Object
179 interpret_services_menu (NSMenu *menu, Lisp_Object prefix, Lisp_Object old)
180 /* --------------------------------------------------------------------------
181    Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side.
182    -------------------------------------------------------------------------- */
184   int i, count;
185   NSMenuItem *item;
186   const char *name;
187   Lisp_Object nameStr;
188   unsigned short key;
189   NSString *keys;
190   Lisp_Object res;
192   count = [menu numberOfItems];
193   for (i = 0; i<count; i++)
194     {
195       item = [menu itemAtIndex: i];
196       name = [[item title] UTF8String];
197       if (!name) continue;
199       nameStr = build_string (name);
201       if ([item hasSubmenu])
202         {
203           old = interpret_services_menu ([item submenu],
204                                         Fcons (nameStr, prefix), old);
205         }
206       else
207         {
208           keys = [item keyEquivalent];
209           if (keys && [keys length] )
210             {
211               key = [keys characterAtIndex: 0];
212               res = make_number (key|super_modifier);
213             }
214           else
215             {
216               res = Qundefined;
217             }
218           old = Fcons (Fcons (res,
219                             Freverse (Fcons (nameStr,
220                                            prefix))),
221                     old);
222         }
223     }
224   return old;
226 #endif
229 /* ==========================================================================
231     Frame parameter setters
233    ========================================================================== */
236 static void
237 x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
239   NSColor *col;
240   EmacsCGFloat r, g, b, alpha;
242   /* Must block_input, because ns_lisp_to_color does block/unblock_input
243      which means that col may be deallocated in its unblock_input if there
244      is user input, unless we also block_input.  */
245   block_input ();
246   if (ns_lisp_to_color (arg, &col))
247     {
248       store_frame_param (f, Qforeground_color, oldval);
249       unblock_input ();
250       error ("Unknown color");
251     }
253   [col retain];
254   [f->output_data.ns->foreground_color release];
255   f->output_data.ns->foreground_color = col;
257   [col getRed: &r green: &g blue: &b alpha: &alpha];
258   FRAME_FOREGROUND_PIXEL (f) =
259     ARGB_TO_ULONG ((int)(alpha*0xff), (int)(r*0xff), (int)(g*0xff), (int)(b*0xff));
261   if (FRAME_NS_VIEW (f))
262     {
263       update_face_from_frame_parameter (f, Qforeground_color, arg);
264       /* recompute_basic_faces (f); */
265       if (FRAME_VISIBLE_P (f))
266         SET_FRAME_GARBAGED (f);
267     }
268   unblock_input ();
272 static void
273 x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
275   struct face *face;
276   NSColor *col;
277   NSView *view = FRAME_NS_VIEW (f);
278   EmacsCGFloat r, g, b, alpha;
280   block_input ();
281   if (ns_lisp_to_color (arg, &col))
282     {
283       store_frame_param (f, Qbackground_color, oldval);
284       unblock_input ();
285       error ("Unknown color");
286     }
288   /* Clear the frame; in some instances the NS-internal GC appears not
289      to update, or it does update and cannot clear old text
290      properly.  */
291   if (FRAME_VISIBLE_P (f))
292     ns_clear_frame (f);
294   [col retain];
295   [f->output_data.ns->background_color release];
296   f->output_data.ns->background_color = col;
298   [col getRed: &r green: &g blue: &b alpha: &alpha];
299   FRAME_BACKGROUND_PIXEL (f) =
300     ARGB_TO_ULONG ((int)(alpha*0xff), (int)(r*0xff), (int)(g*0xff), (int)(b*0xff));
302   if (view != nil)
303     {
304       [[view window] setBackgroundColor: col];
306       if (alpha != (EmacsCGFloat) 1.0)
307           [[view window] setOpaque: NO];
308       else
309           [[view window] setOpaque: YES];
311       face = FRAME_DEFAULT_FACE (f);
312       if (face)
313         {
314           col = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f);
315           face->background = ns_index_color
316             ([col colorWithAlphaComponent: alpha], f);
318           update_face_from_frame_parameter (f, Qbackground_color, arg);
319         }
321       if (FRAME_VISIBLE_P (f))
322         SET_FRAME_GARBAGED (f);
323     }
324   unblock_input ();
328 static void
329 x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
331   NSColor *col;
333   block_input ();
334   if (ns_lisp_to_color (arg, &col))
335     {
336       store_frame_param (f, Qcursor_color, oldval);
337       unblock_input ();
338       error ("Unknown color");
339     }
341   [FRAME_CURSOR_COLOR (f) release];
342   FRAME_CURSOR_COLOR (f) = [col retain];
344   if (FRAME_VISIBLE_P (f))
345     {
346       x_update_cursor (f, 0);
347       x_update_cursor (f, 1);
348     }
349   update_face_from_frame_parameter (f, Qcursor_color, arg);
350   unblock_input ();
354 static void
355 x_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
357   NSView *view = FRAME_NS_VIEW (f);
358   NSTRACE ("x_set_icon_name");
360   /* See if it's changed.  */
361   if (STRINGP (arg))
362     {
363       if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
364         return;
365     }
366   else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
367     return;
369   fset_icon_name (f, arg);
371   if (NILP (arg))
372     {
373       if (!NILP (f->title))
374         arg = f->title;
375       else
376         /* Explicit name and no icon-name -> explicit_name.  */
377         if (f->explicit_name)
378           arg = f->name;
379         else
380           {
381             /* No explicit name and no icon-name ->
382                name has to be rebuild from icon_title_format.  */
383             windows_or_buffers_changed = 62;
384             return;
385           }
386     }
388   /* Don't change the name if it's already NAME.  */
389   if ([[view window] miniwindowTitle]
390       && ([[[view window] miniwindowTitle]
391              isEqualToString: [NSString stringWithUTF8String:
392                                           SSDATA (arg)]]))
393     return;
395   [[view window] setMiniwindowTitle:
396         [NSString stringWithUTF8String: SSDATA (arg)]];
399 static void
400 ns_set_name_internal (struct frame *f, Lisp_Object name)
402   Lisp_Object encoded_name, encoded_icon_name;
403   NSString *str;
404   NSView *view = FRAME_NS_VIEW (f);
407   encoded_name = ENCODE_UTF_8 (name);
409   str = [NSString stringWithUTF8String: SSDATA (encoded_name)];
412   /* Don't change the name if it's already NAME.  */
413   if (! [[[view window] title] isEqualToString: str])
414     [[view window] setTitle: str];
416   if (!STRINGP (f->icon_name))
417     encoded_icon_name = encoded_name;
418   else
419     encoded_icon_name = ENCODE_UTF_8 (f->icon_name);
421   str = [NSString stringWithUTF8String: SSDATA (encoded_icon_name)];
423   if ([[view window] miniwindowTitle]
424       && ! [[[view window] miniwindowTitle] isEqualToString: str])
425     [[view window] setMiniwindowTitle: str];
429 static void
430 ns_set_name (struct frame *f, Lisp_Object name, int explicit)
432   NSTRACE ("ns_set_name");
434   /* Make sure that requests from lisp code override requests from
435      Emacs redisplay code.  */
436   if (explicit)
437     {
438       /* If we're switching from explicit to implicit, we had better
439          update the mode lines and thereby update the title.  */
440       if (f->explicit_name && NILP (name))
441         update_mode_lines = 21;
443       f->explicit_name = ! NILP (name);
444     }
445   else if (f->explicit_name)
446     return;
448   if (NILP (name))
449     name = build_string ([ns_app_name UTF8String]);
450   else
451     CHECK_STRING (name);
453   /* Don't change the name if it's already NAME.  */
454   if (! NILP (Fstring_equal (name, f->name)))
455     return;
457   fset_name (f, name);
459   /* Title overrides explicit name.  */
460   if (! NILP (f->title))
461     name = f->title;
463   ns_set_name_internal (f, name);
466 static void
467 ns_set_represented_filename (struct frame *f)
469   Lisp_Object filename, encoded_filename;
470   Lisp_Object buf = XWINDOW (f->selected_window)->contents;
471   NSAutoreleasePool *pool;
472   NSString *fstr;
473   NSView *view = FRAME_NS_VIEW (f);
475   NSTRACE ("ns_set_represented_filename");
477   if (f->explicit_name || ! NILP (f->title))
478     return;
480   block_input ();
481   pool = [[NSAutoreleasePool alloc] init];
482   filename = BVAR (XBUFFER (buf), filename);
484   if (! NILP (filename))
485     {
486       encoded_filename = ENCODE_UTF_8 (filename);
488       fstr = [NSString stringWithUTF8String: SSDATA (encoded_filename)];
489       if (fstr == nil) fstr = @"";
490     }
491   else
492     fstr = @"";
494 #ifdef NS_IMPL_COCOA
495   /* Work around a bug observed on 10.3 and later where
496      setTitleWithRepresentedFilename does not clear out previous state
497      if given filename does not exist.  */
498   if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
499     [[view window] setRepresentedFilename: @""];
500 #endif
501   [[view window] setRepresentedFilename: fstr];
503   [pool release];
504   unblock_input ();
508 /* This function should be called when the user's lisp code has
509    specified a name for the frame; the name will override any set by the
510    redisplay code.  */
511 static void
512 x_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
514   NSTRACE ("x_explicitly_set_name");
515   ns_set_name (f, arg, 1);
519 /* This function should be called by Emacs redisplay code to set the
520    name; names set this way will never override names set by the user's
521    lisp code.  */
522 void
523 x_implicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
525   NSTRACE ("x_implicitly_set_name");
527   if (ns_use_proxy_icon)
528     ns_set_represented_filename (f);
530   ns_set_name (f, arg, 0);
534 /* Change the title of frame F to NAME.
535    If NAME is nil, use the frame name as the title.  */
537 static void
538 x_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name)
540   NSTRACE ("x_set_title");
541   /* Don't change the title if it's already NAME.  */
542   if (EQ (name, f->title))
543     return;
545   update_mode_lines = 22;
547   fset_title (f, name);
549   if (NILP (name))
550     name = f->name;
551   else
552     CHECK_STRING (name);
554   ns_set_name_internal (f, name);
557 void
558 ns_set_doc_edited (void)
560   NSAutoreleasePool *pool;
561   Lisp_Object tail, frame;
562   block_input ();
563   pool = [[NSAutoreleasePool alloc] init];
564   FOR_EACH_FRAME (tail, frame)
565     {
566       BOOL edited = NO;
567       struct frame *f = XFRAME (frame);
568       struct window *w;
569       NSView *view;
571       if (! FRAME_NS_P (f)) continue;
572       w = XWINDOW (FRAME_SELECTED_WINDOW (f));
573       view = FRAME_NS_VIEW (f);
574       if (!MINI_WINDOW_P (w))
575         edited = ! NILP (Fbuffer_modified_p (w->contents)) &&
576           ! NILP (Fbuffer_file_name (w->contents));
577       [[view window] setDocumentEdited: edited];
578     }
580   [pool release];
581   unblock_input ();
585 static void
586 x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
588   int nlines;
589   if (FRAME_MINIBUF_ONLY_P (f))
590     return;
592   if (TYPE_RANGED_INTEGERP (int, value))
593     nlines = XINT (value);
594   else
595     nlines = 0;
597   FRAME_MENU_BAR_LINES (f) = 0;
598   if (nlines)
599     {
600       FRAME_EXTERNAL_MENU_BAR (f) = 1;
601       /* Does for all frames, whereas we just want for one frame
602          [NSMenu setMenuBarVisible: YES]; */
603     }
604   else
605     {
606       if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
607         free_frame_menubar (f);
608       /* [NSMenu setMenuBarVisible: NO]; */
609       FRAME_EXTERNAL_MENU_BAR (f) = 0;
610     }
614 /* toolbar support */
615 static void
616 x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
618   /* Currently, when the tool bar changes state, the frame is resized.
620      TODO: It would be better if this didn't occur when 1) the frame
621      is full height or maximized or 2) when specified by
622      `frame-inhibit-implied-resize'.  */
623   int nlines;
625   NSTRACE ("x_set_tool_bar_lines");
627   if (FRAME_MINIBUF_ONLY_P (f))
628     return;
630   if (RANGED_INTEGERP (0, value, INT_MAX))
631     nlines = XFASTINT (value);
632   else
633     nlines = 0;
635   if (nlines)
636     {
637       FRAME_EXTERNAL_TOOL_BAR (f) = 1;
638       update_frame_tool_bar (f);
639     }
640   else
641     {
642       if (FRAME_EXTERNAL_TOOL_BAR (f))
643         {
644           free_frame_tool_bar (f);
645           FRAME_EXTERNAL_TOOL_BAR (f) = 0;
647           {
648             EmacsView *view = FRAME_NS_VIEW (f);
649             int fs_state = [view fullscreenState];
651             if (fs_state == FULLSCREEN_MAXIMIZED)
652               {
653                 [view setFSValue:FULLSCREEN_WIDTH];
654               }
655             else if (fs_state == FULLSCREEN_HEIGHT)
656               {
657                 [view setFSValue:FULLSCREEN_NONE];
658               }
659           }
660        }
661     }
663   {
664     int inhibit
665       = ((f->after_make_frame
666           && !f->tool_bar_resized
667           && (EQ (frame_inhibit_implied_resize, Qt)
668               || (CONSP (frame_inhibit_implied_resize)
669                   && !NILP (Fmemq (Qtool_bar_lines,
670                                    frame_inhibit_implied_resize))))
671           && NILP (get_frame_param (f, Qfullscreen)))
672          ? 0
673          : 2);
675     NSTRACE_MSG ("inhibit:%d", inhibit);
677     frame_size_history_add (f, Qupdate_frame_tool_bar, 0, 0, Qnil);
678     adjust_frame_size (f, -1, -1, inhibit, 0, Qtool_bar_lines);
679   }
683 static void
684 x_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
686   int old_width = FRAME_INTERNAL_BORDER_WIDTH (f);
688   CHECK_TYPE_RANGED_INTEGER (int, arg);
689   f->internal_border_width = XINT (arg);
690   if (FRAME_INTERNAL_BORDER_WIDTH (f) < 0)
691     f->internal_border_width = 0;
693   if (FRAME_INTERNAL_BORDER_WIDTH (f) == old_width)
694     return;
696   if (FRAME_X_WINDOW (f) != 0)
697     adjust_frame_size (f, -1, -1, 3, 0, Qinternal_border_width);
699   SET_FRAME_GARBAGED (f);
703 static void
704 ns_implicitly_set_icon_type (struct frame *f)
706   Lisp_Object tem;
707   EmacsView *view = FRAME_NS_VIEW (f);
708   id image = nil;
709   Lisp_Object chain, elt;
710   NSAutoreleasePool *pool;
711   BOOL setMini = YES;
713   NSTRACE ("ns_implicitly_set_icon_type");
715   block_input ();
716   pool = [[NSAutoreleasePool alloc] init];
717   if (f->output_data.ns->miniimage
718       && [[NSString stringWithUTF8String: SSDATA (f->name)]
719                isEqualToString: [(NSImage *)f->output_data.ns->miniimage name]])
720     {
721       [pool release];
722       unblock_input ();
723       return;
724     }
726   tem = assq_no_quit (Qicon_type, f->param_alist);
727   if (CONSP (tem) && ! NILP (XCDR (tem)))
728     {
729       [pool release];
730       unblock_input ();
731       return;
732     }
734   for (chain = Vns_icon_type_alist;
735        image == nil && CONSP (chain);
736        chain = XCDR (chain))
737     {
738       elt = XCAR (chain);
739       /* Special case: t means go by file type.  */
740       if (SYMBOLP (elt) && EQ (elt, Qt) && SSDATA (f->name)[0] == '/')
741         {
742           NSString *str
743              = [NSString stringWithUTF8String: SSDATA (f->name)];
744           if ([[NSFileManager defaultManager] fileExistsAtPath: str])
745             image = [[[NSWorkspace sharedWorkspace] iconForFile: str] retain];
746         }
747       else if (CONSP (elt) &&
748                STRINGP (XCAR (elt)) &&
749                STRINGP (XCDR (elt)) &&
750                fast_string_match (XCAR (elt), f->name) >= 0)
751         {
752           image = [EmacsImage allocInitFromFile: XCDR (elt)];
753           if (image == nil)
754             image = [[NSImage imageNamed:
755                                [NSString stringWithUTF8String:
756                                             SSDATA (XCDR (elt))]] retain];
757         }
758     }
760   if (image == nil)
761     {
762       image = [[[NSWorkspace sharedWorkspace] iconForFileType: @"text"] retain];
763       setMini = NO;
764     }
766   [f->output_data.ns->miniimage release];
767   f->output_data.ns->miniimage = image;
768   [view setMiniwindowImage: setMini];
769   [pool release];
770   unblock_input ();
774 static void
775 x_set_icon_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
777   EmacsView *view = FRAME_NS_VIEW (f);
778   id image = nil;
779   BOOL setMini = YES;
781   NSTRACE ("x_set_icon_type");
783   if (!NILP (arg) && SYMBOLP (arg))
784     {
785       arg =build_string (SSDATA (SYMBOL_NAME (arg)));
786       store_frame_param (f, Qicon_type, arg);
787     }
789   /* Do it the implicit way.  */
790   if (NILP (arg))
791     {
792       ns_implicitly_set_icon_type (f);
793       return;
794     }
796   CHECK_STRING (arg);
798   image = [EmacsImage allocInitFromFile: arg];
799   if (image == nil)
800     image =[NSImage imageNamed: [NSString stringWithUTF8String:
801                                             SSDATA (arg)]];
803   if (image == nil)
804     {
805       image = [NSImage imageNamed: @"text"];
806       setMini = NO;
807     }
809   f->output_data.ns->miniimage = image;
810   [view setMiniwindowImage: setMini];
813 /* This is the same as the xfns.c definition.  */
814 static void
815 x_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
817   set_frame_cursor_types (f, arg);
820 /* called to set mouse pointer color, but all other terms use it to
821    initialize pointer types (and don't set the color ;) */
822 static void
823 x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
825   /* Don't think we can do this on Nextstep.  */
829 #define Str(x) #x
830 #define Xstr(x) Str(x)
832 static Lisp_Object
833 ns_appkit_version_str (void)
835   char tmp[256];
837 #ifdef NS_IMPL_GNUSTEP
838   sprintf(tmp, "gnustep-gui-%s", Xstr(GNUSTEP_GUI_VERSION));
839 #elif defined (NS_IMPL_COCOA)
840   NSString *osversion
841     = [[NSProcessInfo processInfo] operatingSystemVersionString];
842   sprintf(tmp, "appkit-%.2f %s",
843           NSAppKitVersionNumber,
844           [osversion UTF8String]);
845 #else
846   tmp = "ns-unknown";
847 #endif
848   return build_string (tmp);
852 /* This is for use by x-server-version and collapses all version info we
853    have into a single int.  For a better picture of the implementation
854    running, use ns_appkit_version_str.  */
855 static int
856 ns_appkit_version_int (void)
858 #ifdef NS_IMPL_GNUSTEP
859   return GNUSTEP_GUI_MAJOR_VERSION * 100 + GNUSTEP_GUI_MINOR_VERSION;
860 #elif defined (NS_IMPL_COCOA)
861   return (int)NSAppKitVersionNumber;
862 #endif
863   return 0;
867 static void
868 x_icon (struct frame *f, Lisp_Object parms)
869 /* --------------------------------------------------------------------------
870    Strangely-named function to set icon position parameters in frame.
871    This is irrelevant under macOS, but might be needed under GNUstep,
872    depending on the window manager used.  Note, this is not a standard
873    frame parameter-setter; it is called directly from x-create-frame.
874    -------------------------------------------------------------------------- */
876   Lisp_Object icon_x, icon_y;
877   struct ns_display_info *dpyinfo = check_ns_display_info (Qnil);
879   f->output_data.ns->icon_top = -1;
880   f->output_data.ns->icon_left = -1;
882   /* Set the position of the icon.  */
883   icon_x = x_get_arg (dpyinfo, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
884   icon_y = x_get_arg (dpyinfo, parms, Qicon_top, 0, 0,  RES_TYPE_NUMBER);
885   if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
886     {
887       CHECK_NUMBER (icon_x);
888       CHECK_NUMBER (icon_y);
889       f->output_data.ns->icon_top = XINT (icon_y);
890       f->output_data.ns->icon_left = XINT (icon_x);
891     }
892   else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
893     error ("Both left and top icon corners of icon must be specified");
897 /* Note: see frame.c for template, also where generic functions are
898    implemented.  */
899 frame_parm_handler ns_frame_parm_handlers[] =
901   x_set_autoraise, /* generic OK */
902   x_set_autolower, /* generic OK */
903   x_set_background_color,
904   0, /* x_set_border_color,  may be impossible under Nextstep */
905   0, /* x_set_border_width,  may be impossible under Nextstep */
906   x_set_cursor_color,
907   x_set_cursor_type,
908   x_set_font, /* generic OK */
909   x_set_foreground_color,
910   x_set_icon_name,
911   x_set_icon_type,
912   x_set_internal_border_width, /* generic OK */
913   x_set_right_divider_width,
914   x_set_bottom_divider_width,
915   x_set_menu_bar_lines,
916   x_set_mouse_color,
917   x_explicitly_set_name,
918   x_set_scroll_bar_width, /* generic OK */
919   x_set_scroll_bar_height, /* generic OK */
920   x_set_title,
921   x_set_unsplittable, /* generic OK */
922   x_set_vertical_scroll_bars, /* generic OK */
923   x_set_horizontal_scroll_bars, /* generic OK */
924   x_set_visibility, /* generic OK */
925   x_set_tool_bar_lines,
926   0, /* x_set_scroll_bar_foreground, will ignore (not possible on NS) */
927   0, /* x_set_scroll_bar_background,  will ignore (not possible on NS) */
928   x_set_screen_gamma, /* generic OK */
929   x_set_line_spacing, /* generic OK, sets f->extra_line_spacing to int */
930   x_set_left_fringe, /* generic OK */
931   x_set_right_fringe, /* generic OK */
932   0, /* x_set_wait_for_wm, will ignore */
933   x_set_fullscreen, /* generic OK */
934   x_set_font_backend, /* generic OK */
935   x_set_alpha,
936   0, /* x_set_sticky */
937   0, /* x_set_tool_bar_position */
938   0, /* x_set_inhibit_double_buffering */
939 #ifdef NS_IMPL_COCOA
940   x_set_undecorated,
941 #else
942   0, /* x_set_undecorated */
943 #endif
944   x_set_parent_frame,
945   0, /* x_set_skip_taskbar */
946   x_set_no_focus_on_map,
947   x_set_no_accept_focus,
948   x_set_z_group, /* x_set_z_group */
949   0, /* x_set_override_redirect */
950   x_set_no_special_glyphs,
951 #ifdef NS_IMPL_COCOA
952   ns_set_appearance,
953   ns_set_transparent_titlebar,
954 #endif
958 /* Handler for signals raised during x_create_frame.
959    FRAME is the frame which is partially constructed.  */
961 static void
962 unwind_create_frame (Lisp_Object frame)
964   struct frame *f = XFRAME (frame);
966   /* If frame is already dead, nothing to do.  This can happen if the
967      display is disconnected after the frame has become official, but
968      before x_create_frame removes the unwind protect.  */
969   if (!FRAME_LIVE_P (f))
970     return;
972   /* If frame is ``official'', nothing to do.  */
973   if (NILP (Fmemq (frame, Vframe_list)))
974     {
975 #if defined GLYPH_DEBUG && defined ENABLE_CHECKING
976       struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
977 #endif
979       /* If the frame's image cache refcount is still the same as our
980          private shadow variable, it means we are unwinding a frame
981          for which we didn't yet call init_frame_faces, where the
982          refcount is incremented.  Therefore, we increment it here, so
983          that free_frame_faces, called in x_free_frame_resources
984          below, will not mistakenly decrement the counter that was not
985          incremented yet to account for this new frame.  */
986       if (FRAME_IMAGE_CACHE (f) != NULL
987           && FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount)
988         FRAME_IMAGE_CACHE (f)->refcount++;
990       x_free_frame_resources (f);
991       free_glyphs (f);
993 #if defined GLYPH_DEBUG && defined ENABLE_CHECKING
994       /* Check that reference counts are indeed correct.  */
995       eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
996 #endif
997     }
1001  * Read geometry related parameters from preferences if not in PARMS.
1002  * Returns the union of parms and any preferences read.
1003  */
1005 static Lisp_Object
1006 get_geometry_from_preferences (struct ns_display_info *dpyinfo,
1007                                Lisp_Object parms)
1009   struct {
1010     const char *val;
1011     const char *cls;
1012     Lisp_Object tem;
1013   } r[] = {
1014     { "width",  "Width", Qwidth },
1015     { "height", "Height", Qheight },
1016     { "left", "Left", Qleft },
1017     { "top", "Top", Qtop },
1018   };
1020   int i;
1021   for (i = 0; i < ARRAYELTS (r); ++i)
1022     {
1023       if (NILP (Fassq (r[i].tem, parms)))
1024         {
1025           Lisp_Object value
1026             = x_get_arg (dpyinfo, parms, r[i].tem, r[i].val, r[i].cls,
1027                          RES_TYPE_NUMBER);
1028           if (! EQ (value, Qunbound))
1029             parms = Fcons (Fcons (r[i].tem, value), parms);
1030         }
1031     }
1033   return parms;
1036 /* ==========================================================================
1038     Lisp definitions
1040    ========================================================================== */
1042 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
1043        1, 1, 0,
1044        doc: /* SKIP: real doc in xfns.c.  */)
1045      (Lisp_Object parms)
1047   struct frame *f;
1048   Lisp_Object frame, tem;
1049   Lisp_Object name;
1050   int minibuffer_only = 0;
1051   long window_prompting = 0;
1052   ptrdiff_t count = specpdl_ptr - specpdl;
1053   Lisp_Object display;
1054   struct ns_display_info *dpyinfo = NULL;
1055   Lisp_Object parent, parent_frame;
1056   struct kboard *kb;
1057   static int desc_ctr = 1;
1058   int x_width = 0, x_height = 0;
1060   /* x_get_arg modifies parms.  */
1061   parms = Fcopy_alist (parms);
1063   /* Use this general default value to start with
1064      until we know if this frame has a specified name.  */
1065   Vx_resource_name = Vinvocation_name;
1067   display = x_get_arg (dpyinfo, parms, Qterminal, 0, 0, RES_TYPE_STRING);
1068   if (EQ (display, Qunbound))
1069     display = Qnil;
1070   dpyinfo = check_ns_display_info (display);
1071   kb = dpyinfo->terminal->kboard;
1073   if (!dpyinfo->terminal->name)
1074     error ("Terminal is not live, can't create new frames on it");
1076   name = x_get_arg (dpyinfo, parms, Qname, 0, 0, RES_TYPE_STRING);
1077   if (!STRINGP (name)
1078       && ! EQ (name, Qunbound)
1079       && ! NILP (name))
1080     error ("Invalid frame name--not a string or nil");
1082   if (STRINGP (name))
1083     Vx_resource_name = name;
1085   parent = x_get_arg (dpyinfo, parms, Qparent_id, 0, 0, RES_TYPE_NUMBER);
1086   if (EQ (parent, Qunbound))
1087     parent = Qnil;
1088   if (! NILP (parent))
1089     CHECK_NUMBER (parent);
1091   /* make_frame_without_minibuffer can run Lisp code and garbage collect.  */
1092   /* No need to protect DISPLAY because that's not used after passing
1093      it to make_frame_without_minibuffer.  */
1094   frame = Qnil;
1095   tem = x_get_arg (dpyinfo, parms, Qminibuffer, "minibuffer", "Minibuffer",
1096                   RES_TYPE_SYMBOL);
1097   if (EQ (tem, Qnone) || NILP (tem))
1098       f = make_frame_without_minibuffer (Qnil, kb, display);
1099   else if (EQ (tem, Qonly))
1100     {
1101       f = make_minibuffer_frame ();
1102       minibuffer_only = 1;
1103     }
1104   else if (WINDOWP (tem))
1105       f = make_frame_without_minibuffer (tem, kb, display);
1106   else
1107       f = make_frame (1);
1109   XSETFRAME (frame, f);
1111   f->terminal = dpyinfo->terminal;
1113   f->output_method = output_ns;
1114   f->output_data.ns = xzalloc (sizeof *f->output_data.ns);
1116   FRAME_FONTSET (f) = -1;
1118   fset_icon_name (f, x_get_arg (dpyinfo, parms, Qicon_name,
1119                                 "iconName", "Title",
1120                                 RES_TYPE_STRING));
1121   if (! STRINGP (f->icon_name))
1122     fset_icon_name (f, Qnil);
1124   FRAME_DISPLAY_INFO (f) = dpyinfo;
1126   /* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe.  */
1127   record_unwind_protect (unwind_create_frame, frame);
1129   f->output_data.ns->window_desc = desc_ctr++;
1130   if (TYPE_RANGED_INTEGERP (Window, parent))
1131     {
1132       f->output_data.ns->parent_desc = XFASTINT (parent);
1133       f->output_data.ns->explicit_parent = 1;
1134     }
1135   else
1136     {
1137       f->output_data.ns->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
1138       f->output_data.ns->explicit_parent = 0;
1139     }
1141   /* Set the name; the functions to which we pass f expect the name to
1142      be set.  */
1143   if (EQ (name, Qunbound) || NILP (name) || ! STRINGP (name))
1144     {
1145       fset_name (f, build_string ([ns_app_name UTF8String]));
1146       f->explicit_name = 0;
1147     }
1148   else
1149     {
1150       fset_name (f, name);
1151       f->explicit_name = 1;
1152       specbind (Qx_resource_name, name);
1153     }
1155   block_input ();
1157 #ifdef NS_IMPL_COCOA
1158     mac_register_font_driver (f);
1159 #else
1160     register_font_driver (&nsfont_driver, f);
1161 #endif
1163   image_cache_refcount =
1164     FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
1166   x_default_parameter (f, parms, Qfont_backend, Qnil,
1167                         "fontBackend", "FontBackend", RES_TYPE_STRING);
1169   {
1170     /* use for default font name */
1171     id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */
1172     x_default_parameter (f, parms, Qfontsize,
1173                                     make_number (0 /* (int)[font pointSize] */),
1174                                     "fontSize", "FontSize", RES_TYPE_NUMBER);
1175     // Remove ' Regular', not handled by backends.
1176     char *fontname = xstrdup ([[font displayName] UTF8String]);
1177     int len = strlen (fontname);
1178     if (len > 8 && strcmp (fontname + len - 8, " Regular") == 0)
1179       fontname[len-8] = '\0';
1180     x_default_parameter (f, parms, Qfont,
1181                                  build_string (fontname),
1182                                  "font", "Font", RES_TYPE_STRING);
1183     xfree (fontname);
1184   }
1185   unblock_input ();
1187   x_default_parameter (f, parms, Qborder_width, make_number (0),
1188                        "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
1189   x_default_parameter (f, parms, Qinternal_border_width, make_number (2),
1190                       "internalBorderWidth", "InternalBorderWidth",
1191                       RES_TYPE_NUMBER);
1192   x_default_parameter (f, parms, Qright_divider_width, make_number (0),
1193                        NULL, NULL, RES_TYPE_NUMBER);
1194   x_default_parameter (f, parms, Qbottom_divider_width, make_number (0),
1195                        NULL, NULL, RES_TYPE_NUMBER);
1197   /* default vertical scrollbars on right on Mac */
1198   {
1199       Lisp_Object spos
1200 #ifdef NS_IMPL_GNUSTEP
1201           = Qt;
1202 #else
1203           = Qright;
1204 #endif
1205       x_default_parameter (f, parms, Qvertical_scroll_bars, spos,
1206                            "verticalScrollBars", "VerticalScrollBars",
1207                            RES_TYPE_SYMBOL);
1208   }
1209   x_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil,
1210                        "horizontalScrollBars", "HorizontalScrollBars",
1211                        RES_TYPE_SYMBOL);
1212   x_default_parameter (f, parms, Qforeground_color, build_string ("Black"),
1213                       "foreground", "Foreground", RES_TYPE_STRING);
1214   x_default_parameter (f, parms, Qbackground_color, build_string ("White"),
1215                       "background", "Background", RES_TYPE_STRING);
1216   x_default_parameter (f, parms, Qline_spacing, Qnil,
1217                        "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
1218   x_default_parameter (f, parms, Qleft_fringe, Qnil,
1219                        "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
1220   x_default_parameter (f, parms, Qright_fringe, Qnil,
1221                        "rightFringe", "RightFringe", RES_TYPE_NUMBER);
1222   x_default_parameter (f, parms, Qno_special_glyphs, Qnil,
1223                        NULL, NULL, RES_TYPE_BOOLEAN);
1225   init_frame_faces (f);
1227   /* Read comment about this code in corresponding place in xfns.c.  */
1228   tem = x_get_arg (dpyinfo, parms, Qmin_width, NULL, NULL, RES_TYPE_NUMBER);
1229   if (NUMBERP (tem))
1230     store_frame_param (f, Qmin_width, tem);
1231   tem = x_get_arg (dpyinfo, parms, Qmin_height, NULL, NULL, RES_TYPE_NUMBER);
1232   if (NUMBERP (tem))
1233     store_frame_param (f, Qmin_height, tem);
1234   adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
1235                      FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1,
1236                      Qx_create_frame_1);
1238   tem = x_get_arg (dpyinfo, parms, Qundecorated, NULL, NULL, RES_TYPE_BOOLEAN);
1239   FRAME_UNDECORATED (f) = !NILP (tem) && !EQ (tem, Qunbound);
1240   store_frame_param (f, Qundecorated, FRAME_UNDECORATED (f) ? Qt : Qnil);
1242 #ifdef NS_IMPL_COCOA
1243   tem = x_get_arg (dpyinfo, parms, Qns_appearance, NULL, NULL, RES_TYPE_SYMBOL);
1244   FRAME_NS_APPEARANCE (f) = EQ (tem, Qdark)
1245     ? ns_appearance_vibrant_dark : ns_appearance_aqua;
1246   store_frame_param (f, Qns_appearance, tem);
1248   tem = x_get_arg (dpyinfo, parms, Qns_transparent_titlebar,
1249                    NULL, NULL, RES_TYPE_BOOLEAN);
1250   FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (tem) && !EQ (tem, Qunbound);
1251   store_frame_param (f, Qns_transparent_titlebar, tem);
1252 #endif
1254   parent_frame = x_get_arg (dpyinfo, parms, Qparent_frame, NULL, NULL,
1255                             RES_TYPE_SYMBOL);
1256   /* Accept parent-frame iff parent-id was not specified.  */
1257   if (!NILP (parent)
1258       || EQ (parent_frame, Qunbound)
1259       || NILP (parent_frame)
1260       || !FRAMEP (parent_frame)
1261       || !FRAME_LIVE_P (XFRAME (parent_frame)))
1262     parent_frame = Qnil;
1264   fset_parent_frame (f, parent_frame);
1265   store_frame_param (f, Qparent_frame, parent_frame);
1267   x_default_parameter (f, parms, Qz_group, Qnil, NULL, NULL, RES_TYPE_SYMBOL);
1268   x_default_parameter (f, parms, Qno_focus_on_map, Qnil,
1269                        NULL, NULL, RES_TYPE_BOOLEAN);
1270   x_default_parameter (f, parms, Qno_accept_focus, Qnil,
1271                        NULL, NULL, RES_TYPE_BOOLEAN);
1273   /* The resources controlling the menu-bar and tool-bar are
1274      processed specially at startup, and reflected in the mode
1275      variables; ignore them here.  */
1276   x_default_parameter (f, parms, Qmenu_bar_lines,
1277                        NILP (Vmenu_bar_mode)
1278                        ? make_number (0) : make_number (1),
1279                        NULL, NULL, RES_TYPE_NUMBER);
1280   x_default_parameter (f, parms, Qtool_bar_lines,
1281                        NILP (Vtool_bar_mode)
1282                        ? make_number (0) : make_number (1),
1283                        NULL, NULL, RES_TYPE_NUMBER);
1285   x_default_parameter (f, parms, Qbuffer_predicate, Qnil, "bufferPredicate",
1286                        "BufferPredicate", RES_TYPE_SYMBOL);
1287   x_default_parameter (f, parms, Qtitle, Qnil, "title", "Title",
1288                        RES_TYPE_STRING);
1290   parms = get_geometry_from_preferences (dpyinfo, parms);
1291   window_prompting = x_figure_window_size (f, parms, true, &x_width, &x_height);
1293   tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
1294   f->no_split = minibuffer_only || (!EQ (tem, Qunbound) && !EQ (tem, Qnil));
1296   /* NOTE: on other terms, this is done in set_mouse_color, however this
1297      was not getting called under Nextstep.  */
1298   f->output_data.ns->text_cursor = [NSCursor IBeamCursor];
1299   f->output_data.ns->nontext_cursor = [NSCursor arrowCursor];
1300   f->output_data.ns->modeline_cursor = [NSCursor pointingHandCursor];
1301   f->output_data.ns->hand_cursor = [NSCursor pointingHandCursor];
1302   f->output_data.ns->hourglass_cursor = [NSCursor disappearingItemCursor];
1303   f->output_data.ns->horizontal_drag_cursor = [NSCursor resizeLeftRightCursor];
1304   f->output_data.ns->vertical_drag_cursor = [NSCursor resizeUpDownCursor];
1305   f->output_data.ns->left_edge_cursor = [NSCursor resizeLeftRightCursor];
1306   f->output_data.ns->top_left_corner_cursor = [NSCursor arrowCursor];
1307   f->output_data.ns->top_edge_cursor = [NSCursor resizeUpDownCursor];
1308   f->output_data.ns->top_right_corner_cursor = [NSCursor arrowCursor];
1309   f->output_data.ns->right_edge_cursor = [NSCursor resizeLeftRightCursor];
1310   f->output_data.ns->bottom_right_corner_cursor = [NSCursor arrowCursor];
1311   f->output_data.ns->bottom_edge_cursor = [NSCursor resizeUpDownCursor];
1312   f->output_data.ns->bottom_left_corner_cursor = [NSCursor arrowCursor];
1314   FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor
1315      = [NSCursor arrowCursor];
1316   FRAME_DISPLAY_INFO (f)->horizontal_scroll_bar_cursor
1317      = [NSCursor arrowCursor];
1318   f->output_data.ns->current_pointer = f->output_data.ns->text_cursor;
1320   f->output_data.ns->in_animation = NO;
1322   [[EmacsView alloc] initFrameFromEmacs: f];
1324   x_icon (f, parms);
1326   /* ns_display_info does not have a reference_count.  */
1327   f->terminal->reference_count++;
1329   /* It is now ok to make the frame official even if we get an error
1330      below.  The frame needs to be on Vframe_list or making it visible
1331      won't work.  */
1332   Vframe_list = Fcons (frame, Vframe_list);
1334   x_default_parameter (f, parms, Qicon_type, Qnil,
1335                        "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
1337   x_default_parameter (f, parms, Qauto_raise, Qnil,
1338                        "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
1339   x_default_parameter (f, parms, Qauto_lower, Qnil,
1340                        "autoLower", "AutoLower", RES_TYPE_BOOLEAN);
1341   x_default_parameter (f, parms, Qcursor_type, Qbox,
1342                        "cursorType", "CursorType", RES_TYPE_SYMBOL);
1343   x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
1344                        "scrollBarWidth", "ScrollBarWidth",
1345                        RES_TYPE_NUMBER);
1346   x_default_parameter (f, parms, Qscroll_bar_height, Qnil,
1347                        "scrollBarHeight", "ScrollBarHeight",
1348                        RES_TYPE_NUMBER);
1349   x_default_parameter (f, parms, Qalpha, Qnil,
1350                        "alpha", "Alpha", RES_TYPE_NUMBER);
1351   x_default_parameter (f, parms, Qfullscreen, Qnil,
1352                        "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
1354   /* Allow x_set_window_size, now.  */
1355   f->can_x_set_window_size = true;
1357   if (x_width > 0)
1358     SET_FRAME_WIDTH (f, x_width);
1359   if (x_height > 0)
1360     SET_FRAME_HEIGHT (f, x_height);
1362   adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 0, 1,
1363                      Qx_create_frame_2);
1365   if (! f->output_data.ns->explicit_parent)
1366     {
1367       Lisp_Object visibility;
1369       visibility = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
1370                               RES_TYPE_SYMBOL);
1371       if (EQ (visibility, Qunbound))
1372         visibility = Qt;
1374       if (EQ (visibility, Qicon))
1375         x_iconify_frame (f);
1376       else if (! NILP (visibility))
1377         {
1378           x_make_frame_visible (f);
1379           [[FRAME_NS_VIEW (f) window] makeKeyWindow];
1380         }
1381       else
1382         {
1383           /* Must have been Qnil.  */
1384         }
1385     }
1387   if (FRAME_HAS_MINIBUF_P (f)
1388       && (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame))
1389           || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame)))))
1390     kset_default_minibuffer_frame (kb, frame);
1392   /* All remaining specified parameters, which have not been "used"
1393      by x_get_arg and friends, now go in the misc. alist of the frame.  */
1394   for (tem = parms; CONSP (tem); tem = XCDR (tem))
1395     if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem))))
1396       fset_param_alist (f, Fcons (XCAR (tem), f->param_alist));
1398   if (window_prompting & USPosition)
1399     x_set_offset (f, f->left_pos, f->top_pos, 1);
1401   /* Make sure windows on this frame appear in calls to next-window
1402      and similar functions.  */
1403   Vwindow_list = Qnil;
1405   return unbind_to (count, frame);
1408 void
1409 x_focus_frame (struct frame *f, bool noactivate)
1411   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1413   if (dpyinfo->x_focus_frame != f)
1414     {
1415       EmacsView *view = FRAME_NS_VIEW (f);
1416       block_input ();
1417       [NSApp activateIgnoringOtherApps: YES];
1418       [[view window] makeKeyAndOrderFront: view];
1419       unblock_input ();
1420     }
1423 static BOOL
1424 ns_window_is_ancestor (NSWindow *win, NSWindow *candidate)
1425 /* Test whether CANDIDATE is an ancestor window of WIN.  */
1427   if (candidate == NULL)
1428     return NO;
1429   else if (win == candidate)
1430     return YES;
1431   else
1432     return ns_window_is_ancestor(win, [candidate parentWindow]);
1435 DEFUN ("ns-frame-list-z-order", Fns_frame_list_z_order,
1436        Sns_frame_list_z_order, 0, 1, 0,
1437        doc: /* Return list of Emacs' frames, in Z (stacking) order.
1438 If TERMINAL is non-nil and specifies a live frame, return the child
1439 frames of that frame in Z (stacking) order.
1441 Frames are listed from topmost (first) to bottommost (last).  */)
1442   (Lisp_Object terminal)
1444   Lisp_Object frames = Qnil;
1445   NSWindow *parent = nil;
1447   if (FRAMEP (terminal) && FRAME_LIVE_P (XFRAME (terminal)))
1448     parent = [FRAME_NS_VIEW (XFRAME (terminal)) window];
1450   for (NSWindow *win in [[NSApp orderedWindows] reverseObjectEnumerator])
1451     {
1452       Lisp_Object frame;
1454       /* Check against [win parentWindow] so that it doesn't match
1455          itself.  */
1456       if (parent == nil || ns_window_is_ancestor (parent, [win parentWindow]))
1457         {
1458           XSETFRAME (frame, ((EmacsView *)[win delegate])->emacsframe);
1459           frames = Fcons(frame, frames);
1460         }
1461     }
1463   return frames;
1466 DEFUN ("ns-frame-restack", Fns_frame_restack, Sns_frame_restack, 2, 3, 0,
1467        doc: /* Restack FRAME1 below FRAME2.
1468 This means that if both frames are visible and the display areas of
1469 these frames overlap, FRAME2 (partially) obscures FRAME1.  If optional
1470 third argument ABOVE is non-nil, restack FRAME1 above FRAME2.  This
1471 means that if both frames are visible and the display areas of these
1472 frames overlap, FRAME1 (partially) obscures FRAME2.
1474 Some window managers may refuse to restack windows.  */)
1475      (Lisp_Object frame1, Lisp_Object frame2, Lisp_Object above)
1477   struct frame *f1 = decode_live_frame (frame1);
1478   struct frame *f2 = decode_live_frame (frame2);
1480   if (FRAME_NS_VIEW (f1) && FRAME_NS_VIEW (f2))
1481     {
1482       NSWindow *window = [FRAME_NS_VIEW (f1) window];
1483       NSInteger window2 = [[FRAME_NS_VIEW (f2) window] windowNumber];
1484       NSWindowOrderingMode flag = NILP (above) ? NSWindowBelow : NSWindowAbove;
1486       [window orderWindow: flag
1487                relativeTo: window2];
1489       return Qt;
1490     }
1491   else
1492     {
1493       error ("Cannot restack frames");
1494       return Qnil;
1495     }
1498 DEFUN ("ns-popup-font-panel", Fns_popup_font_panel, Sns_popup_font_panel,
1499        0, 1, "",
1500        doc: /* Pop up the font panel.  */)
1501      (Lisp_Object frame)
1503   struct frame *f = decode_window_system_frame (frame);
1504   id fm = [NSFontManager sharedFontManager];
1505   struct font *font = f->output_data.ns->font;
1506   NSFont *nsfont;
1507 #ifdef NS_IMPL_GNUSTEP
1508   nsfont = ((struct nsfont_info *)font)->nsfont;
1509 #endif
1510 #ifdef NS_IMPL_COCOA
1511   nsfont = (NSFont *) macfont_get_nsctfont (font);
1512 #endif
1513   [fm setSelectedFont: nsfont isMultiple: NO];
1514   [fm orderFrontFontPanel: NSApp];
1515   return Qnil;
1519 DEFUN ("ns-popup-color-panel", Fns_popup_color_panel, Sns_popup_color_panel,
1520        0, 1, "",
1521        doc: /* Pop up the color panel.  */)
1522      (Lisp_Object frame)
1524   check_window_system (NULL);
1525   [NSApp orderFrontColorPanel: NSApp];
1526   return Qnil;
1529 static struct
1531   id panel;
1532   BOOL ret;
1533 #ifdef NS_IMPL_GNUSTEP
1534   NSString *dirS, *initS;
1535   BOOL no_types;
1536 #endif
1537 } ns_fd_data;
1539 void
1540 ns_run_file_dialog (void)
1542   if (ns_fd_data.panel == nil) return;
1543 #ifdef NS_IMPL_COCOA
1544   ns_fd_data.ret = [ns_fd_data.panel runModal];
1545 #else
1546   if (ns_fd_data.no_types)
1547     {
1548       ns_fd_data.ret = [ns_fd_data.panel
1549                            runModalForDirectory: ns_fd_data.dirS
1550                            file: ns_fd_data.initS];
1551     }
1552   else
1553     {
1554       ns_fd_data.ret = [ns_fd_data.panel
1555                            runModalForDirectory: ns_fd_data.dirS
1556                            file: ns_fd_data.initS
1557                            types: nil];
1558     }
1559 #endif
1560   ns_fd_data.panel = nil;
1563 #ifdef NS_IMPL_COCOA
1564 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
1565 #define MODAL_OK_RESPONSE NSModalResponseOK
1566 #endif
1567 #endif
1568 #ifndef MODAL_OK_RESPONSE
1569 #define MODAL_OK_RESPONSE NSOKButton
1570 #endif
1572 DEFUN ("ns-read-file-name", Fns_read_file_name, Sns_read_file_name, 1, 5, 0,
1573        doc: /* Use a graphical panel to read a file name, using prompt PROMPT.
1574 Optional arg DIR, if non-nil, supplies a default directory.
1575 Optional arg MUSTMATCH, if non-nil, means the returned file or
1576 directory must exist.
1577 Optional arg INIT, if non-nil, provides a default file name to use.
1578 Optional arg DIR_ONLY_P, if non-nil, means choose only directories.  */)
1579   (Lisp_Object prompt, Lisp_Object dir, Lisp_Object mustmatch,
1580    Lisp_Object init, Lisp_Object dir_only_p)
1582   static id fileDelegate = nil;
1583   BOOL isSave = NILP (mustmatch) && NILP (dir_only_p);
1584   id panel;
1585   Lisp_Object fname = Qnil;
1587   NSString *promptS = NILP (prompt) || !STRINGP (prompt) ? nil :
1588     [NSString stringWithUTF8String: SSDATA (prompt)];
1589   NSString *dirS = NILP (dir) || !STRINGP (dir) ?
1590     [NSString stringWithUTF8String: SSDATA (BVAR (current_buffer, directory))] :
1591     [NSString stringWithUTF8String: SSDATA (dir)];
1592   NSString *initS = NILP (init) || !STRINGP (init) ? nil :
1593     [NSString stringWithUTF8String: SSDATA (init)];
1594   NSEvent *nxev;
1596   check_window_system (NULL);
1598   if (fileDelegate == nil)
1599     fileDelegate = [EmacsFileDelegate new];
1601   [NSCursor setHiddenUntilMouseMoves: NO];
1603   if ([dirS characterAtIndex: 0] == '~')
1604     dirS = [dirS stringByExpandingTildeInPath];
1606   panel = isSave ?
1607     (id)[EmacsSavePanel savePanel] : (id)[EmacsOpenPanel openPanel];
1609   [panel setTitle: promptS];
1611   [panel setAllowsOtherFileTypes: YES];
1612   [panel setTreatsFilePackagesAsDirectories: YES];
1613   [panel setDelegate: fileDelegate];
1615   if (! NILP (dir_only_p))
1616     {
1617       [panel setCanChooseDirectories: YES];
1618       [panel setCanChooseFiles: NO];
1619     }
1620   else if (! isSave)
1621     {
1622       /* This is not quite what the documentation says, but it is compatible
1623          with the Gtk+ code.  Also, the menu entry says "Open File...".  */
1624       [panel setCanChooseDirectories: NO];
1625       [panel setCanChooseFiles: YES];
1626     }
1628   block_input ();
1629   ns_fd_data.panel = panel;
1630   ns_fd_data.ret = NO;
1631 #ifdef NS_IMPL_COCOA
1632   if (! NILP (mustmatch) || ! NILP (dir_only_p))
1633     [panel setAllowedFileTypes: nil];
1634   if (dirS) [panel setDirectoryURL: [NSURL fileURLWithPath: dirS]];
1635   if (initS && NILP (Ffile_directory_p (init)))
1636     [panel setNameFieldStringValue: [initS lastPathComponent]];
1637   else
1638     [panel setNameFieldStringValue: @""];
1640 #else
1641   ns_fd_data.no_types = NILP (mustmatch) && NILP (dir_only_p);
1642   ns_fd_data.dirS = dirS;
1643   ns_fd_data.initS = initS;
1644 #endif
1646   /* runModalForDirectory/runModal restarts the main event loop when done,
1647      so we must start an event loop and then pop up the file dialog.
1648      The file dialog may pop up a confirm dialog after Ok has been pressed,
1649      so we can not simply pop down on the Ok/Cancel press.
1650    */
1651   nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
1652                             location: NSMakePoint (0, 0)
1653                        modifierFlags: 0
1654                            timestamp: 0
1655                         windowNumber: [[NSApp mainWindow] windowNumber]
1656                              context: [NSApp context]
1657                              subtype: 0
1658                                data1: 0
1659                                data2: NSAPP_DATA2_RUNFILEDIALOG];
1661   [NSApp postEvent: nxev atStart: NO];
1662   while (ns_fd_data.panel != nil)
1663     [NSApp run];
1665   if (ns_fd_data.ret == MODAL_OK_RESPONSE)
1666     {
1667       NSString *str = ns_filename_from_panel (panel);
1668       if (! str) str = ns_directory_from_panel (panel);
1669       if (str) fname = build_string ([str UTF8String]);
1670     }
1672   [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
1673   unblock_input ();
1675   return fname;
1678 const char *
1679 ns_get_defaults_value (const char *key)
1681   NSObject *obj = [[NSUserDefaults standardUserDefaults]
1682                     objectForKey: [NSString stringWithUTF8String: key]];
1684   if (!obj) return NULL;
1686   return [[NSString stringWithFormat: @"%@", obj] UTF8String];
1690 DEFUN ("ns-get-resource", Fns_get_resource, Sns_get_resource, 2, 2, 0,
1691        doc: /* Return the value of the property NAME of OWNER from the defaults database.
1692 If OWNER is nil, Emacs is assumed.  */)
1693      (Lisp_Object owner, Lisp_Object name)
1695   const char *value;
1697   check_window_system (NULL);
1698   if (NILP (owner))
1699     owner = build_string([ns_app_name UTF8String]);
1700   CHECK_STRING (name);
1702   value = ns_get_defaults_value (SSDATA (name));
1704   if (value)
1705     return build_string (value);
1706   return Qnil;
1710 DEFUN ("ns-set-resource", Fns_set_resource, Sns_set_resource, 3, 3, 0,
1711        doc: /* Set property NAME of OWNER to VALUE, from the defaults database.
1712 If OWNER is nil, Emacs is assumed.
1713 If VALUE is nil, the default is removed.  */)
1714      (Lisp_Object owner, Lisp_Object name, Lisp_Object value)
1716   check_window_system (NULL);
1717   if (NILP (owner))
1718     owner = build_string ([ns_app_name UTF8String]);
1719   CHECK_STRING (name);
1720   if (NILP (value))
1721     {
1722       [[NSUserDefaults standardUserDefaults] removeObjectForKey:
1723                          [NSString stringWithUTF8String: SSDATA (name)]];
1724     }
1725   else
1726     {
1727       CHECK_STRING (value);
1728       [[NSUserDefaults standardUserDefaults] setObject:
1729                 [NSString stringWithUTF8String: SSDATA (value)]
1730                                         forKey: [NSString stringWithUTF8String:
1731                                                          SSDATA (name)]];
1732     }
1734   return Qnil;
1738 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
1739        Sx_server_max_request_size,
1740        0, 1, 0,
1741        doc: /* SKIP: real doc in xfns.c.  */)
1742      (Lisp_Object terminal)
1744   check_ns_display_info (terminal);
1745   /* This function has no real equivalent under Nextstep.  Return nil to
1746      indicate this.  */
1747   return Qnil;
1751 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
1752        doc: /* SKIP: real doc in xfns.c.  */)
1753   (Lisp_Object terminal)
1755   check_ns_display_info (terminal);
1756 #ifdef NS_IMPL_GNUSTEP
1757   return build_string ("GNU");
1758 #else
1759   return build_string ("Apple");
1760 #endif
1764 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
1765        doc: /* SKIP: real doc in xfns.c.  */)
1766   (Lisp_Object terminal)
1768   check_ns_display_info (terminal);
1769   /* NOTE: it is unclear what would best correspond with "protocol";
1770            we return 10.3, meaning Panther, since this is roughly the
1771            level that GNUstep's APIs correspond to.  The last number
1772            is where we distinguish between the Apple and GNUstep
1773            implementations ("distributor-specific release number") and
1774            give int'ized versions of major.minor.  */
1775   return list3i (10, 3, ns_appkit_version_int ());
1779 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
1780        doc: /* SKIP: real doc in xfns.c.  */)
1781   (Lisp_Object terminal)
1783   check_ns_display_info (terminal);
1784   return make_number (1);
1788 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
1789        doc: /* SKIP: real doc in xfns.c.  */)
1790   (Lisp_Object terminal)
1792   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
1794   return make_number (x_display_pixel_height (dpyinfo) / (92.0/25.4));
1798 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
1799        doc: /* SKIP: real doc in xfns.c.  */)
1800   (Lisp_Object terminal)
1802   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
1804   return make_number (x_display_pixel_width (dpyinfo) / (92.0/25.4));
1808 DEFUN ("x-display-backing-store", Fx_display_backing_store,
1809        Sx_display_backing_store, 0, 1, 0,
1810        doc: /* SKIP: real doc in xfns.c.  */)
1811   (Lisp_Object terminal)
1813   check_ns_display_info (terminal);
1814   /* Note that the xfns.c version has different return values.  */
1815   switch ([ns_get_window (terminal) backingType])
1816     {
1817     case NSBackingStoreBuffered:
1818       return intern ("buffered");
1819 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300
1820     case NSBackingStoreRetained:
1821       return intern ("retained");
1822     case NSBackingStoreNonretained:
1823       return intern ("non-retained");
1824 #endif
1825     default:
1826       error ("Strange value for backingType parameter of frame");
1827     }
1828   return Qnil;  /* not reached, shut compiler up */
1832 DEFUN ("x-display-visual-class", Fx_display_visual_class,
1833        Sx_display_visual_class, 0, 1, 0,
1834        doc: /* SKIP: real doc in xfns.c.  */)
1835   (Lisp_Object terminal)
1837   NSWindowDepth depth;
1839   check_ns_display_info (terminal);
1840   depth = [[[NSScreen screens] objectAtIndex:0] depth];
1842   if ( depth == NSBestDepth (NSCalibratedWhiteColorSpace, 2, 2, YES, NULL))
1843     return intern ("static-gray");
1844   else if (depth == NSBestDepth (NSCalibratedWhiteColorSpace, 8, 8, YES, NULL))
1845     return intern ("gray-scale");
1846   else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 8, 8, YES, NULL))
1847     return intern ("pseudo-color");
1848   else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 4, 12, NO, NULL))
1849     return intern ("true-color");
1850   else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 8, 24, NO, NULL))
1851     return intern ("direct-color");
1852   else
1853     /* Color management as far as we do it is really handled by
1854        Nextstep itself anyway.  */
1855     return intern ("direct-color");
1859 DEFUN ("x-display-save-under", Fx_display_save_under,
1860        Sx_display_save_under, 0, 1, 0,
1861        doc: /* SKIP: real doc in xfns.c.  */)
1862   (Lisp_Object terminal)
1864   check_ns_display_info (terminal);
1865   switch ([ns_get_window (terminal) backingType])
1866     {
1867     case NSBackingStoreBuffered:
1868       return Qt;
1870 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300
1871     case NSBackingStoreRetained:
1872     case NSBackingStoreNonretained:
1873       return Qnil;
1874 #endif
1876     default:
1877       error ("Strange value for backingType parameter of frame");
1878     }
1879   return Qnil;  /* not reached, shut compiler up */
1883 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
1884        1, 3, 0,
1885        doc: /* SKIP: real doc in xfns.c.  */)
1886      (Lisp_Object display, Lisp_Object resource_string, Lisp_Object must_succeed)
1888   struct ns_display_info *dpyinfo;
1890   CHECK_STRING (display);
1892   nxatoms_of_nsselect ();
1893   dpyinfo = ns_term_init (display);
1894   if (dpyinfo == 0)
1895     {
1896       if (!NILP (must_succeed))
1897         fatal ("Display on %s not responding.\n",
1898                SSDATA (display));
1899       else
1900         error ("Display on %s not responding.\n",
1901                SSDATA (display));
1902     }
1904   return Qnil;
1908 DEFUN ("x-close-connection", Fx_close_connection, Sx_close_connection,
1909        1, 1, 0,
1910        doc: /* SKIP: real doc in xfns.c.  */)
1911      (Lisp_Object terminal)
1913   check_ns_display_info (terminal);
1914   [NSApp terminate: NSApp];
1915   return Qnil;
1919 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
1920        doc: /* SKIP: real doc in xfns.c.  */)
1921      (void)
1923   Lisp_Object result = Qnil;
1924   struct ns_display_info *ndi;
1926   for (ndi = x_display_list; ndi; ndi = ndi->next)
1927     result = Fcons (XCAR (ndi->name_list_element), result);
1929   return result;
1933 DEFUN ("ns-hide-others", Fns_hide_others, Sns_hide_others,
1934        0, 0, 0,
1935        doc: /* Hides all applications other than Emacs.  */)
1936      (void)
1938   check_window_system (NULL);
1939   [NSApp hideOtherApplications: NSApp];
1940   return Qnil;
1943 DEFUN ("ns-hide-emacs", Fns_hide_emacs, Sns_hide_emacs,
1944        1, 1, 0,
1945        doc: /* If ON is non-nil, the entire Emacs application is hidden.
1946 Otherwise if Emacs is hidden, it is unhidden.
1947 If ON is equal to `activate', Emacs is unhidden and becomes
1948 the active application.  */)
1949      (Lisp_Object on)
1951   check_window_system (NULL);
1952   if (EQ (on, intern ("activate")))
1953     {
1954       [NSApp unhide: NSApp];
1955       [NSApp activateIgnoringOtherApps: YES];
1956     }
1957   else if (NILP (on))
1958     [NSApp unhide: NSApp];
1959   else
1960     [NSApp hide: NSApp];
1961   return Qnil;
1965 DEFUN ("ns-emacs-info-panel", Fns_emacs_info_panel, Sns_emacs_info_panel,
1966        0, 0, 0,
1967        doc: /* Shows the 'Info' or 'About' panel for Emacs.  */)
1968      (void)
1970   check_window_system (NULL);
1971   [NSApp orderFrontStandardAboutPanel: nil];
1972   return Qnil;
1976 DEFUN ("ns-font-name", Fns_font_name, Sns_font_name, 1, 1, 0,
1977        doc: /* Determine font PostScript or family name for font NAME.
1978 NAME should be a string containing either the font name or an XLFD
1979 font descriptor.  If string contains `fontset' and not
1980 `fontset-startup', it is left alone.  */)
1981      (Lisp_Object name)
1983   char *nm;
1984   CHECK_STRING (name);
1985   nm = SSDATA (name);
1987   if (nm[0] != '-')
1988     return name;
1989   if (strstr (nm, "fontset") && !strstr (nm, "fontset-startup"))
1990     return name;
1992   return build_string (ns_xlfd_to_fontname (SSDATA (name)));
1996 DEFUN ("ns-list-colors", Fns_list_colors, Sns_list_colors, 0, 1, 0,
1997        doc: /* Return a list of all available colors.
1998 The optional argument FRAME is currently ignored.  */)
1999      (Lisp_Object frame)
2001   Lisp_Object list = Qnil;
2002   NSEnumerator *colorlists;
2003   NSColorList *clist;
2005   if (!NILP (frame))
2006     {
2007       CHECK_FRAME (frame);
2008       if (! FRAME_NS_P (XFRAME (frame)))
2009         error ("non-Nextstep frame used in `ns-list-colors'");
2010     }
2012   block_input ();
2014   colorlists = [[NSColorList availableColorLists] objectEnumerator];
2015   while ((clist = [colorlists nextObject]))
2016     {
2017       if ([[clist name] length] < 7 ||
2018           [[clist name] rangeOfString: @"PANTONE"].location == 0)
2019         {
2020           NSEnumerator *cnames = [[clist allKeys] reverseObjectEnumerator];
2021           NSString *cname;
2022           while ((cname = [cnames nextObject]))
2023             list = Fcons (build_string ([cname UTF8String]), list);
2024 /*           for (i = [[clist allKeys] count] - 1; i >= 0; i--)
2025                list = Fcons (build_string ([[[clist allKeys] objectAtIndex: i]
2026                                              UTF8String]), list); */
2027         }
2028     }
2030   unblock_input ();
2032   return list;
2036 DEFUN ("ns-list-services", Fns_list_services, Sns_list_services, 0, 0, 0,
2037        doc: /* List available Nextstep services by querying NSApp.  */)
2038      (void)
2040 #ifdef NS_IMPL_COCOA
2041   /* You can't get services like this in 10.6+.  */
2042   return Qnil;
2043 #else
2044   Lisp_Object ret = Qnil;
2045   NSMenu *svcs;
2047   check_window_system (NULL);
2048   svcs = [[NSMenu alloc] initWithTitle: @"Services"];
2049   [NSApp setServicesMenu: svcs];
2050   [NSApp registerServicesMenuSendTypes: ns_send_types
2051                            returnTypes: ns_return_types];
2053   [svcs setAutoenablesItems: NO];
2055   ret = interpret_services_menu (svcs, Qnil, ret);
2056   return ret;
2057 #endif
2061 DEFUN ("ns-perform-service", Fns_perform_service, Sns_perform_service,
2062        2, 2, 0,
2063        doc: /* Perform Nextstep SERVICE on SEND.
2064 SEND should be either a string or nil.
2065 The return value is the result of the service, as string, or nil if
2066 there was no result.  */)
2067      (Lisp_Object service, Lisp_Object send)
2069   id pb;
2070   NSString *svcName;
2071   char *utfStr;
2073   CHECK_STRING (service);
2074   check_window_system (NULL);
2076   utfStr = SSDATA (service);
2077   svcName = [NSString stringWithUTF8String: utfStr];
2079   pb =[NSPasteboard pasteboardWithUniqueName];
2080   ns_string_to_pasteboard (pb, send);
2082   if (NSPerformService (svcName, pb) == NO)
2083     Fsignal (Qquit, list1 (build_string ("service not available")));
2085   if ([[pb types] count] == 0)
2086     return build_string ("");
2087   return ns_string_from_pasteboard (pb);
2091 #ifdef NS_IMPL_COCOA
2093 /* Compile and execute the AppleScript SCRIPT and return the error
2094    status as function value.  A zero is returned if compilation and
2095    execution is successful, in which case *RESULT is set to a Lisp
2096    string or a number containing the resulting script value.  Otherwise,
2097    1 is returned.  */
2098 static int
2099 ns_do_applescript (Lisp_Object script, Lisp_Object *result)
2101   NSAppleEventDescriptor *desc;
2102   NSDictionary *errorDict;
2103   NSAppleEventDescriptor *returnDescriptor = NULL;
2105   NSAppleScript *scriptObject =
2106     [[NSAppleScript alloc] initWithSource:
2107                              [NSString stringWithUTF8String: SSDATA (script)]];
2109   returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
2110   [scriptObject release];
2111   *result = Qnil;
2113   if (returnDescriptor != NULL)
2114     {
2115       // successful execution
2116       if (kAENullEvent != [returnDescriptor descriptorType])
2117         {
2118           *result = Qt;
2119           // script returned an AppleScript result
2120           if ((typeUnicodeText == [returnDescriptor descriptorType]) ||
2121 #if defined (NS_IMPL_COCOA)
2122               (typeUTF16ExternalRepresentation
2123                == [returnDescriptor descriptorType]) ||
2124 #endif
2125               (typeUTF8Text == [returnDescriptor descriptorType]) ||
2126               (typeCString == [returnDescriptor descriptorType]))
2127             {
2128               desc = [returnDescriptor coerceToDescriptorType: typeUTF8Text];
2129               if (desc)
2130                 *result = build_string([[desc stringValue] UTF8String]);
2131             }
2132           else
2133             {
2134               /* use typeUTF16ExternalRepresentation? */
2135               // coerce the result to the appropriate ObjC type
2136               desc = [returnDescriptor coerceToDescriptorType: typeUTF8Text];
2137               if (desc)
2138                 *result = make_number([desc int32Value]);
2139             }
2140         }
2141     }
2142   else
2143     {
2144       // no script result, return error
2145       return 1;
2146     }
2147   return 0;
2150 /* Helper function called from sendEvent to run AppleScript
2151    from within the main event loop.  */
2153 void
2154 ns_run_ascript (void)
2156   if (! NILP (as_script))
2157     as_status = ns_do_applescript (as_script, as_result);
2158   as_script = Qnil;
2161 DEFUN ("ns-do-applescript", Fns_do_applescript, Sns_do_applescript, 1, 1, 0,
2162        doc: /* Execute AppleScript SCRIPT and return the result.
2163 If compilation and execution are successful, the resulting script value
2164 is returned as a string, a number or, in the case of other constructs, t.
2165 In case the execution fails, an error is signaled.  */)
2166      (Lisp_Object script)
2168   Lisp_Object result;
2169   int status;
2170   NSEvent *nxev;
2171   struct input_event ev;
2173   CHECK_STRING (script);
2174   check_window_system (NULL);
2176   block_input ();
2178   as_script = script;
2179   as_result = &result;
2181   /* Executing AppleScript requires the event loop to run, otherwise
2182      errors aren't returned and executeAndReturnError hangs forever.
2183      Post an event that runs AppleScript and then start the event
2184      loop.  The event loop is exited when the script is done.  */
2185   nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
2186                             location: NSMakePoint (0, 0)
2187                        modifierFlags: 0
2188                            timestamp: 0
2189                         windowNumber: [[NSApp mainWindow] windowNumber]
2190                              context: [NSApp context]
2191                              subtype: 0
2192                                data1: 0
2193                                data2: NSAPP_DATA2_RUNASSCRIPT];
2195   [NSApp postEvent: nxev atStart: NO];
2197   /* If there are other events, the event loop may exit.  Keep running
2198      until the script has been handled.  */
2199   ns_init_events (&ev);
2200   while (! NILP (as_script))
2201     [NSApp run];
2202   ns_finish_events ();
2204   status = as_status;
2205   as_status = 0;
2206   as_result = 0;
2207   unblock_input ();
2208   if (status == 0)
2209     return result;
2210   else if (!STRINGP (result))
2211     error ("AppleScript error %d", status);
2212   else
2213     error ("%s", SSDATA (result));
2215 #endif
2219 /* ==========================================================================
2221     Miscellaneous functions not called through hooks
2223    ========================================================================== */
2225 /* called from frame.c */
2226 struct ns_display_info *
2227 check_x_display_info (Lisp_Object frame)
2229   return check_ns_display_info (frame);
2233 void
2234 x_set_scroll_bar_default_width (struct frame *f)
2236   int wid = FRAME_COLUMN_WIDTH (f);
2237   FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = NS_SCROLL_BAR_WIDTH_DEFAULT;
2238   FRAME_CONFIG_SCROLL_BAR_COLS (f) = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) +
2239                                       wid - 1) / wid;
2242 void
2243 x_set_scroll_bar_default_height (struct frame *f)
2245   int height = FRAME_LINE_HEIGHT (f);
2246   FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = NS_SCROLL_BAR_WIDTH_DEFAULT;
2247   FRAME_CONFIG_SCROLL_BAR_LINES (f) = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) +
2248                                        height - 1) / height;
2251 /* Terms implement this instead of x-get-resource directly.  */
2252 char *
2253 x_get_string_resource (XrmDatabase rdb, const char *name, const char *class)
2255   /* remove appname prefix; TODO: allow for !="Emacs" */
2256   const char *res, *toCheck = class + (!strncmp (class, "Emacs.", 6) ? 6 : 0);
2258   check_window_system (NULL);
2260   if (inhibit_x_resources)
2261     /* --quick was passed, so this is a no-op.  */
2262     return NULL;
2264   res = ns_get_defaults_value (toCheck);
2265   return (char *) (!res ? NULL
2266                    : !c_strncasecmp (res, "YES", 3) ? "true"
2267                    : !c_strncasecmp (res, "NO", 2) ? "false"
2268                    : res);
2272 Lisp_Object
2273 x_get_focus_frame (struct frame *frame)
2275   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2276   Lisp_Object nsfocus;
2278   if (!dpyinfo->x_focus_frame)
2279     return Qnil;
2281   XSETFRAME (nsfocus, dpyinfo->x_focus_frame);
2282   return nsfocus;
2285 /* ==========================================================================
2287     Lisp definitions that, for whatever reason, we can't alias as 'ns-XXX'.
2289    ========================================================================== */
2292 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
2293        doc: /* SKIP: real doc in xfns.c.  */)
2294      (Lisp_Object color, Lisp_Object frame)
2296   NSColor * col;
2297   check_window_system (NULL);
2298   return ns_lisp_to_color (color, &col) ? Qnil : Qt;
2302 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
2303        doc: /* SKIP: real doc in xfns.c.  */)
2304      (Lisp_Object color, Lisp_Object frame)
2306   NSColor * col;
2307   EmacsCGFloat red, green, blue, alpha;
2309   check_window_system (NULL);
2310   CHECK_STRING (color);
2312   block_input ();
2313   if (ns_lisp_to_color (color, &col))
2314     {
2315       unblock_input ();
2316       return Qnil;
2317     }
2319   [[col colorUsingDefaultColorSpace]
2320         getRed: &red green: &green blue: &blue alpha: &alpha];
2321   unblock_input ();
2322   return list3i (lrint (red * 65280), lrint (green * 65280),
2323                  lrint (blue * 65280));
2327 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
2328        doc: /* SKIP: real doc in xfns.c.  */)
2329      (Lisp_Object terminal)
2331   NSWindowDepth depth;
2332   NSString *colorSpace;
2334   check_ns_display_info (terminal);
2335   depth = [[[NSScreen screens] objectAtIndex:0] depth];
2336   colorSpace = NSColorSpaceFromDepth (depth);
2338   return    [colorSpace isEqualToString: NSDeviceWhiteColorSpace]
2339          || [colorSpace isEqualToString: NSCalibratedWhiteColorSpace]
2340       ? Qnil : Qt;
2344 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
2345        0, 1, 0,
2346        doc: /* SKIP: real doc in xfns.c.  */)
2347   (Lisp_Object terminal)
2349   NSWindowDepth depth;
2351   check_ns_display_info (terminal);
2352   depth = [[[NSScreen screens] objectAtIndex:0] depth];
2354   return NSBitsPerPixelFromDepth (depth) > 1 ? Qt : Qnil;
2358 DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
2359        0, 1, 0,
2360        doc: /* SKIP: real doc in xfns.c.  */)
2361   (Lisp_Object terminal)
2363   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
2365   return make_number (x_display_pixel_width (dpyinfo));
2369 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
2370        Sx_display_pixel_height, 0, 1, 0,
2371        doc: /* SKIP: real doc in xfns.c.  */)
2372   (Lisp_Object terminal)
2374   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
2376   return make_number (x_display_pixel_height (dpyinfo));
2379 #ifdef NS_IMPL_COCOA
2381 /* Returns the name for the screen that OBJ represents, or NULL.
2382    Caller must free return value.
2385 static char *
2386 ns_get_name_from_ioreg (io_object_t obj)
2388   char *name = NULL;
2390   NSDictionary *info = (NSDictionary *)
2391     IODisplayCreateInfoDictionary (obj, kIODisplayOnlyPreferredName);
2392   NSDictionary *names = [info objectForKey:
2393                                 [NSString stringWithUTF8String:
2394                                             kDisplayProductName]];
2396   if ([names count] > 0)
2397     {
2398       NSString *n = [names objectForKey: [[names allKeys]
2399                                                  objectAtIndex:0]];
2400       if (n != nil) name = xstrdup ([n UTF8String]);
2401     }
2403   [info release];
2405   return name;
2408 /* Returns the name for the screen that DID came from, or NULL.
2409    Caller must free return value.
2412 static char *
2413 ns_screen_name (CGDirectDisplayID did)
2415   char *name = NULL;
2417 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
2418 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
2419   if (CGDisplayIOServicePort == NULL)
2420 #endif
2421     {
2422       mach_port_t masterPort;
2423       io_iterator_t it;
2424       io_object_t obj;
2426       /* CGDisplayIOServicePort is deprecated.  Do it another (harder) way.
2428          Is this code OK for macOS < 10.9, and GNUstep?  I suspect it is,
2429          in which case is it worth keeping the other method in here?  */
2431       if (IOMasterPort (MACH_PORT_NULL, &masterPort) != kIOReturnSuccess
2432           || IOServiceGetMatchingServices (masterPort,
2433                                            IOServiceMatching ("IONDRVDevice"),
2434                                            &it) != kIOReturnSuccess)
2435         return name;
2437       /* Must loop until we find a name.  Many devices can have the same unit
2438          number (represents different GPU parts), but only one has a name.  */
2439       while (! name && (obj = IOIteratorNext (it)))
2440         {
2441           CFMutableDictionaryRef props;
2442           const void *val;
2444           if (IORegistryEntryCreateCFProperties (obj,
2445                                                  &props,
2446                                                  kCFAllocatorDefault,
2447                                                  kNilOptions) == kIOReturnSuccess
2448               && props != nil
2449               && (val = CFDictionaryGetValue(props, @"IOFBDependentIndex")))
2450             {
2451               unsigned nr = [(NSNumber *)val unsignedIntegerValue];
2452               if (nr == CGDisplayUnitNumber (did))
2453                 name = ns_get_name_from_ioreg (obj);
2454             }
2456           CFRelease (props);
2457           IOObjectRelease (obj);
2458         }
2460       IOObjectRelease (it);
2461     }
2462 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
2463   else
2464 #endif
2465 #endif /* #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
2466 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
2467     name = ns_get_name_from_ioreg (CGDisplayIOServicePort (did));
2468 #endif
2469   return name;
2471 #endif /* NS_IMPL_COCOA */
2473 static Lisp_Object
2474 ns_make_monitor_attribute_list (struct MonitorInfo *monitors,
2475                                 int n_monitors,
2476                                 int primary_monitor,
2477                                 const char *source)
2479   Lisp_Object monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
2480   Lisp_Object frame, rest;
2481   NSArray *screens = [NSScreen screens];
2482   int i;
2484   FOR_EACH_FRAME (rest, frame)
2485     {
2486       struct frame *f = XFRAME (frame);
2488       if (FRAME_NS_P (f))
2489         {
2490           NSView *view = FRAME_NS_VIEW (f);
2491           NSScreen *screen = [[view window] screen];
2492           NSUInteger k;
2494           i = -1;
2495           for (k = 0; i == -1 && k < [screens count]; ++k)
2496             {
2497               if ([screens objectAtIndex: k] == screen)
2498                 i = (int)k;
2499             }
2501           if (i > -1)
2502             ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
2503         }
2504     }
2506   return make_monitor_attribute_list (monitors, n_monitors, primary_monitor,
2507                                       monitor_frames, source);
2510 DEFUN ("ns-display-monitor-attributes-list",
2511        Fns_display_monitor_attributes_list,
2512        Sns_display_monitor_attributes_list,
2513        0, 1, 0,
2514        doc: /* Return a list of physical monitor attributes on the X display TERMINAL.
2516 The optional argument TERMINAL specifies which display to ask about.
2517 TERMINAL should be a terminal object, a frame or a display name (a string).
2518 If omitted or nil, that stands for the selected frame's display.
2520 In addition to the standard attribute keys listed in
2521 `display-monitor-attributes-list', the following keys are contained in
2522 the attributes:
2524  source -- String describing the source from which multi-monitor
2525            information is obtained, \"NS\" is always the source."
2527 Internal use only, use `display-monitor-attributes-list' instead.  */)
2528   (Lisp_Object terminal)
2530   struct terminal *term = decode_live_terminal (terminal);
2531   NSArray *screens;
2532   NSUInteger i, n_monitors;
2533   struct MonitorInfo *monitors;
2534   Lisp_Object attributes_list = Qnil;
2535   CGFloat primary_display_height = 0;
2537   if (term->type != output_ns)
2538     return Qnil;
2540   screens = [NSScreen screens];
2541   n_monitors = [screens count];
2542   if (n_monitors == 0)
2543     return Qnil;
2545   monitors = xzalloc (n_monitors * sizeof *monitors);
2547   for (i = 0; i < [screens count]; ++i)
2548     {
2549       NSScreen *s = [screens objectAtIndex:i];
2550       struct MonitorInfo *m = &monitors[i];
2551       NSRect fr = [s frame];
2552       NSRect vfr = [s visibleFrame];
2553       short y, vy;
2555 #ifdef NS_IMPL_COCOA
2556       NSDictionary *dict = [s deviceDescription];
2557       NSNumber *nid = [dict objectForKey:@"NSScreenNumber"];
2558       CGDirectDisplayID did = [nid unsignedIntValue];
2559 #endif
2560       if (i == 0)
2561         {
2562           primary_display_height = fr.size.height;
2563           y = (short) fr.origin.y;
2564           vy = (short) vfr.origin.y;
2565         }
2566       else
2567         {
2568           // Flip y coordinate as NS has y starting from the bottom.
2569           y = (short) (primary_display_height - fr.size.height - fr.origin.y);
2570           vy = (short) (primary_display_height -
2571                         vfr.size.height - vfr.origin.y);
2572         }
2574       m->geom.x = (short) fr.origin.x;
2575       m->geom.y = y;
2576       m->geom.width = (unsigned short) fr.size.width;
2577       m->geom.height = (unsigned short) fr.size.height;
2579       m->work.x = (short) vfr.origin.x;
2580       // y is flipped on NS, so vy - y are pixels missing at the bottom,
2581       // and fr.size.height - vfr.size.height are pixels missing in total.
2582       // Pixels missing at top are
2583       // fr.size.height - vfr.size.height - vy + y.
2584       // work.y is then pixels missing at top + y.
2585       m->work.y = (short) (fr.size.height - vfr.size.height) - vy + y + y;
2586       m->work.width = (unsigned short) vfr.size.width;
2587       m->work.height = (unsigned short) vfr.size.height;
2589 #ifdef NS_IMPL_COCOA
2590       m->name = ns_screen_name (did);
2592       {
2593         CGSize mms = CGDisplayScreenSize (did);
2594         m->mm_width = (int) mms.width;
2595         m->mm_height = (int) mms.height;
2596       }
2598 #else
2599       // Assume 92 dpi as x-display-mm-height/x-display-mm-width does.
2600       m->mm_width = (int) (25.4 * fr.size.width / 92.0);
2601       m->mm_height = (int) (25.4 * fr.size.height / 92.0);
2602 #endif
2603     }
2605   // Primary monitor is always first for NS.
2606   attributes_list = ns_make_monitor_attribute_list (monitors, n_monitors,
2607                                                     0, "NS");
2609   free_monitors (monitors, n_monitors);
2610   return attributes_list;
2614 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
2615        0, 1, 0,
2616        doc: /* SKIP: real doc in xfns.c.  */)
2617   (Lisp_Object terminal)
2619   check_ns_display_info (terminal);
2620   return make_number
2621     (NSBitsPerPixelFromDepth ([[[NSScreen screens] objectAtIndex:0] depth]));
2625 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
2626        0, 1, 0,
2627        doc: /* SKIP: real doc in xfns.c.  */)
2628   (Lisp_Object terminal)
2630   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
2631   /* We force 24+ bit depths to 24-bit to prevent an overflow.  */
2632   return make_number (1 << min (dpyinfo->n_planes, 24));
2635 /* TODO: move to xdisp or similar */
2636 static void
2637 compute_tip_xy (struct frame *f,
2638                 Lisp_Object parms,
2639                 Lisp_Object dx,
2640                 Lisp_Object dy,
2641                 int width,
2642                 int height,
2643                 int *root_x,
2644                 int *root_y)
2646   Lisp_Object left, top, right, bottom;
2647   NSPoint pt;
2648   NSScreen *screen;
2650   /* Start with user-specified or mouse position.  */
2651   left = Fcdr (Fassq (Qleft, parms));
2652   top = Fcdr (Fassq (Qtop, parms));
2653   right = Fcdr (Fassq (Qright, parms));
2654   bottom = Fcdr (Fassq (Qbottom, parms));
2656   if ((!INTEGERP (left) && !INTEGERP (right))
2657       || (!INTEGERP (top) && !INTEGERP (bottom)))
2658     pt = [NSEvent mouseLocation];
2659   else
2660     {
2661       /* Absolute coordinates.  */
2662       pt.x = INTEGERP (left) ? XINT (left) : XINT (right);
2663       pt.y = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
2664               - (INTEGERP (top) ? XINT (top) : XINT (bottom))
2665               - height);
2666     }
2668   /* Find the screen that pt is on.  */
2669   for (screen in [NSScreen screens])
2670     if (pt.x >= screen.frame.origin.x
2671         && pt.x < screen.frame.origin.x + screen.frame.size.width
2672         && pt.y >= screen.frame.origin.y
2673         && pt.y < screen.frame.origin.y + screen.frame.size.height)
2674       break;
2676   /* We could use this instead of the if above:
2678          if (CGRectContainsPoint ([screen frame], pt))
2680      which would be neater, but it causes problems building on old
2681      versions of macOS and in GNUstep.  */
2683   /* Ensure in bounds.  (Note, screen origin = lower left.) */
2684   if (INTEGERP (left) || INTEGERP (right))
2685     *root_x = pt.x;
2686   else if (pt.x + XINT (dx) <= screen.frame.origin.x)
2687     *root_x = screen.frame.origin.x;
2688   else if (pt.x + XINT (dx) + width
2689            <= screen.frame.origin.x + screen.frame.size.width)
2690     /* It fits to the right of the pointer.  */
2691     *root_x = pt.x + XINT (dx);
2692   else if (width + XINT (dx) <= pt.x)
2693     /* It fits to the left of the pointer.  */
2694     *root_x = pt.x - width - XINT (dx);
2695   else
2696     /* Put it left justified on the screen -- it ought to fit that way.  */
2697     *root_x = screen.frame.origin.x;
2699   if (INTEGERP (top) || INTEGERP (bottom))
2700     *root_y = pt.y;
2701   else if (pt.y - XINT (dy) - height >= screen.frame.origin.y)
2702     /* It fits below the pointer.  */
2703     *root_y = pt.y - height - XINT (dy);
2704   else if (pt.y + XINT (dy) + height
2705            <= screen.frame.origin.y + screen.frame.size.height)
2706     /* It fits above the pointer.  */
2707       *root_y = pt.y + XINT (dy);
2708   else
2709     /* Put it on the top.  */
2710     *root_y = screen.frame.origin.y + screen.frame.size.height - height;
2714 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
2715        doc: /* SKIP: real doc in xfns.c.  */)
2716      (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
2718   int root_x, root_y;
2719   ptrdiff_t count = SPECPDL_INDEX ();
2720   struct frame *f;
2721   char *str;
2722   NSSize size;
2723   NSColor *color;
2724   Lisp_Object t;
2726   specbind (Qinhibit_redisplay, Qt);
2728   CHECK_STRING (string);
2729   str = SSDATA (string);
2730   f = decode_window_system_frame (frame);
2731   if (NILP (timeout))
2732     timeout = make_number (5);
2733   else
2734     CHECK_NATNUM (timeout);
2736   if (NILP (dx))
2737     dx = make_number (5);
2738   else
2739     CHECK_NUMBER (dx);
2741   if (NILP (dy))
2742     dy = make_number (-10);
2743   else
2744     CHECK_NUMBER (dy);
2746   block_input ();
2747   if (ns_tooltip == nil)
2748     ns_tooltip = [[EmacsTooltip alloc] init];
2749   else
2750     Fx_hide_tip ();
2752   t = x_get_arg (NULL, parms, Qbackground_color, NULL, NULL, RES_TYPE_STRING);
2753   if (ns_lisp_to_color (t, &color) == 0)
2754     [ns_tooltip setBackgroundColor: color];
2756   t = x_get_arg (NULL, parms, Qforeground_color, NULL, NULL, RES_TYPE_STRING);
2757   if (ns_lisp_to_color (t, &color) == 0)
2758     [ns_tooltip setForegroundColor: color];
2760   [ns_tooltip setText: str];
2761   size = [ns_tooltip frame].size;
2763   /* Move the tooltip window where the mouse pointer is.  Resize and
2764      show it.  */
2765   compute_tip_xy (f, parms, dx, dy, (int)size.width, (int)size.height,
2766                   &root_x, &root_y);
2768   [ns_tooltip showAtX: root_x Y: root_y for: XINT (timeout)];
2769   unblock_input ();
2771   return unbind_to (count, Qnil);
2775 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
2776        doc: /* SKIP: real doc in xfns.c.  */)
2777      (void)
2779   if (ns_tooltip == nil || ![ns_tooltip isActive])
2780     return Qnil;
2781   [ns_tooltip hide];
2782   return Qt;
2785 /* Return geometric attributes of FRAME.  According to the value of
2786    ATTRIBUTES return the outer edges of FRAME (Qouter_edges), the inner
2787    edges of FRAME, the root window edges of frame (Qroot_edges).  Any
2788    other value means to return the geometry as returned by
2789    Fx_frame_geometry.  */
2790 static Lisp_Object
2791 frame_geometry (Lisp_Object frame, Lisp_Object attribute)
2793   struct frame *f = decode_live_frame (frame);
2794   Lisp_Object fullscreen_symbol = Fframe_parameter (frame, Qfullscreen);
2795   bool fullscreen = (EQ (fullscreen_symbol, Qfullboth)
2796                      || EQ (fullscreen_symbol, Qfullscreen));
2797   int border = fullscreen ? 0 : f->border_width;
2798   int title_height = fullscreen ? 0 : FRAME_NS_TITLEBAR_HEIGHT (f);
2799   int native_width = FRAME_PIXEL_WIDTH (f);
2800   int native_height = FRAME_PIXEL_HEIGHT (f);
2801   int outer_width = native_width + 2 * border;
2802   int outer_height = native_height + 2 * border + title_height;
2803   int native_left = f->left_pos + border;
2804   int native_top = f->top_pos + border + title_height;
2805   int native_right = f->left_pos + outer_width - border;
2806   int native_bottom = f->top_pos + outer_height - border;
2807   int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f);
2808   int tool_bar_height = FRAME_TOOLBAR_HEIGHT (f);
2809   int tool_bar_width = (tool_bar_height
2810                         ? outer_width - 2 * internal_border_width
2811                         : 0);
2813   /* Construct list.  */
2814   if (EQ (attribute, Qouter_edges))
2815     return list4 (make_number (f->left_pos), make_number (f->top_pos),
2816                   make_number (f->left_pos + outer_width),
2817                   make_number (f->top_pos + outer_height));
2818   else if (EQ (attribute, Qnative_edges))
2819     return list4 (make_number (native_left), make_number (native_top),
2820                   make_number (native_right), make_number (native_bottom));
2821   else if (EQ (attribute, Qinner_edges))
2822     return list4 (make_number (native_left + internal_border_width),
2823                   make_number (native_top
2824                                + tool_bar_height
2825                                + internal_border_width),
2826                   make_number (native_right - internal_border_width),
2827                   make_number (native_bottom - internal_border_width));
2828   else
2829     return
2830       listn (CONSTYPE_HEAP, 10,
2831              Fcons (Qouter_position,
2832                     Fcons (make_number (f->left_pos),
2833                            make_number (f->top_pos))),
2834              Fcons (Qouter_size,
2835                     Fcons (make_number (outer_width),
2836                            make_number (outer_height))),
2837              Fcons (Qexternal_border_size,
2838                     (fullscreen
2839                      ? Fcons (make_number (0), make_number (0))
2840                      : Fcons (make_number (border), make_number (border)))),
2841              Fcons (Qtitle_bar_size,
2842                     Fcons (make_number (0), make_number (title_height))),
2843              Fcons (Qmenu_bar_external, Qnil),
2844              Fcons (Qmenu_bar_size, Fcons (make_number (0), make_number (0))),
2845              Fcons (Qtool_bar_external,
2846                     FRAME_EXTERNAL_TOOL_BAR (f) ? Qt : Qnil),
2847              Fcons (Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f)),
2848              Fcons (Qtool_bar_size,
2849                     Fcons (make_number (tool_bar_width),
2850                            make_number (tool_bar_height))),
2851              Fcons (Qinternal_border_width,
2852                     make_number (internal_border_width)));
2855 DEFUN ("ns-frame-geometry", Fns_frame_geometry, Sns_frame_geometry, 0, 1, 0,
2856        doc: /* Return geometric attributes of FRAME.
2857 FRAME must be a live frame and defaults to the selected one.  The return
2858 value is an association list of the attributes listed below.  All height
2859 and width values are in pixels.
2861 `outer-position' is a cons of the outer left and top edges of FRAME
2862   relative to the origin - the position (0, 0) - of FRAME's display.
2864 `outer-size' is a cons of the outer width and height of FRAME.  The
2865   outer size includes the title bar and the external borders as well as
2866   any menu and/or tool bar of frame.
2868 `external-border-size' is a cons of the horizontal and vertical width of
2869   FRAME's external borders as supplied by the window manager.
2871 `title-bar-size' is a cons of the width and height of the title bar of
2872   FRAME as supplied by the window manager.  If both of them are zero,
2873   FRAME has no title bar.  If only the width is zero, Emacs was not
2874   able to retrieve the width information.
2876 `menu-bar-external', if non-nil, means the menu bar is external (never
2877   included in the inner edges of FRAME).
2879 `menu-bar-size' is a cons of the width and height of the menu bar of
2880   FRAME.
2882 `tool-bar-external', if non-nil, means the tool bar is external (never
2883   included in the inner edges of FRAME).
2885 `tool-bar-position' tells on which side the tool bar on FRAME is and can
2886   be one of `left', `top', `right' or `bottom'.  If this is nil, FRAME
2887   has no tool bar.
2889 `tool-bar-size' is a cons of the width and height of the tool bar of
2890   FRAME.
2892 `internal-border-width' is the width of the internal border of
2893   FRAME.  */)
2894   (Lisp_Object frame)
2896   return frame_geometry (frame, Qnil);
2899 DEFUN ("ns-frame-edges", Fns_frame_edges, Sns_frame_edges, 0, 2, 0,
2900        doc: /* Return edge coordinates of FRAME.
2901 FRAME must be a live frame and defaults to the selected one.  The return
2902 value is a list of the form (LEFT, TOP, RIGHT, BOTTOM).  All values are
2903 in pixels relative to the origin - the position (0, 0) - of FRAME's
2904 display.
2906 If optional argument TYPE is the symbol `outer-edges', return the outer
2907 edges of FRAME.  The outer edges comprise the decorations of the window
2908 manager (like the title bar or external borders) as well as any external
2909 menu or tool bar of FRAME.  If optional argument TYPE is the symbol
2910 `native-edges' or nil, return the native edges of FRAME.  The native
2911 edges exclude the decorations of the window manager and any external
2912 menu or tool bar of FRAME.  If TYPE is the symbol `inner-edges', return
2913 the inner edges of FRAME.  These edges exclude title bar, any borders,
2914 menu bar or tool bar of FRAME.  */)
2915   (Lisp_Object frame, Lisp_Object type)
2917   return frame_geometry (frame, ((EQ (type, Qouter_edges)
2918                                   || EQ (type, Qinner_edges))
2919                                  ? type
2920                                  : Qnative_edges));
2923 DEFUN ("ns-set-mouse-absolute-pixel-position",
2924        Fns_set_mouse_absolute_pixel_position,
2925        Sns_set_mouse_absolute_pixel_position, 2, 2, 0,
2926        doc: /* Move mouse pointer to absolute pixel position (X, Y).
2927 The coordinates X and Y are interpreted in pixels relative to a position
2928 \(0, 0) of the selected frame's display.  */)
2929        (Lisp_Object x, Lisp_Object y)
2931 #ifdef NS_IMPL_COCOA
2932   /* GNUstep doesn't support CGWarpMouseCursorPosition, so none of
2933      this will work.  */
2934   struct frame *f = SELECTED_FRAME ();
2935   EmacsView *view = FRAME_NS_VIEW (f);
2936   NSScreen *screen = [[view window] screen];
2937   NSRect screen_frame = [screen frame];
2938   int mouse_x, mouse_y;
2940   NSScreen *primary_screen = [[NSScreen screens] objectAtIndex:0];
2941   NSRect primary_screen_frame = [primary_screen frame];
2942   CGFloat primary_screen_height = primary_screen_frame.size.height;
2944   if (FRAME_INITIAL_P (f) || !FRAME_NS_P (f))
2945     return Qnil;
2947   CHECK_TYPE_RANGED_INTEGER (int, x);
2948   CHECK_TYPE_RANGED_INTEGER (int, y);
2950   mouse_x = screen_frame.origin.x + XINT (x);
2952   if (screen == primary_screen)
2953     mouse_y = screen_frame.origin.y + XINT (y);
2954   else
2955     mouse_y = (primary_screen_height - screen_frame.size.height
2956                - screen_frame.origin.y) + XINT (y);
2958   CGPoint mouse_pos = CGPointMake(mouse_x, mouse_y);
2959   CGWarpMouseCursorPosition (mouse_pos);
2960 #endif /* NS_IMPL_COCOA */
2962   return Qnil;
2965 DEFUN ("ns-mouse-absolute-pixel-position",
2966        Fns_mouse_absolute_pixel_position,
2967        Sns_mouse_absolute_pixel_position, 0, 0, 0,
2968        doc: /* Return absolute position of mouse cursor in pixels.
2969 The position is returned as a cons cell (X . Y) of the
2970 coordinates of the mouse cursor position in pixels relative to a
2971 position (0, 0) of the selected frame's terminal.  */)
2972      (void)
2974   struct frame *f = SELECTED_FRAME ();
2975   EmacsView *view = FRAME_NS_VIEW (f);
2976   NSScreen *screen = [[view window] screen];
2977   NSPoint pt = [NSEvent mouseLocation];
2979   return Fcons(make_number(pt.x - screen.frame.origin.x),
2980                make_number(screen.frame.size.height -
2981                            (pt.y - screen.frame.origin.y)));
2984 DEFUN ("ns-show-character-palette",
2985        Fns_show_character_palette,
2986        Sns_show_character_palette, 0, 0, 0,
2987        doc: /* Show the macOS character palette.  */)
2988        (void)
2990   struct frame *f = SELECTED_FRAME ();
2991   EmacsView *view = FRAME_NS_VIEW (f);
2992   [NSApp orderFrontCharacterPalette:view];
2994   return Qnil;
2997 /* ==========================================================================
2999     Class implementations
3001    ========================================================================== */
3004   Handle arrow/function/control keys and copy/paste/cut in file dialogs.
3005   Return YES if handled, NO if not.
3006  */
3007 static BOOL
3008 handlePanelKeys (NSSavePanel *panel, NSEvent *theEvent)
3010   NSString *s;
3011   int i;
3012   BOOL ret = NO;
3014   if ([theEvent type] != NSEventTypeKeyDown) return NO;
3015   s = [theEvent characters];
3017   for (i = 0; i < [s length]; ++i)
3018     {
3019       int ch = (int) [s characterAtIndex: i];
3020       switch (ch)
3021         {
3022         case NSHomeFunctionKey:
3023         case NSDownArrowFunctionKey:
3024         case NSUpArrowFunctionKey:
3025         case NSLeftArrowFunctionKey:
3026         case NSRightArrowFunctionKey:
3027         case NSPageUpFunctionKey:
3028         case NSPageDownFunctionKey:
3029         case NSEndFunctionKey:
3030           /* Don't send command modified keys, as those are handled in the
3031              performKeyEquivalent method of the super class.  */
3032           if (! ([theEvent modifierFlags] & NSEventModifierFlagCommand))
3033             {
3034               [panel sendEvent: theEvent];
3035               ret = YES;
3036             }
3037           break;
3038           /* As we don't have the standard key commands for
3039              copy/paste/cut/select-all in our edit menu, we must handle
3040              them here.  TODO: handle Emacs key bindings for copy/cut/select-all
3041              here, paste works, because we have that in our Edit menu.
3042              I.e. refactor out code in nsterm.m, keyDown: to figure out the
3043              correct modifier.  */
3044         case 'x': // Cut
3045         case 'c': // Copy
3046         case 'v': // Paste
3047         case 'a': // Select all
3048           if ([theEvent modifierFlags] & NSEventModifierFlagCommand)
3049             {
3050               [NSApp sendAction:
3051                        (ch == 'x'
3052                         ? @selector(cut:)
3053                         : (ch == 'c'
3054                            ? @selector(copy:)
3055                            : (ch == 'v'
3056                               ? @selector(paste:)
3057                               : @selector(selectAll:))))
3058                              to:nil from:panel];
3059               ret = YES;
3060             }
3061         default:
3062           // Send all control keys, as the text field supports C-a, C-f, C-e
3063           // C-b and more.
3064           if ([theEvent modifierFlags] & NSEventModifierFlagControl)
3065             {
3066               [panel sendEvent: theEvent];
3067               ret = YES;
3068             }
3069           break;
3070         }
3071     }
3074   return ret;
3077 @implementation EmacsSavePanel
3078 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent
3080   BOOL ret = handlePanelKeys (self, theEvent);
3081   if (! ret)
3082     ret = [super performKeyEquivalent:theEvent];
3083   return ret;
3085 @end
3088 @implementation EmacsOpenPanel
3089 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent
3091   // NSOpenPanel inherits NSSavePanel, so passing self is OK.
3092   BOOL ret = handlePanelKeys (self, theEvent);
3093   if (! ret)
3094     ret = [super performKeyEquivalent:theEvent];
3095   return ret;
3097 @end
3100 @implementation EmacsFileDelegate
3101 /* --------------------------------------------------------------------------
3102    Delegate methods for Open/Save panels
3103    -------------------------------------------------------------------------- */
3104 - (BOOL)panel: (id)sender isValidFilename: (NSString *)filename
3106   return YES;
3108 - (BOOL)panel: (id)sender shouldShowFilename: (NSString *)filename
3110   return YES;
3112 - (NSString *)panel: (id)sender userEnteredFilename: (NSString *)filename
3113           confirmed: (BOOL)okFlag
3115   return filename;
3117 @end
3119 #endif
3122 /* ==========================================================================
3124     Lisp interface declaration
3126    ========================================================================== */
3129 void
3130 syms_of_nsfns (void)
3132   DEFSYM (Qfontsize, "fontsize");
3133   DEFSYM (Qframe_title_format, "frame-title-format");
3134   DEFSYM (Qicon_title_format, "icon-title-format");
3135   DEFSYM (Qdark, "dark");
3137   DEFVAR_LISP ("ns-icon-type-alist", Vns_icon_type_alist,
3138                doc: /* Alist of elements (REGEXP . IMAGE) for images of icons associated to frames.
3139 If the title of a frame matches REGEXP, then IMAGE.tiff is
3140 selected as the image of the icon representing the frame when it's
3141 miniaturized.  If an element is t, then Emacs tries to select an icon
3142 based on the filetype of the visited file.
3144 The images have to be installed in a folder called English.lproj in the
3145 Emacs folder.  You have to restart Emacs after installing new icons.
3147 Example: Install an icon Gnus.tiff and execute the following code
3149   (setq ns-icon-type-alist
3150         (append ns-icon-type-alist
3151                 \\='((\"^\\\\*\\\\(Group\\\\*$\\\\|Summary \\\\|Article\\\\*$\\\\)\"
3152                    . \"Gnus\"))))
3154 When you miniaturize a Group, Summary or Article frame, Gnus.tiff will
3155 be used as the image of the icon representing the frame.  */);
3156   Vns_icon_type_alist = list1 (Qt);
3158   DEFVAR_LISP ("ns-version-string", Vns_version_string,
3159                doc: /* Toolkit version for NS Windowing.  */);
3160   Vns_version_string = ns_appkit_version_str ();
3162   DEFVAR_BOOL ("ns-use-proxy-icon", ns_use_proxy_icon,
3163                doc: /* When non-nil display a proxy icon in the titlebar.
3164 Default is t.  */);
3165   ns_use_proxy_icon = true;
3167   defsubr (&Sns_read_file_name);
3168   defsubr (&Sns_get_resource);
3169   defsubr (&Sns_set_resource);
3170   defsubr (&Sxw_display_color_p); /* this and next called directly by C code */
3171   defsubr (&Sx_display_grayscale_p);
3172   defsubr (&Sns_font_name);
3173   defsubr (&Sns_list_colors);
3174 #ifdef NS_IMPL_COCOA
3175   defsubr (&Sns_do_applescript);
3176 #endif
3177   defsubr (&Sxw_color_defined_p);
3178   defsubr (&Sxw_color_values);
3179   defsubr (&Sx_server_max_request_size);
3180   defsubr (&Sx_server_vendor);
3181   defsubr (&Sx_server_version);
3182   defsubr (&Sx_display_pixel_width);
3183   defsubr (&Sx_display_pixel_height);
3184   defsubr (&Sns_display_monitor_attributes_list);
3185   defsubr (&Sns_frame_geometry);
3186   defsubr (&Sns_frame_edges);
3187   defsubr (&Sns_frame_list_z_order);
3188   defsubr (&Sns_frame_restack);
3189   defsubr (&Sns_set_mouse_absolute_pixel_position);
3190   defsubr (&Sns_mouse_absolute_pixel_position);
3191   defsubr (&Sns_show_character_palette);
3192   defsubr (&Sx_display_mm_width);
3193   defsubr (&Sx_display_mm_height);
3194   defsubr (&Sx_display_screens);
3195   defsubr (&Sx_display_planes);
3196   defsubr (&Sx_display_color_cells);
3197   defsubr (&Sx_display_visual_class);
3198   defsubr (&Sx_display_backing_store);
3199   defsubr (&Sx_display_save_under);
3200   defsubr (&Sx_create_frame);
3201   defsubr (&Sx_open_connection);
3202   defsubr (&Sx_close_connection);
3203   defsubr (&Sx_display_list);
3205   defsubr (&Sns_hide_others);
3206   defsubr (&Sns_hide_emacs);
3207   defsubr (&Sns_emacs_info_panel);
3208   defsubr (&Sns_list_services);
3209   defsubr (&Sns_perform_service);
3210   defsubr (&Sns_popup_font_panel);
3211   defsubr (&Sns_popup_color_panel);
3213   defsubr (&Sx_show_tip);
3214   defsubr (&Sx_hide_tip);
3216   as_status = 0;
3217   as_script = Qnil;
3218   as_result = 0;