Allow 'browse-url-emacs' to fetch URL in the selected window
[emacs.git] / src / nsfns.m
blob6407560d89e0af1fe4016f010700678d6c1f7046
1 /* Functions for the NeXT/Open/GNUstep and macOS window system.
3 Copyright (C) 1989, 1992-1994, 2005-2006, 2008-2018 Free Software
4 Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or (at
11 your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
31 #include <config.h>
33 #include <math.h>
34 #include <c-strcase.h>
36 #include "lisp.h"
37 #include "blockinput.h"
38 #include "nsterm.h"
39 #include "window.h"
40 #include "character.h"
41 #include "buffer.h"
42 #include "keyboard.h"
43 #include "termhooks.h"
44 #include "fontset.h"
45 #include "font.h"
47 #ifdef NS_IMPL_COCOA
48 #include <IOKit/graphics/IOGraphicsLib.h>
49 #include "macfont.h"
50 #endif
53 #ifdef HAVE_NS
55 static EmacsTooltip *ns_tooltip = nil;
57 /* Static variables to handle applescript execution.  */
58 static Lisp_Object as_script, *as_result;
59 static int as_status;
61 static ptrdiff_t image_cache_refcount;
63 static struct ns_display_info *ns_display_info_for_name (Lisp_Object);
65 /* ==========================================================================
67     Internal utility functions
69    ========================================================================== */
71 /* Let the user specify a Nextstep display with a Lisp object.
72    OBJECT may be nil, a frame or a terminal object.
73    nil stands for the selected frame--or, if that is not a Nextstep frame,
74    the first Nextstep display on the list.  */
76 static struct ns_display_info *
77 check_ns_display_info (Lisp_Object object)
79   struct ns_display_info *dpyinfo = NULL;
81   if (NILP (object))
82     {
83       struct frame *sf = XFRAME (selected_frame);
85       if (FRAME_NS_P (sf) && FRAME_LIVE_P (sf))
86         dpyinfo = FRAME_DISPLAY_INFO (sf);
87       else if (x_display_list != 0)
88         dpyinfo = x_display_list;
89       else
90         error ("Nextstep windows are not in use or not initialized");
91     }
92   else if (TERMINALP (object))
93     {
94       struct terminal *t = decode_live_terminal (object);
96       if (t->type != output_ns)
97         error ("Terminal %d is not a Nextstep display", t->id);
99       dpyinfo = t->display_info.ns;
100     }
101   else if (STRINGP (object))
102     dpyinfo = ns_display_info_for_name (object);
103   else
104     {
105       struct frame *f = decode_window_system_frame (object);
106       dpyinfo = FRAME_DISPLAY_INFO (f);
107     }
109   return dpyinfo;
113 static id
114 ns_get_window (Lisp_Object maybeFrame)
116   id view =nil, window =nil;
118   if (!FRAMEP (maybeFrame) || !FRAME_NS_P (XFRAME (maybeFrame)))
119     maybeFrame = selected_frame;/*wrong_type_argument (Qframep, maybeFrame); */
121   if (!NILP (maybeFrame))
122     view = FRAME_NS_VIEW (XFRAME (maybeFrame));
123   if (view) window =[view window];
125   return window;
129 /* Return the X display structure for the display named NAME.
130    Open a new connection if necessary.  */
131 static struct ns_display_info *
132 ns_display_info_for_name (Lisp_Object name)
134   struct ns_display_info *dpyinfo;
136   CHECK_STRING (name);
138   for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
139     if (!NILP (Fstring_equal (XCAR (dpyinfo->name_list_element), name)))
140       return dpyinfo;
142   error ("Emacs for Nextstep does not yet support multi-display");
144   Fx_open_connection (name, Qnil, Qnil);
145   dpyinfo = x_display_list;
147   if (dpyinfo == 0)
148     error ("Display on %s not responding.\n", SDATA (name));
150   return dpyinfo;
153 static NSString *
154 ns_filename_from_panel (NSSavePanel *panel)
156 #ifdef NS_IMPL_COCOA
157   NSURL *url = [panel URL];
158   NSString *str = [url path];
159   return str;
160 #else
161   return [panel filename];
162 #endif
165 static NSString *
166 ns_directory_from_panel (NSSavePanel *panel)
168 #ifdef NS_IMPL_COCOA
169   NSURL *url = [panel directoryURL];
170   NSString *str = [url path];
171   return str;
172 #else
173   return [panel directory];
174 #endif
177 #ifndef NS_IMPL_COCOA
178 static Lisp_Object
179 interpret_services_menu (NSMenu *menu, Lisp_Object prefix, Lisp_Object old)
180 /* --------------------------------------------------------------------------
181    Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
182    -------------------------------------------------------------------------- */
184   int i, count;
185   NSMenuItem *item;
186   const char *name;
187   Lisp_Object nameStr;
188   unsigned short key;
189   NSString *keys;
190   Lisp_Object res;
192   count = [menu numberOfItems];
193   for (i = 0; i<count; i++)
194     {
195       item = [menu itemAtIndex: i];
196       name = [[item title] UTF8String];
197       if (!name) continue;
199       nameStr = build_string (name);
201       if ([item hasSubmenu])
202         {
203           old = interpret_services_menu ([item submenu],
204                                         Fcons (nameStr, prefix), old);
205         }
206       else
207         {
208           keys = [item keyEquivalent];
209           if (keys && [keys length] )
210             {
211               key = [keys characterAtIndex: 0];
212               res = make_number (key|super_modifier);
213             }
214           else
215             {
216               res = Qundefined;
217             }
218           old = Fcons (Fcons (res,
219                             Freverse (Fcons (nameStr,
220                                            prefix))),
221                     old);
222         }
223     }
224   return old;
226 #endif
229 /* ==========================================================================
231     Frame parameter setters
233    ========================================================================== */
236 static void
237 x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
239   NSColor *col;
240   EmacsCGFloat r, g, b, alpha;
242   /* Must block_input, because ns_lisp_to_color does block/unblock_input
243      which means that col may be deallocated in its unblock_input if there
244      is user input, unless we also block_input.  */
245   block_input ();
246   if (ns_lisp_to_color (arg, &col))
247     {
248       store_frame_param (f, Qforeground_color, oldval);
249       unblock_input ();
250       error ("Unknown color");
251     }
253   [col retain];
254   [f->output_data.ns->foreground_color release];
255   f->output_data.ns->foreground_color = col;
257   [col getRed: &r green: &g blue: &b alpha: &alpha];
258   FRAME_FOREGROUND_PIXEL (f) =
259     ARGB_TO_ULONG ((int)(alpha*0xff), (int)(r*0xff), (int)(g*0xff), (int)(b*0xff));
261   if (FRAME_NS_VIEW (f))
262     {
263       update_face_from_frame_parameter (f, Qforeground_color, arg);
264       /*recompute_basic_faces (f); */
265       if (FRAME_VISIBLE_P (f))
266         SET_FRAME_GARBAGED (f);
267     }
268   unblock_input ();
272 static void
273 x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
275   struct face *face;
276   NSColor *col;
277   NSView *view = FRAME_NS_VIEW (f);
278   EmacsCGFloat r, g, b, alpha;
280   block_input ();
281   if (ns_lisp_to_color (arg, &col))
282     {
283       store_frame_param (f, Qbackground_color, oldval);
284       unblock_input ();
285       error ("Unknown color");
286     }
288   /* clear the frame; in some instances the NS-internal GC appears not 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   if (ns_use_proxy_icon)
486     ns_set_represented_filename (f);
488   ns_set_name (f, arg, 0);
492 /* Change the title of frame F to NAME.
493    If NAME is nil, use the frame name as the title.  */
495 static void
496 x_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name)
498   NSTRACE ("x_set_title");
499   /* Don't change the title if it's already NAME.  */
500   if (EQ (name, f->title))
501     return;
503   update_mode_lines = 22;
505   fset_title (f, name);
507   if (NILP (name))
508     name = f->name;
509   else
510     CHECK_STRING (name);
512   ns_set_name_internal (f, name);
515 void
516 ns_set_doc_edited (void)
518   NSAutoreleasePool *pool;
519   Lisp_Object tail, frame;
520   block_input ();
521   pool = [[NSAutoreleasePool alloc] init];
522   FOR_EACH_FRAME (tail, frame)
523     {
524       BOOL edited = NO;
525       struct frame *f = XFRAME (frame);
526       struct window *w;
527       NSView *view;
529       if (! FRAME_NS_P (f)) continue;
530       w = XWINDOW (FRAME_SELECTED_WINDOW (f));
531       view = FRAME_NS_VIEW (f);
532       if (!MINI_WINDOW_P (w))
533         edited = ! NILP (Fbuffer_modified_p (w->contents)) &&
534           ! NILP (Fbuffer_file_name (w->contents));
535       [[view window] setDocumentEdited: edited];
536     }
538   [pool release];
539   unblock_input ();
543 static void
544 x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
546   int nlines;
547   if (FRAME_MINIBUF_ONLY_P (f))
548     return;
550   if (TYPE_RANGED_INTEGERP (int, value))
551     nlines = XINT (value);
552   else
553     nlines = 0;
555   FRAME_MENU_BAR_LINES (f) = 0;
556   if (nlines)
557     {
558       FRAME_EXTERNAL_MENU_BAR (f) = 1;
559       /* does for all frames, whereas we just want for one frame
560          [NSMenu setMenuBarVisible: YES]; */
561     }
562   else
563     {
564       if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
565         free_frame_menubar (f);
566       /*      [NSMenu setMenuBarVisible: NO]; */
567       FRAME_EXTERNAL_MENU_BAR (f) = 0;
568     }
572 /* toolbar support */
573 static void
574 x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
576   /* Currently, when the tool bar change state, the frame is resized.
578      TODO: It would be better if this didn't occur when 1) the frame
579      is full height or maximized or 2) when specified by
580      `frame-inhibit-implied-resize'. */
581   int nlines;
583   NSTRACE ("x_set_tool_bar_lines");
585   if (FRAME_MINIBUF_ONLY_P (f))
586     return;
588   if (RANGED_INTEGERP (0, value, INT_MAX))
589     nlines = XFASTINT (value);
590   else
591     nlines = 0;
593   if (nlines)
594     {
595       FRAME_EXTERNAL_TOOL_BAR (f) = 1;
596       update_frame_tool_bar (f);
597     }
598   else
599     {
600       if (FRAME_EXTERNAL_TOOL_BAR (f))
601         {
602           free_frame_tool_bar (f);
603           FRAME_EXTERNAL_TOOL_BAR (f) = 0;
605           {
606             EmacsView *view = FRAME_NS_VIEW (f);
607             int fs_state = [view fullscreenState];
609             if (fs_state == FULLSCREEN_MAXIMIZED)
610               {
611                 [view setFSValue:FULLSCREEN_WIDTH];
612               }
613             else if (fs_state == FULLSCREEN_HEIGHT)
614               {
615                 [view setFSValue:FULLSCREEN_NONE];
616               }
617           }
618        }
619     }
621   {
622     int inhibit
623       = ((f->after_make_frame
624           && !f->tool_bar_resized
625           && (EQ (frame_inhibit_implied_resize, Qt)
626               || (CONSP (frame_inhibit_implied_resize)
627                   && !NILP (Fmemq (Qtool_bar_lines,
628                                    frame_inhibit_implied_resize))))
629           && NILP (get_frame_param (f, Qfullscreen)))
630          ? 0
631          : 2);
633     NSTRACE_MSG ("inhibit:%d", inhibit);
635     frame_size_history_add (f, Qupdate_frame_tool_bar, 0, 0, Qnil);
636     adjust_frame_size (f, -1, -1, inhibit, 0, Qtool_bar_lines);
637   }
641 static void
642 x_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
644   int old_width = FRAME_INTERNAL_BORDER_WIDTH (f);
646   CHECK_TYPE_RANGED_INTEGER (int, arg);
647   f->internal_border_width = XINT (arg);
648   if (FRAME_INTERNAL_BORDER_WIDTH (f) < 0)
649     f->internal_border_width = 0;
651   if (FRAME_INTERNAL_BORDER_WIDTH (f) == old_width)
652     return;
654   if (FRAME_X_WINDOW (f) != 0)
655     adjust_frame_size (f, -1, -1, 3, 0, Qinternal_border_width);
657   SET_FRAME_GARBAGED (f);
661 static void
662 ns_implicitly_set_icon_type (struct frame *f)
664   Lisp_Object tem;
665   EmacsView *view = FRAME_NS_VIEW (f);
666   id image = nil;
667   Lisp_Object chain, elt;
668   NSAutoreleasePool *pool;
669   BOOL setMini = YES;
671   NSTRACE ("ns_implicitly_set_icon_type");
673   block_input ();
674   pool = [[NSAutoreleasePool alloc] init];
675   if (f->output_data.ns->miniimage
676       && [[NSString stringWithUTF8String: SSDATA (f->name)]
677                isEqualToString: [(NSImage *)f->output_data.ns->miniimage name]])
678     {
679       [pool release];
680       unblock_input ();
681       return;
682     }
684   tem = assq_no_quit (Qicon_type, f->param_alist);
685   if (CONSP (tem) && ! NILP (XCDR (tem)))
686     {
687       [pool release];
688       unblock_input ();
689       return;
690     }
692   for (chain = Vns_icon_type_alist;
693        image == nil && CONSP (chain);
694        chain = XCDR (chain))
695     {
696       elt = XCAR (chain);
697       /* special case: t means go by file type */
698       if (SYMBOLP (elt) && EQ (elt, Qt) && SSDATA (f->name)[0] == '/')
699         {
700           NSString *str
701              = [NSString stringWithUTF8String: SSDATA (f->name)];
702           if ([[NSFileManager defaultManager] fileExistsAtPath: str])
703             image = [[[NSWorkspace sharedWorkspace] iconForFile: str] retain];
704         }
705       else if (CONSP (elt) &&
706                STRINGP (XCAR (elt)) &&
707                STRINGP (XCDR (elt)) &&
708                fast_string_match (XCAR (elt), f->name) >= 0)
709         {
710           image = [EmacsImage allocInitFromFile: XCDR (elt)];
711           if (image == nil)
712             image = [[NSImage imageNamed:
713                                [NSString stringWithUTF8String:
714                                             SSDATA (XCDR (elt))]] retain];
715         }
716     }
718   if (image == nil)
719     {
720       image = [[[NSWorkspace sharedWorkspace] iconForFileType: @"text"] retain];
721       setMini = NO;
722     }
724   [f->output_data.ns->miniimage release];
725   f->output_data.ns->miniimage = image;
726   [view setMiniwindowImage: setMini];
727   [pool release];
728   unblock_input ();
732 static void
733 x_set_icon_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
735   EmacsView *view = FRAME_NS_VIEW (f);
736   id image = nil;
737   BOOL setMini = YES;
739   NSTRACE ("x_set_icon_type");
741   if (!NILP (arg) && SYMBOLP (arg))
742     {
743       arg =build_string (SSDATA (SYMBOL_NAME (arg)));
744       store_frame_param (f, Qicon_type, arg);
745     }
747   /* do it the implicit way */
748   if (NILP (arg))
749     {
750       ns_implicitly_set_icon_type (f);
751       return;
752     }
754   CHECK_STRING (arg);
756   image = [EmacsImage allocInitFromFile: arg];
757   if (image == nil)
758     image =[NSImage imageNamed: [NSString stringWithUTF8String:
759                                             SSDATA (arg)]];
761   if (image == nil)
762     {
763       image = [NSImage imageNamed: @"text"];
764       setMini = NO;
765     }
767   f->output_data.ns->miniimage = image;
768   [view setMiniwindowImage: setMini];
771 /* This is the same as the xfns.c definition.  */
772 static void
773 x_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
775   set_frame_cursor_types (f, arg);
778 /* called to set mouse pointer color, but all other terms use it to
779    initialize pointer types (and don't set the color ;) */
780 static void
781 x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
783   /* don't think we can do this on Nextstep */
787 #define Str(x) #x
788 #define Xstr(x) Str(x)
790 static Lisp_Object
791 ns_appkit_version_str (void)
793   char tmp[256];
795 #ifdef NS_IMPL_GNUSTEP
796   sprintf(tmp, "gnustep-gui-%s", Xstr(GNUSTEP_GUI_VERSION));
797 #elif defined (NS_IMPL_COCOA)
798   NSString *osversion
799     = [[NSProcessInfo processInfo] operatingSystemVersionString];
800   sprintf(tmp, "appkit-%.2f %s",
801           NSAppKitVersionNumber,
802           [osversion UTF8String]);
803 #else
804   tmp = "ns-unknown";
805 #endif
806   return build_string (tmp);
810 /* This is for use by x-server-version and collapses all version info we
811    have into a single int.  For a better picture of the implementation
812    running, use ns_appkit_version_str.*/
813 static int
814 ns_appkit_version_int (void)
816 #ifdef NS_IMPL_GNUSTEP
817   return GNUSTEP_GUI_MAJOR_VERSION * 100 + GNUSTEP_GUI_MINOR_VERSION;
818 #elif defined (NS_IMPL_COCOA)
819   return (int)NSAppKitVersionNumber;
820 #endif
821   return 0;
825 static void
826 x_icon (struct frame *f, Lisp_Object parms)
827 /* --------------------------------------------------------------------------
828    Strangely-named function to set icon position parameters in frame.
829    This is irrelevant under macOS, but might be needed under GNUstep,
830    depending on the window manager used.  Note, this is not a standard
831    frame parameter-setter; it is called directly from x-create-frame.
832    -------------------------------------------------------------------------- */
834   Lisp_Object icon_x, icon_y;
835   struct ns_display_info *dpyinfo = check_ns_display_info (Qnil);
837   f->output_data.ns->icon_top = -1;
838   f->output_data.ns->icon_left = -1;
840   /* Set the position of the icon.  */
841   icon_x = x_get_arg (dpyinfo, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
842   icon_y = x_get_arg (dpyinfo, parms, Qicon_top, 0, 0,  RES_TYPE_NUMBER);
843   if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
844     {
845       CHECK_NUMBER (icon_x);
846       CHECK_NUMBER (icon_y);
847       f->output_data.ns->icon_top = XINT (icon_y);
848       f->output_data.ns->icon_left = XINT (icon_x);
849     }
850   else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
851     error ("Both left and top icon corners of icon must be specified");
855 /* Note: see frame.c for template, also where generic functions are impl */
856 frame_parm_handler ns_frame_parm_handlers[] =
858   x_set_autoraise, /* generic OK */
859   x_set_autolower, /* generic OK */
860   x_set_background_color,
861   0, /* x_set_border_color,  may be impossible under Nextstep */
862   0, /* x_set_border_width,  may be impossible under Nextstep */
863   x_set_cursor_color,
864   x_set_cursor_type,
865   x_set_font, /* generic OK */
866   x_set_foreground_color,
867   x_set_icon_name,
868   x_set_icon_type,
869   x_set_internal_border_width, /* generic OK */
870   x_set_right_divider_width,
871   x_set_bottom_divider_width,
872   x_set_menu_bar_lines,
873   x_set_mouse_color,
874   x_explicitly_set_name,
875   x_set_scroll_bar_width, /* generic OK */
876   x_set_scroll_bar_height, /* generic OK */
877   x_set_title,
878   x_set_unsplittable, /* generic OK */
879   x_set_vertical_scroll_bars, /* generic OK */
880   x_set_horizontal_scroll_bars, /* generic OK */
881   x_set_visibility, /* generic OK */
882   x_set_tool_bar_lines,
883   0, /* x_set_scroll_bar_foreground, will ignore (not possible on NS) */
884   0, /* x_set_scroll_bar_background,  will ignore (not possible on NS) */
885   x_set_screen_gamma, /* generic OK */
886   x_set_line_spacing, /* generic OK, sets f->extra_line_spacing to int */
887   x_set_left_fringe, /* generic OK */
888   x_set_right_fringe, /* generic OK */
889   0, /* x_set_wait_for_wm, will ignore */
890   x_set_fullscreen, /* generic OK */
891   x_set_font_backend, /* generic OK */
892   x_set_alpha,
893   0, /* x_set_sticky */
894   0, /* x_set_tool_bar_position */
895   0, /* x_set_inhibit_double_buffering */
896 #ifdef NS_IMPL_COCOA
897   x_set_undecorated,
898 #else
899   0, /*x_set_undecorated */
900 #endif
901   x_set_parent_frame,
902   0, /* x_set_skip_taskbar */
903   x_set_no_focus_on_map,
904   x_set_no_accept_focus,
905   x_set_z_group, /* x_set_z_group */
906   0, /* x_set_override_redirect */
907   x_set_no_special_glyphs,
908 #ifdef NS_IMPL_COCOA
909   ns_set_appearance,
910   ns_set_transparent_titlebar,
911 #endif
915 /* Handler for signals raised during x_create_frame.
916    FRAME is the frame which is partially constructed.  */
918 static void
919 unwind_create_frame (Lisp_Object frame)
921   struct frame *f = XFRAME (frame);
923   /* If frame is already dead, nothing to do.  This can happen if the
924      display is disconnected after the frame has become official, but
925      before x_create_frame removes the unwind protect.  */
926   if (!FRAME_LIVE_P (f))
927     return;
929   /* If frame is ``official'', nothing to do.  */
930   if (NILP (Fmemq (frame, Vframe_list)))
931     {
932 #if defined GLYPH_DEBUG && defined ENABLE_CHECKING
933       struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
934 #endif
936       /* If the frame's image cache refcount is still the same as our
937          private shadow variable, it means we are unwinding a frame
938          for which we didn't yet call init_frame_faces, where the
939          refcount is incremented.  Therefore, we increment it here, so
940          that free_frame_faces, called in x_free_frame_resources
941          below, will not mistakenly decrement the counter that was not
942          incremented yet to account for this new frame.  */
943       if (FRAME_IMAGE_CACHE (f) != NULL
944           && FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount)
945         FRAME_IMAGE_CACHE (f)->refcount++;
947       x_free_frame_resources (f);
948       free_glyphs (f);
950 #if defined GLYPH_DEBUG && defined ENABLE_CHECKING
951       /* Check that reference counts are indeed correct.  */
952       eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
953 #endif
954     }
958  * Read geometry related parameters from preferences if not in PARMS.
959  * Returns the union of parms and any preferences read.
960  */
962 static Lisp_Object
963 get_geometry_from_preferences (struct ns_display_info *dpyinfo,
964                                Lisp_Object parms)
966   struct {
967     const char *val;
968     const char *cls;
969     Lisp_Object tem;
970   } r[] = {
971     { "width",  "Width", Qwidth },
972     { "height", "Height", Qheight },
973     { "left", "Left", Qleft },
974     { "top", "Top", Qtop },
975   };
977   int i;
978   for (i = 0; i < ARRAYELTS (r); ++i)
979     {
980       if (NILP (Fassq (r[i].tem, parms)))
981         {
982           Lisp_Object value
983             = x_get_arg (dpyinfo, parms, r[i].tem, r[i].val, r[i].cls,
984                          RES_TYPE_NUMBER);
985           if (! EQ (value, Qunbound))
986             parms = Fcons (Fcons (r[i].tem, value), parms);
987         }
988     }
990   return parms;
993 /* ==========================================================================
995     Lisp definitions
997    ========================================================================== */
999 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
1000        1, 1, 0,
1001        doc: /* SKIP: real doc in xfns.c.  */)
1002      (Lisp_Object parms)
1004   struct frame *f;
1005   Lisp_Object frame, tem;
1006   Lisp_Object name;
1007   int minibuffer_only = 0;
1008   long window_prompting = 0;
1009   ptrdiff_t count = specpdl_ptr - specpdl;
1010   Lisp_Object display;
1011   struct ns_display_info *dpyinfo = NULL;
1012   Lisp_Object parent, parent_frame;
1013   struct kboard *kb;
1014   static int desc_ctr = 1;
1015   int x_width = 0, x_height = 0;
1017   /* x_get_arg modifies parms.  */
1018   parms = Fcopy_alist (parms);
1020   /* Use this general default value to start with
1021      until we know if this frame has a specified name.  */
1022   Vx_resource_name = Vinvocation_name;
1024   display = x_get_arg (dpyinfo, parms, Qterminal, 0, 0, RES_TYPE_STRING);
1025   if (EQ (display, Qunbound))
1026     display = Qnil;
1027   dpyinfo = check_ns_display_info (display);
1028   kb = dpyinfo->terminal->kboard;
1030   if (!dpyinfo->terminal->name)
1031     error ("Terminal is not live, can't create new frames on it");
1033   name = x_get_arg (dpyinfo, parms, Qname, 0, 0, RES_TYPE_STRING);
1034   if (!STRINGP (name)
1035       && ! EQ (name, Qunbound)
1036       && ! NILP (name))
1037     error ("Invalid frame name--not a string or nil");
1039   if (STRINGP (name))
1040     Vx_resource_name = name;
1042   parent = x_get_arg (dpyinfo, parms, Qparent_id, 0, 0, RES_TYPE_NUMBER);
1043   if (EQ (parent, Qunbound))
1044     parent = Qnil;
1045   if (! NILP (parent))
1046     CHECK_NUMBER (parent);
1048   /* make_frame_without_minibuffer can run Lisp code and garbage collect.  */
1049   /* No need to protect DISPLAY because that's not used after passing
1050      it to make_frame_without_minibuffer.  */
1051   frame = Qnil;
1052   tem = x_get_arg (dpyinfo, parms, Qminibuffer, "minibuffer", "Minibuffer",
1053                   RES_TYPE_SYMBOL);
1054   if (EQ (tem, Qnone) || NILP (tem))
1055       f = make_frame_without_minibuffer (Qnil, kb, display);
1056   else if (EQ (tem, Qonly))
1057     {
1058       f = make_minibuffer_frame ();
1059       minibuffer_only = 1;
1060     }
1061   else if (WINDOWP (tem))
1062       f = make_frame_without_minibuffer (tem, kb, display);
1063   else
1064       f = make_frame (1);
1066   XSETFRAME (frame, f);
1068   f->terminal = dpyinfo->terminal;
1070   f->output_method = output_ns;
1071   f->output_data.ns = xzalloc (sizeof *f->output_data.ns);
1073   FRAME_FONTSET (f) = -1;
1075   fset_icon_name (f, x_get_arg (dpyinfo, parms, Qicon_name,
1076                                 "iconName", "Title",
1077                                 RES_TYPE_STRING));
1078   if (! STRINGP (f->icon_name))
1079     fset_icon_name (f, Qnil);
1081   FRAME_DISPLAY_INFO (f) = dpyinfo;
1083   /* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe.  */
1084   record_unwind_protect (unwind_create_frame, frame);
1086   f->output_data.ns->window_desc = desc_ctr++;
1087   if (TYPE_RANGED_INTEGERP (Window, parent))
1088     {
1089       f->output_data.ns->parent_desc = XFASTINT (parent);
1090       f->output_data.ns->explicit_parent = 1;
1091     }
1092   else
1093     {
1094       f->output_data.ns->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
1095       f->output_data.ns->explicit_parent = 0;
1096     }
1098   /* Set the name; the functions to which we pass f expect the name to
1099      be set.  */
1100   if (EQ (name, Qunbound) || NILP (name) || ! STRINGP (name))
1101     {
1102       fset_name (f, build_string ([ns_app_name UTF8String]));
1103       f->explicit_name = 0;
1104     }
1105   else
1106     {
1107       fset_name (f, name);
1108       f->explicit_name = 1;
1109       specbind (Qx_resource_name, name);
1110     }
1112   block_input ();
1114 #ifdef NS_IMPL_COCOA
1115     mac_register_font_driver (f);
1116 #else
1117     register_font_driver (&nsfont_driver, f);
1118 #endif
1120   image_cache_refcount =
1121     FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
1123   x_default_parameter (f, parms, Qfont_backend, Qnil,
1124                         "fontBackend", "FontBackend", RES_TYPE_STRING);
1126   {
1127     /* use for default font name */
1128     id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */
1129     x_default_parameter (f, parms, Qfontsize,
1130                                     make_number (0 /*(int)[font pointSize]*/),
1131                                     "fontSize", "FontSize", RES_TYPE_NUMBER);
1132     // Remove ' Regular', not handled by backends.
1133     char *fontname = xstrdup ([[font displayName] UTF8String]);
1134     int len = strlen (fontname);
1135     if (len > 8 && strcmp (fontname + len - 8, " Regular") == 0)
1136       fontname[len-8] = '\0';
1137     x_default_parameter (f, parms, Qfont,
1138                                  build_string (fontname),
1139                                  "font", "Font", RES_TYPE_STRING);
1140     xfree (fontname);
1141   }
1142   unblock_input ();
1144   x_default_parameter (f, parms, Qborder_width, make_number (0),
1145                        "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
1146   x_default_parameter (f, parms, Qinternal_border_width, make_number (2),
1147                       "internalBorderWidth", "InternalBorderWidth",
1148                       RES_TYPE_NUMBER);
1149   x_default_parameter (f, parms, Qright_divider_width, make_number (0),
1150                        NULL, NULL, RES_TYPE_NUMBER);
1151   x_default_parameter (f, parms, Qbottom_divider_width, make_number (0),
1152                        NULL, NULL, RES_TYPE_NUMBER);
1154   /* default vertical scrollbars on right on Mac */
1155   {
1156       Lisp_Object spos
1157 #ifdef NS_IMPL_GNUSTEP
1158           = Qt;
1159 #else
1160           = Qright;
1161 #endif
1162       x_default_parameter (f, parms, Qvertical_scroll_bars, spos,
1163                            "verticalScrollBars", "VerticalScrollBars",
1164                            RES_TYPE_SYMBOL);
1165   }
1166   x_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil,
1167                        "horizontalScrollBars", "HorizontalScrollBars",
1168                        RES_TYPE_SYMBOL);
1169   x_default_parameter (f, parms, Qforeground_color, build_string ("Black"),
1170                       "foreground", "Foreground", RES_TYPE_STRING);
1171   x_default_parameter (f, parms, Qbackground_color, build_string ("White"),
1172                       "background", "Background", RES_TYPE_STRING);
1173   /* FIXME: not supported yet in Nextstep */
1174   x_default_parameter (f, parms, Qline_spacing, Qnil,
1175                        "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
1176   x_default_parameter (f, parms, Qleft_fringe, Qnil,
1177                        "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
1178   x_default_parameter (f, parms, Qright_fringe, Qnil,
1179                        "rightFringe", "RightFringe", RES_TYPE_NUMBER);
1180   x_default_parameter (f, parms, Qno_special_glyphs, Qnil,
1181                        NULL, NULL, RES_TYPE_BOOLEAN);
1183   init_frame_faces (f);
1185   /* Read comment about this code in corresponding place in xfns.c.  */
1186   tem = x_get_arg (dpyinfo, parms, Qmin_width, NULL, NULL, RES_TYPE_NUMBER);
1187   if (NUMBERP (tem))
1188     store_frame_param (f, Qmin_width, tem);
1189   tem = x_get_arg (dpyinfo, parms, Qmin_height, NULL, NULL, RES_TYPE_NUMBER);
1190   if (NUMBERP (tem))
1191     store_frame_param (f, Qmin_height, tem);
1192   adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
1193                      FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1,
1194                      Qx_create_frame_1);
1196   tem = x_get_arg (dpyinfo, parms, Qundecorated, NULL, NULL, RES_TYPE_BOOLEAN);
1197   FRAME_UNDECORATED (f) = !NILP (tem) && !EQ (tem, Qunbound);
1198   store_frame_param (f, Qundecorated, FRAME_UNDECORATED (f) ? Qt : Qnil);
1200 #ifdef NS_IMPL_COCOA
1201   tem = x_get_arg (dpyinfo, parms, Qns_appearance, NULL, NULL, RES_TYPE_SYMBOL);
1202   FRAME_NS_APPEARANCE (f) = EQ (tem, Qdark)
1203     ? ns_appearance_vibrant_dark : ns_appearance_aqua;
1204   store_frame_param (f, Qns_appearance, tem);
1206   tem = x_get_arg (dpyinfo, parms, Qns_transparent_titlebar,
1207                    NULL, NULL, RES_TYPE_BOOLEAN);
1208   FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (tem) && !EQ (tem, Qunbound);
1209   store_frame_param (f, Qns_transparent_titlebar, tem);
1210 #endif
1212   parent_frame = x_get_arg (dpyinfo, parms, Qparent_frame, NULL, NULL,
1213                             RES_TYPE_SYMBOL);
1214   /* Accept parent-frame iff parent-id was not specified.  */
1215   if (!NILP (parent)
1216       || EQ (parent_frame, Qunbound)
1217       || NILP (parent_frame)
1218       || !FRAMEP (parent_frame)
1219       || !FRAME_LIVE_P (XFRAME (parent_frame)))
1220     parent_frame = Qnil;
1222   fset_parent_frame (f, parent_frame);
1223   store_frame_param (f, Qparent_frame, parent_frame);
1225   x_default_parameter (f, parms, Qz_group, Qnil, NULL, NULL, RES_TYPE_SYMBOL);
1226   x_default_parameter (f, parms, Qno_focus_on_map, Qnil,
1227                        NULL, NULL, RES_TYPE_BOOLEAN);
1228   x_default_parameter (f, parms, Qno_accept_focus, Qnil,
1229                        NULL, NULL, RES_TYPE_BOOLEAN);
1231   /* The resources controlling the menu-bar and tool-bar are
1232      processed specially at startup, and reflected in the mode
1233      variables; ignore them here.  */
1234   x_default_parameter (f, parms, Qmenu_bar_lines,
1235                        NILP (Vmenu_bar_mode)
1236                        ? make_number (0) : make_number (1),
1237                        NULL, NULL, RES_TYPE_NUMBER);
1238   x_default_parameter (f, parms, Qtool_bar_lines,
1239                        NILP (Vtool_bar_mode)
1240                        ? make_number (0) : make_number (1),
1241                        NULL, NULL, RES_TYPE_NUMBER);
1243   x_default_parameter (f, parms, Qbuffer_predicate, Qnil, "bufferPredicate",
1244                        "BufferPredicate", RES_TYPE_SYMBOL);
1245   x_default_parameter (f, parms, Qtitle, Qnil, "title", "Title",
1246                        RES_TYPE_STRING);
1248   parms = get_geometry_from_preferences (dpyinfo, parms);
1249   window_prompting = x_figure_window_size (f, parms, true, &x_width, &x_height);
1251   tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
1252   f->no_split = minibuffer_only || (!EQ (tem, Qunbound) && !EQ (tem, Qnil));
1254   /* NOTE: on other terms, this is done in set_mouse_color, however this
1255      was not getting called under Nextstep */
1256   f->output_data.ns->text_cursor = [NSCursor IBeamCursor];
1257   f->output_data.ns->nontext_cursor = [NSCursor arrowCursor];
1258   f->output_data.ns->modeline_cursor = [NSCursor pointingHandCursor];
1259   f->output_data.ns->hand_cursor = [NSCursor pointingHandCursor];
1260   f->output_data.ns->hourglass_cursor = [NSCursor disappearingItemCursor];
1261   f->output_data.ns->horizontal_drag_cursor = [NSCursor resizeLeftRightCursor];
1262   f->output_data.ns->vertical_drag_cursor = [NSCursor resizeUpDownCursor];
1263   f->output_data.ns->left_edge_cursor = [NSCursor resizeLeftRightCursor];
1264   f->output_data.ns->top_left_corner_cursor = [NSCursor arrowCursor];
1265   f->output_data.ns->top_edge_cursor = [NSCursor resizeUpDownCursor];
1266   f->output_data.ns->top_right_corner_cursor = [NSCursor arrowCursor];
1267   f->output_data.ns->right_edge_cursor = [NSCursor resizeLeftRightCursor];
1268   f->output_data.ns->bottom_right_corner_cursor = [NSCursor arrowCursor];
1269   f->output_data.ns->bottom_edge_cursor = [NSCursor resizeUpDownCursor];
1270   f->output_data.ns->bottom_left_corner_cursor = [NSCursor arrowCursor];
1272   FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor
1273      = [NSCursor arrowCursor];
1274   FRAME_DISPLAY_INFO (f)->horizontal_scroll_bar_cursor
1275      = [NSCursor arrowCursor];
1276   f->output_data.ns->current_pointer = f->output_data.ns->text_cursor;
1278   f->output_data.ns->in_animation = NO;
1280   [[EmacsView alloc] initFrameFromEmacs: f];
1282   x_icon (f, parms);
1284   /* ns_display_info does not have a reference_count.  */
1285   f->terminal->reference_count++;
1287   /* It is now ok to make the frame official even if we get an error below.
1288      The frame needs to be on Vframe_list or making it visible won't work. */
1289   Vframe_list = Fcons (frame, Vframe_list);
1291   x_default_parameter (f, parms, Qicon_type, Qnil,
1292                        "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
1294   x_default_parameter (f, parms, Qauto_raise, Qnil,
1295                        "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
1296   x_default_parameter (f, parms, Qauto_lower, Qnil,
1297                        "autoLower", "AutoLower", RES_TYPE_BOOLEAN);
1298   x_default_parameter (f, parms, Qcursor_type, Qbox,
1299                        "cursorType", "CursorType", RES_TYPE_SYMBOL);
1300   x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
1301                        "scrollBarWidth", "ScrollBarWidth",
1302                        RES_TYPE_NUMBER);
1303   x_default_parameter (f, parms, Qscroll_bar_height, Qnil,
1304                        "scrollBarHeight", "ScrollBarHeight",
1305                        RES_TYPE_NUMBER);
1306   x_default_parameter (f, parms, Qalpha, Qnil,
1307                        "alpha", "Alpha", RES_TYPE_NUMBER);
1308   x_default_parameter (f, parms, Qfullscreen, Qnil,
1309                        "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
1311   /* Allow x_set_window_size, now.  */
1312   f->can_x_set_window_size = true;
1314   if (x_width > 0)
1315     SET_FRAME_WIDTH (f, x_width);
1316   if (x_height > 0)
1317     SET_FRAME_HEIGHT (f, x_height);
1319   adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 0, 1,
1320                      Qx_create_frame_2);
1322   if (! f->output_data.ns->explicit_parent)
1323     {
1324       Lisp_Object visibility;
1326       visibility = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
1327                               RES_TYPE_SYMBOL);
1328       if (EQ (visibility, Qunbound))
1329         visibility = Qt;
1331       if (EQ (visibility, Qicon))
1332         x_iconify_frame (f);
1333       else if (! NILP (visibility))
1334         {
1335           x_make_frame_visible (f);
1336           [[FRAME_NS_VIEW (f) window] makeKeyWindow];
1337         }
1338       else
1339         {
1340           /* Must have been Qnil.  */
1341         }
1342     }
1344   if (FRAME_HAS_MINIBUF_P (f)
1345       && (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame))
1346           || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame)))))
1347     kset_default_minibuffer_frame (kb, frame);
1349   /* All remaining specified parameters, which have not been "used"
1350      by x_get_arg and friends, now go in the misc. alist of the frame.  */
1351   for (tem = parms; CONSP (tem); tem = XCDR (tem))
1352     if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem))))
1353       fset_param_alist (f, Fcons (XCAR (tem), f->param_alist));
1355   if (window_prompting & USPosition)
1356     x_set_offset (f, f->left_pos, f->top_pos, 1);
1358   /* Make sure windows on this frame appear in calls to next-window
1359      and similar functions.  */
1360   Vwindow_list = Qnil;
1362   return unbind_to (count, frame);
1365 void
1366 x_focus_frame (struct frame *f, bool noactivate)
1368   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1370   if (dpyinfo->x_focus_frame != f)
1371     {
1372       EmacsView *view = FRAME_NS_VIEW (f);
1373       block_input ();
1374       [NSApp activateIgnoringOtherApps: YES];
1375       [[view window] makeKeyAndOrderFront: view];
1376       unblock_input ();
1377     }
1380 static BOOL
1381 ns_window_is_ancestor (NSWindow *win, NSWindow *candidate)
1382 /* Test whether CANDIDATE is an ancestor window of WIN. */
1384   if (candidate == NULL)
1385     return NO;
1386   else if (win == candidate)
1387     return YES;
1388   else
1389     return ns_window_is_ancestor(win, [candidate parentWindow]);
1392 DEFUN ("ns-frame-list-z-order", Fns_frame_list_z_order,
1393        Sns_frame_list_z_order, 0, 1, 0,
1394        doc: /* Return list of Emacs' frames, in Z (stacking) order.
1395 If TERMINAL is non-nil and specifies a live frame, return the child
1396 frames of that frame in Z (stacking) order.
1398 Frames are listed from topmost (first) to bottommost (last).  */)
1399   (Lisp_Object terminal)
1401   Lisp_Object frames = Qnil;
1402   NSWindow *parent = nil;
1404   if (FRAMEP (terminal) && FRAME_LIVE_P (XFRAME (terminal)))
1405     parent = [FRAME_NS_VIEW (XFRAME (terminal)) window];
1407   for (NSWindow *win in [[NSApp orderedWindows] reverseObjectEnumerator])
1408     {
1409       Lisp_Object frame;
1411       /* Check against [win parentWindow] so that it doesn't match itself. */
1412       if (parent == nil || ns_window_is_ancestor (parent, [win parentWindow]))
1413         {
1414           XSETFRAME (frame, ((EmacsView *)[win delegate])->emacsframe);
1415           frames = Fcons(frame, frames);
1416         }
1417     }
1419   return frames;
1422 DEFUN ("ns-frame-restack", Fns_frame_restack, Sns_frame_restack, 2, 3, 0,
1423        doc: /* Restack FRAME1 below FRAME2.
1424 This means that if both frames are visible and the display areas of
1425 these frames overlap, FRAME2 (partially) obscures FRAME1.  If optional
1426 third argument ABOVE is non-nil, restack FRAME1 above FRAME2.  This
1427 means that if both frames are visible and the display areas of these
1428 frames overlap, FRAME1 (partially) obscures FRAME2.
1430 Some window managers may refuse to restack windows.  */)
1431      (Lisp_Object frame1, Lisp_Object frame2, Lisp_Object above)
1433   struct frame *f1 = decode_live_frame (frame1);
1434   struct frame *f2 = decode_live_frame (frame2);
1436   if (FRAME_NS_VIEW (f1) && FRAME_NS_VIEW (f2))
1437     {
1438       NSWindow *window = [FRAME_NS_VIEW (f1) window];
1439       NSInteger window2 = [[FRAME_NS_VIEW (f2) window] windowNumber];
1440       NSWindowOrderingMode flag = NILP (above) ? NSWindowBelow : NSWindowAbove;
1442       [window orderWindow: flag
1443                relativeTo: window2];
1445       return Qt;
1446     }
1447   else
1448     {
1449       error ("Cannot restack frames");
1450       return Qnil;
1451     }
1454 DEFUN ("ns-popup-font-panel", Fns_popup_font_panel, Sns_popup_font_panel,
1455        0, 1, "",
1456        doc: /* Pop up the font panel. */)
1457      (Lisp_Object frame)
1459   struct frame *f = decode_window_system_frame (frame);
1460   id fm = [NSFontManager sharedFontManager];
1461   struct font *font = f->output_data.ns->font;
1462   NSFont *nsfont;
1463 #ifdef NS_IMPL_GNUSTEP
1464   nsfont = ((struct nsfont_info *)font)->nsfont;
1465 #endif
1466 #ifdef NS_IMPL_COCOA
1467   nsfont = (NSFont *) macfont_get_nsctfont (font);
1468 #endif
1469   [fm setSelectedFont: nsfont isMultiple: NO];
1470   [fm orderFrontFontPanel: NSApp];
1471   return Qnil;
1475 DEFUN ("ns-popup-color-panel", Fns_popup_color_panel, Sns_popup_color_panel,
1476        0, 1, "",
1477        doc: /* Pop up the color panel.  */)
1478      (Lisp_Object frame)
1480   check_window_system (NULL);
1481   [NSApp orderFrontColorPanel: NSApp];
1482   return Qnil;
1485 static struct
1487   id panel;
1488   BOOL ret;
1489 #ifdef NS_IMPL_GNUSTEP
1490   NSString *dirS, *initS;
1491   BOOL no_types;
1492 #endif
1493 } ns_fd_data;
1495 void
1496 ns_run_file_dialog (void)
1498   if (ns_fd_data.panel == nil) return;
1499 #ifdef NS_IMPL_COCOA
1500   ns_fd_data.ret = [ns_fd_data.panel runModal];
1501 #else
1502   if (ns_fd_data.no_types)
1503     {
1504       ns_fd_data.ret = [ns_fd_data.panel
1505                            runModalForDirectory: ns_fd_data.dirS
1506                            file: ns_fd_data.initS];
1507     }
1508   else
1509     {
1510       ns_fd_data.ret = [ns_fd_data.panel
1511                            runModalForDirectory: ns_fd_data.dirS
1512                            file: ns_fd_data.initS
1513                            types: nil];
1514     }
1515 #endif
1516   ns_fd_data.panel = nil;
1519 #ifdef NS_IMPL_COCOA
1520 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
1521 #define MODAL_OK_RESPONSE NSModalResponseOK
1522 #endif
1523 #endif
1524 #ifndef MODAL_OK_RESPONSE
1525 #define MODAL_OK_RESPONSE NSOKButton
1526 #endif
1528 DEFUN ("ns-read-file-name", Fns_read_file_name, Sns_read_file_name, 1, 5, 0,
1529        doc: /* Use a graphical panel to read a file name, using prompt PROMPT.
1530 Optional arg DIR, if non-nil, supplies a default directory.
1531 Optional arg MUSTMATCH, if non-nil, means the returned file or
1532 directory must exist.
1533 Optional arg INIT, if non-nil, provides a default file name to use.
1534 Optional arg DIR_ONLY_P, if non-nil, means choose only directories.  */)
1535   (Lisp_Object prompt, Lisp_Object dir, Lisp_Object mustmatch,
1536    Lisp_Object init, Lisp_Object dir_only_p)
1538   static id fileDelegate = nil;
1539   BOOL isSave = NILP (mustmatch) && NILP (dir_only_p);
1540   id panel;
1541   Lisp_Object fname = Qnil;
1543   NSString *promptS = NILP (prompt) || !STRINGP (prompt) ? nil :
1544     [NSString stringWithUTF8String: SSDATA (prompt)];
1545   NSString *dirS = NILP (dir) || !STRINGP (dir) ?
1546     [NSString stringWithUTF8String: SSDATA (BVAR (current_buffer, directory))] :
1547     [NSString stringWithUTF8String: SSDATA (dir)];
1548   NSString *initS = NILP (init) || !STRINGP (init) ? nil :
1549     [NSString stringWithUTF8String: SSDATA (init)];
1550   NSEvent *nxev;
1552   check_window_system (NULL);
1554   if (fileDelegate == nil)
1555     fileDelegate = [EmacsFileDelegate new];
1557   [NSCursor setHiddenUntilMouseMoves: NO];
1559   if ([dirS characterAtIndex: 0] == '~')
1560     dirS = [dirS stringByExpandingTildeInPath];
1562   panel = isSave ?
1563     (id)[EmacsSavePanel savePanel] : (id)[EmacsOpenPanel openPanel];
1565   [panel setTitle: promptS];
1567   [panel setAllowsOtherFileTypes: YES];
1568   [panel setTreatsFilePackagesAsDirectories: YES];
1569   [panel setDelegate: fileDelegate];
1571   if (! NILP (dir_only_p))
1572     {
1573       [panel setCanChooseDirectories: YES];
1574       [panel setCanChooseFiles: NO];
1575     }
1576   else if (! isSave)
1577     {
1578       /* This is not quite what the documentation says, but it is compatible
1579          with the Gtk+ code.  Also, the menu entry says "Open File...".  */
1580       [panel setCanChooseDirectories: NO];
1581       [panel setCanChooseFiles: YES];
1582     }
1584   block_input ();
1585   ns_fd_data.panel = panel;
1586   ns_fd_data.ret = NO;
1587 #ifdef NS_IMPL_COCOA
1588   if (! NILP (mustmatch) || ! NILP (dir_only_p))
1589     [panel setAllowedFileTypes: nil];
1590   if (dirS) [panel setDirectoryURL: [NSURL fileURLWithPath: dirS]];
1591   if (initS && NILP (Ffile_directory_p (init)))
1592     [panel setNameFieldStringValue: [initS lastPathComponent]];
1593   else
1594     [panel setNameFieldStringValue: @""];
1596 #else
1597   ns_fd_data.no_types = NILP (mustmatch) && NILP (dir_only_p);
1598   ns_fd_data.dirS = dirS;
1599   ns_fd_data.initS = initS;
1600 #endif
1602   /* runModalForDirectory/runModal restarts the main event loop when done,
1603      so we must start an event loop and then pop up the file dialog.
1604      The file dialog may pop up a confirm dialog after Ok has been pressed,
1605      so we can not simply pop down on the Ok/Cancel press.
1606    */
1607   nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
1608                             location: NSMakePoint (0, 0)
1609                        modifierFlags: 0
1610                            timestamp: 0
1611                         windowNumber: [[NSApp mainWindow] windowNumber]
1612                              context: [NSApp context]
1613                              subtype: 0
1614                                data1: 0
1615                                data2: NSAPP_DATA2_RUNFILEDIALOG];
1617   [NSApp postEvent: nxev atStart: NO];
1618   while (ns_fd_data.panel != nil)
1619     [NSApp run];
1621   if (ns_fd_data.ret == MODAL_OK_RESPONSE)
1622     {
1623       NSString *str = ns_filename_from_panel (panel);
1624       if (! str) str = ns_directory_from_panel (panel);
1625       if (str) fname = build_string ([str UTF8String]);
1626     }
1628   [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
1629   unblock_input ();
1631   return fname;
1634 const char *
1635 ns_get_defaults_value (const char *key)
1637   NSObject *obj = [[NSUserDefaults standardUserDefaults]
1638                     objectForKey: [NSString stringWithUTF8String: key]];
1640   if (!obj) return NULL;
1642   return [[NSString stringWithFormat: @"%@", obj] UTF8String];
1646 DEFUN ("ns-get-resource", Fns_get_resource, Sns_get_resource, 2, 2, 0,
1647        doc: /* Return the value of the property NAME of OWNER from the defaults database.
1648 If OWNER is nil, Emacs is assumed.  */)
1649      (Lisp_Object owner, Lisp_Object name)
1651   const char *value;
1653   check_window_system (NULL);
1654   if (NILP (owner))
1655     owner = build_string([ns_app_name UTF8String]);
1656   CHECK_STRING (name);
1658   value = ns_get_defaults_value (SSDATA (name));
1660   if (value)
1661     return build_string (value);
1662   return Qnil;
1666 DEFUN ("ns-set-resource", Fns_set_resource, Sns_set_resource, 3, 3, 0,
1667        doc: /* Set property NAME of OWNER to VALUE, from the defaults database.
1668 If OWNER is nil, Emacs is assumed.
1669 If VALUE is nil, the default is removed.  */)
1670      (Lisp_Object owner, Lisp_Object name, Lisp_Object value)
1672   check_window_system (NULL);
1673   if (NILP (owner))
1674     owner = build_string ([ns_app_name UTF8String]);
1675   CHECK_STRING (name);
1676   if (NILP (value))
1677     {
1678       [[NSUserDefaults standardUserDefaults] removeObjectForKey:
1679                          [NSString stringWithUTF8String: SSDATA (name)]];
1680     }
1681   else
1682     {
1683       CHECK_STRING (value);
1684       [[NSUserDefaults standardUserDefaults] setObject:
1685                 [NSString stringWithUTF8String: SSDATA (value)]
1686                                         forKey: [NSString stringWithUTF8String:
1687                                                          SSDATA (name)]];
1688     }
1690   return Qnil;
1694 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
1695        Sx_server_max_request_size,
1696        0, 1, 0,
1697        doc: /* SKIP: real doc in xfns.c.  */)
1698      (Lisp_Object terminal)
1700   check_ns_display_info (terminal);
1701   /* This function has no real equivalent under NeXTstep.  Return nil to
1702      indicate this. */
1703   return Qnil;
1707 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
1708        doc: /* SKIP: real doc in xfns.c.  */)
1709   (Lisp_Object terminal)
1711   check_ns_display_info (terminal);
1712 #ifdef NS_IMPL_GNUSTEP
1713   return build_string ("GNU");
1714 #else
1715   return build_string ("Apple");
1716 #endif
1720 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
1721        doc: /* SKIP: real doc in xfns.c.  */)
1722   (Lisp_Object terminal)
1724   check_ns_display_info (terminal);
1725   /*NOTE: it is unclear what would best correspond with "protocol";
1726           we return 10.3, meaning Panther, since this is roughly the
1727           level that GNUstep's APIs correspond to.
1728           The last number is where we distinguish between the Apple
1729           and GNUstep implementations ("distributor-specific release
1730           number") and give int'ized versions of major.minor. */
1731   return list3i (10, 3, ns_appkit_version_int ());
1735 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
1736        doc: /* SKIP: real doc in xfns.c.  */)
1737   (Lisp_Object terminal)
1739   check_ns_display_info (terminal);
1740   return make_number (1);
1744 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
1745        doc: /* SKIP: real doc in xfns.c.  */)
1746   (Lisp_Object terminal)
1748   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
1750   return make_number (x_display_pixel_height (dpyinfo) / (92.0/25.4));
1754 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
1755        doc: /* SKIP: real doc in xfns.c.  */)
1756   (Lisp_Object terminal)
1758   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
1760   return make_number (x_display_pixel_width (dpyinfo) / (92.0/25.4));
1764 DEFUN ("x-display-backing-store", Fx_display_backing_store,
1765        Sx_display_backing_store, 0, 1, 0,
1766        doc: /* SKIP: real doc in xfns.c.  */)
1767   (Lisp_Object terminal)
1769   check_ns_display_info (terminal);
1770   /* Note that the xfns.c version has different return values.  */
1771   switch ([ns_get_window (terminal) backingType])
1772     {
1773     case NSBackingStoreBuffered:
1774       return intern ("buffered");
1775 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300
1776     case NSBackingStoreRetained:
1777       return intern ("retained");
1778     case NSBackingStoreNonretained:
1779       return intern ("non-retained");
1780 #endif
1781     default:
1782       error ("Strange value for backingType parameter of frame");
1783     }
1784   return Qnil;  /* not reached, shut compiler up */
1788 DEFUN ("x-display-visual-class", Fx_display_visual_class,
1789        Sx_display_visual_class, 0, 1, 0,
1790        doc: /* SKIP: real doc in xfns.c.  */)
1791   (Lisp_Object terminal)
1793   NSWindowDepth depth;
1795   check_ns_display_info (terminal);
1796   depth = [[[NSScreen screens] objectAtIndex:0] depth];
1798   if ( depth == NSBestDepth (NSCalibratedWhiteColorSpace, 2, 2, YES, NULL))
1799     return intern ("static-gray");
1800   else if (depth == NSBestDepth (NSCalibratedWhiteColorSpace, 8, 8, YES, NULL))
1801     return intern ("gray-scale");
1802   else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 8, 8, YES, NULL))
1803     return intern ("pseudo-color");
1804   else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 4, 12, NO, NULL))
1805     return intern ("true-color");
1806   else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 8, 24, NO, NULL))
1807     return intern ("direct-color");
1808   else
1809     /* color mgmt as far as we do it is really handled by Nextstep itself anyway */
1810     return intern ("direct-color");
1814 DEFUN ("x-display-save-under", Fx_display_save_under,
1815        Sx_display_save_under, 0, 1, 0,
1816        doc: /* SKIP: real doc in xfns.c.  */)
1817   (Lisp_Object terminal)
1819   check_ns_display_info (terminal);
1820   switch ([ns_get_window (terminal) backingType])
1821     {
1822     case NSBackingStoreBuffered:
1823       return Qt;
1825 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300
1826     case NSBackingStoreRetained:
1827     case NSBackingStoreNonretained:
1828       return Qnil;
1829 #endif
1831     default:
1832       error ("Strange value for backingType parameter of frame");
1833     }
1834   return Qnil;  /* not reached, shut compiler up */
1838 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
1839        1, 3, 0,
1840        doc: /* SKIP: real doc in xfns.c.  */)
1841      (Lisp_Object display, Lisp_Object resource_string, Lisp_Object must_succeed)
1843   struct ns_display_info *dpyinfo;
1845   CHECK_STRING (display);
1847   nxatoms_of_nsselect ();
1848   dpyinfo = ns_term_init (display);
1849   if (dpyinfo == 0)
1850     {
1851       if (!NILP (must_succeed))
1852         fatal ("Display on %s not responding.\n",
1853                SSDATA (display));
1854       else
1855         error ("Display on %s not responding.\n",
1856                SSDATA (display));
1857     }
1859   return Qnil;
1863 DEFUN ("x-close-connection", Fx_close_connection, Sx_close_connection,
1864        1, 1, 0,
1865        doc: /* SKIP: real doc in xfns.c.  */)
1866      (Lisp_Object terminal)
1868   check_ns_display_info (terminal);
1869   [NSApp terminate: NSApp];
1870   return Qnil;
1874 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
1875        doc: /* SKIP: real doc in xfns.c.  */)
1876      (void)
1878   Lisp_Object result = Qnil;
1879   struct ns_display_info *ndi;
1881   for (ndi = x_display_list; ndi; ndi = ndi->next)
1882     result = Fcons (XCAR (ndi->name_list_element), result);
1884   return result;
1888 DEFUN ("ns-hide-others", Fns_hide_others, Sns_hide_others,
1889        0, 0, 0,
1890        doc: /* Hides all applications other than Emacs.  */)
1891      (void)
1893   check_window_system (NULL);
1894   [NSApp hideOtherApplications: NSApp];
1895   return Qnil;
1898 DEFUN ("ns-hide-emacs", Fns_hide_emacs, Sns_hide_emacs,
1899        1, 1, 0,
1900        doc: /* If ON is non-nil, the entire Emacs application is hidden.
1901 Otherwise if Emacs is hidden, it is unhidden.
1902 If ON is equal to `activate', Emacs is unhidden and becomes
1903 the active application.  */)
1904      (Lisp_Object on)
1906   check_window_system (NULL);
1907   if (EQ (on, intern ("activate")))
1908     {
1909       [NSApp unhide: NSApp];
1910       [NSApp activateIgnoringOtherApps: YES];
1911     }
1912   else if (NILP (on))
1913     [NSApp unhide: NSApp];
1914   else
1915     [NSApp hide: NSApp];
1916   return Qnil;
1920 DEFUN ("ns-emacs-info-panel", Fns_emacs_info_panel, Sns_emacs_info_panel,
1921        0, 0, 0,
1922        doc: /* Shows the 'Info' or 'About' panel for Emacs.  */)
1923      (void)
1925   check_window_system (NULL);
1926   [NSApp orderFrontStandardAboutPanel: nil];
1927   return Qnil;
1931 DEFUN ("ns-font-name", Fns_font_name, Sns_font_name, 1, 1, 0,
1932        doc: /* Determine font PostScript or family name for font NAME.
1933 NAME should be a string containing either the font name or an XLFD
1934 font descriptor.  If string contains `fontset' and not
1935 `fontset-startup', it is left alone. */)
1936      (Lisp_Object name)
1938   char *nm;
1939   CHECK_STRING (name);
1940   nm = SSDATA (name);
1942   if (nm[0] != '-')
1943     return name;
1944   if (strstr (nm, "fontset") && !strstr (nm, "fontset-startup"))
1945     return name;
1947   return build_string (ns_xlfd_to_fontname (SSDATA (name)));
1951 DEFUN ("ns-list-colors", Fns_list_colors, Sns_list_colors, 0, 1, 0,
1952        doc: /* Return a list of all available colors.
1953 The optional argument FRAME is currently ignored.  */)
1954      (Lisp_Object frame)
1956   Lisp_Object list = Qnil;
1957   NSEnumerator *colorlists;
1958   NSColorList *clist;
1960   if (!NILP (frame))
1961     {
1962       CHECK_FRAME (frame);
1963       if (! FRAME_NS_P (XFRAME (frame)))
1964         error ("non-Nextstep frame used in `ns-list-colors'");
1965     }
1967   block_input ();
1969   colorlists = [[NSColorList availableColorLists] objectEnumerator];
1970   while ((clist = [colorlists nextObject]))
1971     {
1972       if ([[clist name] length] < 7 ||
1973           [[clist name] rangeOfString: @"PANTONE"].location == 0)
1974         {
1975           NSEnumerator *cnames = [[clist allKeys] reverseObjectEnumerator];
1976           NSString *cname;
1977           while ((cname = [cnames nextObject]))
1978             list = Fcons (build_string ([cname UTF8String]), list);
1979 /*           for (i = [[clist allKeys] count] - 1; i >= 0; i--)
1980                list = Fcons (build_string ([[[clist allKeys] objectAtIndex: i]
1981                                              UTF8String]), list); */
1982         }
1983     }
1985   unblock_input ();
1987   return list;
1991 DEFUN ("ns-list-services", Fns_list_services, Sns_list_services, 0, 0, 0,
1992        doc: /* List available Nextstep services by querying NSApp.  */)
1993      (void)
1995 #ifdef NS_IMPL_COCOA
1996   /* You can't get services like this in 10.6+.  */
1997   return Qnil;
1998 #else
1999   Lisp_Object ret = Qnil;
2000   NSMenu *svcs;
2002   check_window_system (NULL);
2003   svcs = [[NSMenu alloc] initWithTitle: @"Services"];
2004   [NSApp setServicesMenu: svcs];
2005   [NSApp registerServicesMenuSendTypes: ns_send_types
2006                            returnTypes: ns_return_types];
2008   [svcs setAutoenablesItems: NO];
2010   ret = interpret_services_menu (svcs, Qnil, ret);
2011   return ret;
2012 #endif
2016 DEFUN ("ns-perform-service", Fns_perform_service, Sns_perform_service,
2017        2, 2, 0,
2018        doc: /* Perform Nextstep SERVICE on SEND.
2019 SEND should be either a string or nil.
2020 The return value is the result of the service, as string, or nil if
2021 there was no result.  */)
2022      (Lisp_Object service, Lisp_Object send)
2024   id pb;
2025   NSString *svcName;
2026   char *utfStr;
2028   CHECK_STRING (service);
2029   check_window_system (NULL);
2031   utfStr = SSDATA (service);
2032   svcName = [NSString stringWithUTF8String: utfStr];
2034   pb =[NSPasteboard pasteboardWithUniqueName];
2035   ns_string_to_pasteboard (pb, send);
2037   if (NSPerformService (svcName, pb) == NO)
2038     Fsignal (Qquit, list1 (build_string ("service not available")));
2040   if ([[pb types] count] == 0)
2041     return build_string ("");
2042   return ns_string_from_pasteboard (pb);
2046 #ifdef NS_IMPL_COCOA
2048 /* Compile and execute the AppleScript SCRIPT and return the error
2049    status as function value.  A zero is returned if compilation and
2050    execution is successful, in which case *RESULT is set to a Lisp
2051    string or a number containing the resulting script value.  Otherwise,
2052    1 is returned. */
2053 static int
2054 ns_do_applescript (Lisp_Object script, Lisp_Object *result)
2056   NSAppleEventDescriptor *desc;
2057   NSDictionary *errorDict;
2058   NSAppleEventDescriptor *returnDescriptor = NULL;
2060   NSAppleScript *scriptObject =
2061     [[NSAppleScript alloc] initWithSource:
2062                              [NSString stringWithUTF8String: SSDATA (script)]];
2064   returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
2065   [scriptObject release];
2066   *result = Qnil;
2068   if (returnDescriptor != NULL)
2069     {
2070       // successful execution
2071       if (kAENullEvent != [returnDescriptor descriptorType])
2072         {
2073           *result = Qt;
2074           // script returned an AppleScript result
2075           if ((typeUnicodeText == [returnDescriptor descriptorType]) ||
2076 #if defined (NS_IMPL_COCOA)
2077               (typeUTF16ExternalRepresentation
2078                == [returnDescriptor descriptorType]) ||
2079 #endif
2080               (typeUTF8Text == [returnDescriptor descriptorType]) ||
2081               (typeCString == [returnDescriptor descriptorType]))
2082             {
2083               desc = [returnDescriptor coerceToDescriptorType: typeUTF8Text];
2084               if (desc)
2085                 *result = build_string([[desc stringValue] UTF8String]);
2086             }
2087           else
2088             {
2089               /* use typeUTF16ExternalRepresentation? */
2090               // coerce the result to the appropriate ObjC type
2091               desc = [returnDescriptor coerceToDescriptorType: typeUTF8Text];
2092               if (desc)
2093                 *result = make_number([desc int32Value]);
2094             }
2095         }
2096     }
2097   else
2098     {
2099       // no script result, return error
2100       return 1;
2101     }
2102   return 0;
2105 /* Helper function called from sendEvent to run applescript
2106    from within the main event loop.  */
2108 void
2109 ns_run_ascript (void)
2111   if (! NILP (as_script))
2112     as_status = ns_do_applescript (as_script, as_result);
2113   as_script = Qnil;
2116 DEFUN ("ns-do-applescript", Fns_do_applescript, Sns_do_applescript, 1, 1, 0,
2117        doc: /* Execute AppleScript SCRIPT and return the result.
2118 If compilation and execution are successful, the resulting script value
2119 is returned as a string, a number or, in the case of other constructs, t.
2120 In case the execution fails, an error is signaled. */)
2121      (Lisp_Object script)
2123   Lisp_Object result;
2124   int status;
2125   NSEvent *nxev;
2126   struct input_event ev;
2128   CHECK_STRING (script);
2129   check_window_system (NULL);
2131   block_input ();
2133   as_script = script;
2134   as_result = &result;
2136   /* executing apple script requires the event loop to run, otherwise
2137      errors aren't returned and executeAndReturnError hangs forever.
2138      Post an event that runs applescript and then start the event loop.
2139      The event loop is exited when the script is done.  */
2140   nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
2141                             location: NSMakePoint (0, 0)
2142                        modifierFlags: 0
2143                            timestamp: 0
2144                         windowNumber: [[NSApp mainWindow] windowNumber]
2145                              context: [NSApp context]
2146                              subtype: 0
2147                                data1: 0
2148                                data2: NSAPP_DATA2_RUNASSCRIPT];
2150   [NSApp postEvent: nxev atStart: NO];
2152   // If there are other events, the event loop may exit.  Keep running
2153   // until the script has been handled.  */
2154   ns_init_events (&ev);
2155   while (! NILP (as_script))
2156     [NSApp run];
2157   ns_finish_events ();
2159   status = as_status;
2160   as_status = 0;
2161   as_result = 0;
2162   unblock_input ();
2163   if (status == 0)
2164     return result;
2165   else if (!STRINGP (result))
2166     error ("AppleScript error %d", status);
2167   else
2168     error ("%s", SSDATA (result));
2170 #endif
2174 /* ==========================================================================
2176     Miscellaneous functions not called through hooks
2178    ========================================================================== */
2180 /* called from frame.c */
2181 struct ns_display_info *
2182 check_x_display_info (Lisp_Object frame)
2184   return check_ns_display_info (frame);
2188 void
2189 x_set_scroll_bar_default_width (struct frame *f)
2191   int wid = FRAME_COLUMN_WIDTH (f);
2192   FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = NS_SCROLL_BAR_WIDTH_DEFAULT;
2193   FRAME_CONFIG_SCROLL_BAR_COLS (f) = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) +
2194                                       wid - 1) / wid;
2197 void
2198 x_set_scroll_bar_default_height (struct frame *f)
2200   int height = FRAME_LINE_HEIGHT (f);
2201   FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = NS_SCROLL_BAR_WIDTH_DEFAULT;
2202   FRAME_CONFIG_SCROLL_BAR_LINES (f) = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) +
2203                                        height - 1) / height;
2206 /* terms impl this instead of x-get-resource directly */
2207 char *
2208 x_get_string_resource (XrmDatabase rdb, const char *name, const char *class)
2210   /* remove appname prefix; TODO: allow for !="Emacs" */
2211   const char *res, *toCheck = class + (!strncmp (class, "Emacs.", 6) ? 6 : 0);
2213   check_window_system (NULL);
2215   if (inhibit_x_resources)
2216     /* --quick was passed, so this is a no-op.  */
2217     return NULL;
2219   res = ns_get_defaults_value (toCheck);
2220   return (char *) (!res ? NULL
2221                    : !c_strncasecmp (res, "YES", 3) ? "true"
2222                    : !c_strncasecmp (res, "NO", 2) ? "false"
2223                    : res);
2227 Lisp_Object
2228 x_get_focus_frame (struct frame *frame)
2230   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2231   Lisp_Object nsfocus;
2233   if (!dpyinfo->x_focus_frame)
2234     return Qnil;
2236   XSETFRAME (nsfocus, dpyinfo->x_focus_frame);
2237   return nsfocus;
2240 /* ==========================================================================
2242     Lisp definitions that, for whatever reason, we can't alias as 'ns-XXX'.
2244    ========================================================================== */
2247 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
2248        doc: /* SKIP: real doc in xfns.c.  */)
2249      (Lisp_Object color, Lisp_Object frame)
2251   NSColor * col;
2252   check_window_system (NULL);
2253   return ns_lisp_to_color (color, &col) ? Qnil : Qt;
2257 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
2258        doc: /* SKIP: real doc in xfns.c.  */)
2259      (Lisp_Object color, Lisp_Object frame)
2261   NSColor * col;
2262   EmacsCGFloat red, green, blue, alpha;
2264   check_window_system (NULL);
2265   CHECK_STRING (color);
2267   block_input ();
2268   if (ns_lisp_to_color (color, &col))
2269     {
2270       unblock_input ();
2271       return Qnil;
2272     }
2274   [[col colorUsingDefaultColorSpace]
2275         getRed: &red green: &green blue: &blue alpha: &alpha];
2276   unblock_input ();
2277   return list3i (lrint (red * 65280), lrint (green * 65280),
2278                  lrint (blue * 65280));
2282 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
2283        doc: /* SKIP: real doc in xfns.c.  */)
2284      (Lisp_Object terminal)
2286   NSWindowDepth depth;
2287   NSString *colorSpace;
2289   check_ns_display_info (terminal);
2290   depth = [[[NSScreen screens] objectAtIndex:0] depth];
2291   colorSpace = NSColorSpaceFromDepth (depth);
2293   return    [colorSpace isEqualToString: NSDeviceWhiteColorSpace]
2294          || [colorSpace isEqualToString: NSCalibratedWhiteColorSpace]
2295       ? Qnil : Qt;
2299 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
2300        0, 1, 0,
2301        doc: /* SKIP: real doc in xfns.c.  */)
2302   (Lisp_Object terminal)
2304   NSWindowDepth depth;
2306   check_ns_display_info (terminal);
2307   depth = [[[NSScreen screens] objectAtIndex:0] depth];
2309   return NSBitsPerPixelFromDepth (depth) > 1 ? Qt : Qnil;
2313 DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
2314        0, 1, 0,
2315        doc: /* SKIP: real doc in xfns.c.  */)
2316   (Lisp_Object terminal)
2318   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
2320   return make_number (x_display_pixel_width (dpyinfo));
2324 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
2325        Sx_display_pixel_height, 0, 1, 0,
2326        doc: /* SKIP: real doc in xfns.c.  */)
2327   (Lisp_Object terminal)
2329   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
2331   return make_number (x_display_pixel_height (dpyinfo));
2334 #ifdef NS_IMPL_COCOA
2336 /* Returns the name for the screen that OBJ represents, or NULL.
2337    Caller must free return value.
2340 static char *
2341 ns_get_name_from_ioreg (io_object_t obj)
2343   char *name = NULL;
2345   NSDictionary *info = (NSDictionary *)
2346     IODisplayCreateInfoDictionary (obj, kIODisplayOnlyPreferredName);
2347   NSDictionary *names = [info objectForKey:
2348                                 [NSString stringWithUTF8String:
2349                                             kDisplayProductName]];
2351   if ([names count] > 0)
2352     {
2353       NSString *n = [names objectForKey: [[names allKeys]
2354                                                  objectAtIndex:0]];
2355       if (n != nil) name = xstrdup ([n UTF8String]);
2356     }
2358   [info release];
2360   return name;
2363 /* Returns the name for the screen that DID came from, or NULL.
2364    Caller must free return value.
2367 static char *
2368 ns_screen_name (CGDirectDisplayID did)
2370   char *name = NULL;
2372 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
2373 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
2374   if (CGDisplayIOServicePort == NULL)
2375 #endif
2376     {
2377       mach_port_t masterPort;
2378       io_iterator_t it;
2379       io_object_t obj;
2381       /* CGDisplayIOServicePort is deprecated.  Do it another (harder) way.
2383          Is this code OK for macOS < 10.9, and GNUstep?  I suspect it is,
2384          in which case is it worth keeping the other method in here? */
2386       if (IOMasterPort (MACH_PORT_NULL, &masterPort) != kIOReturnSuccess
2387           || IOServiceGetMatchingServices (masterPort,
2388                                            IOServiceMatching ("IONDRVDevice"),
2389                                            &it) != kIOReturnSuccess)
2390         return name;
2392       /* Must loop until we find a name.  Many devices can have the same unit
2393          number (represents different GPU parts), but only one has a name.  */
2394       while (! name && (obj = IOIteratorNext (it)))
2395         {
2396           CFMutableDictionaryRef props;
2397           const void *val;
2399           if (IORegistryEntryCreateCFProperties (obj,
2400                                                  &props,
2401                                                  kCFAllocatorDefault,
2402                                                  kNilOptions) == kIOReturnSuccess
2403               && props != nil
2404               && (val = CFDictionaryGetValue(props, @"IOFBDependentIndex")))
2405             {
2406               unsigned nr = [(NSNumber *)val unsignedIntegerValue];
2407               if (nr == CGDisplayUnitNumber (did))
2408                 name = ns_get_name_from_ioreg (obj);
2409             }
2411           CFRelease (props);
2412           IOObjectRelease (obj);
2413         }
2415       IOObjectRelease (it);
2416     }
2417 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
2418   else
2419 #endif
2420 #endif /* #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
2421 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
2422     name = ns_get_name_from_ioreg (CGDisplayIOServicePort (did));
2423 #endif
2424   return name;
2426 #endif /* NS_IMPL_COCOA */
2428 static Lisp_Object
2429 ns_make_monitor_attribute_list (struct MonitorInfo *monitors,
2430                                 int n_monitors,
2431                                 int primary_monitor,
2432                                 const char *source)
2434   Lisp_Object monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
2435   Lisp_Object frame, rest;
2436   NSArray *screens = [NSScreen screens];
2437   int i;
2439   FOR_EACH_FRAME (rest, frame)
2440     {
2441       struct frame *f = XFRAME (frame);
2443       if (FRAME_NS_P (f))
2444         {
2445           NSView *view = FRAME_NS_VIEW (f);
2446           NSScreen *screen = [[view window] screen];
2447           NSUInteger k;
2449           i = -1;
2450           for (k = 0; i == -1 && k < [screens count]; ++k)
2451             {
2452               if ([screens objectAtIndex: k] == screen)
2453                 i = (int)k;
2454             }
2456           if (i > -1)
2457             ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
2458         }
2459     }
2461   return make_monitor_attribute_list (monitors, n_monitors, primary_monitor,
2462                                       monitor_frames, source);
2465 DEFUN ("ns-display-monitor-attributes-list",
2466        Fns_display_monitor_attributes_list,
2467        Sns_display_monitor_attributes_list,
2468        0, 1, 0,
2469        doc: /* Return a list of physical monitor attributes on the X display TERMINAL.
2471 The optional argument TERMINAL specifies which display to ask about.
2472 TERMINAL should be a terminal object, a frame or a display name (a string).
2473 If omitted or nil, that stands for the selected frame's display.
2475 In addition to the standard attribute keys listed in
2476 `display-monitor-attributes-list', the following keys are contained in
2477 the attributes:
2479  source -- String describing the source from which multi-monitor
2480            information is obtained, \"NS\" is always the source."
2482 Internal use only, use `display-monitor-attributes-list' instead.  */)
2483   (Lisp_Object terminal)
2485   struct terminal *term = decode_live_terminal (terminal);
2486   NSArray *screens;
2487   NSUInteger i, n_monitors;
2488   struct MonitorInfo *monitors;
2489   Lisp_Object attributes_list = Qnil;
2490   CGFloat primary_display_height = 0;
2492   if (term->type != output_ns)
2493     return Qnil;
2495   screens = [NSScreen screens];
2496   n_monitors = [screens count];
2497   if (n_monitors == 0)
2498     return Qnil;
2500   monitors = xzalloc (n_monitors * sizeof *monitors);
2502   for (i = 0; i < [screens count]; ++i)
2503     {
2504       NSScreen *s = [screens objectAtIndex:i];
2505       struct MonitorInfo *m = &monitors[i];
2506       NSRect fr = [s frame];
2507       NSRect vfr = [s visibleFrame];
2508       short y, vy;
2510 #ifdef NS_IMPL_COCOA
2511       NSDictionary *dict = [s deviceDescription];
2512       NSNumber *nid = [dict objectForKey:@"NSScreenNumber"];
2513       CGDirectDisplayID did = [nid unsignedIntValue];
2514 #endif
2515       if (i == 0)
2516         {
2517           primary_display_height = fr.size.height;
2518           y = (short) fr.origin.y;
2519           vy = (short) vfr.origin.y;
2520         }
2521       else
2522         {
2523           // Flip y coordinate as NS has y starting from the bottom.
2524           y = (short) (primary_display_height - fr.size.height - fr.origin.y);
2525           vy = (short) (primary_display_height -
2526                         vfr.size.height - vfr.origin.y);
2527         }
2529       m->geom.x = (short) fr.origin.x;
2530       m->geom.y = y;
2531       m->geom.width = (unsigned short) fr.size.width;
2532       m->geom.height = (unsigned short) fr.size.height;
2534       m->work.x = (short) vfr.origin.x;
2535       // y is flipped on NS, so vy - y are pixels missing at the bottom,
2536       // and fr.size.height - vfr.size.height are pixels missing in total.
2537       // Pixels missing at top are
2538       // fr.size.height - vfr.size.height - vy + y.
2539       // work.y is then pixels missing at top + y.
2540       m->work.y = (short) (fr.size.height - vfr.size.height) - vy + y + y;
2541       m->work.width = (unsigned short) vfr.size.width;
2542       m->work.height = (unsigned short) vfr.size.height;
2544 #ifdef NS_IMPL_COCOA
2545       m->name = ns_screen_name (did);
2547       {
2548         CGSize mms = CGDisplayScreenSize (did);
2549         m->mm_width = (int) mms.width;
2550         m->mm_height = (int) mms.height;
2551       }
2553 #else
2554       // Assume 92 dpi as x-display-mm-height/x-display-mm-width does.
2555       m->mm_width = (int) (25.4 * fr.size.width / 92.0);
2556       m->mm_height = (int) (25.4 * fr.size.height / 92.0);
2557 #endif
2558     }
2560   // Primary monitor is always first for NS.
2561   attributes_list = ns_make_monitor_attribute_list (monitors, n_monitors,
2562                                                     0, "NS");
2564   free_monitors (monitors, n_monitors);
2565   return attributes_list;
2569 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
2570        0, 1, 0,
2571        doc: /* SKIP: real doc in xfns.c.  */)
2572   (Lisp_Object terminal)
2574   check_ns_display_info (terminal);
2575   return make_number
2576     (NSBitsPerPixelFromDepth ([[[NSScreen screens] objectAtIndex:0] depth]));
2580 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
2581        0, 1, 0,
2582        doc: /* SKIP: real doc in xfns.c.  */)
2583   (Lisp_Object terminal)
2585   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
2586   /* We force 24+ bit depths to 24-bit to prevent an overflow.  */
2587   return make_number (1 << min (dpyinfo->n_planes, 24));
2590 /* TODO: move to xdisp or similar */
2591 static void
2592 compute_tip_xy (struct frame *f,
2593                 Lisp_Object parms,
2594                 Lisp_Object dx,
2595                 Lisp_Object dy,
2596                 int width,
2597                 int height,
2598                 int *root_x,
2599                 int *root_y)
2601   Lisp_Object left, top, right, bottom;
2602   NSPoint pt;
2603   NSScreen *screen;
2605   /* Start with user-specified or mouse position.  */
2606   left = Fcdr (Fassq (Qleft, parms));
2607   top = Fcdr (Fassq (Qtop, parms));
2608   right = Fcdr (Fassq (Qright, parms));
2609   bottom = Fcdr (Fassq (Qbottom, parms));
2611   if ((!INTEGERP (left) && !INTEGERP (right))
2612       || (!INTEGERP (top) && !INTEGERP (bottom)))
2613     pt = [NSEvent mouseLocation];
2614   else
2615     {
2616       /* Absolute coordinates.  */
2617       pt.x = INTEGERP (left) ? XINT (left) : XINT (right);
2618       pt.y = (x_display_pixel_height (FRAME_DISPLAY_INFO (f))
2619               - (INTEGERP (top) ? XINT (top) : XINT (bottom))
2620               - height);
2621     }
2623   /* Find the screen that pt is on. */
2624   for (screen in [NSScreen screens])
2625     if (pt.x >= screen.frame.origin.x
2626         && pt.x < screen.frame.origin.x + screen.frame.size.width
2627         && pt.y >= screen.frame.origin.y
2628         && pt.y < screen.frame.origin.y + screen.frame.size.height)
2629       break;
2631   /* We could use this instead of the if above:
2633          if (CGRectContainsPoint ([screen frame], pt))
2635      which would be neater, but it causes problems building on old
2636      versions of macOS and in GNUstep. */
2638   /* Ensure in bounds.  (Note, screen origin = lower left.) */
2639   if (INTEGERP (left) || INTEGERP (right))
2640     *root_x = pt.x;
2641   else if (pt.x + XINT (dx) <= screen.frame.origin.x)
2642     *root_x = screen.frame.origin.x; /* Can happen for negative dx */
2643   else if (pt.x + XINT (dx) + width
2644            <= screen.frame.origin.x + screen.frame.size.width)
2645     /* It fits to the right of the pointer.  */
2646     *root_x = pt.x + XINT (dx);
2647   else if (width + XINT (dx) <= pt.x)
2648     /* It fits to the left of the pointer.  */
2649     *root_x = pt.x - width - XINT (dx);
2650   else
2651     /* Put it left justified on the screen -- it ought to fit that way.  */
2652     *root_x = screen.frame.origin.x;
2654   if (INTEGERP (top) || INTEGERP (bottom))
2655     *root_y = pt.y;
2656   else if (pt.y - XINT (dy) - height >= screen.frame.origin.y)
2657     /* It fits below the pointer.  */
2658     *root_y = pt.y - height - XINT (dy);
2659   else if (pt.y + XINT (dy) + height
2660            <= screen.frame.origin.y + screen.frame.size.height)
2661     /* It fits above the pointer */
2662       *root_y = pt.y + XINT (dy);
2663   else
2664     /* Put it on the top.  */
2665     *root_y = screen.frame.origin.y + screen.frame.size.height - height;
2669 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
2670        doc: /* SKIP: real doc in xfns.c.  */)
2671      (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
2673   int root_x, root_y;
2674   ptrdiff_t count = SPECPDL_INDEX ();
2675   struct frame *f;
2676   char *str;
2677   NSSize size;
2678   NSColor *color;
2679   Lisp_Object t;
2681   specbind (Qinhibit_redisplay, Qt);
2683   CHECK_STRING (string);
2684   str = SSDATA (string);
2685   f = decode_window_system_frame (frame);
2686   if (NILP (timeout))
2687     timeout = make_number (5);
2688   else
2689     CHECK_NATNUM (timeout);
2691   if (NILP (dx))
2692     dx = make_number (5);
2693   else
2694     CHECK_NUMBER (dx);
2696   if (NILP (dy))
2697     dy = make_number (-10);
2698   else
2699     CHECK_NUMBER (dy);
2701   block_input ();
2702   if (ns_tooltip == nil)
2703     ns_tooltip = [[EmacsTooltip alloc] init];
2704   else
2705     Fx_hide_tip ();
2707   t = x_get_arg (NULL, parms, Qbackground_color, NULL, NULL, RES_TYPE_STRING);
2708   if (ns_lisp_to_color (t, &color) == 0)
2709     [ns_tooltip setBackgroundColor: color];
2711   t = x_get_arg (NULL, parms, Qforeground_color, NULL, NULL, RES_TYPE_STRING);
2712   if (ns_lisp_to_color (t, &color) == 0)
2713     [ns_tooltip setForegroundColor: color];
2715   [ns_tooltip setText: str];
2716   size = [ns_tooltip frame].size;
2718   /* Move the tooltip window where the mouse pointer is.  Resize and
2719      show it.  */
2720   compute_tip_xy (f, parms, dx, dy, (int)size.width, (int)size.height,
2721                   &root_x, &root_y);
2723   [ns_tooltip showAtX: root_x Y: root_y for: XINT (timeout)];
2724   unblock_input ();
2726   return unbind_to (count, Qnil);
2730 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
2731        doc: /* SKIP: real doc in xfns.c.  */)
2732      (void)
2734   if (ns_tooltip == nil || ![ns_tooltip isActive])
2735     return Qnil;
2736   [ns_tooltip hide];
2737   return Qt;
2740 /* Return geometric attributes of FRAME.  According to the value of
2741    ATTRIBUTES return the outer edges of FRAME (Qouter_edges), the inner
2742    edges of FRAME, the root window edges of frame (Qroot_edges).  Any
2743    other value means to return the geometry as returned by
2744    Fx_frame_geometry.  */
2745 static Lisp_Object
2746 frame_geometry (Lisp_Object frame, Lisp_Object attribute)
2748   struct frame *f = decode_live_frame (frame);
2749   Lisp_Object fullscreen_symbol = Fframe_parameter (frame, Qfullscreen);
2750   bool fullscreen = (EQ (fullscreen_symbol, Qfullboth)
2751                      || EQ (fullscreen_symbol, Qfullscreen));
2752   int border = fullscreen ? 0 : f->border_width;
2753   int title_height = fullscreen ? 0 : FRAME_NS_TITLEBAR_HEIGHT (f);
2754   int native_width = FRAME_PIXEL_WIDTH (f);
2755   int native_height = FRAME_PIXEL_HEIGHT (f);
2756   int outer_width = native_width + 2 * border;
2757   int outer_height = native_height + 2 * border + title_height;
2758   int native_left = f->left_pos + border;
2759   int native_top = f->top_pos + border + title_height;
2760   int native_right = f->left_pos + outer_width - border;
2761   int native_bottom = f->top_pos + outer_height - border;
2762   int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f);
2763   int tool_bar_height = FRAME_TOOLBAR_HEIGHT (f);
2764   int tool_bar_width = (tool_bar_height
2765                         ? outer_width - 2 * internal_border_width
2766                         : 0);
2768   /* Construct list.  */
2769   if (EQ (attribute, Qouter_edges))
2770     return list4 (make_number (f->left_pos), make_number (f->top_pos),
2771                   make_number (f->left_pos + outer_width),
2772                   make_number (f->top_pos + outer_height));
2773   else if (EQ (attribute, Qnative_edges))
2774     return list4 (make_number (native_left), make_number (native_top),
2775                   make_number (native_right), make_number (native_bottom));
2776   else if (EQ (attribute, Qinner_edges))
2777     return list4 (make_number (native_left + internal_border_width),
2778                   make_number (native_top
2779                                + tool_bar_height
2780                                + internal_border_width),
2781                   make_number (native_right - internal_border_width),
2782                   make_number (native_bottom - internal_border_width));
2783   else
2784     return
2785       listn (CONSTYPE_HEAP, 10,
2786              Fcons (Qouter_position,
2787                     Fcons (make_number (f->left_pos),
2788                            make_number (f->top_pos))),
2789              Fcons (Qouter_size,
2790                     Fcons (make_number (outer_width),
2791                            make_number (outer_height))),
2792              Fcons (Qexternal_border_size,
2793                     (fullscreen
2794                      ? Fcons (make_number (0), make_number (0))
2795                      : Fcons (make_number (border), make_number (border)))),
2796              Fcons (Qtitle_bar_size,
2797                     Fcons (make_number (0), make_number (title_height))),
2798              Fcons (Qmenu_bar_external, Qnil),
2799              Fcons (Qmenu_bar_size, Fcons (make_number (0), make_number (0))),
2800              Fcons (Qtool_bar_external,
2801                     FRAME_EXTERNAL_TOOL_BAR (f) ? Qt : Qnil),
2802              Fcons (Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f)),
2803              Fcons (Qtool_bar_size,
2804                     Fcons (make_number (tool_bar_width),
2805                            make_number (tool_bar_height))),
2806              Fcons (Qinternal_border_width,
2807                     make_number (internal_border_width)));
2810 DEFUN ("ns-frame-geometry", Fns_frame_geometry, Sns_frame_geometry, 0, 1, 0,
2811        doc: /* Return geometric attributes of FRAME.
2812 FRAME must be a live frame and defaults to the selected one.  The return
2813 value is an association list of the attributes listed below.  All height
2814 and width values are in pixels.
2816 `outer-position' is a cons of the outer left and top edges of FRAME
2817   relative to the origin - the position (0, 0) - of FRAME's display.
2819 `outer-size' is a cons of the outer width and height of FRAME.  The
2820   outer size includes the title bar and the external borders as well as
2821   any menu and/or tool bar of frame.
2823 `external-border-size' is a cons of the horizontal and vertical width of
2824   FRAME's external borders as supplied by the window manager.
2826 `title-bar-size' is a cons of the width and height of the title bar of
2827   FRAME as supplied by the window manager.  If both of them are zero,
2828   FRAME has no title bar.  If only the width is zero, Emacs was not
2829   able to retrieve the width information.
2831 `menu-bar-external', if non-nil, means the menu bar is external (never
2832   included in the inner edges of FRAME).
2834 `menu-bar-size' is a cons of the width and height of the menu bar of
2835   FRAME.
2837 `tool-bar-external', if non-nil, means the tool bar is external (never
2838   included in the inner edges of FRAME).
2840 `tool-bar-position' tells on which side the tool bar on FRAME is and can
2841   be one of `left', `top', `right' or `bottom'.  If this is nil, FRAME
2842   has no tool bar.
2844 `tool-bar-size' is a cons of the width and height of the tool bar of
2845   FRAME.
2847 `internal-border-width' is the width of the internal border of
2848   FRAME.  */)
2849   (Lisp_Object frame)
2851   return frame_geometry (frame, Qnil);
2854 DEFUN ("ns-frame-edges", Fns_frame_edges, Sns_frame_edges, 0, 2, 0,
2855        doc: /* Return edge coordinates of FRAME.
2856 FRAME must be a live frame and defaults to the selected one.  The return
2857 value is a list of the form (LEFT, TOP, RIGHT, BOTTOM).  All values are
2858 in pixels relative to the origin - the position (0, 0) - of FRAME's
2859 display.
2861 If optional argument TYPE is the symbol `outer-edges', return the outer
2862 edges of FRAME.  The outer edges comprise the decorations of the window
2863 manager (like the title bar or external borders) as well as any external
2864 menu or tool bar of FRAME.  If optional argument TYPE is the symbol
2865 `native-edges' or nil, return the native edges of FRAME.  The native
2866 edges exclude the decorations of the window manager and any external
2867 menu or tool bar of FRAME.  If TYPE is the symbol `inner-edges', return
2868 the inner edges of FRAME.  These edges exclude title bar, any borders,
2869 menu bar or tool bar of FRAME.  */)
2870   (Lisp_Object frame, Lisp_Object type)
2872   return frame_geometry (frame, ((EQ (type, Qouter_edges)
2873                                   || EQ (type, Qinner_edges))
2874                                  ? type
2875                                  : Qnative_edges));
2878 DEFUN ("ns-set-mouse-absolute-pixel-position",
2879        Fns_set_mouse_absolute_pixel_position,
2880        Sns_set_mouse_absolute_pixel_position, 2, 2, 0,
2881        doc: /* Move mouse pointer to absolute pixel position (X, Y).
2882 The coordinates X and Y are interpreted in pixels relative to a position
2883 \(0, 0) of the selected frame's display.  */)
2884        (Lisp_Object x, Lisp_Object y)
2886 #ifdef NS_IMPL_COCOA
2887   /* GNUstep doesn't support CGWarpMouseCursorPosition, so none of
2888      this will work. */
2889   struct frame *f = SELECTED_FRAME ();
2890   EmacsView *view = FRAME_NS_VIEW (f);
2891   NSScreen *screen = [[view window] screen];
2892   NSRect screen_frame = [screen frame];
2893   int mouse_x, mouse_y;
2895   NSScreen *primary_screen = [[NSScreen screens] objectAtIndex:0];
2896   NSRect primary_screen_frame = [primary_screen frame];
2897   CGFloat primary_screen_height = primary_screen_frame.size.height;
2899   if (FRAME_INITIAL_P (f) || !FRAME_NS_P (f))
2900     return Qnil;
2902   CHECK_TYPE_RANGED_INTEGER (int, x);
2903   CHECK_TYPE_RANGED_INTEGER (int, y);
2905   mouse_x = screen_frame.origin.x + XINT (x);
2907   if (screen == primary_screen)
2908     mouse_y = screen_frame.origin.y + XINT (y);
2909   else
2910     mouse_y = (primary_screen_height - screen_frame.size.height
2911                - screen_frame.origin.y) + XINT (y);
2913   CGPoint mouse_pos = CGPointMake(mouse_x, mouse_y);
2914   CGWarpMouseCursorPosition (mouse_pos);
2915 #endif /* NS_IMPL_COCOA */
2917   return Qnil;
2920 DEFUN ("ns-mouse-absolute-pixel-position",
2921        Fns_mouse_absolute_pixel_position,
2922        Sns_mouse_absolute_pixel_position, 0, 0, 0,
2923        doc: /* Return absolute position of mouse cursor in pixels.
2924 The position is returned as a cons cell (X . Y) of the
2925 coordinates of the mouse cursor position in pixels relative to a
2926 position (0, 0) of the selected frame's terminal. */)
2927      (void)
2929   struct frame *f = SELECTED_FRAME ();
2930   EmacsView *view = FRAME_NS_VIEW (f);
2931   NSScreen *screen = [[view window] screen];
2932   NSPoint pt = [NSEvent mouseLocation];
2934   return Fcons(make_number(pt.x - screen.frame.origin.x),
2935                make_number(screen.frame.size.height -
2936                            (pt.y - screen.frame.origin.y)));
2939 DEFUN ("ns-show-character-palette",
2940        Fns_show_character_palette,
2941        Sns_show_character_palette, 0, 0, 0,
2942        doc: /* Show the macOS character palette.  */)
2943        (void)
2945   struct frame *f = SELECTED_FRAME ();
2946   EmacsView *view = FRAME_NS_VIEW (f);
2947   [NSApp orderFrontCharacterPalette:view];
2949   return Qnil;
2952 /* ==========================================================================
2954     Class implementations
2956    ========================================================================== */
2959   Handle arrow/function/control keys and copy/paste/cut in file dialogs.
2960   Return YES if handled, NO if not.
2961  */
2962 static BOOL
2963 handlePanelKeys (NSSavePanel *panel, NSEvent *theEvent)
2965   NSString *s;
2966   int i;
2967   BOOL ret = NO;
2969   if ([theEvent type] != NSEventTypeKeyDown) return NO;
2970   s = [theEvent characters];
2972   for (i = 0; i < [s length]; ++i)
2973     {
2974       int ch = (int) [s characterAtIndex: i];
2975       switch (ch)
2976         {
2977         case NSHomeFunctionKey:
2978         case NSDownArrowFunctionKey:
2979         case NSUpArrowFunctionKey:
2980         case NSLeftArrowFunctionKey:
2981         case NSRightArrowFunctionKey:
2982         case NSPageUpFunctionKey:
2983         case NSPageDownFunctionKey:
2984         case NSEndFunctionKey:
2985           /* Don't send command modified keys, as those are handled in the
2986              performKeyEquivalent method of the super class.
2987           */
2988           if (! ([theEvent modifierFlags] & NSEventModifierFlagCommand))
2989             {
2990               [panel sendEvent: theEvent];
2991               ret = YES;
2992             }
2993           break;
2994           /* As we don't have the standard key commands for
2995              copy/paste/cut/select-all in our edit menu, we must handle
2996              them here.  TODO: handle Emacs key bindings for copy/cut/select-all
2997              here, paste works, because we have that in our Edit menu.
2998              I.e. refactor out code in nsterm.m, keyDown: to figure out the
2999              correct modifier.
3000           */
3001         case 'x': // Cut
3002         case 'c': // Copy
3003         case 'v': // Paste
3004         case 'a': // Select all
3005           if ([theEvent modifierFlags] & NSEventModifierFlagCommand)
3006             {
3007               [NSApp sendAction:
3008                        (ch == 'x'
3009                         ? @selector(cut:)
3010                         : (ch == 'c'
3011                            ? @selector(copy:)
3012                            : (ch == 'v'
3013                               ? @selector(paste:)
3014                               : @selector(selectAll:))))
3015                              to:nil from:panel];
3016               ret = YES;
3017             }
3018         default:
3019           // Send all control keys, as the text field supports C-a, C-f, C-e
3020           // C-b and more.
3021           if ([theEvent modifierFlags] & NSEventModifierFlagControl)
3022             {
3023               [panel sendEvent: theEvent];
3024               ret = YES;
3025             }
3026           break;
3027         }
3028     }
3031   return ret;
3034 @implementation EmacsSavePanel
3035 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent
3037   BOOL ret = handlePanelKeys (self, theEvent);
3038   if (! ret)
3039     ret = [super performKeyEquivalent:theEvent];
3040   return ret;
3042 @end
3045 @implementation EmacsOpenPanel
3046 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent
3048   // NSOpenPanel inherits NSSavePanel, so passing self is OK.
3049   BOOL ret = handlePanelKeys (self, theEvent);
3050   if (! ret)
3051     ret = [super performKeyEquivalent:theEvent];
3052   return ret;
3054 @end
3057 @implementation EmacsFileDelegate
3058 /* --------------------------------------------------------------------------
3059    Delegate methods for Open/Save panels
3060    -------------------------------------------------------------------------- */
3061 - (BOOL)panel: (id)sender isValidFilename: (NSString *)filename
3063   return YES;
3065 - (BOOL)panel: (id)sender shouldShowFilename: (NSString *)filename
3067   return YES;
3069 - (NSString *)panel: (id)sender userEnteredFilename: (NSString *)filename
3070           confirmed: (BOOL)okFlag
3072   return filename;
3074 @end
3076 #endif
3079 /* ==========================================================================
3081     Lisp interface declaration
3083    ========================================================================== */
3086 void
3087 syms_of_nsfns (void)
3089   DEFSYM (Qfontsize, "fontsize");
3090   DEFSYM (Qframe_title_format, "frame-title-format");
3091   DEFSYM (Qicon_title_format, "icon-title-format");
3092   DEFSYM (Qdark, "dark");
3094   DEFVAR_LISP ("ns-icon-type-alist", Vns_icon_type_alist,
3095                doc: /* Alist of elements (REGEXP . IMAGE) for images of icons associated to frames.
3096 If the title of a frame matches REGEXP, then IMAGE.tiff is
3097 selected as the image of the icon representing the frame when it's
3098 miniaturized.  If an element is t, then Emacs tries to select an icon
3099 based on the filetype of the visited file.
3101 The images have to be installed in a folder called English.lproj in the
3102 Emacs folder.  You have to restart Emacs after installing new icons.
3104 Example: Install an icon Gnus.tiff and execute the following code
3106   (setq ns-icon-type-alist
3107         (append ns-icon-type-alist
3108                 \\='((\"^\\\\*\\\\(Group\\\\*$\\\\|Summary \\\\|Article\\\\*$\\\\)\"
3109                    . \"Gnus\"))))
3111 When you miniaturize a Group, Summary or Article frame, Gnus.tiff will
3112 be used as the image of the icon representing the frame.  */);
3113   Vns_icon_type_alist = list1 (Qt);
3115   DEFVAR_LISP ("ns-version-string", Vns_version_string,
3116                doc: /* Toolkit version for NS Windowing.  */);
3117   Vns_version_string = ns_appkit_version_str ();
3119   DEFVAR_BOOL ("ns-use-proxy-icon", ns_use_proxy_icon,
3120                doc: /* When non-nil display a proxy icon in the titlebar.
3121 Default is t.  */);
3122   ns_use_proxy_icon = true;
3124   defsubr (&Sns_read_file_name);
3125   defsubr (&Sns_get_resource);
3126   defsubr (&Sns_set_resource);
3127   defsubr (&Sxw_display_color_p); /* this and next called directly by C code */
3128   defsubr (&Sx_display_grayscale_p);
3129   defsubr (&Sns_font_name);
3130   defsubr (&Sns_list_colors);
3131 #ifdef NS_IMPL_COCOA
3132   defsubr (&Sns_do_applescript);
3133 #endif
3134   defsubr (&Sxw_color_defined_p);
3135   defsubr (&Sxw_color_values);
3136   defsubr (&Sx_server_max_request_size);
3137   defsubr (&Sx_server_vendor);
3138   defsubr (&Sx_server_version);
3139   defsubr (&Sx_display_pixel_width);
3140   defsubr (&Sx_display_pixel_height);
3141   defsubr (&Sns_display_monitor_attributes_list);
3142   defsubr (&Sns_frame_geometry);
3143   defsubr (&Sns_frame_edges);
3144   defsubr (&Sns_frame_list_z_order);
3145   defsubr (&Sns_frame_restack);
3146   defsubr (&Sns_set_mouse_absolute_pixel_position);
3147   defsubr (&Sns_mouse_absolute_pixel_position);
3148   defsubr (&Sns_show_character_palette);
3149   defsubr (&Sx_display_mm_width);
3150   defsubr (&Sx_display_mm_height);
3151   defsubr (&Sx_display_screens);
3152   defsubr (&Sx_display_planes);
3153   defsubr (&Sx_display_color_cells);
3154   defsubr (&Sx_display_visual_class);
3155   defsubr (&Sx_display_backing_store);
3156   defsubr (&Sx_display_save_under);
3157   defsubr (&Sx_create_frame);
3158   defsubr (&Sx_open_connection);
3159   defsubr (&Sx_close_connection);
3160   defsubr (&Sx_display_list);
3162   defsubr (&Sns_hide_others);
3163   defsubr (&Sns_hide_emacs);
3164   defsubr (&Sns_emacs_info_panel);
3165   defsubr (&Sns_list_services);
3166   defsubr (&Sns_perform_service);
3167   defsubr (&Sns_popup_font_panel);
3168   defsubr (&Sns_popup_color_panel);
3170   defsubr (&Sx_show_tip);
3171   defsubr (&Sx_hide_tip);
3173   as_status = 0;
3174   as_script = Qnil;
3175   as_result = 0;