; ChangeLog fix
[emacs.git] / src / nsfns.m
blob33d63a65728f02ed5c57c062e2cb2dd84e270eff
1 /* Functions for the NeXT/Open/GNUstep and MacOSX window system.
3 Copyright (C) 1989, 1992-1994, 2005-2006, 2008-2015 Free Software
4 Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
31 #include <config.h>
33 #include <math.h>
34 #include <c-strcase.h>
36 #include "lisp.h"
37 #include "blockinput.h"
38 #include "nsterm.h"
39 #include "window.h"
40 #include "character.h"
41 #include "buffer.h"
42 #include "keyboard.h"
43 #include "termhooks.h"
44 #include "fontset.h"
45 #include "font.h"
47 #ifdef NS_IMPL_COCOA
48 #include <IOKit/graphics/IOGraphicsLib.h>
49 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
50 #include "macfont.h"
51 #endif
52 #endif
54 #if 0
55 int fns_trace_num = 1;
56 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",        \
57                                   __FILE__, __LINE__, ++fns_trace_num)
58 #else
59 #define NSTRACE(x)
60 #endif
62 #ifdef HAVE_NS
64 extern NSArray *ns_send_types, *ns_return_types, *ns_drag_types;
66 extern Lisp_Object Qforeground_color;
67 extern Lisp_Object Qbackground_color;
68 extern Lisp_Object Qcursor_color;
69 extern Lisp_Object Qinternal_border_width;
70 extern Lisp_Object Qvisibility;
71 extern Lisp_Object Qcursor_type;
72 extern Lisp_Object Qicon_type;
73 extern Lisp_Object Qicon_name;
74 extern Lisp_Object Qicon_left;
75 extern Lisp_Object Qicon_top;
76 extern Lisp_Object Qleft;
77 extern Lisp_Object Qright;
78 extern Lisp_Object Qtop;
79 extern Lisp_Object Qdisplay;
80 extern Lisp_Object Qvertical_scroll_bars;
81 extern Lisp_Object Qauto_raise;
82 extern Lisp_Object Qauto_lower;
83 extern Lisp_Object Qbox;
84 extern Lisp_Object Qscroll_bar_width;
85 extern Lisp_Object Qx_resource_name;
86 extern Lisp_Object Qface_set_after_frame_default;
87 extern Lisp_Object Qunderline, Qundefined;
88 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
89 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
92 Lisp_Object Qbuffered;
93 Lisp_Object Qfontsize;
95 EmacsTooltip *ns_tooltip = nil;
97 /* Need forward declaration here to preserve organizational integrity of file */
98 Lisp_Object Fx_open_connection (Lisp_Object, Lisp_Object, Lisp_Object);
100 /* Static variables to handle applescript execution.  */
101 static Lisp_Object as_script, *as_result;
102 static int as_status;
104 #ifdef GLYPH_DEBUG
105 static ptrdiff_t image_cache_refcount;
106 #endif
109 /* ==========================================================================
111     Internal utility functions
113    ========================================================================== */
115 /* Let the user specify a Nextstep display with a Lisp object.
116    OBJECT may be nil, a frame or a terminal object.
117    nil stands for the selected frame--or, if that is not a Nextstep frame,
118    the first Nextstep display on the list.  */
120 static struct ns_display_info *
121 check_ns_display_info (Lisp_Object object)
123   struct ns_display_info *dpyinfo = NULL;
125   if (NILP (object))
126     {
127       struct frame *sf = XFRAME (selected_frame);
129       if (FRAME_NS_P (sf) && FRAME_LIVE_P (sf))
130         dpyinfo = FRAME_DISPLAY_INFO (sf);
131       else if (x_display_list != 0)
132         dpyinfo = x_display_list;
133       else
134         error ("Nextstep windows are not in use or not initialized");
135     }
136   else if (TERMINALP (object))
137     {
138       struct terminal *t = get_terminal (object, 1);
140       if (t->type != output_ns)
141         error ("Terminal %d is not a Nextstep display", t->id);
143       dpyinfo = t->display_info.ns;
144     }
145   else if (STRINGP (object))
146     dpyinfo = ns_display_info_for_name (object);
147   else
148     {
149       struct frame *f = decode_window_system_frame (object);
150       dpyinfo = FRAME_DISPLAY_INFO (f);
151     }
153   return dpyinfo;
157 static id
158 ns_get_window (Lisp_Object maybeFrame)
160   id view =nil, window =nil;
162   if (!FRAMEP (maybeFrame) || !FRAME_NS_P (XFRAME (maybeFrame)))
163     maybeFrame = selected_frame;/*wrong_type_argument (Qframep, maybeFrame); */
165   if (!NILP (maybeFrame))
166     view = FRAME_NS_VIEW (XFRAME (maybeFrame));
167   if (view) window =[view window];
169   return window;
173 /* Return the X display structure for the display named NAME.
174    Open a new connection if necessary.  */
175 struct ns_display_info *
176 ns_display_info_for_name (Lisp_Object name)
178   struct ns_display_info *dpyinfo;
180   CHECK_STRING (name);
182   for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
183     if (!NILP (Fstring_equal (XCAR (dpyinfo->name_list_element), name)))
184       return dpyinfo;
186   error ("Emacs for Nextstep does not yet support multi-display");
188   Fx_open_connection (name, Qnil, Qnil);
189   dpyinfo = x_display_list;
191   if (dpyinfo == 0)
192     error ("Display on %s not responding.\n", SDATA (name));
194   return dpyinfo;
197 static NSString *
198 ns_filename_from_panel (NSSavePanel *panel)
200 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
201   NSURL *url = [panel URL];
202   NSString *str = [url path];
203   return str;
204 #else
205   return [panel filename];
206 #endif
209 static NSString *
210 ns_directory_from_panel (NSSavePanel *panel)
212 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
213   NSURL *url = [panel directoryURL];
214   NSString *str = [url path];
215   return str;
216 #else
217   return [panel directory];
218 #endif
221 static Lisp_Object
222 interpret_services_menu (NSMenu *menu, Lisp_Object prefix, Lisp_Object old)
223 /* --------------------------------------------------------------------------
224    Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
225    -------------------------------------------------------------------------- */
227   int i, count;
228   NSMenuItem *item;
229   const char *name;
230   Lisp_Object nameStr;
231   unsigned short key;
232   NSString *keys;
233   Lisp_Object res;
235   count = [menu numberOfItems];
236   for (i = 0; i<count; i++)
237     {
238       item = [menu itemAtIndex: i];
239       name = [[item title] UTF8String];
240       if (!name) continue;
242       nameStr = build_string (name);
244       if ([item hasSubmenu])
245         {
246           old = interpret_services_menu ([item submenu],
247                                         Fcons (nameStr, prefix), old);
248         }
249       else
250         {
251           keys = [item keyEquivalent];
252           if (keys && [keys length] )
253             {
254               key = [keys characterAtIndex: 0];
255               res = make_number (key|super_modifier);
256             }
257           else
258             {
259               res = Qundefined;
260             }
261           old = Fcons (Fcons (res,
262                             Freverse (Fcons (nameStr,
263                                            prefix))),
264                     old);
265         }
266     }
267   return old;
272 /* ==========================================================================
274     Frame parameter setters
276    ========================================================================== */
279 static void
280 x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
282   NSColor *col;
283   EmacsCGFloat r, g, b, alpha;
285   /* Must block_input, because ns_lisp_to_color does block/unblock_input
286      which means that col may be deallocated in its unblock_input if there
287      is user input, unless we also block_input.  */
288   block_input ();
289   if (ns_lisp_to_color (arg, &col))
290     {
291       store_frame_param (f, Qforeground_color, oldval);
292       unblock_input ();
293       error ("Unknown color");
294     }
296   [col retain];
297   [f->output_data.ns->foreground_color release];
298   f->output_data.ns->foreground_color = col;
300   [col getRed: &r green: &g blue: &b alpha: &alpha];
301   FRAME_FOREGROUND_PIXEL (f) =
302     ARGB_TO_ULONG ((int)(alpha*0xff), (int)(r*0xff), (int)(g*0xff), (int)(b*0xff));
304   if (FRAME_NS_VIEW (f))
305     {
306       update_face_from_frame_parameter (f, Qforeground_color, arg);
307       /*recompute_basic_faces (f); */
308       if (FRAME_VISIBLE_P (f))
309         SET_FRAME_GARBAGED (f);
310     }
311   unblock_input ();
315 static void
316 x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
318   struct face *face;
319   NSColor *col;
320   NSView *view = FRAME_NS_VIEW (f);
321   EmacsCGFloat r, g, b, alpha;
323   block_input ();
324   if (ns_lisp_to_color (arg, &col))
325     {
326       store_frame_param (f, Qbackground_color, oldval);
327       unblock_input ();
328       error ("Unknown color");
329     }
331   /* clear the frame; in some instances the NS-internal GC appears not to
332      update, or it does update and cannot clear old text properly */
333   if (FRAME_VISIBLE_P (f))
334     ns_clear_frame (f);
336   [col retain];
337   [f->output_data.ns->background_color release];
338   f->output_data.ns->background_color = col;
340   [col getRed: &r green: &g blue: &b alpha: &alpha];
341   FRAME_BACKGROUND_PIXEL (f) =
342     ARGB_TO_ULONG ((int)(alpha*0xff), (int)(r*0xff), (int)(g*0xff), (int)(b*0xff));
344   if (view != nil)
345     {
346       [[view window] setBackgroundColor: col];
348       if (alpha != (EmacsCGFloat) 1.0)
349           [[view window] setOpaque: NO];
350       else
351           [[view window] setOpaque: YES];
353       face = FRAME_DEFAULT_FACE (f);
354       if (face)
355         {
356           col = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f);
357           face->background = ns_index_color
358             ([col colorWithAlphaComponent: alpha], f);
360           update_face_from_frame_parameter (f, Qbackground_color, arg);
361         }
363       if (FRAME_VISIBLE_P (f))
364         SET_FRAME_GARBAGED (f);
365     }
366   unblock_input ();
370 static void
371 x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
373   NSColor *col;
375   block_input ();
376   if (ns_lisp_to_color (arg, &col))
377     {
378       store_frame_param (f, Qcursor_color, oldval);
379       unblock_input ();
380       error ("Unknown color");
381     }
383   [FRAME_CURSOR_COLOR (f) release];
384   FRAME_CURSOR_COLOR (f) = [col retain];
386   if (FRAME_VISIBLE_P (f))
387     {
388       x_update_cursor (f, 0);
389       x_update_cursor (f, 1);
390     }
391   update_face_from_frame_parameter (f, Qcursor_color, arg);
392   unblock_input ();
396 static void
397 x_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
399   NSView *view = FRAME_NS_VIEW (f);
400   NSTRACE (x_set_icon_name);
402   /* see if it's changed */
403   if (STRINGP (arg))
404     {
405       if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
406         return;
407     }
408   else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
409     return;
411   fset_icon_name (f, arg);
413   if (NILP (arg))
414     {
415       if (!NILP (f->title))
416         arg = f->title;
417       else
418         /* Explicit name and no icon-name -> explicit_name.  */
419         if (f->explicit_name)
420           arg = f->name;
421         else
422           {
423             /* No explicit name and no icon-name ->
424                name has to be rebuild from icon_title_format.  */
425             windows_or_buffers_changed = 62;
426             return;
427           }
428     }
430   /* Don't change the name if it's already NAME.  */
431   if ([[view window] miniwindowTitle]
432       && ([[[view window] miniwindowTitle]
433              isEqualToString: [NSString stringWithUTF8String:
434                                           SSDATA (arg)]]))
435     return;
437   [[view window] setMiniwindowTitle:
438         [NSString stringWithUTF8String: SSDATA (arg)]];
441 static void
442 ns_set_name_internal (struct frame *f, Lisp_Object name)
444   struct gcpro gcpro1;
445   Lisp_Object encoded_name, encoded_icon_name;
446   NSString *str;
447   NSView *view = FRAME_NS_VIEW (f);
449   GCPRO1 (name);
450   encoded_name = ENCODE_UTF_8 (name);
451   UNGCPRO;
453   str = [NSString stringWithUTF8String: SSDATA (encoded_name)];
455   /* Don't change the name if it's already NAME.  */
456   if (! [[[view window] title] isEqualToString: str])
457     [[view window] setTitle: str];
459   if (!STRINGP (f->icon_name))
460     encoded_icon_name = encoded_name;
461   else
462     encoded_icon_name = ENCODE_UTF_8 (f->icon_name);
464   str = [NSString stringWithUTF8String: SSDATA (encoded_icon_name)];
466   if ([[view window] miniwindowTitle]
467       && ! [[[view window] miniwindowTitle] isEqualToString: str])
468     [[view window] setMiniwindowTitle: str];
472 static void
473 ns_set_name (struct frame *f, Lisp_Object name, int explicit)
475   NSTRACE (ns_set_name);
477   /* Make sure that requests from lisp code override requests from
478      Emacs redisplay code.  */
479   if (explicit)
480     {
481       /* If we're switching from explicit to implicit, we had better
482          update the mode lines and thereby update the title.  */
483       if (f->explicit_name && NILP (name))
484         update_mode_lines = 21;
486       f->explicit_name = ! NILP (name);
487     }
488   else if (f->explicit_name)
489     return;
491   if (NILP (name))
492     name = build_string ([ns_app_name UTF8String]);
493   else
494     CHECK_STRING (name);
496   /* Don't change the name if it's already NAME.  */
497   if (! NILP (Fstring_equal (name, f->name)))
498     return;
500   fset_name (f, name);
502   /* Title overrides explicit name.  */
503   if (! NILP (f->title))
504     name = f->title;
506   ns_set_name_internal (f, name);
510 /* This function should be called when the user's lisp code has
511    specified a name for the frame; the name will override any set by the
512    redisplay code.  */
513 static void
514 x_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
516   NSTRACE (x_explicitly_set_name);
517   ns_set_name (f, arg, 1);
521 /* This function should be called by Emacs redisplay code to set the
522    name; names set this way will never override names set by the user's
523    lisp code.  */
524 void
525 x_implicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
527   NSTRACE (x_implicitly_set_name);
529   /* Deal with NS specific format t.  */
530   if (FRAME_NS_P (f) && ((FRAME_ICONIFIED_P (f) && EQ (Vicon_title_format, Qt))
531                          || EQ (Vframe_title_format, Qt)))
532     ns_set_name_as_filename (f);
533   else
534     ns_set_name (f, arg, 0);
538 /* Change the title of frame F to NAME.
539    If NAME is nil, use the frame name as the title.  */
541 static void
542 x_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name)
544   NSTRACE (x_set_title);
545   /* Don't change the title if it's already NAME.  */
546   if (EQ (name, f->title))
547     return;
549   update_mode_lines = 22;
551   fset_title (f, name);
553   if (NILP (name))
554     name = f->name;
555   else
556     CHECK_STRING (name);
558   ns_set_name_internal (f, name);
562 void
563 ns_set_name_as_filename (struct frame *f)
565   NSView *view;
566   Lisp_Object name, filename;
567   Lisp_Object buf = XWINDOW (f->selected_window)->contents;
568   const char *title;
569   NSAutoreleasePool *pool;
570   struct gcpro gcpro1;
571   Lisp_Object encoded_name, encoded_filename;
572   NSString *str;
573   NSTRACE (ns_set_name_as_filename);
575   if (f->explicit_name || ! NILP (f->title))
576     return;
578   block_input ();
579   pool = [[NSAutoreleasePool alloc] init];
580   filename = BVAR (XBUFFER (buf), filename);
581   name = BVAR (XBUFFER (buf), name);
583   if (NILP (name))
584     {
585       if (! NILP (filename))
586         name = Ffile_name_nondirectory (filename);
587       else
588         name = build_string ([ns_app_name UTF8String]);
589     }
591   GCPRO1 (name);
592   encoded_name = ENCODE_UTF_8 (name);
593   UNGCPRO;
595   view = FRAME_NS_VIEW (f);
597   title = FRAME_ICONIFIED_P (f) ? [[[view window] miniwindowTitle] UTF8String]
598                                 : [[[view window] title] UTF8String];
600   if (title && (! strcmp (title, SSDATA (encoded_name))))
601     {
602       [pool release];
603       unblock_input ();
604       return;
605     }
607   str = [NSString stringWithUTF8String: SSDATA (encoded_name)];
608   if (str == nil) str = @"Bad coding";
610   if (FRAME_ICONIFIED_P (f))
611     [[view window] setMiniwindowTitle: str];
612   else
613     {
614       NSString *fstr;
616       if (! NILP (filename))
617         {
618           GCPRO1 (filename);
619           encoded_filename = ENCODE_UTF_8 (filename);
620           UNGCPRO;
622           fstr = [NSString stringWithUTF8String: SSDATA (encoded_filename)];
623           if (fstr == nil) fstr = @"";
624         }
625       else
626         fstr = @"";
628       ns_set_represented_filename (fstr, f);
629       [[view window] setTitle: str];
630       fset_name (f, name);
631     }
633   [pool release];
634   unblock_input ();
638 void
639 ns_set_doc_edited (void)
641   NSAutoreleasePool *pool;
642   Lisp_Object tail, frame;
643   block_input ();
644   pool = [[NSAutoreleasePool alloc] init];
645   FOR_EACH_FRAME (tail, frame)
646     {
647       BOOL edited = NO;
648       struct frame *f = XFRAME (frame);
649       struct window *w;
650       NSView *view;
652       if (! FRAME_NS_P (f)) continue;
653       w = XWINDOW (FRAME_SELECTED_WINDOW (f));
654       view = FRAME_NS_VIEW (f);
655       if (!MINI_WINDOW_P (w))
656         edited = ! NILP (Fbuffer_modified_p (w->contents)) &&
657           ! NILP (Fbuffer_file_name (w->contents));
658       [[view window] setDocumentEdited: edited];
659     }
661   [pool release];
662   unblock_input ();
666 void
667 x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
669   int nlines;
670   if (FRAME_MINIBUF_ONLY_P (f))
671     return;
673   if (TYPE_RANGED_INTEGERP (int, value))
674     nlines = XINT (value);
675   else
676     nlines = 0;
678   FRAME_MENU_BAR_LINES (f) = 0;
679   if (nlines)
680     {
681       FRAME_EXTERNAL_MENU_BAR (f) = 1;
682       /* does for all frames, whereas we just want for one frame
683          [NSMenu setMenuBarVisible: YES]; */
684     }
685   else
686     {
687       if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
688         free_frame_menubar (f);
689       /*      [NSMenu setMenuBarVisible: NO]; */
690       FRAME_EXTERNAL_MENU_BAR (f) = 0;
691     }
695 /* toolbar support */
696 void
697 x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
699   int nlines;
701   if (FRAME_MINIBUF_ONLY_P (f))
702     return;
704   if (RANGED_INTEGERP (0, value, INT_MAX))
705     nlines = XFASTINT (value);
706   else
707     nlines = 0;
709   if (nlines)
710     {
711       FRAME_EXTERNAL_TOOL_BAR (f) = 1;
712       update_frame_tool_bar (f);
713     }
714   else
715     {
716       if (FRAME_EXTERNAL_TOOL_BAR (f))
717         {
718           free_frame_tool_bar (f);
719           FRAME_EXTERNAL_TOOL_BAR (f) = 0;
720         }
721     }
723   x_set_window_size (f, 0, f->text_cols, f->text_lines, 0);
727 static void
728 ns_implicitly_set_icon_type (struct frame *f)
730   Lisp_Object tem;
731   EmacsView *view = FRAME_NS_VIEW (f);
732   id image = nil;
733   Lisp_Object chain, elt;
734   NSAutoreleasePool *pool;
735   BOOL setMini = YES;
737   NSTRACE (ns_implicitly_set_icon_type);
739   block_input ();
740   pool = [[NSAutoreleasePool alloc] init];
741   if (f->output_data.ns->miniimage
742       && [[NSString stringWithUTF8String: SSDATA (f->name)]
743                isEqualToString: [(NSImage *)f->output_data.ns->miniimage name]])
744     {
745       [pool release];
746       unblock_input ();
747       return;
748     }
750   tem = assq_no_quit (Qicon_type, f->param_alist);
751   if (CONSP (tem) && ! NILP (XCDR (tem)))
752     {
753       [pool release];
754       unblock_input ();
755       return;
756     }
758   for (chain = Vns_icon_type_alist;
759        image == nil && CONSP (chain);
760        chain = XCDR (chain))
761     {
762       elt = XCAR (chain);
763       /* special case: 't' means go by file type */
764       if (SYMBOLP (elt) && EQ (elt, Qt) && SSDATA (f->name)[0] == '/')
765         {
766           NSString *str
767              = [NSString stringWithUTF8String: SSDATA (f->name)];
768           if ([[NSFileManager defaultManager] fileExistsAtPath: str])
769             image = [[[NSWorkspace sharedWorkspace] iconForFile: str] retain];
770         }
771       else if (CONSP (elt) &&
772                STRINGP (XCAR (elt)) &&
773                STRINGP (XCDR (elt)) &&
774                fast_string_match (XCAR (elt), f->name) >= 0)
775         {
776           image = [EmacsImage allocInitFromFile: XCDR (elt)];
777           if (image == nil)
778             image = [[NSImage imageNamed:
779                                [NSString stringWithUTF8String:
780                                             SSDATA (XCDR (elt))]] retain];
781         }
782     }
784   if (image == nil)
785     {
786       image = [[[NSWorkspace sharedWorkspace] iconForFileType: @"text"] retain];
787       setMini = NO;
788     }
790   [f->output_data.ns->miniimage release];
791   f->output_data.ns->miniimage = image;
792   [view setMiniwindowImage: setMini];
793   [pool release];
794   unblock_input ();
798 static void
799 x_set_icon_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
801   EmacsView *view = FRAME_NS_VIEW (f);
802   id image = nil;
803   BOOL setMini = YES;
805   NSTRACE (x_set_icon_type);
807   if (!NILP (arg) && SYMBOLP (arg))
808     {
809       arg =build_string (SSDATA (SYMBOL_NAME (arg)));
810       store_frame_param (f, Qicon_type, arg);
811     }
813   /* do it the implicit way */
814   if (NILP (arg))
815     {
816       ns_implicitly_set_icon_type (f);
817       return;
818     }
820   CHECK_STRING (arg);
822   image = [EmacsImage allocInitFromFile: arg];
823   if (image == nil)
824     image =[NSImage imageNamed: [NSString stringWithUTF8String:
825                                             SSDATA (arg)]];
827   if (image == nil)
828     {
829       image = [NSImage imageNamed: @"text"];
830       setMini = NO;
831     }
833   f->output_data.ns->miniimage = image;
834   [view setMiniwindowImage: setMini];
838 /* TODO: move to nsterm? */
840 ns_lisp_to_cursor_type (Lisp_Object arg)
842   char *str;
843   if (XTYPE (arg) == Lisp_String)
844     str = SSDATA (arg);
845   else if (XTYPE (arg) == Lisp_Symbol)
846     str = SSDATA (SYMBOL_NAME (arg));
847   else return -1;
848   if (!strcmp (str, "box"))     return FILLED_BOX_CURSOR;
849   if (!strcmp (str, "hollow"))  return HOLLOW_BOX_CURSOR;
850   if (!strcmp (str, "hbar"))    return HBAR_CURSOR;
851   if (!strcmp (str, "bar"))     return BAR_CURSOR;
852   if (!strcmp (str, "no"))      return NO_CURSOR;
853   return -1;
857 Lisp_Object
858 ns_cursor_type_to_lisp (int arg)
860   switch (arg)
861     {
862     case FILLED_BOX_CURSOR: return Qbox;
863     case HOLLOW_BOX_CURSOR: return intern ("hollow");
864     case HBAR_CURSOR:       return intern ("hbar");
865     case BAR_CURSOR:        return intern ("bar");
866     case NO_CURSOR:
867     default:                return intern ("no");
868     }
871 /* This is the same as the xfns.c definition.  */
872 static void
873 x_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
875   set_frame_cursor_types (f, arg);
878 /* called to set mouse pointer color, but all other terms use it to
879    initialize pointer types (and don't set the color ;) */
880 static void
881 x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
883   /* don't think we can do this on Nextstep */
887 #define Str(x) #x
888 #define Xstr(x) Str(x)
890 static Lisp_Object
891 ns_appkit_version_str (void)
893   char tmp[80];
895 #ifdef NS_IMPL_GNUSTEP
896   sprintf(tmp, "gnustep-gui-%s", Xstr(GNUSTEP_GUI_VERSION));
897 #elif defined (NS_IMPL_COCOA)
898   sprintf(tmp, "apple-appkit-%.2f", NSAppKitVersionNumber);
899 #else
900   tmp = "ns-unknown";
901 #endif
902   return build_string (tmp);
906 /* This is for use by x-server-version and collapses all version info we
907    have into a single int.  For a better picture of the implementation
908    running, use ns_appkit_version_str.*/
909 static int
910 ns_appkit_version_int (void)
912 #ifdef NS_IMPL_GNUSTEP
913   return GNUSTEP_GUI_MAJOR_VERSION * 100 + GNUSTEP_GUI_MINOR_VERSION;
914 #elif defined (NS_IMPL_COCOA)
915   return (int)NSAppKitVersionNumber;
916 #endif
917   return 0;
921 static void
922 x_icon (struct frame *f, Lisp_Object parms)
923 /* --------------------------------------------------------------------------
924    Strangely-named function to set icon position parameters in frame.
925    This is irrelevant under OS X, but might be needed under GNUstep,
926    depending on the window manager used.  Note, this is not a standard
927    frame parameter-setter; it is called directly from x-create-frame.
928    -------------------------------------------------------------------------- */
930   Lisp_Object icon_x, icon_y;
931   struct ns_display_info *dpyinfo = check_ns_display_info (Qnil);
933   f->output_data.ns->icon_top = -1;
934   f->output_data.ns->icon_left = -1;
936   /* Set the position of the icon.  */
937   icon_x = x_get_arg (dpyinfo, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
938   icon_y = x_get_arg (dpyinfo, parms, Qicon_top, 0, 0,  RES_TYPE_NUMBER);
939   if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
940     {
941       CHECK_NUMBER (icon_x);
942       CHECK_NUMBER (icon_y);
943       f->output_data.ns->icon_top = XINT (icon_y);
944       f->output_data.ns->icon_left = XINT (icon_x);
945     }
946   else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
947     error ("Both left and top icon corners of icon must be specified");
951 /* Note: see frame.c for template, also where generic functions are impl */
952 frame_parm_handler ns_frame_parm_handlers[] =
954   x_set_autoraise, /* generic OK */
955   x_set_autolower, /* generic OK */
956   x_set_background_color,
957   0, /* x_set_border_color,  may be impossible under Nextstep */
958   0, /* x_set_border_width,  may be impossible under Nextstep */
959   x_set_cursor_color,
960   x_set_cursor_type,
961   x_set_font, /* generic OK */
962   x_set_foreground_color,
963   x_set_icon_name,
964   x_set_icon_type,
965   x_set_internal_border_width, /* generic OK */
966   0, /* x_set_right_divider_width */
967   0, /* x_set_bottom_divider_width */
968   x_set_menu_bar_lines,
969   x_set_mouse_color,
970   x_explicitly_set_name,
971   x_set_scroll_bar_width, /* generic OK */
972   x_set_title,
973   x_set_unsplittable, /* generic OK */
974   x_set_vertical_scroll_bars, /* generic OK */
975   x_set_visibility, /* generic OK */
976   x_set_tool_bar_lines,
977   0, /* x_set_scroll_bar_foreground, will ignore (not possible on NS) */
978   0, /* x_set_scroll_bar_background,  will ignore (not possible on NS) */
979   x_set_screen_gamma, /* generic OK */
980   x_set_line_spacing, /* generic OK, sets f->extra_line_spacing to int */
981   x_set_fringe_width, /* generic OK */
982   x_set_fringe_width, /* generic OK */
983   0, /* x_set_wait_for_wm, will ignore */
984   x_set_fullscreen, /* generic OK */
985   x_set_font_backend, /* generic OK */
986   x_set_alpha,
987   0, /* x_set_sticky */
988   0, /* x_set_tool_bar_position */
992 /* Handler for signals raised during x_create_frame.
993    FRAME is the frame which is partially constructed.  */
995 static void
996 unwind_create_frame (Lisp_Object frame)
998   struct frame *f = XFRAME (frame);
1000   /* If frame is already dead, nothing to do.  This can happen if the
1001      display is disconnected after the frame has become official, but
1002      before x_create_frame removes the unwind protect.  */
1003   if (!FRAME_LIVE_P (f))
1004     return;
1006   /* If frame is ``official'', nothing to do.  */
1007   if (NILP (Fmemq (frame, Vframe_list)))
1008     {
1009 #if defined GLYPH_DEBUG && defined ENABLE_CHECKING
1010       struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1011 #endif
1013       x_free_frame_resources (f);
1014       free_glyphs (f);
1016 #ifdef GLYPH_DEBUG
1017       /* Check that reference counts are indeed correct.  */
1018       eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
1019 #endif
1020     }
1024  * Read geometry related parameters from preferences if not in PARMS.
1025  * Returns the union of parms and any preferences read.
1026  */
1028 static Lisp_Object
1029 get_geometry_from_preferences (struct ns_display_info *dpyinfo,
1030                                Lisp_Object parms)
1032   struct {
1033     const char *val;
1034     const char *cls;
1035     Lisp_Object tem;
1036   } r[] = {
1037     { "width",  "Width", Qwidth },
1038     { "height", "Height", Qheight },
1039     { "left", "Left", Qleft },
1040     { "top", "Top", Qtop },
1041   };
1043   int i;
1044   for (i = 0; i < sizeof (r)/sizeof (r[0]); ++i)
1045     {
1046       if (NILP (Fassq (r[i].tem, parms)))
1047         {
1048           Lisp_Object value
1049             = x_get_arg (dpyinfo, parms, r[i].tem, r[i].val, r[i].cls,
1050                          RES_TYPE_NUMBER);
1051           if (! EQ (value, Qunbound))
1052             parms = Fcons (Fcons (r[i].tem, value), parms);
1053         }
1054     }
1056   return parms;
1059 /* ==========================================================================
1061     Lisp definitions
1063    ========================================================================== */
1065 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
1066        1, 1, 0,
1067        doc: /* Make a new Nextstep window, called a "frame" in Emacs terms.
1068 Return an Emacs frame object.
1069 PARMS is an alist of frame parameters.
1070 If the parameters specify that the frame should not have a minibuffer,
1071 and do not specify a specific minibuffer window to use,
1072 then `default-minibuffer-frame' must be a frame whose minibuffer can
1073 be shared by the new frame.
1075 This function is an internal primitive--use `make-frame' instead.  */)
1076      (Lisp_Object parms)
1078   struct frame *f;
1079   Lisp_Object frame, tem;
1080   Lisp_Object name;
1081   int minibuffer_only = 0;
1082   long window_prompting = 0;
1083   int width, height;
1084   ptrdiff_t count = specpdl_ptr - specpdl;
1085   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
1086   Lisp_Object display;
1087   struct ns_display_info *dpyinfo = NULL;
1088   Lisp_Object parent;
1089   struct kboard *kb;
1090   static int desc_ctr = 1;
1092   /* x_get_arg modifies parms.  */
1093   parms = Fcopy_alist (parms);
1095   /* Use this general default value to start with
1096      until we know if this frame has a specified name.  */
1097   Vx_resource_name = Vinvocation_name;
1099   display = x_get_arg (dpyinfo, parms, Qterminal, 0, 0, RES_TYPE_STRING);
1100   if (EQ (display, Qunbound))
1101     display = Qnil;
1102   dpyinfo = check_ns_display_info (display);
1103   kb = dpyinfo->terminal->kboard;
1105   if (!dpyinfo->terminal->name)
1106     error ("Terminal is not live, can't create new frames on it");
1108   name = x_get_arg (dpyinfo, parms, Qname, 0, 0, RES_TYPE_STRING);
1109   if (!STRINGP (name)
1110       && ! EQ (name, Qunbound)
1111       && ! NILP (name))
1112     error ("Invalid frame name--not a string or nil");
1114   if (STRINGP (name))
1115     Vx_resource_name = name;
1117   parent = x_get_arg (dpyinfo, parms, Qparent_id, 0, 0, RES_TYPE_NUMBER);
1118   if (EQ (parent, Qunbound))
1119     parent = Qnil;
1120   if (! NILP (parent))
1121     CHECK_NUMBER (parent);
1123   /* make_frame_without_minibuffer can run Lisp code and garbage collect.  */
1124   /* No need to protect DISPLAY because that's not used after passing
1125      it to make_frame_without_minibuffer.  */
1126   frame = Qnil;
1127   GCPRO4 (parms, parent, name, frame);
1128   tem = x_get_arg (dpyinfo, parms, Qminibuffer, "minibuffer", "Minibuffer",
1129                   RES_TYPE_SYMBOL);
1130   if (EQ (tem, Qnone) || NILP (tem))
1131       f = make_frame_without_minibuffer (Qnil, kb, display);
1132   else if (EQ (tem, Qonly))
1133     {
1134       f = make_minibuffer_frame ();
1135       minibuffer_only = 1;
1136     }
1137   else if (WINDOWP (tem))
1138       f = make_frame_without_minibuffer (tem, kb, display);
1139   else
1140       f = make_frame (1);
1142   XSETFRAME (frame, f);
1144   f->terminal = dpyinfo->terminal;
1146   f->output_method = output_ns;
1147   f->output_data.ns = xzalloc (sizeof *f->output_data.ns);
1149   FRAME_FONTSET (f) = -1;
1151   fset_icon_name (f, x_get_arg (dpyinfo, parms, Qicon_name,
1152                                 "iconName", "Title",
1153                                 RES_TYPE_STRING));
1154   if (! STRINGP (f->icon_name))
1155     fset_icon_name (f, Qnil);
1157   FRAME_DISPLAY_INFO (f) = dpyinfo;
1159   /* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe.  */
1160   record_unwind_protect (unwind_create_frame, frame);
1162   f->output_data.ns->window_desc = desc_ctr++;
1163   if (TYPE_RANGED_INTEGERP (Window, parent))
1164     {
1165       f->output_data.ns->parent_desc = XFASTINT (parent);
1166       f->output_data.ns->explicit_parent = 1;
1167     }
1168   else
1169     {
1170       f->output_data.ns->parent_desc = FRAME_DISPLAY_INFO (f)->root_window;
1171       f->output_data.ns->explicit_parent = 0;
1172     }
1174   /* Set the name; the functions to which we pass f expect the name to
1175      be set.  */
1176   if (EQ (name, Qunbound) || NILP (name) || ! STRINGP (name))
1177     {
1178       fset_name (f, build_string ([ns_app_name UTF8String]));
1179       f->explicit_name = 0;
1180     }
1181   else
1182     {
1183       fset_name (f, name);
1184       f->explicit_name = 1;
1185       specbind (Qx_resource_name, name);
1186     }
1188   block_input ();
1190 #ifdef NS_IMPL_COCOA
1191 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
1192   if (CTGetCoreTextVersion != NULL
1193       && CTGetCoreTextVersion () >= kCTVersionNumber10_5)
1194     mac_register_font_driver (f);
1195 #endif
1196 #endif
1197   register_font_driver (&nsfont_driver, f);
1199   x_default_parameter (f, parms, Qfont_backend, Qnil,
1200                         "fontBackend", "FontBackend", RES_TYPE_STRING);
1202   {
1203     /* use for default font name */
1204     id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */
1205     x_default_parameter (f, parms, Qfontsize,
1206                                     make_number (0 /*(int)[font pointSize]*/),
1207                                     "fontSize", "FontSize", RES_TYPE_NUMBER);
1208     // Remove ' Regular', not handled by backends.
1209     char *fontname = xstrdup ([[font displayName] UTF8String]);
1210     int len = strlen (fontname);
1211     if (len > 8 && strcmp (fontname + len - 8, " Regular") == 0)
1212       fontname[len-8] = '\0';
1213     x_default_parameter (f, parms, Qfont,
1214                                  build_string (fontname),
1215                                  "font", "Font", RES_TYPE_STRING);
1216     xfree (fontname);
1217   }
1218   unblock_input ();
1220   x_default_parameter (f, parms, Qborder_width, make_number (0),
1221                        "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
1222   x_default_parameter (f, parms, Qinternal_border_width, make_number (2),
1223                       "internalBorderWidth", "InternalBorderWidth",
1224                       RES_TYPE_NUMBER);
1226   /* default scrollbars on right on Mac */
1227   {
1228       Lisp_Object spos
1229 #ifdef NS_IMPL_GNUSTEP
1230           = Qt;
1231 #else
1232           = Qright;
1233 #endif
1234       x_default_parameter (f, parms, Qvertical_scroll_bars, spos,
1235                            "verticalScrollBars", "VerticalScrollBars",
1236                            RES_TYPE_SYMBOL);
1237   }
1238   x_default_parameter (f, parms, Qforeground_color, build_string ("Black"),
1239                       "foreground", "Foreground", RES_TYPE_STRING);
1240   x_default_parameter (f, parms, Qbackground_color, build_string ("White"),
1241                       "background", "Background", RES_TYPE_STRING);
1242   /* FIXME: not supported yet in Nextstep */
1243   x_default_parameter (f, parms, Qline_spacing, Qnil,
1244                        "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
1245   x_default_parameter (f, parms, Qleft_fringe, Qnil,
1246                        "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
1247   x_default_parameter (f, parms, Qright_fringe, Qnil,
1248                        "rightFringe", "RightFringe", RES_TYPE_NUMBER);
1250 #ifdef GLYPH_DEBUG
1251   image_cache_refcount =
1252     FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0;
1253 #endif
1255   init_frame_faces (f);
1257   /* Read comment about this code in corresponding place in xfns.c.  */
1258   width = FRAME_TEXT_WIDTH (f);
1259   height = FRAME_TEXT_HEIGHT (f);
1260   FRAME_TEXT_HEIGHT (f) = 0;
1261   SET_FRAME_WIDTH (f, 0);
1262   change_frame_size (f, width, height, 1, 0, 0, 1);
1264   /* The resources controlling the menu-bar and tool-bar are
1265      processed specially at startup, and reflected in the mode
1266      variables; ignore them here.  */
1267   x_default_parameter (f, parms, Qmenu_bar_lines,
1268                        NILP (Vmenu_bar_mode)
1269                        ? make_number (0) : make_number (1),
1270                        NULL, NULL, RES_TYPE_NUMBER);
1271   x_default_parameter (f, parms, Qtool_bar_lines,
1272                        NILP (Vtool_bar_mode)
1273                        ? make_number (0) : make_number (1),
1274                        NULL, NULL, RES_TYPE_NUMBER);
1276   x_default_parameter (f, parms, Qbuffer_predicate, Qnil, "bufferPredicate",
1277                        "BufferPredicate", RES_TYPE_SYMBOL);
1278   x_default_parameter (f, parms, Qtitle, Qnil, "title", "Title",
1279                        RES_TYPE_STRING);
1281   parms = get_geometry_from_preferences (dpyinfo, parms);
1282   window_prompting = x_figure_window_size (f, parms, 1);
1284   tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
1285   f->no_split = minibuffer_only || (!EQ (tem, Qunbound) && !EQ (tem, Qnil));
1287   /* NOTE: on other terms, this is done in set_mouse_color, however this
1288      was not getting called under Nextstep */
1289   f->output_data.ns->text_cursor = [NSCursor IBeamCursor];
1290   f->output_data.ns->nontext_cursor = [NSCursor arrowCursor];
1291   f->output_data.ns->modeline_cursor = [NSCursor pointingHandCursor];
1292   f->output_data.ns->hand_cursor = [NSCursor pointingHandCursor];
1293   f->output_data.ns->hourglass_cursor = [NSCursor disappearingItemCursor];
1294   f->output_data.ns->horizontal_drag_cursor = [NSCursor resizeLeftRightCursor];
1295   f->output_data.ns->vertical_drag_cursor = [NSCursor resizeUpDownCursor];
1296   FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor
1297      = [NSCursor arrowCursor];
1298   f->output_data.ns->current_pointer = f->output_data.ns->text_cursor;
1300   [[EmacsView alloc] initFrameFromEmacs: f];
1302   x_icon (f, parms);
1304   /* ns_display_info does not have a reference_count.  */
1305   f->terminal->reference_count++;
1307   /* It is now ok to make the frame official even if we get an error below.
1308      The frame needs to be on Vframe_list or making it visible won't work. */
1309   Vframe_list = Fcons (frame, Vframe_list);
1311   x_default_parameter (f, parms, Qicon_type, Qnil,
1312                        "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
1314   x_default_parameter (f, parms, Qauto_raise, Qnil,
1315                        "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
1316   x_default_parameter (f, parms, Qauto_lower, Qnil,
1317                        "autoLower", "AutoLower", RES_TYPE_BOOLEAN);
1318   x_default_parameter (f, parms, Qcursor_type, Qbox,
1319                        "cursorType", "CursorType", RES_TYPE_SYMBOL);
1320   x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
1321                        "scrollBarWidth", "ScrollBarWidth",
1322                        RES_TYPE_NUMBER);
1323   x_default_parameter (f, parms, Qalpha, Qnil,
1324                        "alpha", "Alpha", RES_TYPE_NUMBER);
1325   x_default_parameter (f, parms, Qfullscreen, Qnil,
1326                        "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
1328   width = FRAME_TEXT_WIDTH (f);
1329   height = FRAME_TEXT_HEIGHT (f);
1330   FRAME_TEXT_HEIGHT (f) = 0;
1331   SET_FRAME_WIDTH (f, 0);
1332   change_frame_size (f, width, height, 1, 0, 0, 1);
1334   if (! f->output_data.ns->explicit_parent)
1335     {
1336       Lisp_Object visibility;
1338       visibility = x_get_arg (dpyinfo, parms, Qvisibility, 0, 0,
1339                               RES_TYPE_SYMBOL);
1340       if (EQ (visibility, Qunbound))
1341         visibility = Qt;
1343       if (EQ (visibility, Qicon))
1344         x_iconify_frame (f);
1345       else if (! NILP (visibility))
1346         {
1347           x_make_frame_visible (f);
1348           [[FRAME_NS_VIEW (f) window] makeKeyWindow];
1349         }
1350       else
1351         {
1352           /* Must have been Qnil.  */
1353         }
1354     }
1356   if (FRAME_HAS_MINIBUF_P (f)
1357       && (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame))
1358           || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame)))))
1359     kset_default_minibuffer_frame (kb, frame);
1361   /* All remaining specified parameters, which have not been "used"
1362      by x_get_arg and friends, now go in the misc. alist of the frame.  */
1363   for (tem = parms; CONSP (tem); tem = XCDR (tem))
1364     if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem))))
1365       fset_param_alist (f, Fcons (XCAR (tem), f->param_alist));
1367   UNGCPRO;
1369   if (window_prompting & USPosition)
1370     x_set_offset (f, f->left_pos, f->top_pos, 1);
1372   /* Make sure windows on this frame appear in calls to next-window
1373      and similar functions.  */
1374   Vwindow_list = Qnil;
1376   return unbind_to (count, frame);
1379 void
1380 x_focus_frame (struct frame *f)
1382   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1384   if (dpyinfo->x_focus_frame != f)
1385     {
1386       EmacsView *view = FRAME_NS_VIEW (f);
1387       block_input ();
1388       [NSApp activateIgnoringOtherApps: YES];
1389       [[view window] makeKeyAndOrderFront: view];
1390       unblock_input ();
1391     }
1395 DEFUN ("ns-popup-font-panel", Fns_popup_font_panel, Sns_popup_font_panel,
1396        0, 1, "",
1397        doc: /* Pop up the font panel. */)
1398      (Lisp_Object frame)
1400   struct frame *f = decode_window_system_frame (frame);
1401   id fm = [NSFontManager sharedFontManager];
1402   struct font *font = f->output_data.ns->font;
1403   NSFont *nsfont;
1404   if (EQ (font->driver->type, Qns))
1405     nsfont = ((struct nsfont_info *)font)->nsfont;
1406 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
1407   else
1408     nsfont = (NSFont *) macfont_get_nsctfont (font);
1409 #endif
1410   [fm setSelectedFont: nsfont isMultiple: NO];
1411   [fm orderFrontFontPanel: NSApp];
1412   return Qnil;
1416 DEFUN ("ns-popup-color-panel", Fns_popup_color_panel, Sns_popup_color_panel,
1417        0, 1, "",
1418        doc: /* Pop up the color panel.  */)
1419      (Lisp_Object frame)
1421   check_window_system (NULL);
1422   [NSApp orderFrontColorPanel: NSApp];
1423   return Qnil;
1426 static struct
1428   id panel;
1429   BOOL ret;
1430 #if ! defined (NS_IMPL_COCOA) || \
1431   MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
1432   NSString *dirS, *initS;
1433   BOOL no_types;
1434 #endif
1435 } ns_fd_data;
1437 void
1438 ns_run_file_dialog (void)
1440   if (ns_fd_data.panel == nil) return;
1441 #if defined (NS_IMPL_COCOA) && \
1442   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1443   ns_fd_data.ret = [ns_fd_data.panel runModal];
1444 #else
1445   if (ns_fd_data.no_types)
1446     {
1447       ns_fd_data.ret = [ns_fd_data.panel
1448                            runModalForDirectory: ns_fd_data.dirS
1449                            file: ns_fd_data.initS];
1450     }
1451   else
1452     {
1453       ns_fd_data.ret = [ns_fd_data.panel
1454                            runModalForDirectory: ns_fd_data.dirS
1455                            file: ns_fd_data.initS
1456                            types: nil];
1457     }
1458 #endif
1459   ns_fd_data.panel = nil;
1462 DEFUN ("ns-read-file-name", Fns_read_file_name, Sns_read_file_name, 1, 5, 0,
1463        doc: /* Use a graphical panel to read a file name, using prompt PROMPT.
1464 Optional arg DIR, if non-nil, supplies a default directory.
1465 Optional arg MUSTMATCH, if non-nil, means the returned file or
1466 directory must exist.
1467 Optional arg INIT, if non-nil, provides a default file name to use.
1468 Optional arg DIR_ONLY_P, if non-nil, means choose only directories.  */)
1469   (Lisp_Object prompt, Lisp_Object dir, Lisp_Object mustmatch,
1470    Lisp_Object init, Lisp_Object dir_only_p)
1472   static id fileDelegate = nil;
1473   BOOL ret;
1474   BOOL isSave = NILP (mustmatch) && NILP (dir_only_p);
1475   id panel;
1476   Lisp_Object fname;
1478   NSString *promptS = NILP (prompt) || !STRINGP (prompt) ? nil :
1479     [NSString stringWithUTF8String: SSDATA (prompt)];
1480   NSString *dirS = NILP (dir) || !STRINGP (dir) ?
1481     [NSString stringWithUTF8String: SSDATA (BVAR (current_buffer, directory))] :
1482     [NSString stringWithUTF8String: SSDATA (dir)];
1483   NSString *initS = NILP (init) || !STRINGP (init) ? nil :
1484     [NSString stringWithUTF8String: SSDATA (init)];
1485   NSEvent *nxev;
1487   check_window_system (NULL);
1489   if (fileDelegate == nil)
1490     fileDelegate = [EmacsFileDelegate new];
1492   [NSCursor setHiddenUntilMouseMoves: NO];
1494   if ([dirS characterAtIndex: 0] == '~')
1495     dirS = [dirS stringByExpandingTildeInPath];
1497   panel = isSave ?
1498     (id)[EmacsSavePanel savePanel] : (id)[EmacsOpenPanel openPanel];
1500   [panel setTitle: promptS];
1502   [panel setAllowsOtherFileTypes: YES];
1503   [panel setTreatsFilePackagesAsDirectories: YES];
1504   [panel setDelegate: fileDelegate];
1506   if (! NILP (dir_only_p))
1507     {
1508       [panel setCanChooseDirectories: YES];
1509       [panel setCanChooseFiles: NO];
1510     }
1511   else if (! isSave)
1512     {
1513       /* This is not quite what the documentation says, but it is compatible
1514          with the Gtk+ code.  Also, the menu entry says "Open File...".  */
1515       [panel setCanChooseDirectories: NO];
1516       [panel setCanChooseFiles: YES];
1517     }
1519   block_input ();
1520   ns_fd_data.panel = panel;
1521   ns_fd_data.ret = NO;
1522 #if defined (NS_IMPL_COCOA) && \
1523   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1524   if (! NILP (mustmatch) || ! NILP (dir_only_p))
1525     [panel setAllowedFileTypes: nil];
1526   if (dirS) [panel setDirectoryURL: [NSURL fileURLWithPath: dirS]];
1527   if (initS && NILP (Ffile_directory_p (init)))
1528     [panel setNameFieldStringValue: [initS lastPathComponent]];
1529   else
1530     [panel setNameFieldStringValue: @""];
1532 #else
1533   ns_fd_data.no_types = NILP (mustmatch) && NILP (dir_only_p);
1534   ns_fd_data.dirS = dirS;
1535   ns_fd_data.initS = initS;
1536 #endif
1538   /* runModalForDirectory/runModal restarts the main event loop when done,
1539      so we must start an event loop and then pop up the file dialog.
1540      The file dialog may pop up a confirm dialog after Ok has been pressed,
1541      so we can not simply pop down on the Ok/Cancel press.
1542    */
1543   nxev = [NSEvent otherEventWithType: NSApplicationDefined
1544                             location: NSMakePoint (0, 0)
1545                        modifierFlags: 0
1546                            timestamp: 0
1547                         windowNumber: [[NSApp mainWindow] windowNumber]
1548                              context: [NSApp context]
1549                              subtype: 0
1550                                data1: 0
1551                                data2: NSAPP_DATA2_RUNFILEDIALOG];
1553   [NSApp postEvent: nxev atStart: NO];
1554   while (ns_fd_data.panel != nil)
1555     [NSApp run];
1557   ret = (ns_fd_data.ret == NSOKButton);
1559   if (ret)
1560     {
1561       NSString *str = ns_filename_from_panel (panel);
1562       if (! str) str = ns_directory_from_panel (panel);
1563       if (! str) ret = NO;
1564       else fname = build_string ([str UTF8String]);
1565     }
1567   [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow];
1568   unblock_input ();
1570   return ret ? fname : Qnil;
1573 const char *
1574 ns_get_defaults_value (const char *key)
1576   NSObject *obj = [[NSUserDefaults standardUserDefaults]
1577                     objectForKey: [NSString stringWithUTF8String: key]];
1579   if (!obj) return NULL;
1581   return [[NSString stringWithFormat: @"%@", obj] UTF8String];
1585 DEFUN ("ns-get-resource", Fns_get_resource, Sns_get_resource, 2, 2, 0,
1586        doc: /* Return the value of the property NAME of OWNER from the defaults database.
1587 If OWNER is nil, Emacs is assumed.  */)
1588      (Lisp_Object owner, Lisp_Object name)
1590   const char *value;
1592   check_window_system (NULL);
1593   if (NILP (owner))
1594     owner = build_string([ns_app_name UTF8String]);
1595   CHECK_STRING (name);
1597   value = ns_get_defaults_value (SSDATA (name));
1599   if (value)
1600     return build_string (value);
1601   return Qnil;
1605 DEFUN ("ns-set-resource", Fns_set_resource, Sns_set_resource, 3, 3, 0,
1606        doc: /* Set property NAME of OWNER to VALUE, from the defaults database.
1607 If OWNER is nil, Emacs is assumed.
1608 If VALUE is nil, the default is removed.  */)
1609      (Lisp_Object owner, Lisp_Object name, Lisp_Object value)
1611   check_window_system (NULL);
1612   if (NILP (owner))
1613     owner = build_string ([ns_app_name UTF8String]);
1614   CHECK_STRING (name);
1615   if (NILP (value))
1616     {
1617       [[NSUserDefaults standardUserDefaults] removeObjectForKey:
1618                          [NSString stringWithUTF8String: SSDATA (name)]];
1619     }
1620   else
1621     {
1622       CHECK_STRING (value);
1623       [[NSUserDefaults standardUserDefaults] setObject:
1624                 [NSString stringWithUTF8String: SSDATA (value)]
1625                                         forKey: [NSString stringWithUTF8String:
1626                                                          SSDATA (name)]];
1627     }
1629   return Qnil;
1633 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
1634        Sx_server_max_request_size,
1635        0, 1, 0,
1636        doc: /* This function is a no-op.  It is only present for completeness.  */)
1637      (Lisp_Object terminal)
1639   check_ns_display_info (terminal);
1640   /* This function has no real equivalent under NeXTstep.  Return nil to
1641      indicate this. */
1642   return Qnil;
1646 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
1647        doc: /* Return the "vendor ID" string of Nextstep display server TERMINAL.
1648 \(Labeling every distributor as a "vendor" embodies the false assumption
1649 that operating systems cannot be developed and distributed noncommercially.)
1650 The optional argument TERMINAL specifies which display to ask about.
1651 TERMINAL should be a terminal object, a frame or a display name (a string).
1652 If omitted or nil, that stands for the selected frame's display.  */)
1653   (Lisp_Object terminal)
1655   check_ns_display_info (terminal);
1656 #ifdef NS_IMPL_GNUSTEP
1657   return build_string ("GNU");
1658 #else
1659   return build_string ("Apple");
1660 #endif
1664 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
1665        doc: /* Return the version numbers of the server of display TERMINAL.
1666 The value is a list of three integers: the major and minor
1667 version numbers of the X Protocol in use, and the distributor-specific release
1668 number.  See also the function `x-server-vendor'.
1670 The optional argument TERMINAL specifies which display to ask about.
1671 TERMINAL should be a terminal object, a frame or a display name (a string).
1672 If omitted or nil, that stands for the selected frame's display.  */)
1673   (Lisp_Object terminal)
1675   check_ns_display_info (terminal);
1676   /*NOTE: it is unclear what would best correspond with "protocol";
1677           we return 10.3, meaning Panther, since this is roughly the
1678           level that GNUstep's APIs correspond to.
1679           The last number is where we distinguish between the Apple
1680           and GNUstep implementations ("distributor-specific release
1681           number") and give int'ized versions of major.minor. */
1682   return list3i (10, 3, ns_appkit_version_int ());
1686 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
1687        doc: /* Return the number of screens on Nextstep display server TERMINAL.
1688 The optional argument TERMINAL specifies which display to ask about.
1689 TERMINAL should be a terminal object, a frame or a display name (a string).
1690 If omitted or nil, that stands for the selected frame's display.
1692 Note: "screen" here is not in Nextstep terminology but in X11's.  For
1693 the number of physical monitors, use `(length
1694 (display-monitor-attributes-list TERMINAL))' instead.  */)
1695   (Lisp_Object terminal)
1697   check_ns_display_info (terminal);
1698   return make_number (1);
1702 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
1703        doc: /* Return the height in millimeters of the Nextstep display TERMINAL.
1704 The optional argument TERMINAL specifies which display to ask about.
1705 TERMINAL should be a terminal object, a frame or a display name (a string).
1706 If omitted or nil, that stands for the selected frame's display.
1708 On \"multi-monitor\" setups this refers to the height in millimeters for
1709 all physical monitors associated with TERMINAL.  To get information
1710 for each physical monitor, use `display-monitor-attributes-list'.  */)
1711   (Lisp_Object terminal)
1713   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
1715   return make_number (x_display_pixel_height (dpyinfo) / (92.0/25.4));
1719 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
1720        doc: /* Return the width in millimeters of the Nextstep display TERMINAL.
1721 The optional argument TERMINAL specifies which display to ask about.
1722 TERMINAL should be a terminal object, a frame or a display name (a string).
1723 If omitted or nil, that stands for the selected frame's display.
1725 On \"multi-monitor\" setups this refers to the width in millimeters for
1726 all physical monitors associated with TERMINAL.  To get information
1727 for each physical monitor, use `display-monitor-attributes-list'.  */)
1728   (Lisp_Object terminal)
1730   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
1732   return make_number (x_display_pixel_width (dpyinfo) / (92.0/25.4));
1736 DEFUN ("x-display-backing-store", Fx_display_backing_store,
1737        Sx_display_backing_store, 0, 1, 0,
1738        doc: /* Return an indication of whether the Nextstep display TERMINAL does backing store.
1739 The value may be `buffered', `retained', or `non-retained'.
1740 The optional argument TERMINAL specifies which display to ask about.
1741 TERMINAL should be a terminal object, a frame or a display name (a string).
1742 If omitted or nil, that stands for the selected frame's display.  */)
1743   (Lisp_Object terminal)
1745   check_ns_display_info (terminal);
1746   switch ([ns_get_window (terminal) backingType])
1747     {
1748     case NSBackingStoreBuffered:
1749       return intern ("buffered");
1750     case NSBackingStoreRetained:
1751       return intern ("retained");
1752     case NSBackingStoreNonretained:
1753       return intern ("non-retained");
1754     default:
1755       error ("Strange value for backingType parameter of frame");
1756     }
1757   return Qnil;  /* not reached, shut compiler up */
1761 DEFUN ("x-display-visual-class", Fx_display_visual_class,
1762        Sx_display_visual_class, 0, 1, 0,
1763        doc: /* Return the visual class of the Nextstep display TERMINAL.
1764 The value is one of the symbols `static-gray', `gray-scale',
1765 `static-color', `pseudo-color', `true-color', or `direct-color'.
1767 The optional argument TERMINAL specifies which display to ask about.
1768 TERMINAL should a terminal object, a frame or a display name (a string).
1769 If omitted or nil, that stands for the selected frame's display.  */)
1770   (Lisp_Object terminal)
1772   NSWindowDepth depth;
1774   check_ns_display_info (terminal);
1775   depth = [[[NSScreen screens] objectAtIndex:0] depth];
1777   if ( depth == NSBestDepth (NSCalibratedWhiteColorSpace, 2, 2, YES, NULL))
1778     return intern ("static-gray");
1779   else if (depth == NSBestDepth (NSCalibratedWhiteColorSpace, 8, 8, YES, NULL))
1780     return intern ("gray-scale");
1781   else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 8, 8, YES, NULL))
1782     return intern ("pseudo-color");
1783   else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 4, 12, NO, NULL))
1784     return intern ("true-color");
1785   else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 8, 24, NO, NULL))
1786     return intern ("direct-color");
1787   else
1788     /* color mgmt as far as we do it is really handled by Nextstep itself anyway */
1789     return intern ("direct-color");
1793 DEFUN ("x-display-save-under", Fx_display_save_under,
1794        Sx_display_save_under, 0, 1, 0,
1795        doc: /* Return t if TERMINAL supports the save-under feature.
1796 The optional argument TERMINAL specifies which display to ask about.
1797 TERMINAL should be a terminal object, a frame or a display name (a string).
1798 If omitted or nil, that stands for the selected frame's display.  */)
1799   (Lisp_Object terminal)
1801   check_ns_display_info (terminal);
1802   switch ([ns_get_window (terminal) backingType])
1803     {
1804     case NSBackingStoreBuffered:
1805       return Qt;
1807     case NSBackingStoreRetained:
1808     case NSBackingStoreNonretained:
1809       return Qnil;
1811     default:
1812       error ("Strange value for backingType parameter of frame");
1813     }
1814   return Qnil;  /* not reached, shut compiler up */
1818 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
1819        1, 3, 0,
1820        doc: /* Open a connection to a display server.
1821 DISPLAY is the name of the display to connect to.
1822 Optional second arg XRM-STRING is a string of resources in xrdb format.
1823 If the optional third arg MUST-SUCCEED is non-nil,
1824 terminate Emacs if we can't open the connection.
1825 \(In the Nextstep version, the last two arguments are currently ignored.)  */)
1826      (Lisp_Object display, Lisp_Object resource_string, Lisp_Object must_succeed)
1828   struct ns_display_info *dpyinfo;
1830   CHECK_STRING (display);
1832   nxatoms_of_nsselect ();
1833   dpyinfo = ns_term_init (display);
1834   if (dpyinfo == 0)
1835     {
1836       if (!NILP (must_succeed))
1837         fatal ("Display on %s not responding.\n",
1838                SSDATA (display));
1839       else
1840         error ("Display on %s not responding.\n",
1841                SSDATA (display));
1842     }
1844   return Qnil;
1848 DEFUN ("x-close-connection", Fx_close_connection, Sx_close_connection,
1849        1, 1, 0,
1850        doc: /* Close the connection to TERMINAL's Nextstep display server.
1851 For TERMINAL, specify a terminal object, a frame or a display name (a
1852 string).  If TERMINAL is nil, that stands for the selected frame's
1853 terminal.  */)
1854      (Lisp_Object terminal)
1856   check_ns_display_info (terminal);
1857   [NSApp terminate: NSApp];
1858   return Qnil;
1862 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
1863        doc: /* Return the list of display names that Emacs has connections to.  */)
1864      (void)
1866   Lisp_Object result = Qnil;
1867   struct ns_display_info *ndi;
1869   for (ndi = x_display_list; ndi; ndi = ndi->next)
1870     result = Fcons (XCAR (ndi->name_list_element), result);
1872   return result;
1876 DEFUN ("ns-hide-others", Fns_hide_others, Sns_hide_others,
1877        0, 0, 0,
1878        doc: /* Hides all applications other than Emacs.  */)
1879      (void)
1881   check_window_system (NULL);
1882   [NSApp hideOtherApplications: NSApp];
1883   return Qnil;
1886 DEFUN ("ns-hide-emacs", Fns_hide_emacs, Sns_hide_emacs,
1887        1, 1, 0,
1888        doc: /* If ON is non-nil, the entire Emacs application is hidden.
1889 Otherwise if Emacs is hidden, it is unhidden.
1890 If ON is equal to `activate', Emacs is unhidden and becomes
1891 the active application.  */)
1892      (Lisp_Object on)
1894   check_window_system (NULL);
1895   if (EQ (on, intern ("activate")))
1896     {
1897       [NSApp unhide: NSApp];
1898       [NSApp activateIgnoringOtherApps: YES];
1899     }
1900   else if (NILP (on))
1901     [NSApp unhide: NSApp];
1902   else
1903     [NSApp hide: NSApp];
1904   return Qnil;
1908 DEFUN ("ns-emacs-info-panel", Fns_emacs_info_panel, Sns_emacs_info_panel,
1909        0, 0, 0,
1910        doc: /* Shows the 'Info' or 'About' panel for Emacs.  */)
1911      (void)
1913   check_window_system (NULL);
1914   [NSApp orderFrontStandardAboutPanel: nil];
1915   return Qnil;
1919 DEFUN ("ns-font-name", Fns_font_name, Sns_font_name, 1, 1, 0,
1920        doc: /* Determine font PostScript or family name for font NAME.
1921 NAME should be a string containing either the font name or an XLFD
1922 font descriptor.  If string contains `fontset' and not
1923 `fontset-startup', it is left alone. */)
1924      (Lisp_Object name)
1926   char *nm;
1927   CHECK_STRING (name);
1928   nm = SSDATA (name);
1930   if (nm[0] != '-')
1931     return name;
1932   if (strstr (nm, "fontset") && !strstr (nm, "fontset-startup"))
1933     return name;
1935   return build_string (ns_xlfd_to_fontname (SSDATA (name)));
1939 DEFUN ("ns-list-colors", Fns_list_colors, Sns_list_colors, 0, 1, 0,
1940        doc: /* Return a list of all available colors.
1941 The optional argument FRAME is currently ignored.  */)
1942      (Lisp_Object frame)
1944   Lisp_Object list = Qnil;
1945   NSEnumerator *colorlists;
1946   NSColorList *clist;
1948   if (!NILP (frame))
1949     {
1950       CHECK_FRAME (frame);
1951       if (! FRAME_NS_P (XFRAME (frame)))
1952         error ("non-Nextstep frame used in `ns-list-colors'");
1953     }
1955   block_input ();
1957   colorlists = [[NSColorList availableColorLists] objectEnumerator];
1958   while ((clist = [colorlists nextObject]))
1959     {
1960       if ([[clist name] length] < 7 ||
1961           [[clist name] rangeOfString: @"PANTONE"].location == 0)
1962         {
1963           NSEnumerator *cnames = [[clist allKeys] reverseObjectEnumerator];
1964           NSString *cname;
1965           while ((cname = [cnames nextObject]))
1966             list = Fcons (build_string ([cname UTF8String]), list);
1967 /*           for (i = [[clist allKeys] count] - 1; i >= 0; i--)
1968                list = Fcons (build_string ([[[clist allKeys] objectAtIndex: i]
1969                                              UTF8String]), list); */
1970         }
1971     }
1973   unblock_input ();
1975   return list;
1979 DEFUN ("ns-list-services", Fns_list_services, Sns_list_services, 0, 0, 0,
1980        doc: /* List available Nextstep services by querying NSApp.  */)
1981      (void)
1983 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
1984   /* You can't get services like this in 10.6+.  */
1985   return Qnil;
1986 #else
1987   Lisp_Object ret = Qnil;
1988   NSMenu *svcs;
1989 #ifdef NS_IMPL_COCOA
1990   id delegate;
1991 #endif
1993   check_window_system (NULL);
1994   svcs = [[NSMenu alloc] initWithTitle: @"Services"];
1995   [NSApp setServicesMenu: svcs];
1996   [NSApp registerServicesMenuSendTypes: ns_send_types
1997                            returnTypes: ns_return_types];
1999 /* On Tiger, services menu updating was made lazier (waits for user to
2000    actually click on the menu), so we have to force things along: */
2001 #ifdef NS_IMPL_COCOA
2002   delegate = [svcs delegate];
2003   if (delegate != nil)
2004     {
2005       if ([delegate respondsToSelector: @selector (menuNeedsUpdate:)])
2006         [delegate menuNeedsUpdate: svcs];
2007       if ([delegate respondsToSelector:
2008                        @selector (menu:updateItem:atIndex:shouldCancel:)])
2009         {
2010           int i, len = [delegate numberOfItemsInMenu: svcs];
2011           for (i =0; i<len; i++)
2012             [svcs addItemWithTitle: @"" action: NULL keyEquivalent: @""];
2013           for (i =0; i<len; i++)
2014             if (![delegate menu: svcs
2015                      updateItem: (NSMenuItem *)[svcs itemAtIndex: i]
2016                         atIndex: i shouldCancel: NO])
2017               break;
2018         }
2019     }
2020 #endif
2022   [svcs setAutoenablesItems: NO];
2023 #ifdef NS_IMPL_COCOA
2024   [svcs update]; /* on OS X, converts from '/' structure */
2025 #endif
2027   ret = interpret_services_menu (svcs, Qnil, ret);
2028   return ret;
2029 #endif
2033 DEFUN ("ns-perform-service", Fns_perform_service, Sns_perform_service,
2034        2, 2, 0,
2035        doc: /* Perform Nextstep SERVICE on SEND.
2036 SEND should be either a string or nil.
2037 The return value is the result of the service, as string, or nil if
2038 there was no result.  */)
2039      (Lisp_Object service, Lisp_Object send)
2041   id pb;
2042   NSString *svcName;
2043   char *utfStr;
2045   CHECK_STRING (service);
2046   check_window_system (NULL);
2048   utfStr = SSDATA (service);
2049   svcName = [NSString stringWithUTF8String: utfStr];
2051   pb =[NSPasteboard pasteboardWithUniqueName];
2052   ns_string_to_pasteboard (pb, send);
2054   if (NSPerformService (svcName, pb) == NO)
2055     Fsignal (Qquit, list1 (build_string ("service not available")));
2057   if ([[pb types] count] == 0)
2058     return build_string ("");
2059   return ns_string_from_pasteboard (pb);
2063 DEFUN ("ns-convert-utf8-nfd-to-nfc", Fns_convert_utf8_nfd_to_nfc,
2064        Sns_convert_utf8_nfd_to_nfc, 1, 1, 0,
2065        doc: /* Return an NFC string that matches the UTF-8 NFD string STR.  */)
2066      (Lisp_Object str)
2068 /* TODO: If GNUstep ever implements precomposedStringWithCanonicalMapping,
2069          remove this. */
2070   NSString *utfStr;
2071   Lisp_Object ret = Qnil;
2072   NSAutoreleasePool *pool;
2074   CHECK_STRING (str);
2075   pool = [[NSAutoreleasePool alloc] init];
2076   utfStr = [NSString stringWithUTF8String: SSDATA (str)];
2077 #ifdef NS_IMPL_COCOA
2078   if (utfStr)
2079     utfStr = [utfStr precomposedStringWithCanonicalMapping];
2080 #endif
2081   if (utfStr)
2082     {
2083       const char *cstr = [utfStr UTF8String];
2084       if (cstr)
2085         ret = build_string (cstr);
2086     }
2088   [pool release];
2089   if (NILP (ret))
2090     error ("Invalid UTF-8");
2092   return ret;
2096 #ifdef NS_IMPL_COCOA
2098 /* Compile and execute the AppleScript SCRIPT and return the error
2099    status as function value.  A zero is returned if compilation and
2100    execution is successful, in which case *RESULT is set to a Lisp
2101    string or a number containing the resulting script value.  Otherwise,
2102    1 is returned. */
2103 static int
2104 ns_do_applescript (Lisp_Object script, Lisp_Object *result)
2106   NSAppleEventDescriptor *desc;
2107   NSDictionary* errorDict;
2108   NSAppleEventDescriptor* returnDescriptor = NULL;
2110   NSAppleScript* scriptObject =
2111     [[NSAppleScript alloc] initWithSource:
2112                              [NSString stringWithUTF8String: SSDATA (script)]];
2114   returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
2115   [scriptObject release];
2117   *result = Qnil;
2119   if (returnDescriptor != NULL)
2120     {
2121       // successful execution
2122       if (kAENullEvent != [returnDescriptor descriptorType])
2123         {
2124           *result = Qt;
2125           // script returned an AppleScript result
2126           if ((typeUnicodeText == [returnDescriptor descriptorType]) ||
2127 #if defined (NS_IMPL_COCOA)
2128               (typeUTF16ExternalRepresentation
2129                == [returnDescriptor descriptorType]) ||
2130 #endif
2131               (typeUTF8Text == [returnDescriptor descriptorType]) ||
2132               (typeCString == [returnDescriptor descriptorType]))
2133             {
2134               desc = [returnDescriptor coerceToDescriptorType: typeUTF8Text];
2135               if (desc)
2136                 *result = build_string([[desc stringValue] UTF8String]);
2137             }
2138           else
2139             {
2140               /* use typeUTF16ExternalRepresentation? */
2141               // coerce the result to the appropriate ObjC type
2142               desc = [returnDescriptor coerceToDescriptorType: typeUTF8Text];
2143               if (desc)
2144                 *result = make_number([desc int32Value]);
2145             }
2146         }
2147     }
2148   else
2149     {
2150       // no script result, return error
2151       return 1;
2152     }
2153   return 0;
2156 /* Helper function called from sendEvent to run applescript
2157    from within the main event loop.  */
2159 void
2160 ns_run_ascript (void)
2162   if (! NILP (as_script))
2163     as_status = ns_do_applescript (as_script, as_result);
2164   as_script = Qnil;
2167 DEFUN ("ns-do-applescript", Fns_do_applescript, Sns_do_applescript, 1, 1, 0,
2168        doc: /* Execute AppleScript SCRIPT and return the result.
2169 If compilation and execution are successful, the resulting script value
2170 is returned as a string, a number or, in the case of other constructs, t.
2171 In case the execution fails, an error is signaled. */)
2172      (Lisp_Object script)
2174   Lisp_Object result;
2175   int status;
2176   NSEvent *nxev;
2178   CHECK_STRING (script);
2179   check_window_system (NULL);
2181   block_input ();
2183   as_script = script;
2184   as_result = &result;
2186   /* executing apple script requires the event loop to run, otherwise
2187      errors aren't returned and executeAndReturnError hangs forever.
2188      Post an event that runs applescript and then start the event loop.
2189      The event loop is exited when the script is done.  */
2190   nxev = [NSEvent otherEventWithType: NSApplicationDefined
2191                             location: NSMakePoint (0, 0)
2192                        modifierFlags: 0
2193                            timestamp: 0
2194                         windowNumber: [[NSApp mainWindow] windowNumber]
2195                              context: [NSApp context]
2196                              subtype: 0
2197                                data1: 0
2198                                data2: NSAPP_DATA2_RUNASSCRIPT];
2200   [NSApp postEvent: nxev atStart: NO];
2202   // If there are other events, the event loop may exit.  Keep running
2203   // until the script has been handled.  */
2204   while (! NILP (as_script))
2205     [NSApp run];
2207   status = as_status;
2208   as_status = 0;
2209   as_result = 0;
2210   unblock_input ();
2211   if (status == 0)
2212     return result;
2213   else if (!STRINGP (result))
2214     error ("AppleScript error %d", status);
2215   else
2216     error ("%s", SSDATA (result));
2218 #endif
2222 /* ==========================================================================
2224     Miscellaneous functions not called through hooks
2226    ========================================================================== */
2228 /* called from frame.c */
2229 struct ns_display_info *
2230 check_x_display_info (Lisp_Object frame)
2232   return check_ns_display_info (frame);
2236 void
2237 x_set_scroll_bar_default_width (struct frame *f)
2239   int wid = FRAME_COLUMN_WIDTH (f);
2240   FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = NS_SCROLL_BAR_WIDTH_DEFAULT;
2241   FRAME_CONFIG_SCROLL_BAR_COLS (f) = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) +
2242                                       wid - 1) / wid;
2245 /* terms impl this instead of x-get-resource directly */
2246 char *
2247 x_get_string_resource (XrmDatabase rdb, const char *name, const char *class)
2249   /* remove appname prefix; TODO: allow for !="Emacs" */
2250   const char *res, *toCheck = class + (!strncmp (class, "Emacs.", 6) ? 6 : 0);
2252   check_window_system (NULL);
2254   if (inhibit_x_resources)
2255     /* --quick was passed, so this is a no-op.  */
2256     return NULL;
2258   res = ns_get_defaults_value (toCheck);
2259   return (!res ? NULL :
2260           (!c_strncasecmp (res, "YES", 3) ? "true" :
2261            (!c_strncasecmp (res, "NO", 2) ? "false" : (char *) res)));
2265 Lisp_Object
2266 x_get_focus_frame (struct frame *frame)
2268   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2269   Lisp_Object nsfocus;
2271   if (!dpyinfo->x_focus_frame)
2272     return Qnil;
2274   XSETFRAME (nsfocus, dpyinfo->x_focus_frame);
2275   return nsfocus;
2278 /* ==========================================================================
2280     Lisp definitions that, for whatever reason, we can't alias as 'ns-XXX'.
2282    ========================================================================== */
2285 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
2286        doc: /* Internal function called by `color-defined-p', which see.
2287 \(Note that the Nextstep version of this function ignores FRAME.)  */)
2288      (Lisp_Object color, Lisp_Object frame)
2290   NSColor * col;
2291   check_window_system (NULL);
2292   return ns_lisp_to_color (color, &col) ? Qnil : Qt;
2296 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
2297        doc: /* Internal function called by `color-values', which see.  */)
2298      (Lisp_Object color, Lisp_Object frame)
2300   NSColor * col;
2301   EmacsCGFloat red, green, blue, alpha;
2303   check_window_system (NULL);
2304   CHECK_STRING (color);
2306   block_input ();
2307   if (ns_lisp_to_color (color, &col))
2308     {
2309       unblock_input ();
2310       return Qnil;
2311     }
2313   [[col colorUsingDefaultColorSpace]
2314         getRed: &red green: &green blue: &blue alpha: &alpha];
2315   unblock_input ();
2316   return list3i (lrint (red * 65280), lrint (green * 65280),
2317                  lrint (blue * 65280));
2321 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
2322        doc: /* Internal function called by `display-color-p', which see.  */)
2323      (Lisp_Object terminal)
2325   NSWindowDepth depth;
2326   NSString *colorSpace;
2328   check_ns_display_info (terminal);
2329   depth = [[[NSScreen screens] objectAtIndex:0] depth];
2330   colorSpace = NSColorSpaceFromDepth (depth);
2332   return    [colorSpace isEqualToString: NSDeviceWhiteColorSpace]
2333          || [colorSpace isEqualToString: NSCalibratedWhiteColorSpace]
2334       ? Qnil : Qt;
2338 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
2339        0, 1, 0,
2340        doc: /* Return t if the Nextstep display supports shades of gray.
2341 Note that color displays do support shades of gray.
2342 The optional argument TERMINAL specifies which display to ask about.
2343 TERMINAL should be a terminal object, a frame or a display name (a string).
2344 If omitted or nil, that stands for the selected frame's display.  */)
2345   (Lisp_Object terminal)
2347   NSWindowDepth depth;
2349   check_ns_display_info (terminal);
2350   depth = [[[NSScreen screens] objectAtIndex:0] depth];
2352   return NSBitsPerPixelFromDepth (depth) > 1 ? Qt : Qnil;
2356 DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
2357        0, 1, 0,
2358        doc: /* Return the width in pixels of the Nextstep display TERMINAL.
2359 The optional argument TERMINAL specifies which display to ask about.
2360 TERMINAL should be a terminal object, a frame or a display name (a string).
2361 If omitted or nil, that stands for the selected frame's display.
2363 On \"multi-monitor\" setups this refers to the pixel width for all
2364 physical monitors associated with TERMINAL.  To get information for
2365 each physical monitor, use `display-monitor-attributes-list'.  */)
2366   (Lisp_Object terminal)
2368   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
2370   return make_number (x_display_pixel_width (dpyinfo));
2374 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
2375        Sx_display_pixel_height, 0, 1, 0,
2376        doc: /* Return the height in pixels of the Nextstep display TERMINAL.
2377 The optional argument TERMINAL specifies which display to ask about.
2378 TERMINAL should be a terminal object, a frame or a display name (a string).
2379 If omitted or nil, that stands for the selected frame's display.
2381 On \"multi-monitor\" setups this refers to the pixel height for all
2382 physical monitors associated with TERMINAL.  To get information for
2383 each physical monitor, use `display-monitor-attributes-list'.  */)
2384   (Lisp_Object terminal)
2386   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
2388   return make_number (x_display_pixel_height (dpyinfo));
2391 #ifdef NS_IMPL_COCOA
2393 /* Returns the name for the screen that OBJ represents, or NULL.
2394    Caller must free return value.
2397 static char *
2398 ns_get_name_from_ioreg (io_object_t obj)
2400   char *name = NULL;
2402   NSDictionary *info = (NSDictionary *)
2403     IODisplayCreateInfoDictionary (obj, kIODisplayOnlyPreferredName);
2404   NSDictionary *names = [info objectForKey:
2405                                 [NSString stringWithUTF8String:
2406                                             kDisplayProductName]];
2408   if ([names count] > 0)
2409     {
2410       NSString *n = [names objectForKey: [[names allKeys]
2411                                                  objectAtIndex:0]];
2412       if (n != nil) name = xstrdup ([n UTF8String]);
2413     }
2415   [info release];
2417   return name;
2420 /* Returns the name for the screen that DID came from, or NULL.
2421    Caller must free return value.
2424 static char *
2425 ns_screen_name (CGDirectDisplayID did)
2427   char *name = NULL;
2429 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
2430   mach_port_t masterPort;
2431   io_iterator_t it;
2432   io_object_t obj;
2434   // CGDisplayIOServicePort is deprecated.  Do it another (harder) way.
2436   if (IOMasterPort (MACH_PORT_NULL, &masterPort) != kIOReturnSuccess
2437       || IOServiceGetMatchingServices (masterPort,
2438                                        IOServiceMatching ("IONDRVDevice"),
2439                                        &it) != kIOReturnSuccess)
2440     return name;
2442   /* Must loop until we find a name.  Many devices can have the same unit
2443      number (represents different GPU parts), but only one has a name.  */
2444   while (! name && (obj = IOIteratorNext (it)))
2445     {
2446       CFMutableDictionaryRef props;
2447       const void *val;
2449       if (IORegistryEntryCreateCFProperties (obj,
2450                                              &props,
2451                                              kCFAllocatorDefault,
2452                                              kNilOptions) == kIOReturnSuccess
2453           && props != nil
2454           && (val = CFDictionaryGetValue(props, @"IOFBDependentIndex")))
2455         {
2456           unsigned nr = [(NSNumber *)val unsignedIntegerValue];
2457           if (nr == CGDisplayUnitNumber (did))
2458             name = ns_get_name_from_ioreg (obj);
2459         }
2461       CFRelease (props);
2462       IOObjectRelease (obj);
2463     }
2465   IOObjectRelease (it);
2467 #else
2469   name = ns_get_name_from_ioreg (CGDisplayIOServicePort (did));
2471 #endif
2472   return name;
2474 #endif
2476 static Lisp_Object
2477 ns_make_monitor_attribute_list (struct MonitorInfo *monitors,
2478                                 int n_monitors,
2479                                 int primary_monitor,
2480                                 const char *source)
2482   Lisp_Object monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
2483   Lisp_Object frame, rest;
2484   NSArray *screens = [NSScreen screens];
2485   int i;
2487   FOR_EACH_FRAME (rest, frame)
2488     {
2489       struct frame *f = XFRAME (frame);
2491       if (FRAME_NS_P (f))
2492         {
2493           NSView *view = FRAME_NS_VIEW (f);
2494           NSScreen *screen = [[view window] screen];
2495           NSUInteger k;
2497           i = -1;
2498           for (k = 0; i == -1 && k < [screens count]; ++k)
2499             {
2500               if ([screens objectAtIndex: k] == screen)
2501                 i = (int)k;
2502             }
2504           if (i > -1)
2505             ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
2506         }
2507     }
2509   return make_monitor_attribute_list (monitors, n_monitors, primary_monitor,
2510                                       monitor_frames, source);
2513 DEFUN ("ns-display-monitor-attributes-list",
2514        Fns_display_monitor_attributes_list,
2515        Sns_display_monitor_attributes_list,
2516        0, 1, 0,
2517        doc: /* Return a list of physical monitor attributes on the X display TERMINAL.
2519 The optional argument TERMINAL specifies which display to ask about.
2520 TERMINAL should be a terminal object, a frame or a display name (a string).
2521 If omitted or nil, that stands for the selected frame's display.
2523 In addition to the standard attribute keys listed in
2524 `display-monitor-attributes-list', the following keys are contained in
2525 the attributes:
2527  source -- String describing the source from which multi-monitor
2528            information is obtained, \"NS\" is always the source."
2530 Internal use only, use `display-monitor-attributes-list' instead.  */)
2531   (Lisp_Object terminal)
2533   struct terminal *term = get_terminal (terminal, 1);
2534   NSArray *screens;
2535   NSUInteger i, n_monitors;
2536   struct MonitorInfo *monitors;
2537   Lisp_Object attributes_list = Qnil;
2538   CGFloat primary_display_height = 0;
2540   if (term->type != output_ns)
2541     return Qnil;
2543   screens = [NSScreen screens];
2544   n_monitors = [screens count];
2545   if (n_monitors == 0)
2546     return Qnil;
2548   monitors = xzalloc (n_monitors * sizeof *monitors);
2550   for (i = 0; i < [screens count]; ++i)
2551     {
2552       NSScreen *s = [screens objectAtIndex:i];
2553       struct MonitorInfo *m = &monitors[i];
2554       NSRect fr = [s frame];
2555       NSRect vfr = [s visibleFrame];
2556       short y, vy;
2558 #ifdef NS_IMPL_COCOA
2559       NSDictionary *dict = [s deviceDescription];
2560       NSNumber *nid = [dict objectForKey:@"NSScreenNumber"];
2561       CGDirectDisplayID did = [nid unsignedIntValue];
2562 #endif
2563       if (i == 0)
2564         {
2565           primary_display_height = fr.size.height;
2566           y = (short) fr.origin.y;
2567           vy = (short) vfr.origin.y;
2568         }
2569       else
2570         {
2571           // Flip y coordinate as NS has y starting from the bottom.
2572           y = (short) (primary_display_height - fr.size.height - fr.origin.y);
2573           vy = (short) (primary_display_height -
2574                         vfr.size.height - vfr.origin.y);
2575         }
2577       m->geom.x = (short) fr.origin.x;
2578       m->geom.y = y;
2579       m->geom.width = (unsigned short) fr.size.width;
2580       m->geom.height = (unsigned short) fr.size.height;
2582       m->work.x = (short) vfr.origin.x;
2583       // y is flipped on NS, so vy - y are pixels missing at the bottom,
2584       // and fr.size.height - vfr.size.height are pixels missing in total.
2585       // Pixels missing at top are
2586       // fr.size.height - vfr.size.height - vy + y.
2587       // work.y is then pixels missing at top + y.
2588       m->work.y = (short) (fr.size.height - vfr.size.height) - vy + y + y;
2589       m->work.width = (unsigned short) vfr.size.width;
2590       m->work.height = (unsigned short) vfr.size.height;
2592 #ifdef NS_IMPL_COCOA
2593       m->name = ns_screen_name (did);
2595       {
2596         CGSize mms = CGDisplayScreenSize (did);
2597         m->mm_width = (int) mms.width;
2598         m->mm_height = (int) mms.height;
2599       }
2601 #else
2602       // Assume 92 dpi as x-display-mm-height/x-display-mm-width does.
2603       m->mm_width = (int) (25.4 * fr.size.width / 92.0);
2604       m->mm_height = (int) (25.4 * fr.size.height / 92.0);
2605 #endif
2606     }
2608   // Primary monitor is always first for NS.
2609   attributes_list = ns_make_monitor_attribute_list (monitors, n_monitors,
2610                                                     0, "NS");
2612   free_monitors (monitors, n_monitors);
2613   return attributes_list;
2617 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
2618        0, 1, 0,
2619        doc: /* Return the number of bitplanes of the Nextstep display TERMINAL.
2620 The optional argument TERMINAL specifies which display to ask about.
2621 TERMINAL should be a terminal object, a frame or a display name (a string).
2622 If omitted or nil, that stands for the selected frame's display.  */)
2623   (Lisp_Object terminal)
2625   check_ns_display_info (terminal);
2626   return make_number
2627     (NSBitsPerPixelFromDepth ([[[NSScreen screens] objectAtIndex:0] depth]));
2631 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
2632        0, 1, 0,
2633        doc: /* Returns the number of color cells of the Nextstep display TERMINAL.
2634 The optional argument TERMINAL specifies which display to ask about.
2635 TERMINAL should be a terminal object, a frame or a display name (a string).
2636 If omitted or nil, that stands for the selected frame's display.  */)
2637   (Lisp_Object terminal)
2639   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
2640   /* We force 24+ bit depths to 24-bit to prevent an overflow.  */
2641   return make_number (1 << min (dpyinfo->n_planes, 24));
2645 /* Unused dummy def needed for compatibility. */
2646 Lisp_Object tip_frame;
2648 /* TODO: move to xdisp or similar */
2649 static void
2650 compute_tip_xy (struct frame *f,
2651                 Lisp_Object parms,
2652                 Lisp_Object dx,
2653                 Lisp_Object dy,
2654                 int width,
2655                 int height,
2656                 int *root_x,
2657                 int *root_y)
2659   Lisp_Object left, top;
2660   EmacsView *view = FRAME_NS_VIEW (f);
2661   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2662   NSPoint pt;
2664   /* Start with user-specified or mouse position.  */
2665   left = Fcdr (Fassq (Qleft, parms));
2666   top = Fcdr (Fassq (Qtop, parms));
2668   if (!INTEGERP (left) || !INTEGERP (top))
2669     {
2670       pt.x = dpyinfo->last_mouse_motion_x;
2671       pt.y = dpyinfo->last_mouse_motion_y;
2672       /* Convert to screen coordinates */
2673       pt = [view convertPoint: pt toView: nil];
2674       pt = [[view window] convertBaseToScreen: pt];
2675     }
2676   else
2677     {
2678       /* Absolute coordinates.  */
2679       pt.x = XINT (left);
2680       pt.y = x_display_pixel_height (FRAME_DISPLAY_INFO (f)) - XINT (top)
2681         - height;
2682     }
2684   /* Ensure in bounds.  (Note, screen origin = lower left.) */
2685   if (INTEGERP (left))
2686     *root_x = pt.x;
2687   else if (pt.x + XINT (dx) <= 0)
2688     *root_x = 0; /* Can happen for negative dx */
2689   else if (pt.x + XINT (dx) + width
2690            <= x_display_pixel_width (FRAME_DISPLAY_INFO (f)))
2691     /* It fits to the right of the pointer.  */
2692     *root_x = pt.x + XINT (dx);
2693   else if (width + XINT (dx) <= pt.x)
2694     /* It fits to the left of the pointer.  */
2695     *root_x = pt.x - width - XINT (dx);
2696   else
2697     /* Put it left justified on the screen -- it ought to fit that way.  */
2698     *root_x = 0;
2700   if (INTEGERP (top))
2701     *root_y = pt.y;
2702   else if (pt.y - XINT (dy) - height >= 0)
2703     /* It fits below the pointer.  */
2704     *root_y = pt.y - height - XINT (dy);
2705   else if (pt.y + XINT (dy) + height
2706            <= x_display_pixel_height (FRAME_DISPLAY_INFO (f)))
2707     /* It fits above the pointer */
2708       *root_y = pt.y + XINT (dy);
2709   else
2710     /* Put it on the top.  */
2711     *root_y = x_display_pixel_height (FRAME_DISPLAY_INFO (f)) - height;
2715 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
2716        doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
2717 A tooltip window is a small window displaying a string.
2719 This is an internal function; Lisp code should call `tooltip-show'.
2721 FRAME nil or omitted means use the selected frame.
2723 PARMS is an optional list of frame parameters which can be used to
2724 change the tooltip's appearance.
2726 Automatically hide the tooltip after TIMEOUT seconds.  TIMEOUT nil
2727 means use the default timeout of 5 seconds.
2729 If the list of frame parameters PARMS contains a `left' parameter,
2730 the tooltip is displayed at that x-position.  Otherwise it is
2731 displayed at the mouse position, with offset DX added (default is 5 if
2732 DX isn't specified).  Likewise for the y-position; if a `top' frame
2733 parameter is specified, it determines the y-position of the tooltip
2734 window, otherwise it is displayed at the mouse position, with offset
2735 DY added (default is -10).
2737 A tooltip's maximum size is specified by `x-max-tooltip-size'.
2738 Text larger than the specified size is clipped.  */)
2739      (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
2741   int root_x, root_y;
2742   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
2743   ptrdiff_t count = SPECPDL_INDEX ();
2744   struct frame *f;
2745   char *str;
2746   NSSize size;
2748   specbind (Qinhibit_redisplay, Qt);
2750   GCPRO4 (string, parms, frame, timeout);
2752   CHECK_STRING (string);
2753   str = SSDATA (string);
2754   f = decode_window_system_frame (frame);
2755   if (NILP (timeout))
2756     timeout = make_number (5);
2757   else
2758     CHECK_NATNUM (timeout);
2760   if (NILP (dx))
2761     dx = make_number (5);
2762   else
2763     CHECK_NUMBER (dx);
2765   if (NILP (dy))
2766     dy = make_number (-10);
2767   else
2768     CHECK_NUMBER (dy);
2770   block_input ();
2771   if (ns_tooltip == nil)
2772     ns_tooltip = [[EmacsTooltip alloc] init];
2773   else
2774     Fx_hide_tip ();
2776   [ns_tooltip setText: str];
2777   size = [ns_tooltip frame].size;
2779   /* Move the tooltip window where the mouse pointer is.  Resize and
2780      show it.  */
2781   compute_tip_xy (f, parms, dx, dy, (int)size.width, (int)size.height,
2782                   &root_x, &root_y);
2784   [ns_tooltip showAtX: root_x Y: root_y for: XINT (timeout)];
2785   unblock_input ();
2787   UNGCPRO;
2788   return unbind_to (count, Qnil);
2792 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
2793        doc: /* Hide the current tooltip window, if there is any.
2794 Value is t if tooltip was open, nil otherwise.  */)
2795      (void)
2797   if (ns_tooltip == nil || ![ns_tooltip isActive])
2798     return Qnil;
2799   [ns_tooltip hide];
2800   return Qt;
2804 /* ==========================================================================
2806     Class implementations
2808    ========================================================================== */
2811   Handle arrow/function/control keys and copy/paste/cut in file dialogs.
2812   Return YES if handled, NO if not.
2813  */
2814 static BOOL
2815 handlePanelKeys (NSSavePanel *panel, NSEvent *theEvent)
2817   NSString *s;
2818   int i;
2819   BOOL ret = NO;
2821   if ([theEvent type] != NSKeyDown) return NO;
2822   s = [theEvent characters];
2824   for (i = 0; i < [s length]; ++i)
2825     {
2826       int ch = (int) [s characterAtIndex: i];
2827       switch (ch)
2828         {
2829         case NSHomeFunctionKey:
2830         case NSDownArrowFunctionKey:
2831         case NSUpArrowFunctionKey:
2832         case NSLeftArrowFunctionKey:
2833         case NSRightArrowFunctionKey:
2834         case NSPageUpFunctionKey:
2835         case NSPageDownFunctionKey:
2836         case NSEndFunctionKey:
2837           /* Don't send command modified keys, as those are handled in the
2838              performKeyEquivalent method of the super class.
2839           */
2840           if (! ([theEvent modifierFlags] & NSCommandKeyMask))
2841             {
2842               [panel sendEvent: theEvent];
2843               ret = YES;
2844             }
2845           break;
2846           /* As we don't have the standard key commands for
2847              copy/paste/cut/select-all in our edit menu, we must handle
2848              them here.  TODO: handle Emacs key bindings for copy/cut/select-all
2849              here, paste works, because we have that in our Edit menu.
2850              I.e. refactor out code in nsterm.m, keyDown: to figure out the
2851              correct modifier.
2852           */
2853         case 'x': // Cut
2854         case 'c': // Copy
2855         case 'v': // Paste
2856         case 'a': // Select all
2857           if ([theEvent modifierFlags] & NSCommandKeyMask)
2858             {
2859               [NSApp sendAction:
2860                        (ch == 'x'
2861                         ? @selector(cut:)
2862                         : (ch == 'c'
2863                            ? @selector(copy:)
2864                            : (ch == 'v'
2865                               ? @selector(paste:)
2866                               : @selector(selectAll:))))
2867                              to:nil from:panel];
2868               ret = YES;
2869             }
2870         default:
2871           // Send all control keys, as the text field supports C-a, C-f, C-e
2872           // C-b and more.
2873           if ([theEvent modifierFlags] & NSControlKeyMask)
2874             {
2875               [panel sendEvent: theEvent];
2876               ret = YES;
2877             }
2878           break;
2879         }
2880     }
2883   return ret;
2886 @implementation EmacsSavePanel
2887 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent
2889   BOOL ret = handlePanelKeys (self, theEvent);
2890   if (! ret)
2891     ret = [super performKeyEquivalent:theEvent];
2892   return ret;
2894 @end
2897 @implementation EmacsOpenPanel
2898 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent
2900   // NSOpenPanel inherits NSSavePanel, so passing self is OK.
2901   BOOL ret = handlePanelKeys (self, theEvent);
2902   if (! ret)
2903     ret = [super performKeyEquivalent:theEvent];
2904   return ret;
2906 @end
2909 @implementation EmacsFileDelegate
2910 /* --------------------------------------------------------------------------
2911    Delegate methods for Open/Save panels
2912    -------------------------------------------------------------------------- */
2913 - (BOOL)panel: (id)sender isValidFilename: (NSString *)filename
2915   return YES;
2917 - (BOOL)panel: (id)sender shouldShowFilename: (NSString *)filename
2919   return YES;
2921 - (NSString *)panel: (id)sender userEnteredFilename: (NSString *)filename
2922           confirmed: (BOOL)okFlag
2924   return filename;
2926 @end
2928 #endif
2931 /* ==========================================================================
2933     Lisp interface declaration
2935    ========================================================================== */
2938 void
2939 syms_of_nsfns (void)
2941   Qfontsize = intern_c_string ("fontsize");
2942   staticpro (&Qfontsize);
2944   DEFVAR_LISP ("ns-icon-type-alist", Vns_icon_type_alist,
2945                doc: /* Alist of elements (REGEXP . IMAGE) for images of icons associated to frames.
2946 If the title of a frame matches REGEXP, then IMAGE.tiff is
2947 selected as the image of the icon representing the frame when it's
2948 miniaturized.  If an element is t, then Emacs tries to select an icon
2949 based on the filetype of the visited file.
2951 The images have to be installed in a folder called English.lproj in the
2952 Emacs folder.  You have to restart Emacs after installing new icons.
2954 Example: Install an icon Gnus.tiff and execute the following code
2956   (setq ns-icon-type-alist
2957         (append ns-icon-type-alist
2958                 '((\"^\\\\*\\\\(Group\\\\*$\\\\|Summary \\\\|Article\\\\*$\\\\)\"
2959                    . \"Gnus\"))))
2961 When you miniaturize a Group, Summary or Article frame, Gnus.tiff will
2962 be used as the image of the icon representing the frame.  */);
2963   Vns_icon_type_alist = list1 (Qt);
2965   DEFVAR_LISP ("ns-version-string", Vns_version_string,
2966                doc: /* Toolkit version for NS Windowing.  */);
2967   Vns_version_string = ns_appkit_version_str ();
2969   defsubr (&Sns_read_file_name);
2970   defsubr (&Sns_get_resource);
2971   defsubr (&Sns_set_resource);
2972   defsubr (&Sxw_display_color_p); /* this and next called directly by C code */
2973   defsubr (&Sx_display_grayscale_p);
2974   defsubr (&Sns_font_name);
2975   defsubr (&Sns_list_colors);
2976 #ifdef NS_IMPL_COCOA
2977   defsubr (&Sns_do_applescript);
2978 #endif
2979   defsubr (&Sxw_color_defined_p);
2980   defsubr (&Sxw_color_values);
2981   defsubr (&Sx_server_max_request_size);
2982   defsubr (&Sx_server_vendor);
2983   defsubr (&Sx_server_version);
2984   defsubr (&Sx_display_pixel_width);
2985   defsubr (&Sx_display_pixel_height);
2986   defsubr (&Sns_display_monitor_attributes_list);
2987   defsubr (&Sx_display_mm_width);
2988   defsubr (&Sx_display_mm_height);
2989   defsubr (&Sx_display_screens);
2990   defsubr (&Sx_display_planes);
2991   defsubr (&Sx_display_color_cells);
2992   defsubr (&Sx_display_visual_class);
2993   defsubr (&Sx_display_backing_store);
2994   defsubr (&Sx_display_save_under);
2995   defsubr (&Sx_create_frame);
2996   defsubr (&Sx_open_connection);
2997   defsubr (&Sx_close_connection);
2998   defsubr (&Sx_display_list);
3000   defsubr (&Sns_hide_others);
3001   defsubr (&Sns_hide_emacs);
3002   defsubr (&Sns_emacs_info_panel);
3003   defsubr (&Sns_list_services);
3004   defsubr (&Sns_perform_service);
3005   defsubr (&Sns_convert_utf8_nfd_to_nfc);
3006   defsubr (&Sns_popup_font_panel);
3007   defsubr (&Sns_popup_color_panel);
3009   defsubr (&Sx_show_tip);
3010   defsubr (&Sx_hide_tip);
3012   as_status = 0;
3013   as_script = Qnil;
3014   as_result = 0;