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