; Revert "Improve diff-mode navigation/manipulation"
[emacs.git] / src / nsfns.m
bloba709935db96ffc51f8e6a27a610d21f1ebe6a183
1 /* Functions for the NeXT/Open/GNUstep and macOS window system.
3 Copyright (C) 1989, 1992-1994, 2005-2006, 2008-2017 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 <http://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);
64 static void ns_set_name_as_filename (struct frame *);
66 /* ==========================================================================
68     Internal utility functions
70    ========================================================================== */
72 /* Let the user specify a Nextstep display with a Lisp object.
73    OBJECT may be nil, a frame or a terminal object.
74    nil stands for the selected frame--or, if that is not a Nextstep frame,
75    the first Nextstep display on the list.  */
77 static struct ns_display_info *
78 check_ns_display_info (Lisp_Object object)
80   struct ns_display_info *dpyinfo = NULL;
82   if (NILP (object))
83     {
84       struct frame *sf = XFRAME (selected_frame);
86       if (FRAME_NS_P (sf) && FRAME_LIVE_P (sf))
87         dpyinfo = FRAME_DISPLAY_INFO (sf);
88       else if (x_display_list != 0)
89         dpyinfo = x_display_list;
90       else
91         error ("Nextstep windows are not in use or not initialized");
92     }
93   else if (TERMINALP (object))
94     {
95       struct terminal *t = decode_live_terminal (object);
97       if (t->type != output_ns)
98         error ("Terminal %d is not a Nextstep display", t->id);
100       dpyinfo = t->display_info.ns;
101     }
102   else if (STRINGP (object))
103     dpyinfo = ns_display_info_for_name (object);
104   else
105     {
106       struct frame *f = decode_window_system_frame (object);
107       dpyinfo = FRAME_DISPLAY_INFO (f);
108     }
110   return dpyinfo;
114 static id
115 ns_get_window (Lisp_Object maybeFrame)
117   id view =nil, window =nil;
119   if (!FRAMEP (maybeFrame) || !FRAME_NS_P (XFRAME (maybeFrame)))
120     maybeFrame = selected_frame;/*wrong_type_argument (Qframep, maybeFrame); */
122   if (!NILP (maybeFrame))
123     view = FRAME_NS_VIEW (XFRAME (maybeFrame));
124   if (view) window =[view window];
126   return window;
130 /* Return the X display structure for the display named NAME.
131    Open a new connection if necessary.  */
132 static struct ns_display_info *
133 ns_display_info_for_name (Lisp_Object name)
135   struct ns_display_info *dpyinfo;
137   CHECK_STRING (name);
139   for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
140     if (!NILP (Fstring_equal (XCAR (dpyinfo->name_list_element), name)))
141       return dpyinfo;
143   error ("Emacs for Nextstep does not yet support multi-display");
145   Fx_open_connection (name, Qnil, Qnil);
146   dpyinfo = x_display_list;
148   if (dpyinfo == 0)
149     error ("Display on %s not responding.\n", SDATA (name));
151   return dpyinfo;
154 static NSString *
155 ns_filename_from_panel (NSSavePanel *panel)
157 #ifdef NS_IMPL_COCOA
158   NSURL *url = [panel URL];
159   NSString *str = [url path];
160   return str;
161 #else
162   return [panel filename];
163 #endif
166 static NSString *
167 ns_directory_from_panel (NSSavePanel *panel)
169 #ifdef NS_IMPL_COCOA
170   NSURL *url = [panel directoryURL];
171   NSString *str = [url path];
172   return str;
173 #else
174   return [panel directory];
175 #endif
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;
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 to
289      update, or it does update and cannot clear old text properly */
290   if (FRAME_VISIBLE_P (f))
291     ns_clear_frame (f);
293   [col retain];
294   [f->output_data.ns->background_color release];
295   f->output_data.ns->background_color = col;
297   [col getRed: &r green: &g blue: &b alpha: &alpha];
298   FRAME_BACKGROUND_PIXEL (f) =
299     ARGB_TO_ULONG ((int)(alpha*0xff), (int)(r*0xff), (int)(g*0xff), (int)(b*0xff));
301   if (view != nil)
302     {
303       [[view window] setBackgroundColor: col];
305       if (alpha != (EmacsCGFloat) 1.0)
306           [[view window] setOpaque: NO];
307       else
308           [[view window] setOpaque: YES];
310       face = FRAME_DEFAULT_FACE (f);
311       if (face)
312         {
313           col = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f);
314           face->background = ns_index_color
315             ([col colorWithAlphaComponent: alpha], f);
317           update_face_from_frame_parameter (f, Qbackground_color, arg);
318         }
320       if (FRAME_VISIBLE_P (f))
321         SET_FRAME_GARBAGED (f);
322     }
323   unblock_input ();
327 static void
328 x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
330   NSColor *col;
332   block_input ();
333   if (ns_lisp_to_color (arg, &col))
334     {
335       store_frame_param (f, Qcursor_color, oldval);
336       unblock_input ();
337       error ("Unknown color");
338     }
340   [FRAME_CURSOR_COLOR (f) release];
341   FRAME_CURSOR_COLOR (f) = [col retain];
343   if (FRAME_VISIBLE_P (f))
344     {
345       x_update_cursor (f, 0);
346       x_update_cursor (f, 1);
347     }
348   update_face_from_frame_parameter (f, Qcursor_color, arg);
349   unblock_input ();
353 static void
354 x_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
356   NSView *view = FRAME_NS_VIEW (f);
357   NSTRACE ("x_set_icon_name");
359   /* see if it's changed */
360   if (STRINGP (arg))
361     {
362       if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
363         return;
364     }
365   else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
366     return;
368   fset_icon_name (f, arg);
370   if (NILP (arg))
371     {
372       if (!NILP (f->title))
373         arg = f->title;
374       else
375         /* Explicit name and no icon-name -> explicit_name.  */
376         if (f->explicit_name)
377           arg = f->name;
378         else
379           {
380             /* No explicit name and no icon-name ->
381                name has to be rebuild from icon_title_format.  */
382             windows_or_buffers_changed = 62;
383             return;
384           }
385     }
387   /* Don't change the name if it's already NAME.  */
388   if ([[view window] miniwindowTitle]
389       && ([[[view window] miniwindowTitle]
390              isEqualToString: [NSString stringWithUTF8String:
391                                           SSDATA (arg)]]))
392     return;
394   [[view window] setMiniwindowTitle:
395         [NSString stringWithUTF8String: SSDATA (arg)]];
398 static void
399 ns_set_name_internal (struct frame *f, Lisp_Object name)
401   Lisp_Object encoded_name, encoded_icon_name;
402   NSString *str;
403   NSView *view = FRAME_NS_VIEW (f);
406   encoded_name = ENCODE_UTF_8 (name);
408   str = [NSString stringWithUTF8String: SSDATA (encoded_name)];
411   /* Don't change the name if it's already NAME.  */
412   if (! [[[view window] title] isEqualToString: str])
413     [[view window] setTitle: str];
415   if (!STRINGP (f->icon_name))
416     encoded_icon_name = encoded_name;
417   else
418     encoded_icon_name = ENCODE_UTF_8 (f->icon_name);
420   str = [NSString stringWithUTF8String: SSDATA (encoded_icon_name)];
422   if ([[view window] miniwindowTitle]
423       && ! [[[view window] miniwindowTitle] isEqualToString: str])
424     [[view window] setMiniwindowTitle: str];
428 static void
429 ns_set_name (struct frame *f, Lisp_Object name, int explicit)
431   NSTRACE ("ns_set_name");
433   /* Make sure that requests from lisp code override requests from
434      Emacs redisplay code.  */
435   if (explicit)
436     {
437       /* If we're switching from explicit to implicit, we had better
438          update the mode lines and thereby update the title.  */
439       if (f->explicit_name && NILP (name))
440         update_mode_lines = 21;
442       f->explicit_name = ! NILP (name);
443     }
444   else if (f->explicit_name)
445     return;
447   if (NILP (name))
448     name = build_string ([ns_app_name UTF8String]);
449   else
450     CHECK_STRING (name);
452   /* Don't change the name if it's already NAME.  */
453   if (! NILP (Fstring_equal (name, f->name)))
454     return;
456   fset_name (f, name);
458   /* Title overrides explicit name.  */
459   if (! NILP (f->title))
460     name = f->title;
462   ns_set_name_internal (f, name);
466 /* This function should be called when the user's lisp code has
467    specified a name for the frame; the name will override any set by the
468    redisplay code.  */
469 static void
470 x_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
472   NSTRACE ("x_explicitly_set_name");
473   ns_set_name (f, arg, 1);
477 /* This function should be called by Emacs redisplay code to set the
478    name; names set this way will never override names set by the user's
479    lisp code.  */
480 void
481 x_implicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
483   NSTRACE ("x_implicitly_set_name");
485   Lisp_Object frame_title = buffer_local_value
486     (Qframe_title_format, XWINDOW (f->selected_window)->contents);
487   Lisp_Object icon_title = buffer_local_value
488     (Qicon_title_format, XWINDOW (f->selected_window)->contents);
490   /* Deal with NS specific format t.  */
491   if (FRAME_NS_P (f) && ((FRAME_ICONIFIED_P (f) && EQ (icon_title, Qt))
492                          || EQ (frame_title, Qt)))
493     ns_set_name_as_filename (f);
494   else
495     ns_set_name (f, arg, 0);
499 /* Change the title of frame F to NAME.
500    If NAME is nil, use the frame name as the title.  */
502 static void
503 x_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name)
505   NSTRACE ("x_set_title");
506   /* Don't change the title if it's already NAME.  */
507   if (EQ (name, f->title))
508     return;
510   update_mode_lines = 22;
512   fset_title (f, name);
514   if (NILP (name))
515     name = f->name;
516   else
517     CHECK_STRING (name);
519   ns_set_name_internal (f, name);
523 static void
524 ns_set_name_as_filename (struct frame *f)
526   NSView *view;
527   Lisp_Object name, filename;
528   Lisp_Object buf = XWINDOW (f->selected_window)->contents;
529   const char *title;
530   NSAutoreleasePool *pool;
531   Lisp_Object encoded_name, encoded_filename;
532   NSString *str;
533   NSTRACE ("ns_set_name_as_filename");
535   if (f->explicit_name || ! NILP (f->title))
536     return;
538   block_input ();
539   pool = [[NSAutoreleasePool alloc] init];
540   filename = BVAR (XBUFFER (buf), filename);
541   name = BVAR (XBUFFER (buf), name);
543   if (NILP (name))
544     {
545       if (! NILP (filename))
546         name = Ffile_name_nondirectory (filename);
547       else
548         name = build_string ([ns_app_name UTF8String]);
549     }
551   encoded_name = ENCODE_UTF_8 (name);
553   view = FRAME_NS_VIEW (f);
555   title = FRAME_ICONIFIED_P (f) ? [[[view window] miniwindowTitle] UTF8String]
556                                 : [[[view window] title] UTF8String];
558   if (title && (! strcmp (title, SSDATA (encoded_name))))
559     {
560       [pool release];
561       unblock_input ();
562       return;
563     }
565   str = [NSString stringWithUTF8String: SSDATA (encoded_name)];
566   if (str == nil) str = @"Bad coding";
568   if (FRAME_ICONIFIED_P (f))
569     [[view window] setMiniwindowTitle: str];
570   else
571     {
572       NSString *fstr;
574       if (! NILP (filename))
575         {
576           encoded_filename = ENCODE_UTF_8 (filename);
578           fstr = [NSString stringWithUTF8String: SSDATA (encoded_filename)];
579           if (fstr == nil) fstr = @"";
580         }
581       else
582         fstr = @"";
584       ns_set_represented_filename (fstr, f);
585       [[view window] setTitle: str];
586       fset_name (f, name);
587     }
589   [pool release];
590   unblock_input ();
594 void
595 ns_set_doc_edited (void)
597   NSAutoreleasePool *pool;
598   Lisp_Object tail, frame;
599   block_input ();
600   pool = [[NSAutoreleasePool alloc] init];
601   FOR_EACH_FRAME (tail, frame)
602     {
603       BOOL edited = NO;
604       struct frame *f = XFRAME (frame);
605       struct window *w;
606       NSView *view;
608       if (! FRAME_NS_P (f)) continue;
609       w = XWINDOW (FRAME_SELECTED_WINDOW (f));
610       view = FRAME_NS_VIEW (f);
611       if (!MINI_WINDOW_P (w))
612         edited = ! NILP (Fbuffer_modified_p (w->contents)) &&
613           ! NILP (Fbuffer_file_name (w->contents));
614       [[view window] setDocumentEdited: edited];
615     }
617   [pool release];
618   unblock_input ();
622 static void
623 x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
625   int nlines;
626   if (FRAME_MINIBUF_ONLY_P (f))
627     return;
629   if (TYPE_RANGED_INTEGERP (int, value))
630     nlines = XINT (value);
631   else
632     nlines = 0;
634   FRAME_MENU_BAR_LINES (f) = 0;
635   if (nlines)
636     {
637       FRAME_EXTERNAL_MENU_BAR (f) = 1;
638       /* does for all frames, whereas we just want for one frame
639          [NSMenu setMenuBarVisible: YES]; */
640     }
641   else
642     {
643       if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
644         free_frame_menubar (f);
645       /*      [NSMenu setMenuBarVisible: NO]; */
646       FRAME_EXTERNAL_MENU_BAR (f) = 0;
647     }
651 /* toolbar support */
652 static void
653 x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
655   /* Currently, when the tool bar change state, the frame is resized.
657      TODO: It would be better if this didn't occur when 1) the frame
658      is full height or maximized or 2) when specified by
659      `frame-inhibit-implied-resize'. */
660   int nlines;
662   NSTRACE ("x_set_tool_bar_lines");
664   if (FRAME_MINIBUF_ONLY_P (f))
665     return;
667   if (RANGED_INTEGERP (0, value, INT_MAX))
668     nlines = XFASTINT (value);
669   else
670     nlines = 0;
672   if (nlines)
673     {
674       FRAME_EXTERNAL_TOOL_BAR (f) = 1;
675       update_frame_tool_bar (f);
676     }
677   else
678     {
679       if (FRAME_EXTERNAL_TOOL_BAR (f))
680         {
681           free_frame_tool_bar (f);
682           FRAME_EXTERNAL_TOOL_BAR (f) = 0;
684           {
685             EmacsView *view = FRAME_NS_VIEW (f);
686             int fs_state = [view fullscreenState];
688             if (fs_state == FULLSCREEN_MAXIMIZED)
689               {
690                 [view setFSValue:FULLSCREEN_WIDTH];
691               }
692             else if (fs_state == FULLSCREEN_HEIGHT)
693               {
694                 [view setFSValue:FULLSCREEN_NONE];
695               }
696           }
697        }
698     }
700   {
701     int inhibit
702       = ((f->after_make_frame
703           && !f->tool_bar_resized
704           && (EQ (frame_inhibit_implied_resize, Qt)
705               || (CONSP (frame_inhibit_implied_resize)
706                   && !NILP (Fmemq (Qtool_bar_lines,
707                                    frame_inhibit_implied_resize))))
708           && NILP (get_frame_param (f, Qfullscreen)))
709          ? 0
710          : 2);
712     NSTRACE_MSG ("inhibit:%d", inhibit);
714     frame_size_history_add (f, Qupdate_frame_tool_bar, 0, 0, Qnil);
715     adjust_frame_size (f, -1, -1, inhibit, 0, Qtool_bar_lines);
716   }
720 static void
721 x_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
723   int old_width = FRAME_INTERNAL_BORDER_WIDTH (f);
725   CHECK_TYPE_RANGED_INTEGER (int, arg);
726   f->internal_border_width = XINT (arg);
727   if (FRAME_INTERNAL_BORDER_WIDTH (f) < 0)
728     f->internal_border_width = 0;
730   if (FRAME_INTERNAL_BORDER_WIDTH (f) == old_width)
731     return;
733   if (FRAME_X_WINDOW (f) != 0)
734     adjust_frame_size (f, -1, -1, 3, 0, Qinternal_border_width);
736   SET_FRAME_GARBAGED (f);
740 static void
741 ns_implicitly_set_icon_type (struct frame *f)
743   Lisp_Object tem;
744   EmacsView *view = FRAME_NS_VIEW (f);
745   id image = nil;
746   Lisp_Object chain, elt;
747   NSAutoreleasePool *pool;
748   BOOL setMini = YES;
750   NSTRACE ("ns_implicitly_set_icon_type");
752   block_input ();
753   pool = [[NSAutoreleasePool alloc] init];
754   if (f->output_data.ns->miniimage
755       && [[NSString stringWithUTF8String: SSDATA (f->name)]
756                isEqualToString: [(NSImage *)f->output_data.ns->miniimage name]])
757     {
758       [pool release];
759       unblock_input ();
760       return;
761     }
763   tem = assq_no_quit (Qicon_type, f->param_alist);
764   if (CONSP (tem) && ! NILP (XCDR (tem)))
765     {
766       [pool release];
767       unblock_input ();
768       return;
769     }
771   for (chain = Vns_icon_type_alist;
772        image == nil && CONSP (chain);
773        chain = XCDR (chain))
774     {
775       elt = XCAR (chain);
776       /* special case: t means go by file type */
777       if (SYMBOLP (elt) && EQ (elt, Qt) && SSDATA (f->name)[0] == '/')
778         {
779           NSString *str
780              = [NSString stringWithUTF8String: SSDATA (f->name)];
781           if ([[NSFileManager defaultManager] fileExistsAtPath: str])
782             image = [[[NSWorkspace sharedWorkspace] iconForFile: str] retain];
783         }
784       else if (CONSP (elt) &&
785                STRINGP (XCAR (elt)) &&
786                STRINGP (XCDR (elt)) &&
787                fast_string_match (XCAR (elt), f->name) >= 0)
788         {
789           image = [EmacsImage allocInitFromFile: XCDR (elt)];
790           if (image == nil)
791             image = [[NSImage imageNamed:
792                                [NSString stringWithUTF8String:
793                                             SSDATA (XCDR (elt))]] retain];
794         }
795     }
797   if (image == nil)
798     {
799       image = [[[NSWorkspace sharedWorkspace] iconForFileType: @"text"] retain];
800       setMini = NO;
801     }
803   [f->output_data.ns->miniimage release];
804   f->output_data.ns->miniimage = image;
805   [view setMiniwindowImage: setMini];
806   [pool release];
807   unblock_input ();
811 static void
812 x_set_icon_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
814   EmacsView *view = FRAME_NS_VIEW (f);
815   id image = nil;
816   BOOL setMini = YES;
818   NSTRACE ("x_set_icon_type");
820   if (!NILP (arg) && SYMBOLP (arg))
821     {
822       arg =build_string (SSDATA (SYMBOL_NAME (arg)));
823       store_frame_param (f, Qicon_type, arg);
824     }
826   /* do it the implicit way */
827   if (NILP (arg))
828     {
829       ns_implicitly_set_icon_type (f);
830       return;
831     }
833   CHECK_STRING (arg);
835   image = [EmacsImage allocInitFromFile: arg];
836   if (image == nil)
837     image =[NSImage imageNamed: [NSString stringWithUTF8String:
838                                             SSDATA (arg)]];
840   if (image == nil)
841     {
842       image = [NSImage imageNamed: @"text"];
843       setMini = NO;
844     }
846   f->output_data.ns->miniimage = image;
847   [view setMiniwindowImage: setMini];
850 /* This is the same as the xfns.c definition.  */
851 static void
852 x_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
854   set_frame_cursor_types (f, arg);
857 /* called to set mouse pointer color, but all other terms use it to
858    initialize pointer types (and don't set the color ;) */
859 static void
860 x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
862   /* don't think we can do this on Nextstep */
866 #define Str(x) #x
867 #define Xstr(x) Str(x)
869 static Lisp_Object
870 ns_appkit_version_str (void)
872   char tmp[256];
874 #ifdef NS_IMPL_GNUSTEP
875   sprintf(tmp, "gnustep-gui-%s", Xstr(GNUSTEP_GUI_VERSION));
876 #elif defined (NS_IMPL_COCOA)
877   NSString *osversion
878     = [[NSProcessInfo processInfo] operatingSystemVersionString];
879   sprintf(tmp, "appkit-%.2f %s",
880           NSAppKitVersionNumber,
881           [osversion UTF8String]);
882 #else
883   tmp = "ns-unknown";
884 #endif
885   return build_string (tmp);
889 /* This is for use by x-server-version and collapses all version info we
890    have into a single int.  For a better picture of the implementation
891    running, use ns_appkit_version_str.*/
892 static int
893 ns_appkit_version_int (void)
895 #ifdef NS_IMPL_GNUSTEP
896   return GNUSTEP_GUI_MAJOR_VERSION * 100 + GNUSTEP_GUI_MINOR_VERSION;
897 #elif defined (NS_IMPL_COCOA)
898   return (int)NSAppKitVersionNumber;
899 #endif
900   return 0;
904 static void
905 x_icon (struct frame *f, Lisp_Object parms)
906 /* --------------------------------------------------------------------------
907    Strangely-named function to set icon position parameters in frame.
908    This is irrelevant under macOS, but might be needed under GNUstep,
909    depending on the window manager used.  Note, this is not a standard
910    frame parameter-setter; it is called directly from x-create-frame.
911    -------------------------------------------------------------------------- */
913   Lisp_Object icon_x, icon_y;
914   struct ns_display_info *dpyinfo = check_ns_display_info (Qnil);
916   f->output_data.ns->icon_top = -1;
917   f->output_data.ns->icon_left = -1;
919   /* Set the position of the icon.  */
920   icon_x = x_get_arg (dpyinfo, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
921   icon_y = x_get_arg (dpyinfo, parms, Qicon_top, 0, 0,  RES_TYPE_NUMBER);
922   if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
923     {
924       CHECK_NUMBER (icon_x);
925       CHECK_NUMBER (icon_y);
926       f->output_data.ns->icon_top = XINT (icon_y);
927       f->output_data.ns->icon_left = XINT (icon_x);
928     }
929   else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
930     error ("Both left and top icon corners of icon must be specified");
934 /* Note: see frame.c for template, also where generic functions are impl */
935 frame_parm_handler ns_frame_parm_handlers[] =
937   x_set_autoraise, /* generic OK */
938   x_set_autolower, /* generic OK */
939   x_set_background_color,
940   0, /* x_set_border_color,  may be impossible under Nextstep */
941   0, /* x_set_border_width,  may be impossible under Nextstep */
942   x_set_cursor_color,
943   x_set_cursor_type,
944   x_set_font, /* generic OK */
945   x_set_foreground_color,
946   x_set_icon_name,
947   x_set_icon_type,
948   x_set_internal_border_width, /* generic OK */
949   x_set_right_divider_width,
950   x_set_bottom_divider_width,
951   x_set_menu_bar_lines,
952   x_set_mouse_color,
953   x_explicitly_set_name,
954   x_set_scroll_bar_width, /* generic OK */
955   x_set_scroll_bar_height, /* generic OK */
956   x_set_title,
957   x_set_unsplittable, /* generic OK */
958   x_set_vertical_scroll_bars, /* generic OK */
959   x_set_horizontal_scroll_bars, /* generic OK */
960   x_set_visibility, /* generic OK */
961   x_set_tool_bar_lines,
962   0, /* x_set_scroll_bar_foreground, will ignore (not possible on NS) */
963   0, /* x_set_scroll_bar_background,  will ignore (not possible on NS) */
964   x_set_screen_gamma, /* generic OK */
965   x_set_line_spacing, /* generic OK, sets f->extra_line_spacing to int */
966   x_set_left_fringe, /* generic OK */
967   x_set_right_fringe, /* generic OK */
968   0, /* x_set_wait_for_wm, will ignore */
969   x_set_fullscreen, /* generic OK */
970   x_set_font_backend, /* generic OK */
971   x_set_alpha,
972   0, /* x_set_sticky */
973   0, /* x_set_tool_bar_position */
974   0, /* x_set_inhibit_double_buffering */
978 /* Handler for signals raised during x_create_frame.
979    FRAME is the frame which is partially constructed.  */
981 static void
982 unwind_create_frame (Lisp_Object frame)
984   struct frame *f = XFRAME (frame);
986   /* If frame is already dead, nothing to do.  This can happen if the
987      display is disconnected after the frame has become official, but
988      before x_create_frame removes the unwind protect.  */
989   if (!FRAME_LIVE_P (f))
990     return;
992   /* If frame is ``official'', nothing to do.  */
993   if (NILP (Fmemq (frame, Vframe_list)))
994     {
995 #if defined GLYPH_DEBUG && defined ENABLE_CHECKING
996       struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
997 #endif
999       /* If the frame's image cache refcount is still the same as our
1000          private shadow variable, it means we are unwinding a frame
1001          for which we didn't yet call init_frame_faces, where the
1002          refcount is incremented.  Therefore, we increment it here, so
1003          that free_frame_faces, called in x_free_frame_resources
1004          below, will not mistakenly decrement the counter that was not
1005          incremented yet to account for this new frame.  */
1006       if (FRAME_IMAGE_CACHE (f) != NULL
1007           && FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount)
1008         FRAME_IMAGE_CACHE (f)->refcount++;
1010       x_free_frame_resources (f);
1011       free_glyphs (f);
1013 #if defined GLYPH_DEBUG && defined ENABLE_CHECKING
1014       /* Check that reference counts are indeed correct.  */
1015       eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
1016 #endif
1017     }
1021  * Read geometry related parameters from preferences if not in PARMS.
1022  * Returns the union of parms and any preferences read.
1023  */
1025 static Lisp_Object
1026 get_geometry_from_preferences (struct ns_display_info *dpyinfo,
1027                                Lisp_Object parms)
1029   struct {
1030     const char *val;
1031     const char *cls;
1032     Lisp_Object tem;
1033   } r[] = {
1034     { "width",  "Width", Qwidth },
1035     { "height", "Height", Qheight },
1036     { "left", "Left", Qleft },
1037     { "top", "Top", Qtop },
1038   };
1040   int i;
1041   for (i = 0; i < ARRAYELTS (r); ++i)
1042     {
1043       if (NILP (Fassq (r[i].tem, parms)))
1044         {
1045           Lisp_Object value
1046             = x_get_arg (dpyinfo, parms, r[i].tem, r[i].val, r[i].cls,
1047                          RES_TYPE_NUMBER);
1048           if (! EQ (value, Qunbound))
1049             parms = Fcons (Fcons (r[i].tem, value), parms);
1050         }
1051     }
1053   return parms;
1056 /* ==========================================================================
1058     Lisp definitions
1060    ========================================================================== */
1062 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
1063        1, 1, 0,
1064        doc: /* Make a new Nextstep window, called a "frame" in Emacs terms.
1065 Return an Emacs frame object.
1066 PARMS is an alist of frame parameters.
1067 If the parameters specify that the frame should not have a minibuffer,
1068 and do not specify a specific minibuffer window to use,
1069 then `default-minibuffer-frame' must be a frame whose minibuffer can
1070 be shared by the new frame.
1072 This function is an internal primitive--use `make-frame' instead.  */)
1073      (Lisp_Object parms)
1075   struct frame *f;
1076   Lisp_Object frame, tem;
1077   Lisp_Object name;
1078   int minibuffer_only = 0;
1079   long window_prompting = 0;
1080   ptrdiff_t count = specpdl_ptr - specpdl;
1081   Lisp_Object display;
1082   struct ns_display_info *dpyinfo = NULL;
1083   Lisp_Object parent;
1084   struct kboard *kb;
1085   static int desc_ctr = 1;
1086   int x_width = 0, x_height = 0;
1088   /* x_get_arg modifies parms.  */
1089   parms = Fcopy_alist (parms);
1091   /* Use this general default value to start with
1092      until we know if this frame has a specified name.  */
1093   Vx_resource_name = Vinvocation_name;
1095   display = x_get_arg (dpyinfo, parms, Qterminal, 0, 0, RES_TYPE_STRING);
1096   if (EQ (display, Qunbound))
1097     display = Qnil;
1098   dpyinfo = check_ns_display_info (display);
1099   kb = dpyinfo->terminal->kboard;
1101   if (!dpyinfo->terminal->name)
1102     error ("Terminal is not live, can't create new frames on it");
1104   name = x_get_arg (dpyinfo, parms, Qname, 0, 0, RES_TYPE_STRING);
1105   if (!STRINGP (name)
1106       && ! EQ (name, Qunbound)
1107       && ! NILP (name))
1108     error ("Invalid frame name--not a string or nil");
1110   if (STRINGP (name))
1111     Vx_resource_name = name;
1113   parent = x_get_arg (dpyinfo, parms, Qparent_id, 0, 0, RES_TYPE_NUMBER);
1114   if (EQ (parent, Qunbound))
1115     parent = Qnil;
1116   if (! NILP (parent))
1117     CHECK_NUMBER (parent);
1119   /* make_frame_without_minibuffer can run Lisp code and garbage collect.  */
1120   /* No need to protect DISPLAY because that's not used after passing
1121      it to make_frame_without_minibuffer.  */
1122   frame = Qnil;
1123   tem = x_get_arg (dpyinfo, parms, Qminibuffer, "minibuffer", "Minibuffer",
1124                   RES_TYPE_SYMBOL);
1125   if (EQ (tem, Qnone) || NILP (tem))
1126       f = make_frame_without_minibuffer (Qnil, kb, display);
1127   else if (EQ (tem, Qonly))
1128     {
1129       f = make_minibuffer_frame ();
1130       minibuffer_only = 1;
1131     }
1132   else if (WINDOWP (tem))
1133       f = make_frame_without_minibuffer (tem, kb, display);
1134   else
1135       f = make_frame (1);
1137   XSETFRAME (frame, f);
1139   f->terminal = dpyinfo->terminal;
1141   f->output_method = output_ns;
1142   f->output_data.ns = xzalloc (sizeof *f->output_data.ns);
1144   FRAME_FONTSET (f) = -1;
1146   fset_icon_name (f, x_get_arg (dpyinfo, parms, Qicon_name,
1147                                 "iconName", "Title",
1148                                 RES_TYPE_STRING));
1149   if (! STRINGP (f->icon_name))
1150     fset_icon_name (f, Qnil);
1152   FRAME_DISPLAY_INFO (f) = dpyinfo;
1154   /* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe.  */
1155   record_unwind_protect (unwind_create_frame, frame);
1157   f->output_data.ns->window_desc = desc_ctr++;
1158   if (TYPE_RANGED_INTEGERP (Window, parent))
1159     {
1160       f->output_data.ns->parent_desc = XFASTINT (parent);
1161       f->output_data.ns->explicit_parent = 1;
1162     }
1163   else
1164     {
1165       f->output_data.ns->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
1166       f->output_data.ns->explicit_parent = 0;
1167     }
1169   /* Set the name; the functions to which we pass f expect the name to
1170      be set.  */
1171   if (EQ (name, Qunbound) || NILP (name) || ! STRINGP (name))
1172     {
1173       fset_name (f, build_string ([ns_app_name UTF8String]));
1174       f->explicit_name = 0;
1175     }
1176   else
1177     {
1178       fset_name (f, name);
1179       f->explicit_name = 1;
1180       specbind (Qx_resource_name, name);
1181     }
1183   block_input ();
1185 #ifdef NS_IMPL_COCOA
1186     mac_register_font_driver (f);
1187 #else
1188     register_font_driver (&nsfont_driver, f);
1189 #endif
1191   image_cache_refcount =
1192     FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
1194   x_default_parameter (f, parms, Qfont_backend, Qnil,
1195                         "fontBackend", "FontBackend", RES_TYPE_STRING);
1197   {
1198     /* use for default font name */
1199     id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */
1200     x_default_parameter (f, parms, Qfontsize,
1201                                     make_number (0 /*(int)[font pointSize]*/),
1202                                     "fontSize", "FontSize", RES_TYPE_NUMBER);
1203     // Remove ' Regular', not handled by backends.
1204     char *fontname = xstrdup ([[font displayName] UTF8String]);
1205     int len = strlen (fontname);
1206     if (len > 8 && strcmp (fontname + len - 8, " Regular") == 0)
1207       fontname[len-8] = '\0';
1208     x_default_parameter (f, parms, Qfont,
1209                                  build_string (fontname),
1210                                  "font", "Font", RES_TYPE_STRING);
1211     xfree (fontname);
1212   }
1213   unblock_input ();
1215   x_default_parameter (f, parms, Qborder_width, make_number (0),
1216                        "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
1217   x_default_parameter (f, parms, Qinternal_border_width, make_number (2),
1218                       "internalBorderWidth", "InternalBorderWidth",
1219                       RES_TYPE_NUMBER);
1221   /* default vertical scrollbars on right on Mac */
1222   {
1223       Lisp_Object spos
1224 #ifdef NS_IMPL_GNUSTEP
1225           = Qt;
1226 #else
1227           = Qright;
1228 #endif
1229       x_default_parameter (f, parms, Qvertical_scroll_bars, spos,
1230                            "verticalScrollBars", "VerticalScrollBars",
1231                            RES_TYPE_SYMBOL);
1232   }
1233   x_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil,
1234                        "horizontalScrollBars", "HorizontalScrollBars",
1235                        RES_TYPE_SYMBOL);
1236   x_default_parameter (f, parms, Qforeground_color, build_string ("Black"),
1237                       "foreground", "Foreground", RES_TYPE_STRING);
1238   x_default_parameter (f, parms, Qbackground_color, build_string ("White"),
1239                       "background", "Background", RES_TYPE_STRING);
1240   /* FIXME: not supported yet in Nextstep */
1241   x_default_parameter (f, parms, Qline_spacing, Qnil,
1242                        "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
1243   x_default_parameter (f, parms, Qleft_fringe, Qnil,
1244                        "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
1245   x_default_parameter (f, parms, Qright_fringe, Qnil,
1246                        "rightFringe", "RightFringe", RES_TYPE_NUMBER);
1248   init_frame_faces (f);
1250   /* Read comment about this code in corresponding place in xfns.c.  */
1251   adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
1252                      FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1,
1253                      Qx_create_frame_1);
1255   /* The resources controlling the menu-bar and tool-bar are
1256      processed specially at startup, and reflected in the mode
1257      variables; ignore them here.  */
1258   x_default_parameter (f, parms, Qmenu_bar_lines,
1259                        NILP (Vmenu_bar_mode)
1260                        ? make_number (0) : make_number (1),
1261                        NULL, NULL, RES_TYPE_NUMBER);
1262   x_default_parameter (f, parms, Qtool_bar_lines,
1263                        NILP (Vtool_bar_mode)
1264                        ? make_number (0) : make_number (1),
1265                        NULL, NULL, RES_TYPE_NUMBER);
1267   x_default_parameter (f, parms, Qbuffer_predicate, Qnil, "bufferPredicate",
1268                        "BufferPredicate", RES_TYPE_SYMBOL);
1269   x_default_parameter (f, parms, Qtitle, Qnil, "title", "Title",
1270                        RES_TYPE_STRING);
1272   parms = get_geometry_from_preferences (dpyinfo, parms);
1273   window_prompting = x_figure_window_size (f, parms, true, &x_width, &x_height);
1275   tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
1276   f->no_split = minibuffer_only || (!EQ (tem, Qunbound) && !EQ (tem, Qnil));
1278   /* NOTE: on other terms, this is done in set_mouse_color, however this
1279      was not getting called under Nextstep */
1280   f->output_data.ns->text_cursor = [NSCursor IBeamCursor];
1281   f->output_data.ns->nontext_cursor = [NSCursor arrowCursor];
1282   f->output_data.ns->modeline_cursor = [NSCursor pointingHandCursor];
1283   f->output_data.ns->hand_cursor = [NSCursor pointingHandCursor];
1284   f->output_data.ns->hourglass_cursor = [NSCursor disappearingItemCursor];
1285   f->output_data.ns->horizontal_drag_cursor = [NSCursor resizeLeftRightCursor];
1286   f->output_data.ns->vertical_drag_cursor = [NSCursor resizeUpDownCursor];
1287   FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor
1288      = [NSCursor arrowCursor];
1289   FRAME_DISPLAY_INFO (f)->horizontal_scroll_bar_cursor
1290      = [NSCursor arrowCursor];
1291   f->output_data.ns->current_pointer = f->output_data.ns->text_cursor;
1293   f->output_data.ns->in_animation = NO;
1295   [[EmacsView alloc] initFrameFromEmacs: f];
1297   x_icon (f, parms);
1299   /* ns_display_info does not have a reference_count.  */
1300   f->terminal->reference_count++;
1302   /* It is now ok to make the frame official even if we get an error below.
1303      The frame needs to be on Vframe_list or making it visible won't work. */
1304   Vframe_list = Fcons (frame, Vframe_list);
1306   x_default_parameter (f, parms, Qicon_type, Qnil,
1307                        "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
1309   x_default_parameter (f, parms, Qauto_raise, Qnil,
1310                        "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
1311   x_default_parameter (f, parms, Qauto_lower, Qnil,
1312                        "autoLower", "AutoLower", RES_TYPE_BOOLEAN);
1313   x_default_parameter (f, parms, Qcursor_type, Qbox,
1314                        "cursorType", "CursorType", RES_TYPE_SYMBOL);
1315   x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
1316                        "scrollBarWidth", "ScrollBarWidth",
1317                        RES_TYPE_NUMBER);
1318   x_default_parameter (f, parms, Qscroll_bar_height, Qnil,
1319                        "scrollBarHeight", "ScrollBarHeight",
1320                        RES_TYPE_NUMBER);
1321   x_default_parameter (f, parms, Qalpha, Qnil,
1322                        "alpha", "Alpha", RES_TYPE_NUMBER);
1323   x_default_parameter (f, parms, Qfullscreen, Qnil,
1324                        "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
1326   /* Allow x_set_window_size, now.  */
1327   f->can_x_set_window_size = true;
1329   if (x_width > 0)
1330     SET_FRAME_WIDTH (f, x_width);
1331   if (x_height > 0)
1332     SET_FRAME_HEIGHT (f, x_height);
1334   adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 0, 1,
1335                      Qx_create_frame_2);
1337   if (! f->output_data.ns->explicit_parent)
1338     {
1339       Lisp_Object visibility;
1341       visibility = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
1342                               RES_TYPE_SYMBOL);
1343       if (EQ (visibility, Qunbound))
1344         visibility = Qt;
1346       if (EQ (visibility, Qicon))
1347         x_iconify_frame (f);
1348       else if (! NILP (visibility))
1349         {
1350           x_make_frame_visible (f);
1351           [[FRAME_NS_VIEW (f) window] makeKeyWindow];
1352         }
1353       else
1354         {
1355           /* Must have been Qnil.  */
1356         }
1357     }
1359   if (FRAME_HAS_MINIBUF_P (f)
1360       && (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame))
1361           || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame)))))
1362     kset_default_minibuffer_frame (kb, frame);
1364   /* All remaining specified parameters, which have not been "used"
1365      by x_get_arg and friends, now go in the misc. alist of the frame.  */
1366   for (tem = parms; CONSP (tem); tem = XCDR (tem))
1367     if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem))))
1368       fset_param_alist (f, Fcons (XCAR (tem), f->param_alist));
1370   if (window_prompting & USPosition)
1371     x_set_offset (f, f->left_pos, f->top_pos, 1);
1373   /* Make sure windows on this frame appear in calls to next-window
1374      and similar functions.  */
1375   Vwindow_list = Qnil;
1377   return unbind_to (count, frame);
1380 void
1381 x_focus_frame (struct frame *f)
1383   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1385   if (dpyinfo->x_focus_frame != f)
1386     {
1387       EmacsView *view = FRAME_NS_VIEW (f);
1388       block_input ();
1389       [NSApp activateIgnoringOtherApps: YES];
1390       [[view window] makeKeyAndOrderFront: view];
1391       unblock_input ();
1392     }
1396 DEFUN ("ns-popup-font-panel", Fns_popup_font_panel, Sns_popup_font_panel,
1397        0, 1, "",
1398        doc: /* Pop up the font panel. */)
1399      (Lisp_Object frame)
1401   struct frame *f = decode_window_system_frame (frame);
1402   id fm = [NSFontManager sharedFontManager];
1403   struct font *font = f->output_data.ns->font;
1404   NSFont *nsfont;
1405 #ifdef NS_IMPL_GNUSTEP
1406   nsfont = ((struct nsfont_info *)font)->nsfont;
1407 #endif
1408 #ifdef NS_IMPL_COCOA
1409   nsfont = (NSFont *) macfont_get_nsctfont (font);
1410 #endif
1411   [fm setSelectedFont: nsfont isMultiple: NO];
1412   [fm orderFrontFontPanel: NSApp];
1413   return Qnil;
1417 DEFUN ("ns-popup-color-panel", Fns_popup_color_panel, Sns_popup_color_panel,
1418        0, 1, "",
1419        doc: /* Pop up the color panel.  */)
1420      (Lisp_Object frame)
1422   check_window_system (NULL);
1423   [NSApp orderFrontColorPanel: NSApp];
1424   return Qnil;
1427 static struct
1429   id panel;
1430   BOOL ret;
1431 #ifdef NS_IMPL_GNUSTEP
1432   NSString *dirS, *initS;
1433   BOOL no_types;
1434 #endif
1435 } ns_fd_data;
1437 void
1438 ns_run_file_dialog (void)
1440   if (ns_fd_data.panel == nil) return;
1441 #ifdef NS_IMPL_COCOA
1442   ns_fd_data.ret = [ns_fd_data.panel runModal];
1443 #else
1444   if (ns_fd_data.no_types)
1445     {
1446       ns_fd_data.ret = [ns_fd_data.panel
1447                            runModalForDirectory: ns_fd_data.dirS
1448                            file: ns_fd_data.initS];
1449     }
1450   else
1451     {
1452       ns_fd_data.ret = [ns_fd_data.panel
1453                            runModalForDirectory: ns_fd_data.dirS
1454                            file: ns_fd_data.initS
1455                            types: nil];
1456     }
1457 #endif
1458   ns_fd_data.panel = nil;
1461 #ifdef NS_IMPL_COCOA
1462 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_9
1463 #define MODAL_OK_RESPONSE NSModalResponseOK
1464 #endif
1465 #endif
1466 #ifndef MODAL_OK_RESPONSE
1467 #define MODAL_OK_RESPONSE NSOKButton
1468 #endif
1470 DEFUN ("ns-read-file-name", Fns_read_file_name, Sns_read_file_name, 1, 5, 0,
1471        doc: /* Use a graphical panel to read a file name, using prompt PROMPT.
1472 Optional arg DIR, if non-nil, supplies a default directory.
1473 Optional arg MUSTMATCH, if non-nil, means the returned file or
1474 directory must exist.
1475 Optional arg INIT, if non-nil, provides a default file name to use.
1476 Optional arg DIR_ONLY_P, if non-nil, means choose only directories.  */)
1477   (Lisp_Object prompt, Lisp_Object dir, Lisp_Object mustmatch,
1478    Lisp_Object init, Lisp_Object dir_only_p)
1480   static id fileDelegate = nil;
1481   BOOL isSave = NILP (mustmatch) && NILP (dir_only_p);
1482   id panel;
1483   Lisp_Object fname = Qnil;
1485   NSString *promptS = NILP (prompt) || !STRINGP (prompt) ? nil :
1486     [NSString stringWithUTF8String: SSDATA (prompt)];
1487   NSString *dirS = NILP (dir) || !STRINGP (dir) ?
1488     [NSString stringWithUTF8String: SSDATA (BVAR (current_buffer, directory))] :
1489     [NSString stringWithUTF8String: SSDATA (dir)];
1490   NSString *initS = NILP (init) || !STRINGP (init) ? nil :
1491     [NSString stringWithUTF8String: SSDATA (init)];
1492   NSEvent *nxev;
1494   check_window_system (NULL);
1496   if (fileDelegate == nil)
1497     fileDelegate = [EmacsFileDelegate new];
1499   [NSCursor setHiddenUntilMouseMoves: NO];
1501   if ([dirS characterAtIndex: 0] == '~')
1502     dirS = [dirS stringByExpandingTildeInPath];
1504   panel = isSave ?
1505     (id)[EmacsSavePanel savePanel] : (id)[EmacsOpenPanel openPanel];
1507   [panel setTitle: promptS];
1509   [panel setAllowsOtherFileTypes: YES];
1510   [panel setTreatsFilePackagesAsDirectories: YES];
1511   [panel setDelegate: fileDelegate];
1513   if (! NILP (dir_only_p))
1514     {
1515       [panel setCanChooseDirectories: YES];
1516       [panel setCanChooseFiles: NO];
1517     }
1518   else if (! isSave)
1519     {
1520       /* This is not quite what the documentation says, but it is compatible
1521          with the Gtk+ code.  Also, the menu entry says "Open File...".  */
1522       [panel setCanChooseDirectories: NO];
1523       [panel setCanChooseFiles: YES];
1524     }
1526   block_input ();
1527   ns_fd_data.panel = panel;
1528   ns_fd_data.ret = NO;
1529 #ifdef NS_IMPL_COCOA
1530   if (! NILP (mustmatch) || ! NILP (dir_only_p))
1531     [panel setAllowedFileTypes: nil];
1532   if (dirS) [panel setDirectoryURL: [NSURL fileURLWithPath: dirS]];
1533   if (initS && NILP (Ffile_directory_p (init)))
1534     [panel setNameFieldStringValue: [initS lastPathComponent]];
1535   else
1536     [panel setNameFieldStringValue: @""];
1538 #else
1539   ns_fd_data.no_types = NILP (mustmatch) && NILP (dir_only_p);
1540   ns_fd_data.dirS = dirS;
1541   ns_fd_data.initS = initS;
1542 #endif
1544   /* runModalForDirectory/runModal restarts the main event loop when done,
1545      so we must start an event loop and then pop up the file dialog.
1546      The file dialog may pop up a confirm dialog after Ok has been pressed,
1547      so we can not simply pop down on the Ok/Cancel press.
1548    */
1549   nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
1550                             location: NSMakePoint (0, 0)
1551                        modifierFlags: 0
1552                            timestamp: 0
1553                         windowNumber: [[NSApp mainWindow] windowNumber]
1554                              context: [NSApp context]
1555                              subtype: 0
1556                                data1: 0
1557                                data2: NSAPP_DATA2_RUNFILEDIALOG];
1559   [NSApp postEvent: nxev atStart: NO];
1560   while (ns_fd_data.panel != nil)
1561     [NSApp run];
1563   if (ns_fd_data.ret == MODAL_OK_RESPONSE)
1564     {
1565       NSString *str = ns_filename_from_panel (panel);
1566       if (! str) str = ns_directory_from_panel (panel);
1567       if (str) fname = build_string ([str UTF8String]);
1568     }
1570   [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
1571   unblock_input ();
1573   return fname;
1576 const char *
1577 ns_get_defaults_value (const char *key)
1579   NSObject *obj = [[NSUserDefaults standardUserDefaults]
1580                     objectForKey: [NSString stringWithUTF8String: key]];
1582   if (!obj) return NULL;
1584   return [[NSString stringWithFormat: @"%@", obj] UTF8String];
1588 DEFUN ("ns-get-resource", Fns_get_resource, Sns_get_resource, 2, 2, 0,
1589        doc: /* Return the value of the property NAME of OWNER from the defaults database.
1590 If OWNER is nil, Emacs is assumed.  */)
1591      (Lisp_Object owner, Lisp_Object name)
1593   const char *value;
1595   check_window_system (NULL);
1596   if (NILP (owner))
1597     owner = build_string([ns_app_name UTF8String]);
1598   CHECK_STRING (name);
1600   value = ns_get_defaults_value (SSDATA (name));
1602   if (value)
1603     return build_string (value);
1604   return Qnil;
1608 DEFUN ("ns-set-resource", Fns_set_resource, Sns_set_resource, 3, 3, 0,
1609        doc: /* Set property NAME of OWNER to VALUE, from the defaults database.
1610 If OWNER is nil, Emacs is assumed.
1611 If VALUE is nil, the default is removed.  */)
1612      (Lisp_Object owner, Lisp_Object name, Lisp_Object value)
1614   check_window_system (NULL);
1615   if (NILP (owner))
1616     owner = build_string ([ns_app_name UTF8String]);
1617   CHECK_STRING (name);
1618   if (NILP (value))
1619     {
1620       [[NSUserDefaults standardUserDefaults] removeObjectForKey:
1621                          [NSString stringWithUTF8String: SSDATA (name)]];
1622     }
1623   else
1624     {
1625       CHECK_STRING (value);
1626       [[NSUserDefaults standardUserDefaults] setObject:
1627                 [NSString stringWithUTF8String: SSDATA (value)]
1628                                         forKey: [NSString stringWithUTF8String:
1629                                                          SSDATA (name)]];
1630     }
1632   return Qnil;
1636 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
1637        Sx_server_max_request_size,
1638        0, 1, 0,
1639        doc: /* This function is a no-op.  It is only present for completeness.  */)
1640      (Lisp_Object terminal)
1642   check_ns_display_info (terminal);
1643   /* This function has no real equivalent under NeXTstep.  Return nil to
1644      indicate this. */
1645   return Qnil;
1649 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
1650        doc: /* Return the "vendor ID" string of Nextstep display server TERMINAL.
1651 \(Labeling every distributor as a "vendor" embodies the false assumption
1652 that operating systems cannot be developed and distributed noncommercially.)
1653 The optional argument TERMINAL specifies which display to ask about.
1654 TERMINAL should be a terminal object, a frame or a display name (a string).
1655 If omitted or nil, that stands for the selected frame's display.  */)
1656   (Lisp_Object terminal)
1658   check_ns_display_info (terminal);
1659 #ifdef NS_IMPL_GNUSTEP
1660   return build_string ("GNU");
1661 #else
1662   return build_string ("Apple");
1663 #endif
1667 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
1668        doc: /* Return the version numbers of the server of display TERMINAL.
1669 The value is a list of three integers: the major and minor
1670 version numbers of the X Protocol in use, and the distributor-specific release
1671 number.  See also the function `x-server-vendor'.
1673 The optional argument TERMINAL specifies which display to ask about.
1674 TERMINAL should be a terminal object, a frame or a display name (a string).
1675 If omitted or nil, that stands for the selected frame's display.  */)
1676   (Lisp_Object terminal)
1678   check_ns_display_info (terminal);
1679   /*NOTE: it is unclear what would best correspond with "protocol";
1680           we return 10.3, meaning Panther, since this is roughly the
1681           level that GNUstep's APIs correspond to.
1682           The last number is where we distinguish between the Apple
1683           and GNUstep implementations ("distributor-specific release
1684           number") and give int'ized versions of major.minor. */
1685   return list3i (10, 3, ns_appkit_version_int ());
1689 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
1690        doc: /* Return the number of screens on Nextstep display server TERMINAL.
1691 The optional argument TERMINAL specifies which display to ask about.
1692 TERMINAL should be a terminal object, a frame or a display name (a string).
1693 If omitted or nil, that stands for the selected frame's display.
1695 Note: "screen" here is not in Nextstep terminology but in X11's.  For
1696 the number of physical monitors, use `(length
1697 \(display-monitor-attributes-list TERMINAL))' instead.  */)
1698   (Lisp_Object terminal)
1700   check_ns_display_info (terminal);
1701   return make_number (1);
1705 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
1706        doc: /* Return the height in millimeters of the Nextstep display TERMINAL.
1707 The optional argument TERMINAL specifies which display to ask about.
1708 TERMINAL should be a terminal object, a frame or a display name (a string).
1709 If omitted or nil, that stands for the selected frame's display.
1711 On \"multi-monitor\" setups this refers to the height in millimeters for
1712 all physical monitors associated with TERMINAL.  To get information
1713 for each physical monitor, use `display-monitor-attributes-list'.  */)
1714   (Lisp_Object terminal)
1716   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
1718   return make_number (x_display_pixel_height (dpyinfo) / (92.0/25.4));
1722 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
1723        doc: /* Return the width in millimeters of the Nextstep display TERMINAL.
1724 The optional argument TERMINAL specifies which display to ask about.
1725 TERMINAL should be a terminal object, a frame or a display name (a string).
1726 If omitted or nil, that stands for the selected frame's display.
1728 On \"multi-monitor\" setups this refers to the width in millimeters for
1729 all physical monitors associated with TERMINAL.  To get information
1730 for each physical monitor, use `display-monitor-attributes-list'.  */)
1731   (Lisp_Object terminal)
1733   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
1735   return make_number (x_display_pixel_width (dpyinfo) / (92.0/25.4));
1739 DEFUN ("x-display-backing-store", Fx_display_backing_store,
1740        Sx_display_backing_store, 0, 1, 0,
1741        doc: /* Return an indication of whether the Nextstep display TERMINAL does backing store.
1742 The value may be `buffered', `retained', or `non-retained'.
1743 The optional argument TERMINAL specifies which display to ask about.
1744 TERMINAL should be a terminal object, a frame or a display name (a string).
1745 If omitted or nil, that stands for the selected frame's display.  */)
1746   (Lisp_Object terminal)
1748   check_ns_display_info (terminal);
1749   switch ([ns_get_window (terminal) backingType])
1750     {
1751     case NSBackingStoreBuffered:
1752       return intern ("buffered");
1753     case NSBackingStoreRetained:
1754       return intern ("retained");
1755     case NSBackingStoreNonretained:
1756       return intern ("non-retained");
1757     default:
1758       error ("Strange value for backingType parameter of frame");
1759     }
1760   return Qnil;  /* not reached, shut compiler up */
1764 DEFUN ("x-display-visual-class", Fx_display_visual_class,
1765        Sx_display_visual_class, 0, 1, 0,
1766        doc: /* Return the visual class of the Nextstep display TERMINAL.
1767 The value is one of the symbols `static-gray', `gray-scale',
1768 `static-color', `pseudo-color', `true-color', or `direct-color'.
1770 The optional argument TERMINAL specifies which display to ask about.
1771 TERMINAL should a terminal object, a frame or a display name (a string).
1772 If omitted or nil, that stands for the selected frame's display.  */)
1773   (Lisp_Object terminal)
1775   NSWindowDepth depth;
1777   check_ns_display_info (terminal);
1778   depth = [[[NSScreen screens] objectAtIndex:0] depth];
1780   if ( depth == NSBestDepth (NSCalibratedWhiteColorSpace, 2, 2, YES, NULL))
1781     return intern ("static-gray");
1782   else if (depth == NSBestDepth (NSCalibratedWhiteColorSpace, 8, 8, YES, NULL))
1783     return intern ("gray-scale");
1784   else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 8, 8, YES, NULL))
1785     return intern ("pseudo-color");
1786   else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 4, 12, NO, NULL))
1787     return intern ("true-color");
1788   else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 8, 24, NO, NULL))
1789     return intern ("direct-color");
1790   else
1791     /* color mgmt as far as we do it is really handled by Nextstep itself anyway */
1792     return intern ("direct-color");
1796 DEFUN ("x-display-save-under", Fx_display_save_under,
1797        Sx_display_save_under, 0, 1, 0,
1798        doc: /* Return t if TERMINAL supports the save-under feature.
1799 The optional argument TERMINAL specifies which display to ask about.
1800 TERMINAL should be a terminal object, a frame or a display name (a string).
1801 If omitted or nil, that stands for the selected frame's display.  */)
1802   (Lisp_Object terminal)
1804   check_ns_display_info (terminal);
1805   switch ([ns_get_window (terminal) backingType])
1806     {
1807     case NSBackingStoreBuffered:
1808       return Qt;
1810     case NSBackingStoreRetained:
1811     case NSBackingStoreNonretained:
1812       return Qnil;
1814     default:
1815       error ("Strange value for backingType parameter of frame");
1816     }
1817   return Qnil;  /* not reached, shut compiler up */
1821 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
1822        1, 3, 0,
1823        doc: /* Open a connection to a display server.
1824 DISPLAY is the name of the display to connect to.
1825 Optional second arg XRM-STRING is a string of resources in xrdb format.
1826 If the optional third arg MUST-SUCCEED is non-nil,
1827 terminate Emacs if we can't open the connection.
1828 \(In the Nextstep version, the last two arguments are currently ignored.)  */)
1829      (Lisp_Object display, Lisp_Object resource_string, Lisp_Object must_succeed)
1831   struct ns_display_info *dpyinfo;
1833   CHECK_STRING (display);
1835   nxatoms_of_nsselect ();
1836   dpyinfo = ns_term_init (display);
1837   if (dpyinfo == 0)
1838     {
1839       if (!NILP (must_succeed))
1840         fatal ("Display on %s not responding.\n",
1841                SSDATA (display));
1842       else
1843         error ("Display on %s not responding.\n",
1844                SSDATA (display));
1845     }
1847   return Qnil;
1851 DEFUN ("x-close-connection", Fx_close_connection, Sx_close_connection,
1852        1, 1, 0,
1853        doc: /* Close the connection to TERMINAL's Nextstep display server.
1854 For TERMINAL, specify a terminal object, a frame or a display name (a
1855 string).  If TERMINAL is nil, that stands for the selected frame's
1856 terminal.  */)
1857      (Lisp_Object terminal)
1859   check_ns_display_info (terminal);
1860   [NSApp terminate: NSApp];
1861   return Qnil;
1865 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
1866        doc: /* Return the list of display names that Emacs has connections to.  */)
1867      (void)
1869   Lisp_Object result = Qnil;
1870   struct ns_display_info *ndi;
1872   for (ndi = x_display_list; ndi; ndi = ndi->next)
1873     result = Fcons (XCAR (ndi->name_list_element), result);
1875   return result;
1879 DEFUN ("ns-hide-others", Fns_hide_others, Sns_hide_others,
1880        0, 0, 0,
1881        doc: /* Hides all applications other than Emacs.  */)
1882      (void)
1884   check_window_system (NULL);
1885   [NSApp hideOtherApplications: NSApp];
1886   return Qnil;
1889 DEFUN ("ns-hide-emacs", Fns_hide_emacs, Sns_hide_emacs,
1890        1, 1, 0,
1891        doc: /* If ON is non-nil, the entire Emacs application is hidden.
1892 Otherwise if Emacs is hidden, it is unhidden.
1893 If ON is equal to `activate', Emacs is unhidden and becomes
1894 the active application.  */)
1895      (Lisp_Object on)
1897   check_window_system (NULL);
1898   if (EQ (on, intern ("activate")))
1899     {
1900       [NSApp unhide: NSApp];
1901       [NSApp activateIgnoringOtherApps: YES];
1902     }
1903   else if (NILP (on))
1904     [NSApp unhide: NSApp];
1905   else
1906     [NSApp hide: NSApp];
1907   return Qnil;
1911 DEFUN ("ns-emacs-info-panel", Fns_emacs_info_panel, Sns_emacs_info_panel,
1912        0, 0, 0,
1913        doc: /* Shows the 'Info' or 'About' panel for Emacs.  */)
1914      (void)
1916   check_window_system (NULL);
1917   [NSApp orderFrontStandardAboutPanel: nil];
1918   return Qnil;
1922 DEFUN ("ns-font-name", Fns_font_name, Sns_font_name, 1, 1, 0,
1923        doc: /* Determine font PostScript or family name for font NAME.
1924 NAME should be a string containing either the font name or an XLFD
1925 font descriptor.  If string contains `fontset' and not
1926 `fontset-startup', it is left alone. */)
1927      (Lisp_Object name)
1929   char *nm;
1930   CHECK_STRING (name);
1931   nm = SSDATA (name);
1933   if (nm[0] != '-')
1934     return name;
1935   if (strstr (nm, "fontset") && !strstr (nm, "fontset-startup"))
1936     return name;
1938   return build_string (ns_xlfd_to_fontname (SSDATA (name)));
1942 DEFUN ("ns-list-colors", Fns_list_colors, Sns_list_colors, 0, 1, 0,
1943        doc: /* Return a list of all available colors.
1944 The optional argument FRAME is currently ignored.  */)
1945      (Lisp_Object frame)
1947   Lisp_Object list = Qnil;
1948   NSEnumerator *colorlists;
1949   NSColorList *clist;
1951   if (!NILP (frame))
1952     {
1953       CHECK_FRAME (frame);
1954       if (! FRAME_NS_P (XFRAME (frame)))
1955         error ("non-Nextstep frame used in `ns-list-colors'");
1956     }
1958   block_input ();
1960   colorlists = [[NSColorList availableColorLists] objectEnumerator];
1961   while ((clist = [colorlists nextObject]))
1962     {
1963       if ([[clist name] length] < 7 ||
1964           [[clist name] rangeOfString: @"PANTONE"].location == 0)
1965         {
1966           NSEnumerator *cnames = [[clist allKeys] reverseObjectEnumerator];
1967           NSString *cname;
1968           while ((cname = [cnames nextObject]))
1969             list = Fcons (build_string ([cname UTF8String]), list);
1970 /*           for (i = [[clist allKeys] count] - 1; i >= 0; i--)
1971                list = Fcons (build_string ([[[clist allKeys] objectAtIndex: i]
1972                                              UTF8String]), list); */
1973         }
1974     }
1976   unblock_input ();
1978   return list;
1982 DEFUN ("ns-list-services", Fns_list_services, Sns_list_services, 0, 0, 0,
1983        doc: /* List available Nextstep services by querying NSApp.  */)
1984      (void)
1986 #ifdef NS_IMPL_COCOA
1987   /* You can't get services like this in 10.6+.  */
1988   return Qnil;
1989 #else
1990   Lisp_Object ret = Qnil;
1991   NSMenu *svcs;
1992 #ifdef NS_IMPL_COCOA
1993   id delegate;
1994 #endif
1996   check_window_system (NULL);
1997   svcs = [[NSMenu alloc] initWithTitle: @"Services"];
1998   [NSApp setServicesMenu: svcs];
1999   [NSApp registerServicesMenuSendTypes: ns_send_types
2000                            returnTypes: ns_return_types];
2002 /* On Tiger, services menu updating was made lazier (waits for user to
2003    actually click on the menu), so we have to force things along: */
2004 #ifdef NS_IMPL_COCOA
2005   delegate = [svcs delegate];
2006   if (delegate != nil)
2007     {
2008       if ([delegate respondsToSelector: @selector (menuNeedsUpdate:)])
2009         [delegate menuNeedsUpdate: svcs];
2010       if ([delegate respondsToSelector:
2011                        @selector (menu:updateItem:atIndex:shouldCancel:)])
2012         {
2013           int i, len = [delegate numberOfItemsInMenu: svcs];
2014           for (i =0; i<len; i++)
2015             [svcs addItemWithTitle: @"" action: NULL keyEquivalent: @""];
2016           for (i =0; i<len; i++)
2017             if (![delegate menu: svcs
2018                      updateItem: (NSMenuItem *)[svcs itemAtIndex: i]
2019                         atIndex: i shouldCancel: NO])
2020               break;
2021         }
2022     }
2023 #endif
2025   [svcs setAutoenablesItems: NO];
2026 #ifdef NS_IMPL_COCOA
2027   [svcs update]; /* on macOS, converts from '/' structure */
2028 #endif
2030   ret = interpret_services_menu (svcs, Qnil, ret);
2031   return ret;
2032 #endif
2036 DEFUN ("ns-perform-service", Fns_perform_service, Sns_perform_service,
2037        2, 2, 0,
2038        doc: /* Perform Nextstep SERVICE on SEND.
2039 SEND should be either a string or nil.
2040 The return value is the result of the service, as string, or nil if
2041 there was no result.  */)
2042      (Lisp_Object service, Lisp_Object send)
2044   id pb;
2045   NSString *svcName;
2046   char *utfStr;
2048   CHECK_STRING (service);
2049   check_window_system (NULL);
2051   utfStr = SSDATA (service);
2052   svcName = [NSString stringWithUTF8String: utfStr];
2054   pb =[NSPasteboard pasteboardWithUniqueName];
2055   ns_string_to_pasteboard (pb, send);
2057   if (NSPerformService (svcName, pb) == NO)
2058     Fsignal (Qquit, list1 (build_string ("service not available")));
2060   if ([[pb types] count] == 0)
2061     return build_string ("");
2062   return ns_string_from_pasteboard (pb);
2066 #ifdef NS_IMPL_COCOA
2068 /* Compile and execute the AppleScript SCRIPT and return the error
2069    status as function value.  A zero is returned if compilation and
2070    execution is successful, in which case *RESULT is set to a Lisp
2071    string or a number containing the resulting script value.  Otherwise,
2072    1 is returned. */
2073 static int
2074 ns_do_applescript (Lisp_Object script, Lisp_Object *result)
2076   NSAppleEventDescriptor *desc;
2077   NSDictionary* errorDict;
2078   NSAppleEventDescriptor* returnDescriptor = NULL;
2080   NSAppleScript* scriptObject =
2081     [[NSAppleScript alloc] initWithSource:
2082                              [NSString stringWithUTF8String: SSDATA (script)]];
2084   returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
2085   [scriptObject release];
2086   *result = Qnil;
2088   if (returnDescriptor != NULL)
2089     {
2090       // successful execution
2091       if (kAENullEvent != [returnDescriptor descriptorType])
2092         {
2093           *result = Qt;
2094           // script returned an AppleScript result
2095           if ((typeUnicodeText == [returnDescriptor descriptorType]) ||
2096 #if defined (NS_IMPL_COCOA)
2097               (typeUTF16ExternalRepresentation
2098                == [returnDescriptor descriptorType]) ||
2099 #endif
2100               (typeUTF8Text == [returnDescriptor descriptorType]) ||
2101               (typeCString == [returnDescriptor descriptorType]))
2102             {
2103               desc = [returnDescriptor coerceToDescriptorType: typeUTF8Text];
2104               if (desc)
2105                 *result = build_string([[desc stringValue] UTF8String]);
2106             }
2107           else
2108             {
2109               /* use typeUTF16ExternalRepresentation? */
2110               // coerce the result to the appropriate ObjC type
2111               desc = [returnDescriptor coerceToDescriptorType: typeUTF8Text];
2112               if (desc)
2113                 *result = make_number([desc int32Value]);
2114             }
2115         }
2116     }
2117   else
2118     {
2119       // no script result, return error
2120       return 1;
2121     }
2122   return 0;
2125 /* Helper function called from sendEvent to run applescript
2126    from within the main event loop.  */
2128 void
2129 ns_run_ascript (void)
2131   if (! NILP (as_script))
2132     as_status = ns_do_applescript (as_script, as_result);
2133   as_script = Qnil;
2136 DEFUN ("ns-do-applescript", Fns_do_applescript, Sns_do_applescript, 1, 1, 0,
2137        doc: /* Execute AppleScript SCRIPT and return the result.
2138 If compilation and execution are successful, the resulting script value
2139 is returned as a string, a number or, in the case of other constructs, t.
2140 In case the execution fails, an error is signaled. */)
2141      (Lisp_Object script)
2143   Lisp_Object result;
2144   int status;
2145   NSEvent *nxev;
2146   struct input_event ev;
2148   CHECK_STRING (script);
2149   check_window_system (NULL);
2151   block_input ();
2153   as_script = script;
2154   as_result = &result;
2156   /* executing apple script requires the event loop to run, otherwise
2157      errors aren't returned and executeAndReturnError hangs forever.
2158      Post an event that runs applescript and then start the event loop.
2159      The event loop is exited when the script is done.  */
2160   nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
2161                             location: NSMakePoint (0, 0)
2162                        modifierFlags: 0
2163                            timestamp: 0
2164                         windowNumber: [[NSApp mainWindow] windowNumber]
2165                              context: [NSApp context]
2166                              subtype: 0
2167                                data1: 0
2168                                data2: NSAPP_DATA2_RUNASSCRIPT];
2170   [NSApp postEvent: nxev atStart: NO];
2172   // If there are other events, the event loop may exit.  Keep running
2173   // until the script has been handled.  */
2174   ns_init_events (&ev);
2175   while (! NILP (as_script))
2176     [NSApp run];
2177   ns_finish_events ();
2179   status = as_status;
2180   as_status = 0;
2181   as_result = 0;
2182   unblock_input ();
2183   if (status == 0)
2184     return result;
2185   else if (!STRINGP (result))
2186     error ("AppleScript error %d", status);
2187   else
2188     error ("%s", SSDATA (result));
2190 #endif
2194 /* ==========================================================================
2196     Miscellaneous functions not called through hooks
2198    ========================================================================== */
2200 /* called from frame.c */
2201 struct ns_display_info *
2202 check_x_display_info (Lisp_Object frame)
2204   return check_ns_display_info (frame);
2208 void
2209 x_set_scroll_bar_default_width (struct frame *f)
2211   int wid = FRAME_COLUMN_WIDTH (f);
2212   FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = NS_SCROLL_BAR_WIDTH_DEFAULT;
2213   FRAME_CONFIG_SCROLL_BAR_COLS (f) = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) +
2214                                       wid - 1) / wid;
2217 void
2218 x_set_scroll_bar_default_height (struct frame *f)
2220   int height = FRAME_LINE_HEIGHT (f);
2221   FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = NS_SCROLL_BAR_WIDTH_DEFAULT;
2222   FRAME_CONFIG_SCROLL_BAR_LINES (f) = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) +
2223                                        height - 1) / height;
2226 /* terms impl this instead of x-get-resource directly */
2227 char *
2228 x_get_string_resource (XrmDatabase rdb, const char *name, const char *class)
2230   /* remove appname prefix; TODO: allow for !="Emacs" */
2231   const char *res, *toCheck = class + (!strncmp (class, "Emacs.", 6) ? 6 : 0);
2233   check_window_system (NULL);
2235   if (inhibit_x_resources)
2236     /* --quick was passed, so this is a no-op.  */
2237     return NULL;
2239   res = ns_get_defaults_value (toCheck);
2240   return (char *) (!res ? NULL
2241                    : !c_strncasecmp (res, "YES", 3) ? "true"
2242                    : !c_strncasecmp (res, "NO", 2) ? "false"
2243                    : res);
2247 Lisp_Object
2248 x_get_focus_frame (struct frame *frame)
2250   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2251   Lisp_Object nsfocus;
2253   if (!dpyinfo->x_focus_frame)
2254     return Qnil;
2256   XSETFRAME (nsfocus, dpyinfo->x_focus_frame);
2257   return nsfocus;
2260 /* ==========================================================================
2262     Lisp definitions that, for whatever reason, we can't alias as 'ns-XXX'.
2264    ========================================================================== */
2267 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
2268        doc: /* Internal function called by `color-defined-p', which see.
2269 \(Note that the Nextstep version of this function ignores FRAME.)  */)
2270      (Lisp_Object color, Lisp_Object frame)
2272   NSColor * col;
2273   check_window_system (NULL);
2274   return ns_lisp_to_color (color, &col) ? Qnil : Qt;
2278 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
2279        doc: /* Internal function called by `color-values', which see.  */)
2280      (Lisp_Object color, Lisp_Object frame)
2282   NSColor * col;
2283   EmacsCGFloat red, green, blue, alpha;
2285   check_window_system (NULL);
2286   CHECK_STRING (color);
2288   block_input ();
2289   if (ns_lisp_to_color (color, &col))
2290     {
2291       unblock_input ();
2292       return Qnil;
2293     }
2295   [[col colorUsingDefaultColorSpace]
2296         getRed: &red green: &green blue: &blue alpha: &alpha];
2297   unblock_input ();
2298   return list3i (lrint (red * 65280), lrint (green * 65280),
2299                  lrint (blue * 65280));
2303 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
2304        doc: /* Internal function called by `display-color-p', which see.  */)
2305      (Lisp_Object terminal)
2307   NSWindowDepth depth;
2308   NSString *colorSpace;
2310   check_ns_display_info (terminal);
2311   depth = [[[NSScreen screens] objectAtIndex:0] depth];
2312   colorSpace = NSColorSpaceFromDepth (depth);
2314   return    [colorSpace isEqualToString: NSDeviceWhiteColorSpace]
2315          || [colorSpace isEqualToString: NSCalibratedWhiteColorSpace]
2316       ? Qnil : Qt;
2320 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
2321        0, 1, 0,
2322        doc: /* Return t if the Nextstep display supports shades of gray.
2323 Note that color displays do support shades of gray.
2324 The optional argument TERMINAL specifies which display to ask about.
2325 TERMINAL should be a terminal object, a frame or a display name (a string).
2326 If omitted or nil, that stands for the selected frame's display.  */)
2327   (Lisp_Object terminal)
2329   NSWindowDepth depth;
2331   check_ns_display_info (terminal);
2332   depth = [[[NSScreen screens] objectAtIndex:0] depth];
2334   return NSBitsPerPixelFromDepth (depth) > 1 ? Qt : Qnil;
2338 DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
2339        0, 1, 0,
2340        doc: /* Return the width in pixels of the Nextstep display TERMINAL.
2341 The optional argument TERMINAL specifies which display to ask about.
2342 TERMINAL should be a terminal object, a frame or a display name (a string).
2343 If omitted or nil, that stands for the selected frame's display.
2345 On \"multi-monitor\" setups this refers to the pixel width for all
2346 physical monitors associated with TERMINAL.  To get information for
2347 each physical monitor, use `display-monitor-attributes-list'.  */)
2348   (Lisp_Object terminal)
2350   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
2352   return make_number (x_display_pixel_width (dpyinfo));
2356 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
2357        Sx_display_pixel_height, 0, 1, 0,
2358        doc: /* Return the height in pixels of the Nextstep display TERMINAL.
2359 The optional argument TERMINAL specifies which display to ask about.
2360 TERMINAL should be a terminal object, a frame or a display name (a string).
2361 If omitted or nil, that stands for the selected frame's display.
2363 On \"multi-monitor\" setups this refers to the pixel height for all
2364 physical monitors associated with TERMINAL.  To get information for
2365 each physical monitor, use `display-monitor-attributes-list'.  */)
2366   (Lisp_Object terminal)
2368   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
2370   return make_number (x_display_pixel_height (dpyinfo));
2373 #ifdef NS_IMPL_COCOA
2375 /* Returns the name for the screen that OBJ represents, or NULL.
2376    Caller must free return value.
2379 static char *
2380 ns_get_name_from_ioreg (io_object_t obj)
2382   char *name = NULL;
2384   NSDictionary *info = (NSDictionary *)
2385     IODisplayCreateInfoDictionary (obj, kIODisplayOnlyPreferredName);
2386   NSDictionary *names = [info objectForKey:
2387                                 [NSString stringWithUTF8String:
2388                                             kDisplayProductName]];
2390   if ([names count] > 0)
2391     {
2392       NSString *n = [names objectForKey: [[names allKeys]
2393                                                  objectAtIndex:0]];
2394       if (n != nil) name = xstrdup ([n UTF8String]);
2395     }
2397   [info release];
2399   return name;
2402 /* Returns the name for the screen that DID came from, or NULL.
2403    Caller must free return value.
2406 static char *
2407 ns_screen_name (CGDirectDisplayID did)
2409   char *name = NULL;
2411 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
2412   mach_port_t masterPort;
2413   io_iterator_t it;
2414   io_object_t obj;
2416   // CGDisplayIOServicePort is deprecated.  Do it another (harder) way.
2418   if (IOMasterPort (MACH_PORT_NULL, &masterPort) != kIOReturnSuccess
2419       || IOServiceGetMatchingServices (masterPort,
2420                                        IOServiceMatching ("IONDRVDevice"),
2421                                        &it) != kIOReturnSuccess)
2422     return name;
2424   /* Must loop until we find a name.  Many devices can have the same unit
2425      number (represents different GPU parts), but only one has a name.  */
2426   while (! name && (obj = IOIteratorNext (it)))
2427     {
2428       CFMutableDictionaryRef props;
2429       const void *val;
2431       if (IORegistryEntryCreateCFProperties (obj,
2432                                              &props,
2433                                              kCFAllocatorDefault,
2434                                              kNilOptions) == kIOReturnSuccess
2435           && props != nil
2436           && (val = CFDictionaryGetValue(props, @"IOFBDependentIndex")))
2437         {
2438           unsigned nr = [(NSNumber *)val unsignedIntegerValue];
2439           if (nr == CGDisplayUnitNumber (did))
2440             name = ns_get_name_from_ioreg (obj);
2441         }
2443       CFRelease (props);
2444       IOObjectRelease (obj);
2445     }
2447   IOObjectRelease (it);
2449 #else
2451   name = ns_get_name_from_ioreg (CGDisplayIOServicePort (did));
2453 #endif
2454   return name;
2456 #endif
2458 static Lisp_Object
2459 ns_make_monitor_attribute_list (struct MonitorInfo *monitors,
2460                                 int n_monitors,
2461                                 int primary_monitor,
2462                                 const char *source)
2464   Lisp_Object monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
2465   Lisp_Object frame, rest;
2466   NSArray *screens = [NSScreen screens];
2467   int i;
2469   FOR_EACH_FRAME (rest, frame)
2470     {
2471       struct frame *f = XFRAME (frame);
2473       if (FRAME_NS_P (f))
2474         {
2475           NSView *view = FRAME_NS_VIEW (f);
2476           NSScreen *screen = [[view window] screen];
2477           NSUInteger k;
2479           i = -1;
2480           for (k = 0; i == -1 && k < [screens count]; ++k)
2481             {
2482               if ([screens objectAtIndex: k] == screen)
2483                 i = (int)k;
2484             }
2486           if (i > -1)
2487             ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
2488         }
2489     }
2491   return make_monitor_attribute_list (monitors, n_monitors, primary_monitor,
2492                                       monitor_frames, source);
2495 DEFUN ("ns-display-monitor-attributes-list",
2496        Fns_display_monitor_attributes_list,
2497        Sns_display_monitor_attributes_list,
2498        0, 1, 0,
2499        doc: /* Return a list of physical monitor attributes on the X display TERMINAL.
2501 The optional argument TERMINAL specifies which display to ask about.
2502 TERMINAL should be a terminal object, a frame or a display name (a string).
2503 If omitted or nil, that stands for the selected frame's display.
2505 In addition to the standard attribute keys listed in
2506 `display-monitor-attributes-list', the following keys are contained in
2507 the attributes:
2509  source -- String describing the source from which multi-monitor
2510            information is obtained, \"NS\" is always the source."
2512 Internal use only, use `display-monitor-attributes-list' instead.  */)
2513   (Lisp_Object terminal)
2515   struct terminal *term = decode_live_terminal (terminal);
2516   NSArray *screens;
2517   NSUInteger i, n_monitors;
2518   struct MonitorInfo *monitors;
2519   Lisp_Object attributes_list = Qnil;
2520   CGFloat primary_display_height = 0;
2522   if (term->type != output_ns)
2523     return Qnil;
2525   screens = [NSScreen screens];
2526   n_monitors = [screens count];
2527   if (n_monitors == 0)
2528     return Qnil;
2530   monitors = xzalloc (n_monitors * sizeof *monitors);
2532   for (i = 0; i < [screens count]; ++i)
2533     {
2534       NSScreen *s = [screens objectAtIndex:i];
2535       struct MonitorInfo *m = &monitors[i];
2536       NSRect fr = [s frame];
2537       NSRect vfr = [s visibleFrame];
2538       short y, vy;
2540 #ifdef NS_IMPL_COCOA
2541       NSDictionary *dict = [s deviceDescription];
2542       NSNumber *nid = [dict objectForKey:@"NSScreenNumber"];
2543       CGDirectDisplayID did = [nid unsignedIntValue];
2544 #endif
2545       if (i == 0)
2546         {
2547           primary_display_height = fr.size.height;
2548           y = (short) fr.origin.y;
2549           vy = (short) vfr.origin.y;
2550         }
2551       else
2552         {
2553           // Flip y coordinate as NS has y starting from the bottom.
2554           y = (short) (primary_display_height - fr.size.height - fr.origin.y);
2555           vy = (short) (primary_display_height -
2556                         vfr.size.height - vfr.origin.y);
2557         }
2559       m->geom.x = (short) fr.origin.x;
2560       m->geom.y = y;
2561       m->geom.width = (unsigned short) fr.size.width;
2562       m->geom.height = (unsigned short) fr.size.height;
2564       m->work.x = (short) vfr.origin.x;
2565       // y is flipped on NS, so vy - y are pixels missing at the bottom,
2566       // and fr.size.height - vfr.size.height are pixels missing in total.
2567       // Pixels missing at top are
2568       // fr.size.height - vfr.size.height - vy + y.
2569       // work.y is then pixels missing at top + y.
2570       m->work.y = (short) (fr.size.height - vfr.size.height) - vy + y + y;
2571       m->work.width = (unsigned short) vfr.size.width;
2572       m->work.height = (unsigned short) vfr.size.height;
2574 #ifdef NS_IMPL_COCOA
2575       m->name = ns_screen_name (did);
2577       {
2578         CGSize mms = CGDisplayScreenSize (did);
2579         m->mm_width = (int) mms.width;
2580         m->mm_height = (int) mms.height;
2581       }
2583 #else
2584       // Assume 92 dpi as x-display-mm-height/x-display-mm-width does.
2585       m->mm_width = (int) (25.4 * fr.size.width / 92.0);
2586       m->mm_height = (int) (25.4 * fr.size.height / 92.0);
2587 #endif
2588     }
2590   // Primary monitor is always first for NS.
2591   attributes_list = ns_make_monitor_attribute_list (monitors, n_monitors,
2592                                                     0, "NS");
2594   free_monitors (monitors, n_monitors);
2595   return attributes_list;
2599 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
2600        0, 1, 0,
2601        doc: /* Return the number of bitplanes of the Nextstep display TERMINAL.
2602 The optional argument TERMINAL specifies which display to ask about.
2603 TERMINAL should be a terminal object, a frame or a display name (a string).
2604 If omitted or nil, that stands for the selected frame's display.  */)
2605   (Lisp_Object terminal)
2607   check_ns_display_info (terminal);
2608   return make_number
2609     (NSBitsPerPixelFromDepth ([[[NSScreen screens] objectAtIndex:0] depth]));
2613 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
2614        0, 1, 0,
2615        doc: /* Returns the number of color cells of the Nextstep display TERMINAL.
2616 The optional argument TERMINAL specifies which display to ask about.
2617 TERMINAL should be a terminal object, a frame or a display name (a string).
2618 If omitted or nil, that stands for the selected frame's display.  */)
2619   (Lisp_Object terminal)
2621   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
2622   /* We force 24+ bit depths to 24-bit to prevent an overflow.  */
2623   return make_number (1 << min (dpyinfo->n_planes, 24));
2627 /* Unused dummy def needed for compatibility. */
2628 Lisp_Object tip_frame;
2630 /* TODO: move to xdisp or similar */
2631 static void
2632 compute_tip_xy (struct frame *f,
2633                 Lisp_Object parms,
2634                 Lisp_Object dx,
2635                 Lisp_Object dy,
2636                 int width,
2637                 int height,
2638                 int *root_x,
2639                 int *root_y)
2641   Lisp_Object left, top, right, bottom;
2642   EmacsView *view = FRAME_NS_VIEW (f);
2643   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2644   NSPoint pt;
2646   /* Start with user-specified or mouse position.  */
2647   left = Fcdr (Fassq (Qleft, parms));
2648   top = Fcdr (Fassq (Qtop, parms));
2649   right = Fcdr (Fassq (Qright, parms));
2650   bottom = Fcdr (Fassq (Qbottom, parms));
2652   if ((!INTEGERP (left) && !INTEGERP (right))
2653       || (!INTEGERP (top) && !INTEGERP (bottom)))
2654     {
2655       pt.x = dpyinfo->last_mouse_motion_x;
2656       pt.y = dpyinfo->last_mouse_motion_y;
2657       /* Convert to screen coordinates */
2658       pt = [view convertPoint: pt toView: nil];
2659 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
2660       pt = [[view window] convertBaseToScreen: pt];
2661 #else
2662       {
2663         NSRect r = NSMakeRect (pt.x, pt.y, 0, 0);
2664         r = [[view window] convertRectToScreen: r];
2665         pt.x = r.origin.x;
2666         pt.y = r.origin.y;
2667       }
2668 #endif
2669     }
2670   else
2671     {
2672       /* Absolute coordinates.  */
2673       pt.x = INTEGERP (left) ? XINT (left) : XINT (right);
2674       pt.y = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
2675               - (INTEGERP (top) ? XINT (top) : XINT (bottom))
2676               - height);
2677     }
2679   /* Ensure in bounds.  (Note, screen origin = lower left.) */
2680   if (INTEGERP (left) || INTEGERP (right))
2681     *root_x = pt.x;
2682   else if (pt.x + XINT (dx) <= 0)
2683     *root_x = 0; /* Can happen for negative dx */
2684   else if (pt.x + XINT (dx) + width
2685            <= x_display_pixel_width (FRAME_DISPLAY_INFO (f)))
2686     /* It fits to the right of the pointer.  */
2687     *root_x = pt.x + XINT (dx);
2688   else if (width + XINT (dx) <= pt.x)
2689     /* It fits to the left of the pointer.  */
2690     *root_x = pt.x - width - XINT (dx);
2691   else
2692     /* Put it left justified on the screen -- it ought to fit that way.  */
2693     *root_x = 0;
2695   if (INTEGERP (top) || INTEGERP (bottom))
2696     *root_y = pt.y;
2697   else if (pt.y - XINT (dy) - height >= 0)
2698     /* It fits below the pointer.  */
2699     *root_y = pt.y - height - XINT (dy);
2700   else if (pt.y + XINT (dy) + height
2701            <= x_display_pixel_height (FRAME_DISPLAY_INFO (f)))
2702     /* It fits above the pointer */
2703       *root_y = pt.y + XINT (dy);
2704   else
2705     /* Put it on the top.  */
2706     *root_y = x_display_pixel_height (FRAME_DISPLAY_INFO (f)) - height;
2710 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
2711        doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
2712 A tooltip window is a small window displaying a string.
2714 This is an internal function; Lisp code should call `tooltip-show'.
2716 FRAME nil or omitted means use the selected frame.
2718 PARMS is an optional list of frame parameters which can be used to
2719 change the tooltip's appearance.
2721 Automatically hide the tooltip after TIMEOUT seconds.  TIMEOUT nil
2722 means use the default timeout of 5 seconds.
2724 If the list of frame parameters PARMS contains a `left' parameter,
2725 display the tooltip at that x-position.  If the list of frame parameters
2726 PARMS contains no `left' but a `right' parameter, display the tooltip
2727 right-adjusted at that x-position. Otherwise display it at the
2728 x-position of the mouse, with offset DX added (default is 5 if DX isn't
2729 specified).
2731 Likewise for the y-position: If a `top' frame parameter is specified, it
2732 determines the position of the upper edge of the tooltip window.  If a
2733 `bottom' parameter but no `top' frame parameter is specified, it
2734 determines the position of the lower edge of the tooltip window.
2735 Otherwise display the tooltip window at the y-position of the mouse,
2736 with offset DY added (default is -10).
2738 A tooltip's maximum size is specified by `x-max-tooltip-size'.
2739 Text larger than the specified size is clipped.  */)
2740      (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
2742   int root_x, root_y;
2743   ptrdiff_t count = SPECPDL_INDEX ();
2744   struct frame *f;
2745   char *str;
2746   NSSize size;
2748   specbind (Qinhibit_redisplay, Qt);
2750   CHECK_STRING (string);
2751   str = SSDATA (string);
2752   f = decode_window_system_frame (frame);
2753   if (NILP (timeout))
2754     timeout = make_number (5);
2755   else
2756     CHECK_NATNUM (timeout);
2758   if (NILP (dx))
2759     dx = make_number (5);
2760   else
2761     CHECK_NUMBER (dx);
2763   if (NILP (dy))
2764     dy = make_number (-10);
2765   else
2766     CHECK_NUMBER (dy);
2768   block_input ();
2769   if (ns_tooltip == nil)
2770     ns_tooltip = [[EmacsTooltip alloc] init];
2771   else
2772     Fx_hide_tip ();
2774   [ns_tooltip setText: str];
2775   size = [ns_tooltip frame].size;
2777   /* Move the tooltip window where the mouse pointer is.  Resize and
2778      show it.  */
2779   compute_tip_xy (f, parms, dx, dy, (int)size.width, (int)size.height,
2780                   &root_x, &root_y);
2782   [ns_tooltip showAtX: root_x Y: root_y for: XINT (timeout)];
2783   unblock_input ();
2785   return unbind_to (count, Qnil);
2789 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
2790        doc: /* Hide the current tooltip window, if there is any.
2791 Value is t if tooltip was open, nil otherwise.  */)
2792      (void)
2794   if (ns_tooltip == nil || ![ns_tooltip isActive])
2795     return Qnil;
2796   [ns_tooltip hide];
2797   return Qt;
2800 /* Return geometric attributes of FRAME.  According to the value of
2801    ATTRIBUTES return the outer edges of FRAME (Qouter_edges), the inner
2802    edges of FRAME, the root window edges of frame (Qroot_edges).  Any
2803    other value means to return the geometry as returned by
2804    Fx_frame_geometry.  */
2805 static Lisp_Object
2806 frame_geometry (Lisp_Object frame, Lisp_Object attribute)
2808   struct frame *f = decode_live_frame (frame);
2809   Lisp_Object fullscreen_symbol = Fframe_parameter (frame, Qfullscreen);
2810   bool fullscreen = (EQ (fullscreen_symbol, Qfullboth)
2811                      || EQ (fullscreen_symbol, Qfullscreen));
2812   int border = fullscreen ? 0 : f->border_width;
2813   int title_height = fullscreen ? 0 : FRAME_NS_TITLEBAR_HEIGHT (f);
2814   int native_width = FRAME_PIXEL_WIDTH (f);
2815   int native_height = FRAME_PIXEL_HEIGHT (f);
2816   int outer_width = native_width + 2 * border;
2817   int outer_height = native_height + 2 * border + title_height;
2818   int native_left = f->left_pos + border;
2819   int native_top = f->top_pos + border + title_height;
2820   int native_right = f->left_pos + outer_width - border;
2821   int native_bottom = f->top_pos + outer_height - border;
2822   int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f);
2823   int tool_bar_height = FRAME_TOOLBAR_HEIGHT (f);
2824   int tool_bar_width = (tool_bar_height
2825                         ? outer_width - 2 * internal_border_width
2826                         : 0);
2828   /* Construct list.  */
2829   if (EQ (attribute, Qouter_edges))
2830     return list4 (make_number (f->left_pos), make_number (f->top_pos),
2831                   make_number (f->left_pos + outer_width),
2832                   make_number (f->top_pos + outer_height));
2833   else if (EQ (attribute, Qnative_edges))
2834     return list4 (make_number (native_left), make_number (native_top),
2835                   make_number (native_right), make_number (native_bottom));
2836   else if (EQ (attribute, Qinner_edges))
2837     return list4 (make_number (native_left + internal_border_width),
2838                   make_number (native_top
2839                                + tool_bar_height
2840                                + internal_border_width),
2841                   make_number (native_right - internal_border_width),
2842                   make_number (native_bottom - internal_border_width));
2843   else
2844     return
2845       listn (CONSTYPE_HEAP, 10,
2846              Fcons (Qouter_position,
2847                     Fcons (make_number (f->left_pos),
2848                            make_number (f->top_pos))),
2849              Fcons (Qouter_size,
2850                     Fcons (make_number (outer_width),
2851                            make_number (outer_height))),
2852              Fcons (Qexternal_border_size,
2853                     (fullscreen
2854                      ? Fcons (make_number (0), make_number (0))
2855                      : Fcons (make_number (border), make_number (border)))),
2856              Fcons (Qtitle_bar_size,
2857                     Fcons (make_number (0), make_number (title_height))),
2858              Fcons (Qmenu_bar_external, Qnil),
2859              Fcons (Qmenu_bar_size, Fcons (make_number (0), make_number (0))),
2860              Fcons (Qtool_bar_external,
2861                     FRAME_EXTERNAL_TOOL_BAR (f) ? Qt : Qnil),
2862              Fcons (Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f)),
2863              Fcons (Qtool_bar_size,
2864                     Fcons (make_number (tool_bar_width),
2865                            make_number (tool_bar_height))),
2866              Fcons (Qinternal_border_width,
2867                     make_number (internal_border_width)));
2870 DEFUN ("ns-frame-geometry", Fns_frame_geometry, Sns_frame_geometry, 0, 1, 0,
2871        doc: /* Return geometric attributes of FRAME.
2872 FRAME must be a live frame and defaults to the selected one.  The return
2873 value is an association list of the attributes listed below.  All height
2874 and width values are in pixels.
2876 `outer-position' is a cons of the outer left and top edges of FRAME
2877   relative to the origin - the position (0, 0) - of FRAME's display.
2879 `outer-size' is a cons of the outer width and height of FRAME.  The
2880   outer size includes the title bar and the external borders as well as
2881   any menu and/or tool bar of frame.
2883 `external-border-size' is a cons of the horizontal and vertical width of
2884   FRAME's external borders as supplied by the window manager.
2886 `title-bar-size' is a cons of the width and height of the title bar of
2887   FRAME as supplied by the window manager.  If both of them are zero,
2888   FRAME has no title bar.  If only the width is zero, Emacs was not
2889   able to retrieve the width information.
2891 `menu-bar-external', if non-nil, means the menu bar is external (never
2892   included in the inner edges of FRAME).
2894 `menu-bar-size' is a cons of the width and height of the menu bar of
2895   FRAME.
2897 `tool-bar-external', if non-nil, means the tool bar is external (never
2898   included in the inner edges of FRAME).
2900 `tool-bar-position' tells on which side the tool bar on FRAME is and can
2901   be one of `left', `top', `right' or `bottom'.  If this is nil, FRAME
2902   has no tool bar.
2904 `tool-bar-size' is a cons of the width and height of the tool bar of
2905   FRAME.
2907 `internal-border-width' is the width of the internal border of
2908   FRAME.  */)
2909   (Lisp_Object frame)
2911   return frame_geometry (frame, Qnil);
2914 DEFUN ("ns-frame-edges", Fns_frame_edges, Sns_frame_edges, 0, 2, 0,
2915        doc: /* Return edge coordinates of FRAME.
2916 FRAME must be a live frame and defaults to the selected one.  The return
2917 value is a list of the form (LEFT, TOP, RIGHT, BOTTOM).  All values are
2918 in pixels relative to the origin - the position (0, 0) - of FRAME's
2919 display.
2921 If optional argument TYPE is the symbol `outer-edges', return the outer
2922 edges of FRAME.  The outer edges comprise the decorations of the window
2923 manager (like the title bar or external borders) as well as any external
2924 menu or tool bar of FRAME.  If optional argument TYPE is the symbol
2925 `native-edges' or nil, return the native edges of FRAME.  The native
2926 edges exclude the decorations of the window manager and any external
2927 menu or tool bar of FRAME.  If TYPE is the symbol `inner-edges', return
2928 the inner edges of FRAME.  These edges exclude title bar, any borders,
2929 menu bar or tool bar of FRAME.  */)
2930   (Lisp_Object frame, Lisp_Object type)
2932   return frame_geometry (frame, ((EQ (type, Qouter_edges)
2933                                   || EQ (type, Qinner_edges))
2934                                  ? type
2935                                  : Qnative_edges));
2938 /* ==========================================================================
2940     Class implementations
2942    ========================================================================== */
2945   Handle arrow/function/control keys and copy/paste/cut in file dialogs.
2946   Return YES if handled, NO if not.
2947  */
2948 static BOOL
2949 handlePanelKeys (NSSavePanel *panel, NSEvent *theEvent)
2951   NSString *s;
2952   int i;
2953   BOOL ret = NO;
2955   if ([theEvent type] != NSEventTypeKeyDown) return NO;
2956   s = [theEvent characters];
2958   for (i = 0; i < [s length]; ++i)
2959     {
2960       int ch = (int) [s characterAtIndex: i];
2961       switch (ch)
2962         {
2963         case NSHomeFunctionKey:
2964         case NSDownArrowFunctionKey:
2965         case NSUpArrowFunctionKey:
2966         case NSLeftArrowFunctionKey:
2967         case NSRightArrowFunctionKey:
2968         case NSPageUpFunctionKey:
2969         case NSPageDownFunctionKey:
2970         case NSEndFunctionKey:
2971           /* Don't send command modified keys, as those are handled in the
2972              performKeyEquivalent method of the super class.
2973           */
2974           if (! ([theEvent modifierFlags] & NSEventModifierFlagCommand))
2975             {
2976               [panel sendEvent: theEvent];
2977               ret = YES;
2978             }
2979           break;
2980           /* As we don't have the standard key commands for
2981              copy/paste/cut/select-all in our edit menu, we must handle
2982              them here.  TODO: handle Emacs key bindings for copy/cut/select-all
2983              here, paste works, because we have that in our Edit menu.
2984              I.e. refactor out code in nsterm.m, keyDown: to figure out the
2985              correct modifier.
2986           */
2987         case 'x': // Cut
2988         case 'c': // Copy
2989         case 'v': // Paste
2990         case 'a': // Select all
2991           if ([theEvent modifierFlags] & NSEventModifierFlagCommand)
2992             {
2993               [NSApp sendAction:
2994                        (ch == 'x'
2995                         ? @selector(cut:)
2996                         : (ch == 'c'
2997                            ? @selector(copy:)
2998                            : (ch == 'v'
2999                               ? @selector(paste:)
3000                               : @selector(selectAll:))))
3001                              to:nil from:panel];
3002               ret = YES;
3003             }
3004         default:
3005           // Send all control keys, as the text field supports C-a, C-f, C-e
3006           // C-b and more.
3007           if ([theEvent modifierFlags] & NSEventModifierFlagControl)
3008             {
3009               [panel sendEvent: theEvent];
3010               ret = YES;
3011             }
3012           break;
3013         }
3014     }
3017   return ret;
3020 @implementation EmacsSavePanel
3021 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent
3023   BOOL ret = handlePanelKeys (self, theEvent);
3024   if (! ret)
3025     ret = [super performKeyEquivalent:theEvent];
3026   return ret;
3028 @end
3031 @implementation EmacsOpenPanel
3032 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent
3034   // NSOpenPanel inherits NSSavePanel, so passing self is OK.
3035   BOOL ret = handlePanelKeys (self, theEvent);
3036   if (! ret)
3037     ret = [super performKeyEquivalent:theEvent];
3038   return ret;
3040 @end
3043 @implementation EmacsFileDelegate
3044 /* --------------------------------------------------------------------------
3045    Delegate methods for Open/Save panels
3046    -------------------------------------------------------------------------- */
3047 - (BOOL)panel: (id)sender isValidFilename: (NSString *)filename
3049   return YES;
3051 - (BOOL)panel: (id)sender shouldShowFilename: (NSString *)filename
3053   return YES;
3055 - (NSString *)panel: (id)sender userEnteredFilename: (NSString *)filename
3056           confirmed: (BOOL)okFlag
3058   return filename;
3060 @end
3062 #endif
3065 /* ==========================================================================
3067     Lisp interface declaration
3069    ========================================================================== */
3072 void
3073 syms_of_nsfns (void)
3075   DEFSYM (Qfontsize, "fontsize");
3076   DEFSYM (Qframe_title_format, "frame-title-format");
3077   DEFSYM (Qicon_title_format, "icon-title-format");
3079   DEFVAR_LISP ("ns-icon-type-alist", Vns_icon_type_alist,
3080                doc: /* Alist of elements (REGEXP . IMAGE) for images of icons associated to frames.
3081 If the title of a frame matches REGEXP, then IMAGE.tiff is
3082 selected as the image of the icon representing the frame when it's
3083 miniaturized.  If an element is t, then Emacs tries to select an icon
3084 based on the filetype of the visited file.
3086 The images have to be installed in a folder called English.lproj in the
3087 Emacs folder.  You have to restart Emacs after installing new icons.
3089 Example: Install an icon Gnus.tiff and execute the following code
3091   (setq ns-icon-type-alist
3092         (append ns-icon-type-alist
3093                 \\='((\"^\\\\*\\\\(Group\\\\*$\\\\|Summary \\\\|Article\\\\*$\\\\)\"
3094                    . \"Gnus\"))))
3096 When you miniaturize a Group, Summary or Article frame, Gnus.tiff will
3097 be used as the image of the icon representing the frame.  */);
3098   Vns_icon_type_alist = list1 (Qt);
3100   DEFVAR_LISP ("ns-version-string", Vns_version_string,
3101                doc: /* Toolkit version for NS Windowing.  */);
3102   Vns_version_string = ns_appkit_version_str ();
3104   defsubr (&Sns_read_file_name);
3105   defsubr (&Sns_get_resource);
3106   defsubr (&Sns_set_resource);
3107   defsubr (&Sxw_display_color_p); /* this and next called directly by C code */
3108   defsubr (&Sx_display_grayscale_p);
3109   defsubr (&Sns_font_name);
3110   defsubr (&Sns_list_colors);
3111 #ifdef NS_IMPL_COCOA
3112   defsubr (&Sns_do_applescript);
3113 #endif
3114   defsubr (&Sxw_color_defined_p);
3115   defsubr (&Sxw_color_values);
3116   defsubr (&Sx_server_max_request_size);
3117   defsubr (&Sx_server_vendor);
3118   defsubr (&Sx_server_version);
3119   defsubr (&Sx_display_pixel_width);
3120   defsubr (&Sx_display_pixel_height);
3121   defsubr (&Sns_display_monitor_attributes_list);
3122   defsubr (&Sns_frame_geometry);
3123   defsubr (&Sns_frame_edges);
3124   defsubr (&Sx_display_mm_width);
3125   defsubr (&Sx_display_mm_height);
3126   defsubr (&Sx_display_screens);
3127   defsubr (&Sx_display_planes);
3128   defsubr (&Sx_display_color_cells);
3129   defsubr (&Sx_display_visual_class);
3130   defsubr (&Sx_display_backing_store);
3131   defsubr (&Sx_display_save_under);
3132   defsubr (&Sx_create_frame);
3133   defsubr (&Sx_open_connection);
3134   defsubr (&Sx_close_connection);
3135   defsubr (&Sx_display_list);
3137   defsubr (&Sns_hide_others);
3138   defsubr (&Sns_hide_emacs);
3139   defsubr (&Sns_emacs_info_panel);
3140   defsubr (&Sns_list_services);
3141   defsubr (&Sns_perform_service);
3142   defsubr (&Sns_popup_font_panel);
3143   defsubr (&Sns_popup_color_panel);
3145   defsubr (&Sx_show_tip);
3146   defsubr (&Sx_hide_tip);
3148   as_status = 0;
3149   as_script = Qnil;
3150   as_result = 0;