X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/e1b96d7e637cf76864013f8dba68135f07638ab8..8478885dfab16359b989e030949b4d485062f54b:/src/nsfns.m diff --git a/src/nsfns.m b/src/nsfns.m index 7643c8b6e1..33d63a6572 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -1,6 +1,6 @@ /* Functions for the NeXT/Open/GNUstep and MacOSX window system. -Copyright (C) 1989, 1992-1994, 2005-2006, 2008-2013 Free Software +Copyright (C) 1989, 1992-1994, 2005-2006, 2008-2015 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -46,6 +46,9 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu) #ifdef NS_IMPL_COCOA #include +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +#include "macfont.h" +#endif #endif #if 0 @@ -89,9 +92,6 @@ extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle; Lisp_Object Qbuffered; Lisp_Object Qfontsize; -/* hack for OS X file panels */ -char panelOK = 0; - EmacsTooltip *ns_tooltip = nil; /* Need forward declaration here to preserve organizational integrity of file */ @@ -105,7 +105,6 @@ static int as_status; static ptrdiff_t image_cache_refcount; #endif -static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes, Qsource; /* ========================================================================== @@ -128,7 +127,7 @@ check_ns_display_info (Lisp_Object object) struct frame *sf = XFRAME (selected_frame); if (FRAME_NS_P (sf) && FRAME_LIVE_P (sf)) - dpyinfo = FRAME_NS_DISPLAY_INFO (sf); + dpyinfo = FRAME_DISPLAY_INFO (sf); else if (x_display_list != 0) dpyinfo = x_display_list; else @@ -147,8 +146,8 @@ check_ns_display_info (Lisp_Object object) dpyinfo = ns_display_info_for_name (object); else { - FRAME_PTR f = decode_window_system_frame (object); - dpyinfo = FRAME_NS_DISPLAY_INFO (f); + struct frame *f = decode_window_system_frame (object); + dpyinfo = FRAME_DISPLAY_INFO (f); } return dpyinfo; @@ -176,28 +175,21 @@ ns_get_window (Lisp_Object maybeFrame) struct ns_display_info * ns_display_info_for_name (Lisp_Object name) { - Lisp_Object names; struct ns_display_info *dpyinfo; CHECK_STRING (name); - for (dpyinfo = x_display_list, names = ns_display_name_list; - dpyinfo; - dpyinfo = dpyinfo->next, names = XCDR (names)) - { - Lisp_Object tem; - tem = Fstring_equal (XCAR (XCAR (names)), name); - if (!NILP (tem)) - return dpyinfo; - } + for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) + if (!NILP (Fstring_equal (XCAR (dpyinfo->name_list_element), name))) + return dpyinfo; - error ("Emacs for OpenStep does not yet support multi-display."); + error ("Emacs for Nextstep does not yet support multi-display"); Fx_open_connection (name, Qnil, Qnil); dpyinfo = x_display_list; if (dpyinfo == 0) - error ("OpenStep on %s not responding.\n", SDATA (name)); + error ("Display on %s not responding.\n", SDATA (name)); return dpyinfo; } @@ -288,11 +280,16 @@ static void x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { NSColor *col; - CGFloat r, g, b, alpha; + EmacsCGFloat r, g, b, alpha; + /* Must block_input, because ns_lisp_to_color does block/unblock_input + which means that col may be deallocated in its unblock_input if there + is user input, unless we also block_input. */ + block_input (); if (ns_lisp_to_color (arg, &col)) { store_frame_param (f, Qforeground_color, oldval); + unblock_input (); error ("Unknown color"); } @@ -309,8 +306,9 @@ x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) update_face_from_frame_parameter (f, Qforeground_color, arg); /*recompute_basic_faces (f); */ if (FRAME_VISIBLE_P (f)) - redraw_frame (f); + SET_FRAME_GARBAGED (f); } + unblock_input (); } @@ -320,11 +318,13 @@ x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) struct face *face; NSColor *col; NSView *view = FRAME_NS_VIEW (f); - CGFloat r, g, b, alpha; + EmacsCGFloat r, g, b, alpha; + block_input (); if (ns_lisp_to_color (arg, &col)) { store_frame_param (f, Qbackground_color, oldval); + unblock_input (); error ("Unknown color"); } @@ -345,7 +345,7 @@ x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { [[view window] setBackgroundColor: col]; - if (alpha != 1.0) + if (alpha != (EmacsCGFloat) 1.0) [[view window] setOpaque: NO]; else [[view window] setOpaque: YES]; @@ -361,8 +361,9 @@ x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) } if (FRAME_VISIBLE_P (f)) - redraw_frame (f); + SET_FRAME_GARBAGED (f); } + unblock_input (); } @@ -371,9 +372,11 @@ x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { NSColor *col; + block_input (); if (ns_lisp_to_color (arg, &col)) { store_frame_param (f, Qcursor_color, oldval); + unblock_input (); error ("Unknown color"); } @@ -386,6 +389,7 @@ x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) x_update_cursor (f, 1); } update_face_from_frame_parameter (f, Qcursor_color, arg); + unblock_input (); } @@ -411,23 +415,23 @@ x_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) if (!NILP (f->title)) arg = f->title; else - /* explicit name and no icon-name -> explicit_name */ + /* Explicit name and no icon-name -> explicit_name. */ if (f->explicit_name) arg = f->name; else { - /* no explicit name and no icon-name -> - name has to be rebuild from icon_title_format */ - windows_or_buffers_changed++; + /* No explicit name and no icon-name -> + name has to be rebuild from icon_title_format. */ + windows_or_buffers_changed = 62; return; } } /* Don't change the name if it's already NAME. */ - if ([[view window] miniwindowTitle] && - ([[[view window] miniwindowTitle] + if ([[view window] miniwindowTitle] + && ([[[view window] miniwindowTitle] isEqualToString: [NSString stringWithUTF8String: - SSDATA (arg)]])) + SSDATA (arg)]])) return; [[view window] setMiniwindowTitle: @@ -435,7 +439,7 @@ x_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) } static void -ns_set_name_internal (FRAME_PTR f, Lisp_Object name) +ns_set_name_internal (struct frame *f, Lisp_Object name) { struct gcpro gcpro1; Lisp_Object encoded_name, encoded_icon_name; @@ -459,8 +463,8 @@ ns_set_name_internal (FRAME_PTR f, Lisp_Object name) str = [NSString stringWithUTF8String: SSDATA (encoded_icon_name)]; - if ([[view window] miniwindowTitle] && - ! [[[view window] miniwindowTitle] isEqualToString: str]) + if ([[view window] miniwindowTitle] + && ! [[[view window] miniwindowTitle] isEqualToString: str]) [[view window] setMiniwindowTitle: str]; } @@ -477,7 +481,7 @@ ns_set_name (struct frame *f, Lisp_Object name, int explicit) /* If we're switching from explicit to implicit, we had better update the mode lines and thereby update the title. */ if (f->explicit_name && NILP (name)) - update_mode_lines = 1; + update_mode_lines = 21; f->explicit_name = ! NILP (name); } @@ -485,7 +489,7 @@ ns_set_name (struct frame *f, Lisp_Object name, int explicit) return; if (NILP (name)) - name = build_string([ns_app_name UTF8String]); + name = build_string ([ns_app_name UTF8String]); else CHECK_STRING (name); @@ -495,7 +499,7 @@ ns_set_name (struct frame *f, Lisp_Object name, int explicit) fset_name (f, name); - /* title overrides explicit name */ + /* Title overrides explicit name. */ if (! NILP (f->title)) name = f->title; @@ -507,7 +511,7 @@ ns_set_name (struct frame *f, Lisp_Object name, int explicit) specified a name for the frame; the name will override any set by the redisplay code. */ static void -x_explicitly_set_name (FRAME_PTR f, Lisp_Object arg, Lisp_Object oldval) +x_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { NSTRACE (x_explicitly_set_name); ns_set_name (f, arg, 1); @@ -518,7 +522,7 @@ x_explicitly_set_name (FRAME_PTR f, Lisp_Object arg, Lisp_Object oldval) name; names set this way will never override names set by the user's lisp code. */ void -x_implicitly_set_name (FRAME_PTR f, Lisp_Object arg, Lisp_Object oldval) +x_implicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { NSTRACE (x_implicitly_set_name); @@ -542,7 +546,7 @@ x_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name) if (EQ (name, f->title)) return; - update_mode_lines = 1; + update_mode_lines = 22; fset_title (f, name); @@ -617,18 +621,11 @@ ns_set_name_as_filename (struct frame *f) fstr = [NSString stringWithUTF8String: SSDATA (encoded_filename)]; if (fstr == nil) fstr = @""; -#ifdef NS_IMPL_COCOA - /* work around a bug observed on 10.3 and later where - setTitleWithRepresentedFilename does not clear out previous state - if given filename does not exist */ - if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr]) - [[view window] setRepresentedFilename: @""]; -#endif } else fstr = @""; - [[view window] setRepresentedFilename: fstr]; + ns_set_represented_filename (fstr, f); [[view window] setTitle: str]; fset_name (f, name); } @@ -639,18 +636,30 @@ ns_set_name_as_filename (struct frame *f) void -ns_set_doc_edited (struct frame *f, Lisp_Object arg) +ns_set_doc_edited (void) { - NSView *view = FRAME_NS_VIEW (f); NSAutoreleasePool *pool; - if (!MINI_WINDOW_P (XWINDOW (f->selected_window))) + Lisp_Object tail, frame; + block_input (); + pool = [[NSAutoreleasePool alloc] init]; + FOR_EACH_FRAME (tail, frame) { - block_input (); - pool = [[NSAutoreleasePool alloc] init]; - [[view window] setDocumentEdited: !NILP (arg)]; - [pool release]; - unblock_input (); + BOOL edited = NO; + struct frame *f = XFRAME (frame); + struct window *w; + NSView *view; + + if (! FRAME_NS_P (f)) continue; + w = XWINDOW (FRAME_SELECTED_WINDOW (f)); + view = FRAME_NS_VIEW (f); + if (!MINI_WINDOW_P (w)) + edited = ! NILP (Fbuffer_modified_p (w->contents)) && + ! NILP (Fbuffer_file_name (w->contents)); + [[view window] setDocumentEdited: edited]; } + + [pool release]; + unblock_input (); } @@ -711,11 +720,11 @@ x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) } } - x_set_window_size (f, 0, f->text_cols, f->text_lines); + x_set_window_size (f, 0, f->text_cols, f->text_lines, 0); } -void +static void ns_implicitly_set_icon_type (struct frame *f) { Lisp_Object tem; @@ -860,15 +869,11 @@ ns_cursor_type_to_lisp (int arg) } /* This is the same as the xfns.c definition. */ -void -x_set_cursor_type (FRAME_PTR f, Lisp_Object arg, Lisp_Object oldval) +static void +x_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval) { set_frame_cursor_types (f, arg); - - /* Make sure the cursor gets redrawn. */ - cursor_type_changed = 1; } - /* called to set mouse pointer color, but all other terms use it to initialize pointer types (and don't set the color ;) */ @@ -889,7 +894,7 @@ ns_appkit_version_str (void) #ifdef NS_IMPL_GNUSTEP sprintf(tmp, "gnustep-gui-%s", Xstr(GNUSTEP_GUI_VERSION)); -#elif defined(NS_IMPL_COCOA) +#elif defined (NS_IMPL_COCOA) sprintf(tmp, "apple-appkit-%.2f", NSAppKitVersionNumber); #else tmp = "ns-unknown"; @@ -906,7 +911,7 @@ ns_appkit_version_int (void) { #ifdef NS_IMPL_GNUSTEP return GNUSTEP_GUI_MAJOR_VERSION * 100 + GNUSTEP_GUI_MINOR_VERSION; -#elif defined(NS_IMPL_COCOA) +#elif defined (NS_IMPL_COCOA) return (int)NSAppKitVersionNumber; #endif return 0; @@ -925,8 +930,8 @@ x_icon (struct frame *f, Lisp_Object parms) Lisp_Object icon_x, icon_y; struct ns_display_info *dpyinfo = check_ns_display_info (Qnil); - f->output_data.ns->icon_top = Qnil; - f->output_data.ns->icon_left = Qnil; + f->output_data.ns->icon_top = -1; + f->output_data.ns->icon_left = -1; /* Set the position of the icon. */ icon_x = x_get_arg (dpyinfo, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER); @@ -935,8 +940,8 @@ x_icon (struct frame *f, Lisp_Object parms) { CHECK_NUMBER (icon_x); CHECK_NUMBER (icon_y); - f->output_data.ns->icon_top = icon_y; - f->output_data.ns->icon_left = icon_x; + f->output_data.ns->icon_top = XINT (icon_y); + f->output_data.ns->icon_left = XINT (icon_x); } else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound)) error ("Both left and top icon corners of icon must be specified"); @@ -958,6 +963,8 @@ frame_parm_handler ns_frame_parm_handlers[] = x_set_icon_name, x_set_icon_type, x_set_internal_border_width, /* generic OK */ + 0, /* x_set_right_divider_width */ + 0, /* x_set_bottom_divider_width */ x_set_menu_bar_lines, x_set_mouse_color, x_explicitly_set_name, @@ -985,7 +992,7 @@ frame_parm_handler ns_frame_parm_handlers[] = /* Handler for signals raised during x_create_frame. FRAME is the frame which is partially constructed. */ -static Lisp_Object +static void unwind_create_frame (Lisp_Object frame) { struct frame *f = XFRAME (frame); @@ -994,13 +1001,13 @@ unwind_create_frame (Lisp_Object frame) display is disconnected after the frame has become official, but before x_create_frame removes the unwind protect. */ if (!FRAME_LIVE_P (f)) - return Qnil; + return; /* If frame is ``official'', nothing to do. */ if (NILP (Fmemq (frame, Vframe_list))) { #if defined GLYPH_DEBUG && defined ENABLE_CHECKING - struct ns_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); #endif x_free_frame_resources (f); @@ -1010,10 +1017,7 @@ unwind_create_frame (Lisp_Object frame) /* Check that reference counts are indeed correct. */ eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount); #endif - return Qt; } - - return Qnil; } /* @@ -1075,7 +1079,7 @@ This function is an internal primitive--use `make-frame' instead. */) Lisp_Object frame, tem; Lisp_Object name; int minibuffer_only = 0; - int window_prompting = 0; + long window_prompting = 0; int width, height; ptrdiff_t count = specpdl_ptr - specpdl; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; @@ -1083,7 +1087,6 @@ This function is an internal primitive--use `make-frame' instead. */) struct ns_display_info *dpyinfo = NULL; Lisp_Object parent; struct kboard *kb; - Lisp_Object tfont, tfontsize; static int desc_ctr = 1; /* x_get_arg modifies parms. */ @@ -1151,9 +1154,9 @@ This function is an internal primitive--use `make-frame' instead. */) if (! STRINGP (f->icon_name)) fset_icon_name (f, Qnil); - FRAME_NS_DISPLAY_INFO (f) = dpyinfo; + FRAME_DISPLAY_INFO (f) = dpyinfo; - /* With FRAME_NS_DISPLAY_INFO set up, this unwind-protect is safe. */ + /* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe. */ record_unwind_protect (unwind_create_frame, frame); f->output_data.ns->window_desc = desc_ctr++; @@ -1164,7 +1167,7 @@ This function is an internal primitive--use `make-frame' instead. */) } else { - f->output_data.ns->parent_desc = FRAME_NS_DISPLAY_INFO (f)->root_window; + f->output_data.ns->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; f->output_data.ns->explicit_parent = 0; } @@ -1183,19 +1186,34 @@ This function is an internal primitive--use `make-frame' instead. */) } block_input (); + +#ifdef NS_IMPL_COCOA +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + if (CTGetCoreTextVersion != NULL + && CTGetCoreTextVersion () >= kCTVersionNumber10_5) + mac_register_font_driver (f); +#endif +#endif register_font_driver (&nsfont_driver, f); + x_default_parameter (f, parms, Qfont_backend, Qnil, "fontBackend", "FontBackend", RES_TYPE_STRING); { /* use for default font name */ id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */ - tfontsize = x_default_parameter (f, parms, Qfontsize, + x_default_parameter (f, parms, Qfontsize, make_number (0 /*(int)[font pointSize]*/), "fontSize", "FontSize", RES_TYPE_NUMBER); - tfont = x_default_parameter (f, parms, Qfont, - build_string ([[font fontName] UTF8String]), + // Remove ' Regular', not handled by backends. + char *fontname = xstrdup ([[font displayName] UTF8String]); + int len = strlen (fontname); + if (len > 8 && strcmp (fontname + len - 8, " Regular") == 0) + fontname[len-8] = '\0'; + x_default_parameter (f, parms, Qfont, + build_string (fontname), "font", "Font", RES_TYPE_STRING); + xfree (fontname); } unblock_input (); @@ -1236,6 +1254,13 @@ This function is an internal primitive--use `make-frame' instead. */) init_frame_faces (f); + /* Read comment about this code in corresponding place in xfns.c. */ + width = FRAME_TEXT_WIDTH (f); + height = FRAME_TEXT_HEIGHT (f); + FRAME_TEXT_HEIGHT (f) = 0; + SET_FRAME_WIDTH (f, 0); + change_frame_size (f, width, height, 1, 0, 0, 1); + /* The resources controlling the menu-bar and tool-bar are processed specially at startup, and reflected in the mode variables; ignore them here. */ @@ -1267,7 +1292,8 @@ This function is an internal primitive--use `make-frame' instead. */) f->output_data.ns->hand_cursor = [NSCursor pointingHandCursor]; f->output_data.ns->hourglass_cursor = [NSCursor disappearingItemCursor]; f->output_data.ns->horizontal_drag_cursor = [NSCursor resizeLeftRightCursor]; - FRAME_NS_DISPLAY_INFO (f)->vertical_scroll_bar_cursor + f->output_data.ns->vertical_drag_cursor = [NSCursor resizeUpDownCursor]; + FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor = [NSCursor arrowCursor]; f->output_data.ns->current_pointer = f->output_data.ns->text_cursor; @@ -1299,12 +1325,11 @@ This function is an internal primitive--use `make-frame' instead. */) x_default_parameter (f, parms, Qfullscreen, Qnil, "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); - width = FRAME_COLS (f); - height = FRAME_LINES (f); - - SET_FRAME_COLS (f, 0); - FRAME_LINES (f) = 0; - change_frame_size (f, height, width, 1, 0, 0); + width = FRAME_TEXT_WIDTH (f); + height = FRAME_TEXT_HEIGHT (f); + FRAME_TEXT_HEIGHT (f) = 0; + SET_FRAME_WIDTH (f, 0); + change_frame_size (f, width, height, 1, 0, 0, 1); if (! f->output_data.ns->explicit_parent) { @@ -1351,14 +1376,10 @@ This function is an internal primitive--use `make-frame' instead. */) return unbind_to (count, frame); } - -DEFUN ("x-focus-frame", Fx_focus_frame, Sx_focus_frame, 1, 1, 0, - doc: /* Set the input focus to FRAME. -FRAME nil means use the selected frame. */) - (Lisp_Object frame) +void +x_focus_frame (struct frame *f) { - struct frame *f = decode_window_system_frame (frame); - struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f); + struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); if (dpyinfo->x_focus_frame != f) { @@ -1368,8 +1389,6 @@ FRAME nil means use the selected frame. */) [[view window] makeKeyAndOrderFront: view]; unblock_input (); } - - return Qnil; } @@ -1380,9 +1399,15 @@ DEFUN ("ns-popup-font-panel", Fns_popup_font_panel, Sns_popup_font_panel, { struct frame *f = decode_window_system_frame (frame); id fm = [NSFontManager sharedFontManager]; - - [fm setSelectedFont: ((struct nsfont_info *)f->output_data.ns->font)->nsfont - isMultiple: NO]; + struct font *font = f->output_data.ns->font; + NSFont *nsfont; + if (EQ (font->driver->type, Qns)) + nsfont = ((struct nsfont_info *)font)->nsfont; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + else + nsfont = (NSFont *) macfont_get_nsctfont (font); +#endif + [fm setSelectedFont: nsfont isMultiple: NO]; [fm orderFrontFontPanel: NSApp]; return Qnil; } @@ -1398,6 +1423,41 @@ DEFUN ("ns-popup-color-panel", Fns_popup_color_panel, Sns_popup_color_panel, return Qnil; } +static struct +{ + id panel; + BOOL ret; +#if ! defined (NS_IMPL_COCOA) || \ + MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 + NSString *dirS, *initS; + BOOL no_types; +#endif +} ns_fd_data; + +void +ns_run_file_dialog (void) +{ + if (ns_fd_data.panel == nil) return; +#if defined (NS_IMPL_COCOA) && \ + MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + ns_fd_data.ret = [ns_fd_data.panel runModal]; +#else + if (ns_fd_data.no_types) + { + ns_fd_data.ret = [ns_fd_data.panel + runModalForDirectory: ns_fd_data.dirS + file: ns_fd_data.initS]; + } + else + { + ns_fd_data.ret = [ns_fd_data.panel + runModalForDirectory: ns_fd_data.dirS + file: ns_fd_data.initS + types: nil]; + } +#endif + ns_fd_data.panel = nil; +} DEFUN ("ns-read-file-name", Fns_read_file_name, Sns_read_file_name, 1, 5, 0, doc: /* Use a graphical panel to read a file name, using prompt PROMPT. @@ -1411,6 +1471,7 @@ Optional arg DIR_ONLY_P, if non-nil, means choose only directories. */) { static id fileDelegate = nil; BOOL ret; + BOOL isSave = NILP (mustmatch) && NILP (dir_only_p); id panel; Lisp_Object fname; @@ -1421,6 +1482,7 @@ Optional arg DIR_ONLY_P, if non-nil, means choose only directories. */) [NSString stringWithUTF8String: SSDATA (dir)]; NSString *initS = NILP (init) || !STRINGP (init) ? nil : [NSString stringWithUTF8String: SSDATA (init)]; + NSEvent *nxev; check_window_system (NULL); @@ -1432,7 +1494,7 @@ Optional arg DIR_ONLY_P, if non-nil, means choose only directories. */) if ([dirS characterAtIndex: 0] == '~') dirS = [dirS stringByExpandingTildeInPath]; - panel = NILP (mustmatch) && NILP (dir_only_p) ? + panel = isSave ? (id)[EmacsSavePanel savePanel] : (id)[EmacsOpenPanel openPanel]; [panel setTitle: promptS]; @@ -1441,13 +1503,12 @@ Optional arg DIR_ONLY_P, if non-nil, means choose only directories. */) [panel setTreatsFilePackagesAsDirectories: YES]; [panel setDelegate: fileDelegate]; - panelOK = 0; if (! NILP (dir_only_p)) { [panel setCanChooseDirectories: YES]; [panel setCanChooseFiles: NO]; } - else + else if (! isSave) { /* This is not quite what the documentation says, but it is compatible with the Gtk+ code. Also, the menu entry says "Open File...". */ @@ -1455,7 +1516,9 @@ Optional arg DIR_ONLY_P, if non-nil, means choose only directories. */) [panel setCanChooseFiles: YES]; } - block_input (); + block_input (); + ns_fd_data.panel = panel; + ns_fd_data.ret = NO; #if defined (NS_IMPL_COCOA) && \ MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 if (! NILP (mustmatch) || ! NILP (dir_only_p)) @@ -1466,24 +1529,37 @@ Optional arg DIR_ONLY_P, if non-nil, means choose only directories. */) else [panel setNameFieldStringValue: @""]; - ret = [panel runModal]; #else - if (NILP (mustmatch) && NILP (dir_only_p)) - { - ret = [panel runModalForDirectory: dirS file: initS]; - } - else - { - ret = [panel runModalForDirectory: dirS file: initS types: nil]; - } + ns_fd_data.no_types = NILP (mustmatch) && NILP (dir_only_p); + ns_fd_data.dirS = dirS; + ns_fd_data.initS = initS; #endif - ret = (ret == NSOKButton) || panelOK; + /* runModalForDirectory/runModal restarts the main event loop when done, + so we must start an event loop and then pop up the file dialog. + The file dialog may pop up a confirm dialog after Ok has been pressed, + so we can not simply pop down on the Ok/Cancel press. + */ + nxev = [NSEvent otherEventWithType: NSApplicationDefined + location: NSMakePoint (0, 0) + modifierFlags: 0 + timestamp: 0 + windowNumber: [[NSApp mainWindow] windowNumber] + context: [NSApp context] + subtype: 0 + data1: 0 + data2: NSAPP_DATA2_RUNFILEDIALOG]; + + [NSApp postEvent: nxev atStart: NO]; + while (ns_fd_data.panel != nil) + [NSApp run]; + + ret = (ns_fd_data.ret == NSOKButton); if (ret) { - NSString *str = [panel getFilename]; - if (! str) str = [panel getDirectory]; + NSString *str = ns_filename_from_panel (panel); + if (! str) str = ns_directory_from_panel (panel); if (! str) ret = NO; else fname = build_string ([str UTF8String]); } @@ -1758,10 +1834,10 @@ terminate Emacs if we can't open the connection. if (dpyinfo == 0) { if (!NILP (must_succeed)) - fatal ("OpenStep on %s not responding.\n", + fatal ("Display on %s not responding.\n", SSDATA (display)); else - error ("OpenStep on %s not responding.\n", + error ("Display on %s not responding.\n", SSDATA (display)); } @@ -1787,11 +1863,11 @@ DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0, doc: /* Return the list of display names that Emacs has connections to. */) (void) { - Lisp_Object tail, result; + Lisp_Object result = Qnil; + struct ns_display_info *ndi; - result = Qnil; - for (tail = ns_display_name_list; CONSP (tail); tail = XCDR (tail)) - result = Fcons (XCAR (XCAR (tail)), result); + for (ndi = x_display_list; ndi; ndi = ndi->next) + result = Fcons (XCAR (ndi->name_list_element), result); return result; } @@ -1910,7 +1986,9 @@ DEFUN ("ns-list-services", Fns_list_services, Sns_list_services, 0, 0, 0, #else Lisp_Object ret = Qnil; NSMenu *svcs; +#ifdef NS_IMPL_COCOA id delegate; +#endif check_window_system (NULL); svcs = [[NSMenu alloc] initWithTitle: @"Services"]; @@ -1974,7 +2052,7 @@ there was no result. */) ns_string_to_pasteboard (pb, send); if (NSPerformService (svcName, pb) == NO) - Fsignal (Qquit, Fcons (build_string ("service not available"), Qnil)); + Fsignal (Qquit, list1 (build_string ("service not available"))); if ([[pb types] count] == 0) return build_string (""); @@ -1990,19 +2068,28 @@ DEFUN ("ns-convert-utf8-nfd-to-nfc", Fns_convert_utf8_nfd_to_nfc, /* TODO: If GNUstep ever implements precomposedStringWithCanonicalMapping, remove this. */ NSString *utfStr; + Lisp_Object ret = Qnil; + NSAutoreleasePool *pool; CHECK_STRING (str); + pool = [[NSAutoreleasePool alloc] init]; utfStr = [NSString stringWithUTF8String: SSDATA (str)]; - if (![utfStr respondsToSelector: - @selector (precomposedStringWithCanonicalMapping)]) +#ifdef NS_IMPL_COCOA + if (utfStr) + utfStr = [utfStr precomposedStringWithCanonicalMapping]; +#endif + if (utfStr) { - message1 - ("Warning: ns-convert-utf8-nfd-to-nfc unsupported under GNUstep.\n"); - return Qnil; + const char *cstr = [utfStr UTF8String]; + if (cstr) + ret = build_string (cstr); } - else - utfStr = [utfStr precomposedStringWithCanonicalMapping]; - return build_string ([utfStr UTF8String]); + + [pool release]; + if (NILP (ret)) + error ("Invalid UTF-8"); + + return ret; } @@ -2155,14 +2242,13 @@ x_set_scroll_bar_default_width (struct frame *f) wid - 1) / wid; } - /* terms impl this instead of x-get-resource directly */ -const char * -x_get_string_resource (XrmDatabase rdb, char *name, char *class) +char * +x_get_string_resource (XrmDatabase rdb, const char *name, const char *class) { /* remove appname prefix; TODO: allow for !="Emacs" */ - char *toCheck = class + (!strncmp (class, "Emacs.", 6) ? 6 : 0); - const char *res; + const char *res, *toCheck = class + (!strncmp (class, "Emacs.", 6) ? 6 : 0); + check_window_system (NULL); if (inhibit_x_resources) @@ -2170,16 +2256,16 @@ x_get_string_resource (XrmDatabase rdb, char *name, char *class) return NULL; res = ns_get_defaults_value (toCheck); - return !res ? NULL : - (!c_strncasecmp (res, "YES", 3) ? "true" : - (!c_strncasecmp (res, "NO", 2) ? "false" : res)); + return (!res ? NULL : + (!c_strncasecmp (res, "YES", 3) ? "true" : + (!c_strncasecmp (res, "NO", 2) ? "false" : (char *) res))); } Lisp_Object x_get_focus_frame (struct frame *frame) { - struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame); + struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame); Lisp_Object nsfocus; if (!dpyinfo->x_focus_frame) @@ -2189,37 +2275,6 @@ x_get_focus_frame (struct frame *frame) return nsfocus; } - -int -x_pixel_width (struct frame *f) -{ - return FRAME_PIXEL_WIDTH (f); -} - - -int -x_pixel_height (struct frame *f) -{ - return FRAME_PIXEL_HEIGHT (f); -} - - -int -x_screen_planes (struct frame *f) -{ - return FRAME_NS_DISPLAY_INFO (f)->n_planes; -} - - -void -x_sync (struct frame *f) -{ - /* XXX Not implemented XXX */ - return; -} - - - /* ========================================================================== Lisp definitions that, for whatever reason, we can't alias as 'ns-XXX'. @@ -2243,16 +2298,21 @@ DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, (Lisp_Object color, Lisp_Object frame) { NSColor * col; - CGFloat red, green, blue, alpha; + EmacsCGFloat red, green, blue, alpha; check_window_system (NULL); CHECK_STRING (color); + block_input (); if (ns_lisp_to_color (color, &col)) - return Qnil; + { + unblock_input (); + return Qnil; + } - [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace] + [[col colorUsingDefaultColorSpace] getRed: &red green: &green blue: &blue alpha: &alpha]; + unblock_input (); return list3i (lrint (red * 65280), lrint (green * 65280), lrint (blue * 65280)); } @@ -2328,44 +2388,87 @@ each physical monitor, use `display-monitor-attributes-list'. */) return make_number (x_display_pixel_height (dpyinfo)); } -struct MonitorInfo { - XRectangle geom, work; - int mm_width, mm_height; - char *name; -}; +#ifdef NS_IMPL_COCOA -static void -free_monitors (struct MonitorInfo *monitors, int n_monitors) +/* Returns the name for the screen that OBJ represents, or NULL. + Caller must free return value. +*/ + +static char * +ns_get_name_from_ioreg (io_object_t obj) { - int i; - for (i = 0; i < n_monitors; ++i) - xfree (monitors[i].name); - xfree (monitors); + char *name = NULL; + + NSDictionary *info = (NSDictionary *) + IODisplayCreateInfoDictionary (obj, kIODisplayOnlyPreferredName); + NSDictionary *names = [info objectForKey: + [NSString stringWithUTF8String: + kDisplayProductName]]; + + if ([names count] > 0) + { + NSString *n = [names objectForKey: [[names allKeys] + objectAtIndex:0]]; + if (n != nil) name = xstrdup ([n UTF8String]); + } + + [info release]; + + return name; } -#ifdef NS_IMPL_COCOA -/* Returns the name for the screen that DICT came from, or NULL. +/* Returns the name for the screen that DID came from, or NULL. Caller must free return value. */ -char * +static char * ns_screen_name (CGDirectDisplayID did) { char *name = NULL; - NSDictionary *info = (NSDictionary *) - IODisplayCreateInfoDictionary (CGDisplayIOServicePort (did), - kIODisplayOnlyPreferredName); - NSDictionary *names - = [info objectForKey: - [NSString stringWithUTF8String:kDisplayProductName]]; - - if ([names count] > 0) { - NSString *n = [names objectForKey: [[names allKeys] objectAtIndex:0]]; - if (n != nil) - name = xstrdup ([n UTF8String]); - } - [info release]; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 + mach_port_t masterPort; + io_iterator_t it; + io_object_t obj; + + // CGDisplayIOServicePort is deprecated. Do it another (harder) way. + + if (IOMasterPort (MACH_PORT_NULL, &masterPort) != kIOReturnSuccess + || IOServiceGetMatchingServices (masterPort, + IOServiceMatching ("IONDRVDevice"), + &it) != kIOReturnSuccess) + return name; + + /* Must loop until we find a name. Many devices can have the same unit + number (represents different GPU parts), but only one has a name. */ + while (! name && (obj = IOIteratorNext (it))) + { + CFMutableDictionaryRef props; + const void *val; + + if (IORegistryEntryCreateCFProperties (obj, + &props, + kCFAllocatorDefault, + kNilOptions) == kIOReturnSuccess + && props != nil + && (val = CFDictionaryGetValue(props, @"IOFBDependentIndex"))) + { + unsigned nr = [(NSNumber *)val unsignedIntegerValue]; + if (nr == CGDisplayUnitNumber (did)) + name = ns_get_name_from_ioreg (obj); + } + + CFRelease (props); + IOObjectRelease (obj); + } + + IOObjectRelease (it); + +#else + + name = ns_get_name_from_ioreg (CGDisplayIOServicePort (did)); + +#endif return name; } #endif @@ -2377,8 +2480,7 @@ ns_make_monitor_attribute_list (struct MonitorInfo *monitors, const char *source) { Lisp_Object monitor_frames = Fmake_vector (make_number (n_monitors), Qnil); - Lisp_Object frame, rest, attributes_list = Qnil; - Lisp_Object primary_monitor_attributes = Qnil; + Lisp_Object frame, rest; NSArray *screens = [NSScreen screens]; int i; @@ -2404,41 +2506,8 @@ ns_make_monitor_attribute_list (struct MonitorInfo *monitors, } } - for (i = 0; i < n_monitors; ++i) - { - Lisp_Object geometry, workarea, attributes = Qnil; - struct MonitorInfo *mi = &monitors[i]; - - if (mi->geom.width == 0) continue; - - workarea = list4i (mi->work.x, mi->work.y, - mi->work.width, mi->work.height); - geometry = list4i (mi->geom.x, mi->geom.y, - mi->geom.width, mi->geom.height); - attributes = Fcons (Fcons (Qsource, - make_string (source, strlen (source))), - attributes); - attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)), - attributes); - attributes = Fcons (Fcons (Qmm_size, - list2i (mi->mm_width, mi->mm_height)), - attributes); - attributes = Fcons (Fcons (Qworkarea, workarea), attributes); - attributes = Fcons (Fcons (Qgeometry, geometry), attributes); - if (mi->name) - attributes = Fcons (Fcons (Qname, make_string (mi->name, - strlen (mi->name))), - attributes); - - if (i == primary_monitor) - primary_monitor_attributes = attributes; - else - attributes_list = Fcons (attributes, attributes_list); - } - - if (!NILP (primary_monitor_attributes)) - attributes_list = Fcons (primary_monitor_attributes, attributes_list); - return attributes_list; + return make_monitor_attribute_list (monitors, n_monitors, primary_monitor, + monitor_frames, source); } DEFUN ("ns-display-monitor-attributes-list", @@ -2476,7 +2545,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */) if (n_monitors == 0) return Qnil; - monitors = (struct MonitorInfo *) xzalloc (n_monitors * sizeof (*monitors)); + monitors = xzalloc (n_monitors * sizeof *monitors); for (i = 0; i < [screens count]; ++i) { @@ -2484,11 +2553,10 @@ Internal use only, use `display-monitor-attributes-list' instead. */) struct MonitorInfo *m = &monitors[i]; NSRect fr = [s frame]; NSRect vfr = [s visibleFrame]; - NSDictionary *dict = [s deviceDescription]; - NSValue *resval = [dict valueForKey:NSDeviceResolution]; short y, vy; #ifdef NS_IMPL_COCOA + NSDictionary *dict = [s deviceDescription]; NSNumber *nid = [dict objectForKey:@"NSScreenNumber"]; CGDirectDisplayID did = [nid unsignedIntValue]; #endif @@ -2505,7 +2573,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */) vy = (short) (primary_display_height - vfr.size.height - vfr.origin.y); } - + m->geom.x = (short) fr.origin.x; m->geom.y = y; m->geom.width = (unsigned short) fr.size.width; @@ -2590,6 +2658,7 @@ compute_tip_xy (struct frame *f, { Lisp_Object left, top; EmacsView *view = FRAME_NS_VIEW (f); + struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); NSPoint pt; /* Start with user-specified or mouse position. */ @@ -2598,7 +2667,8 @@ compute_tip_xy (struct frame *f, if (!INTEGERP (left) || !INTEGERP (top)) { - pt = last_mouse_motion_position; + pt.x = dpyinfo->last_mouse_motion_x; + pt.y = dpyinfo->last_mouse_motion_y; /* Convert to screen coordinates */ pt = [view convertPoint: pt toView: nil]; pt = [[view window] convertBaseToScreen: pt]; @@ -2607,7 +2677,7 @@ compute_tip_xy (struct frame *f, { /* Absolute coordinates. */ pt.x = XINT (left); - pt.y = x_display_pixel_height (FRAME_NS_DISPLAY_INFO (f)) - XINT (top) + pt.y = x_display_pixel_height (FRAME_DISPLAY_INFO (f)) - XINT (top) - height; } @@ -2617,7 +2687,7 @@ compute_tip_xy (struct frame *f, else if (pt.x + XINT (dx) <= 0) *root_x = 0; /* Can happen for negative dx */ else if (pt.x + XINT (dx) + width - <= x_display_pixel_width (FRAME_NS_DISPLAY_INFO (f))) + <= x_display_pixel_width (FRAME_DISPLAY_INFO (f))) /* It fits to the right of the pointer. */ *root_x = pt.x + XINT (dx); else if (width + XINT (dx) <= pt.x) @@ -2633,12 +2703,12 @@ compute_tip_xy (struct frame *f, /* It fits below the pointer. */ *root_y = pt.y - height - XINT (dy); else if (pt.y + XINT (dy) + height - <= x_display_pixel_height (FRAME_NS_DISPLAY_INFO (f))) + <= x_display_pixel_height (FRAME_DISPLAY_INFO (f))) /* It fits above the pointer */ *root_y = pt.y + XINT (dy); else /* Put it on the top. */ - *root_y = x_display_pixel_height (FRAME_NS_DISPLAY_INFO (f)) - height; + *root_y = x_display_pixel_height (FRAME_DISPLAY_INFO (f)) - height; } @@ -2764,8 +2834,14 @@ handlePanelKeys (NSSavePanel *panel, NSEvent *theEvent) case NSPageUpFunctionKey: case NSPageDownFunctionKey: case NSEndFunctionKey: - [panel sendEvent: theEvent]; - ret = YES; + /* Don't send command modified keys, as those are handled in the + performKeyEquivalent method of the super class. + */ + if (! ([theEvent modifierFlags] & NSCommandKeyMask)) + { + [panel sendEvent: theEvent]; + ret = YES; + } break; /* As we don't have the standard key commands for copy/paste/cut/select-all in our edit menu, we must handle @@ -2808,33 +2884,6 @@ handlePanelKeys (NSSavePanel *panel, NSEvent *theEvent) } @implementation EmacsSavePanel -#ifdef NS_IMPL_COCOA -/* -------------------------------------------------------------------------- - These are overridden to intercept on OS X: ending panel restarts NSApp - event loop if it is stopped. Not sure if this is correct behavior, - perhaps should check if running and if so send an appdefined. - -------------------------------------------------------------------------- */ -- (void) ok: (id)sender -{ - [super ok: sender]; - panelOK = 1; - [NSApp stop: self]; -} -- (void) cancel: (id)sender -{ - [super cancel: sender]; - [NSApp stop: self]; -} -#endif -- (NSString *) getFilename -{ - return ns_filename_from_panel (self); -} -- (NSString *) getDirectory -{ - return ns_directory_from_panel (self); -} - - (BOOL)performKeyEquivalent:(NSEvent *)theEvent { BOOL ret = handlePanelKeys (self, theEvent); @@ -2846,39 +2895,6 @@ handlePanelKeys (NSSavePanel *panel, NSEvent *theEvent) @implementation EmacsOpenPanel -#ifdef NS_IMPL_COCOA -/* -------------------------------------------------------------------------- - These are overridden to intercept on OS X: ending panel restarts NSApp - event loop if it is stopped. Not sure if this is correct behavior, - perhaps should check if running and if so send an appdefined. - -------------------------------------------------------------------------- */ -- (void) ok: (id)sender -{ - [super ok: sender]; - - // If not choosing directories, and Open is pressed on a directory, return. - if (! [self canChooseDirectories] && [self getDirectory] && - ! [self getFilename]) - return; - - panelOK = 1; - [NSApp stop: self]; -} -- (void) cancel: (id)sender -{ - [super cancel: sender]; - [NSApp stop: self]; -} - -#endif -- (NSString *) getFilename -{ - return ns_filename_from_panel (self); -} -- (NSString *) getDirectory -{ - return ns_directory_from_panel (self); -} - (BOOL)performKeyEquivalent:(NSEvent *)theEvent { // NSOpenPanel inherits NSSavePanel, so passing self is OK. @@ -2922,11 +2938,6 @@ handlePanelKeys (NSSavePanel *panel, NSEvent *theEvent) void syms_of_nsfns (void) { - DEFSYM (Qgeometry, "geometry"); - DEFSYM (Qworkarea, "workarea"); - DEFSYM (Qmm_size, "mm-size"); - DEFSYM (Qframes, "frames"); - DEFSYM (Qsource, "source"); Qfontsize = intern_c_string ("fontsize"); staticpro (&Qfontsize); @@ -2949,7 +2960,7 @@ Example: Install an icon Gnus.tiff and execute the following code When you miniaturize a Group, Summary or Article frame, Gnus.tiff will be used as the image of the icon representing the frame. */); - Vns_icon_type_alist = Fcons (Qt, Qnil); + Vns_icon_type_alist = list1 (Qt); DEFVAR_LISP ("ns-version-string", Vns_version_string, doc: /* Toolkit version for NS Windowing. */); @@ -2992,7 +3003,6 @@ be used as the image of the icon representing the frame. */); defsubr (&Sns_list_services); defsubr (&Sns_perform_service); defsubr (&Sns_convert_utf8_nfd_to_nfc); - defsubr (&Sx_focus_frame); defsubr (&Sns_popup_font_panel); defsubr (&Sns_popup_color_panel);