nsfns.m 94.5 KB
Newer Older
1
/* Functions for the NeXT/Open/GNUstep and macOS window system.
Glenn Morris's avatar
Glenn Morris committed
2

Paul Eggert's avatar
Paul Eggert committed
3
Copyright (C) 1989, 1992-1994, 2005-2006, 2008-2017 Free Software
4
Foundation, Inc.
5 6 7

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 11
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
12 13 14 15 16 17 18

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

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/>.  */
20

21
/*
22 23 24
Originally by Carl Edman
Updated by Christian Limpach (chris@nice.ch)
OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25
macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 27 28
GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
*/

29 30
/* This should be the first include, as it may set up #defines affecting
   interpretation of even the system includes. */
Dan Nicolaescu's avatar
Dan Nicolaescu committed
31
#include <config.h>
32

33
#include <math.h>
34
#include <c-strcase.h>
35

36 37 38 39
#include "lisp.h"
#include "blockinput.h"
#include "nsterm.h"
#include "window.h"
40
#include "character.h"
41 42 43 44 45 46
#include "buffer.h"
#include "keyboard.h"
#include "termhooks.h"
#include "fontset.h"
#include "font.h"

47 48
#ifdef NS_IMPL_COCOA
#include <IOKit/graphics/IOGraphicsLib.h>
49 50
#include "macfont.h"
#endif
51

52 53 54

#ifdef HAVE_NS

55
static EmacsTooltip *ns_tooltip = nil;
56

57 58 59
/* Static variables to handle applescript execution.  */
static Lisp_Object as_script, *as_result;
static int as_status;
60

61 62
static ptrdiff_t image_cache_refcount;

63 64
static struct ns_display_info *ns_display_info_for_name (Lisp_Object);
static void ns_set_name_as_filename (struct frame *);
65

66 67 68 69 70 71
/* ==========================================================================

    Internal utility functions

   ========================================================================== */

72 73 74
/* Let the user specify a Nextstep display with a Lisp object.
   OBJECT may be nil, a frame or a terminal object.
   nil stands for the selected frame--or, if that is not a Nextstep frame,
75
   the first Nextstep display on the list.  */
76

77
static struct ns_display_info *
78
check_ns_display_info (Lisp_Object object)
79
{
80 81 82
  struct ns_display_info *dpyinfo = NULL;

  if (NILP (object))
83
    {
84 85 86
      struct frame *sf = XFRAME (selected_frame);

      if (FRAME_NS_P (sf) && FRAME_LIVE_P (sf))
87
	dpyinfo = FRAME_DISPLAY_INFO (sf);
88
      else if (x_display_list != 0)
89
	dpyinfo = x_display_list;
90
      else
91
        error ("Nextstep windows are not in use or not initialized");
92
    }
93
  else if (TERMINALP (object))
94
    {
95
      struct terminal *t = decode_live_terminal (object);
96 97

      if (t->type != output_ns)
98
        error ("Terminal %d is not a Nextstep display", t->id);
99

100
      dpyinfo = t->display_info.ns;
101
    }
102 103
  else if (STRINGP (object))
    dpyinfo = ns_display_info_for_name (object);
104 105
  else
    {
Dmitry Antipov's avatar
Dmitry Antipov committed
106
      struct frame *f = decode_window_system_frame (object);
107
      dpyinfo = FRAME_DISPLAY_INFO (f);
108
    }
109 110

  return dpyinfo;
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
}


static id
ns_get_window (Lisp_Object maybeFrame)
{
  id view =nil, window =nil;

  if (!FRAMEP (maybeFrame) || !FRAME_NS_P (XFRAME (maybeFrame)))
    maybeFrame = selected_frame;/*wrong_type_argument (Qframep, maybeFrame); */

  if (!NILP (maybeFrame))
    view = FRAME_NS_VIEW (XFRAME (maybeFrame));
  if (view) window =[view window];

  return window;
}


/* Return the X display structure for the display named NAME.
   Open a new connection if necessary.  */
132
static struct ns_display_info *
133
ns_display_info_for_name (Lisp_Object name)
134 135 136 137 138
{
  struct ns_display_info *dpyinfo;

  CHECK_STRING (name);

139 140 141
  for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
    if (!NILP (Fstring_equal (XCAR (dpyinfo->name_list_element), name)))
      return dpyinfo;
142

Glenn Morris's avatar
Glenn Morris committed
143
  error ("Emacs for Nextstep does not yet support multi-display");
144

145 146
  Fx_open_connection (name, Qnil, Qnil);
  dpyinfo = x_display_list;
147 148

  if (dpyinfo == 0)
149
    error ("Display on %s not responding.\n", SDATA (name));
150 151 152 153

  return dpyinfo;
}

154 155 156
static NSString *
ns_filename_from_panel (NSSavePanel *panel)
{
157
#ifdef NS_IMPL_COCOA
158 159 160 161 162 163 164 165 166 167 168
  NSURL *url = [panel URL];
  NSString *str = [url path];
  return str;
#else
  return [panel filename];
#endif
}

static NSString *
ns_directory_from_panel (NSSavePanel *panel)
{
169
#ifdef NS_IMPL_COCOA
170 171 172 173 174 175 176
  NSURL *url = [panel directoryURL];
  NSString *str = [url path];
  return str;
#else
  return [panel directory];
#endif
}
177 178 179 180 181 182 183 184

static Lisp_Object
interpret_services_menu (NSMenu *menu, Lisp_Object prefix, Lisp_Object old)
/* --------------------------------------------------------------------------
   Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
   -------------------------------------------------------------------------- */
{
  int i, count;
185
  NSMenuItem *item;
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
  const char *name;
  Lisp_Object nameStr;
  unsigned short key;
  NSString *keys;
  Lisp_Object res;

  count = [menu numberOfItems];
  for (i = 0; i<count; i++)
    {
      item = [menu itemAtIndex: i];
      name = [[item title] UTF8String];
      if (!name) continue;

      nameStr = build_string (name);

      if ([item hasSubmenu])
        {
          old = interpret_services_menu ([item submenu],
                                        Fcons (nameStr, prefix), old);
        }
      else
        {
          keys = [item keyEquivalent];
          if (keys && [keys length] )
            {
              key = [keys characterAtIndex: 0];
              res = make_number (key|super_modifier);
            }
          else
            {
              res = Qundefined;
            }
          old = Fcons (Fcons (res,
                            Freverse (Fcons (nameStr,
                                           prefix))),
                    old);
        }
    }
  return old;
}



/* ==========================================================================

    Frame parameter setters

   ========================================================================== */


static void
237
x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
238 239
{
  NSColor *col;
240
  EmacsCGFloat r, g, b, alpha;
241

Jan Djärv's avatar
Jan Djärv committed
242 243 244 245
  /* 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 ();
246 247 248
  if (ns_lisp_to_color (arg, &col))
    {
      store_frame_param (f, Qforeground_color, oldval);
Jan Djärv's avatar
Jan Djärv committed
249
      unblock_input ();
250 251 252 253 254 255 256
      error ("Unknown color");
    }

  [col retain];
  [f->output_data.ns->foreground_color release];
  f->output_data.ns->foreground_color = col;

257 258 259 260
  [col getRed: &r green: &g blue: &b alpha: &alpha];
  FRAME_FOREGROUND_PIXEL (f) =
    ARGB_TO_ULONG ((int)(alpha*0xff), (int)(r*0xff), (int)(g*0xff), (int)(b*0xff));

261 262 263 264 265
  if (FRAME_NS_VIEW (f))
    {
      update_face_from_frame_parameter (f, Qforeground_color, arg);
      /*recompute_basic_faces (f); */
      if (FRAME_VISIBLE_P (f))
Jan Djärv's avatar
Jan Djärv committed
266
        SET_FRAME_GARBAGED (f);
267
    }
Jan Djärv's avatar
Jan Djärv committed
268
  unblock_input ();
269 270 271 272
}


static void
273
x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
274 275 276 277
{
  struct face *face;
  NSColor *col;
  NSView *view = FRAME_NS_VIEW (f);
278
  EmacsCGFloat r, g, b, alpha;
279

Jan Djärv's avatar
Jan Djärv committed
280
  block_input ();
281 282 283
  if (ns_lisp_to_color (arg, &col))
    {
      store_frame_param (f, Qbackground_color, oldval);
Jan Djärv's avatar
Jan Djärv committed
284
      unblock_input ();
285 286 287 288 289 290 291 292 293 294 295
      error ("Unknown color");
    }

  /* clear the frame; in some instances the NS-internal GC appears not to
     update, or it does update and cannot clear old text properly */
  if (FRAME_VISIBLE_P (f))
    ns_clear_frame (f);

  [col retain];
  [f->output_data.ns->background_color release];
  f->output_data.ns->background_color = col;
296 297 298 299 300

  [col getRed: &r green: &g blue: &b alpha: &alpha];
  FRAME_BACKGROUND_PIXEL (f) =
    ARGB_TO_ULONG ((int)(alpha*0xff), (int)(r*0xff), (int)(g*0xff), (int)(b*0xff));

301 302 303 304
  if (view != nil)
    {
      [[view window] setBackgroundColor: col];

305
      if (alpha != (EmacsCGFloat) 1.0)
306 307 308 309 310 311 312
          [[view window] setOpaque: NO];
      else
          [[view window] setOpaque: YES];

      face = FRAME_DEFAULT_FACE (f);
      if (face)
        {
313
          col = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f);
314 315
          face->background = ns_index_color
            ([col colorWithAlphaComponent: alpha], f);
316 317 318 319 320

          update_face_from_frame_parameter (f, Qbackground_color, arg);
        }

      if (FRAME_VISIBLE_P (f))
Jan Djärv's avatar
Jan Djärv committed
321
        SET_FRAME_GARBAGED (f);
322
    }
Jan Djärv's avatar
Jan Djärv committed
323
  unblock_input ();
324 325 326 327
}


static void
328
x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
329 330 331
{
  NSColor *col;

Jan Djärv's avatar
Jan Djärv committed
332
  block_input ();
333 334 335
  if (ns_lisp_to_color (arg, &col))
    {
      store_frame_param (f, Qcursor_color, oldval);
Jan Djärv's avatar
Jan Djärv committed
336
      unblock_input ();
337 338 339
      error ("Unknown color");
    }

340 341
  [FRAME_CURSOR_COLOR (f) release];
  FRAME_CURSOR_COLOR (f) = [col retain];
342 343 344 345 346 347 348

  if (FRAME_VISIBLE_P (f))
    {
      x_update_cursor (f, 0);
      x_update_cursor (f, 1);
    }
  update_face_from_frame_parameter (f, Qcursor_color, arg);
Jan Djärv's avatar
Jan Djärv committed
349
  unblock_input ();
350 351
}

352

353
static void
354
x_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
355 356
{
  NSView *view = FRAME_NS_VIEW (f);
357
  NSTRACE ("x_set_icon_name");
358 359 360 361 362 363 364 365 366 367

  /* see if it's changed */
  if (STRINGP (arg))
    {
      if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
        return;
    }
  else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
    return;

368
  fset_icon_name (f, arg);
369 370 371

  if (NILP (arg))
    {
372 373
      if (!NILP (f->title))
        arg = f->title;
374
      else
375
        /* Explicit name and no icon-name -> explicit_name.  */
376
        if (f->explicit_name)
377
          arg = f->name;
378 379
        else
          {
380 381 382
            /* No explicit name and no icon-name ->
               name has to be rebuild from icon_title_format.  */
            windows_or_buffers_changed = 62;
383 384 385 386 387
            return;
          }
    }

  /* Don't change the name if it's already NAME.  */
388 389
  if ([[view window] miniwindowTitle]
      && ([[[view window] miniwindowTitle]
390
             isEqualToString: [NSString stringWithUTF8String:
391
					  SSDATA (arg)]]))
392 393 394
    return;

  [[view window] setMiniwindowTitle:
395
        [NSString stringWithUTF8String: SSDATA (arg)]];
396 397 398
}

static void
Dmitry Antipov's avatar
Dmitry Antipov committed
399
ns_set_name_internal (struct frame *f, Lisp_Object name)
400
{
401 402
  Lisp_Object encoded_name, encoded_icon_name;
  NSString *str;
403 404
  NSView *view = FRAME_NS_VIEW (f);

405

406
  encoded_name = ENCODE_UTF_8 (name);
407

408
  str = [NSString stringWithUTF8String: SSDATA (encoded_name)];
409

410

411 412 413
  /* Don't change the name if it's already NAME.  */
  if (! [[[view window] title] isEqualToString: str])
    [[view window] setTitle: str];
414

415
  if (!STRINGP (f->icon_name))
416
    encoded_icon_name = encoded_name;
417
  else
418
    encoded_icon_name = ENCODE_UTF_8 (f->icon_name);
419

420
  str = [NSString stringWithUTF8String: SSDATA (encoded_icon_name)];
421

422 423
  if ([[view window] miniwindowTitle]
      && ! [[[view window] miniwindowTitle] isEqualToString: str])
424
    [[view window] setMiniwindowTitle: str];
425 426 427 428 429 430

}

static void
ns_set_name (struct frame *f, Lisp_Object name, int explicit)
{
431
  NSTRACE ("ns_set_name");
432 433 434 435 436 437 438 439

  /* Make sure that requests from lisp code override requests from
     Emacs redisplay code.  */
  if (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))
440
        update_mode_lines = 21;
441 442 443 444 445 446 447

      f->explicit_name = ! NILP (name);
    }
  else if (f->explicit_name)
    return;

  if (NILP (name))
448
    name = build_string ([ns_app_name UTF8String]);
449 450 451 452
  else
    CHECK_STRING (name);

  /* Don't change the name if it's already NAME.  */
453
  if (! NILP (Fstring_equal (name, f->name)))
454
    return;
455

456
  fset_name (f, name);
457

458
  /* Title overrides explicit name.  */
459 460
  if (! NILP (f->title))
    name = f->title;
461

462
  ns_set_name_internal (f, name);
463 464 465 466 467 468 469
}


/* This function should be called when the user's lisp code has
   specified a name for the frame; the name will override any set by the
   redisplay code.  */
static void
Dmitry Antipov's avatar
Dmitry Antipov committed
470
x_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
471
{
472
  NSTRACE ("x_explicitly_set_name");
473 474 475 476 477 478 479 480
  ns_set_name (f, arg, 1);
}


/* This function should be called by Emacs redisplay code to set the
   name; names set this way will never override names set by the user's
   lisp code.  */
void
Dmitry Antipov's avatar
Dmitry Antipov committed
481
x_implicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
482
{
483
  NSTRACE ("x_implicitly_set_name");
484

485 486 487 488 489
  Lisp_Object frame_title = buffer_local_value
    (Qframe_title_format, XWINDOW (f->selected_window)->contents);
  Lisp_Object icon_title = buffer_local_value
    (Qicon_title_format, XWINDOW (f->selected_window)->contents);

490
  /* Deal with NS specific format t.  */
491 492
  if (FRAME_NS_P (f) && ((FRAME_ICONIFIED_P (f) && EQ (icon_title, Qt))
                         || EQ (frame_title, Qt)))
493
    ns_set_name_as_filename (f);
494 495 496 497 498 499
  else
    ns_set_name (f, arg, 0);
}


/* Change the title of frame F to NAME.
500
   If NAME is nil, use the frame name as the title.  */
501 502

static void
503
x_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name)
504
{
505
  NSTRACE ("x_set_title");
506
  /* Don't change the title if it's already NAME.  */
507
  if (EQ (name, f->title))
508 509
    return;

510
  update_mode_lines = 22;
511

512
  fset_title (f, name);
513 514

  if (NILP (name))
515
    name = f->name;
516 517 518 519
  else
    CHECK_STRING (name);

  ns_set_name_internal (f, name);
520 521 522
}


523
static void
524 525
ns_set_name_as_filename (struct frame *f)
{
526
  NSView *view;
527
  Lisp_Object name, filename;
528
  Lisp_Object buf = XWINDOW (f->selected_window)->contents;
529 530
  const char *title;
  NSAutoreleasePool *pool;
531 532
  Lisp_Object encoded_name, encoded_filename;
  NSString *str;
533
  NSTRACE ("ns_set_name_as_filename");
534

Jan Djärv's avatar
Jan Djärv committed
535
  if (f->explicit_name || ! NILP (f->title))
536 537
    return;

538
  block_input ();
539
  pool = [[NSAutoreleasePool alloc] init];
Jan Djärv's avatar
Jan Djärv committed
540 541
  filename = BVAR (XBUFFER (buf), filename);
  name = BVAR (XBUFFER (buf), name);
542 543

  if (NILP (name))
544 545 546 547 548 549
    {
      if (! NILP (filename))
        name = Ffile_name_nondirectory (filename);
      else
        name = build_string ([ns_app_name UTF8String]);
    }
550

551 552
  encoded_name = ENCODE_UTF_8 (name);

553 554
  view = FRAME_NS_VIEW (f);

555 556 557
  title = FRAME_ICONIFIED_P (f) ? [[[view window] miniwindowTitle] UTF8String]
                                : [[[view window] title] UTF8String];

558
  if (title && (! strcmp (title, SSDATA (encoded_name))))
559 560
    {
      [pool release];
561
      unblock_input ();
562 563 564
      return;
    }

565
  str = [NSString stringWithUTF8String: SSDATA (encoded_name)];
566 567 568 569
  if (str == nil) str = @"Bad coding";

  if (FRAME_ICONIFIED_P (f))
    [[view window] setMiniwindowTitle: str];
570
  else
571
    {
572 573 574
      NSString *fstr;

      if (! NILP (filename))
575
        {
576 577
          encoded_filename = ENCODE_UTF_8 (filename);

578
          fstr = [NSString stringWithUTF8String: SSDATA (encoded_filename)];
579
          if (fstr == nil) fstr = @"";
580 581
        }
      else
582 583
        fstr = @"";

584
      ns_set_represented_filename (fstr, f);
585
      [[view window] setTitle: str];
586
      fset_name (f, name);
587
    }
588

589
  [pool release];
590
  unblock_input ();
591 592 593 594
}


void
595
ns_set_doc_edited (void)
596 597
{
  NSAutoreleasePool *pool;
598 599 600 601
  Lisp_Object tail, frame;
  block_input ();
  pool = [[NSAutoreleasePool alloc] init];
  FOR_EACH_FRAME (tail, frame)
602
    {
603 604
      BOOL edited = NO;
      struct frame *f = XFRAME (frame);
605 606 607 608 609 610
      struct window *w;
      NSView *view;

      if (! FRAME_NS_P (f)) continue;
      w = XWINDOW (FRAME_SELECTED_WINDOW (f));
      view = FRAME_NS_VIEW (f);
611 612 613 614
      if (!MINI_WINDOW_P (w))
        edited = ! NILP (Fbuffer_modified_p (w->contents)) &&
          ! NILP (Fbuffer_file_name (w->contents));
      [[view window] setDocumentEdited: edited];
615
    }
616 617 618

  [pool release];
  unblock_input ();
619 620 621
}


622
static void
623
x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
624 625 626 627 628
{
  int nlines;
  if (FRAME_MINIBUF_ONLY_P (f))
    return;

629
  if (TYPE_RANGED_INTEGERP (int, value))
630 631 632 633 634 635 636 637
    nlines = XINT (value);
  else
    nlines = 0;

  FRAME_MENU_BAR_LINES (f) = 0;
  if (nlines)
    {
      FRAME_EXTERNAL_MENU_BAR (f) = 1;
638 639
      /* does for all frames, whereas we just want for one frame
	 [NSMenu setMenuBarVisible: YES]; */
640 641 642 643 644
    }
  else
    {
      if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
        free_frame_menubar (f);
645
      /*      [NSMenu setMenuBarVisible: NO]; */
646 647 648 649 650
      FRAME_EXTERNAL_MENU_BAR (f) = 0;
    }
}


651
/* toolbar support */
652
static void
653
x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
654
{
655 656 657 658 659
  /* Currently, when the tool bar change state, the frame is resized.

     TODO: It would be better if this didn't occur when 1) the frame
     is full height or maximized or 2) when specified by
     `frame-inhibit-implied-resize'. */
660 661
  int nlines;

662 663
  NSTRACE ("x_set_tool_bar_lines");

664 665 666
  if (FRAME_MINIBUF_ONLY_P (f))
    return;

667
  if (RANGED_INTEGERP (0, value, INT_MAX))
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
    nlines = XFASTINT (value);
  else
    nlines = 0;

  if (nlines)
    {
      FRAME_EXTERNAL_TOOL_BAR (f) = 1;
      update_frame_tool_bar (f);
    }
  else
    {
      if (FRAME_EXTERNAL_TOOL_BAR (f))
        {
          free_frame_tool_bar (f);
          FRAME_EXTERNAL_TOOL_BAR (f) = 0;
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697

          {
            EmacsView *view = FRAME_NS_VIEW (f);
            int fs_state = [view fullscreenState];

            if (fs_state == FULLSCREEN_MAXIMIZED)
              {
                [view setFSValue:FULLSCREEN_WIDTH];
              }
            else if (fs_state == FULLSCREEN_HEIGHT)
              {
                [view setFSValue:FULLSCREEN_NONE];
              }
          }
       }
698 699
    }

700 701 702 703 704 705 706 707 708 709 710 711
  {
    int inhibit
      = ((f->after_make_frame
	  && !f->tool_bar_resized
	  && (EQ (frame_inhibit_implied_resize, Qt)
	      || (CONSP (frame_inhibit_implied_resize)
		  && !NILP (Fmemq (Qtool_bar_lines,
				   frame_inhibit_implied_resize))))
	  && NILP (get_frame_param (f, Qfullscreen)))
	 ? 0
	 : 2);

712 713
    NSTRACE_MSG ("inhibit:%d", inhibit);

714 715 716
    frame_size_history_add (f, Qupdate_frame_tool_bar, 0, 0, Qnil);
    adjust_frame_size (f, -1, -1, inhibit, 0, Qtool_bar_lines);
  }
717 718 719
}


720
static void
721 722 723 724 725
x_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
{
  int old_width = FRAME_INTERNAL_BORDER_WIDTH (f);

  CHECK_TYPE_RANGED_INTEGER (int, arg);
726
  f->internal_border_width = XINT (arg);
727
  if (FRAME_INTERNAL_BORDER_WIDTH (f) < 0)
728
    f->internal_border_width = 0;
729 730 731 732 733

  if (FRAME_INTERNAL_BORDER_WIDTH (f) == old_width)
    return;

  if (FRAME_X_WINDOW (f) != 0)
734
    adjust_frame_size (f, -1, -1, 3, 0, Qinternal_border_width);
735 736 737 738 739

  SET_FRAME_GARBAGED (f);
}


740
static void
741 742 743 744
ns_implicitly_set_icon_type (struct frame *f)
{
  Lisp_Object tem;
  EmacsView *view = FRAME_NS_VIEW (f);
745
  id image = nil;
746 747 748 749
  Lisp_Object chain, elt;
  NSAutoreleasePool *pool;
  BOOL setMini = YES;

750
  NSTRACE ("ns_implicitly_set_icon_type");
751

752
  block_input ();
753 754
  pool = [[NSAutoreleasePool alloc] init];
  if (f->output_data.ns->miniimage
755
      && [[NSString stringWithUTF8String: SSDATA (f->name)]
756 757 758
               isEqualToString: [(NSImage *)f->output_data.ns->miniimage name]])
    {
      [pool release];
759
      unblock_input ();
760 761 762
      return;
    }

763
  tem = assq_no_quit (Qicon_type, f->param_alist);
764 765 766
  if (CONSP (tem) && ! NILP (XCDR (tem)))
    {
      [pool release];
767
      unblock_input ();
768 769 770 771
      return;
    }

  for (chain = Vns_icon_type_alist;
772
       image == nil && CONSP (chain);
773 774 775
       chain = XCDR (chain))
    {
      elt = XCAR (chain);
776
      /* special case: t means go by file type */
777
      if (SYMBOLP (elt) && EQ (elt, Qt) && SSDATA (f->name)[0] == '/')
778
        {
779
          NSString *str
780
	     = [NSString stringWithUTF8String: SSDATA (f->name)];
781 782 783 784 785 786
          if ([[NSFileManager defaultManager] fileExistsAtPath: str])
            image = [[[NSWorkspace sharedWorkspace] iconForFile: str] retain];
        }
      else if (CONSP (elt) &&
               STRINGP (XCAR (elt)) &&
               STRINGP (XCDR (elt)) &&
787
               fast_string_match (XCAR (elt), f->name) >= 0)
788 789 790 791 792
        {
          image = [EmacsImage allocInitFromFile: XCDR (elt)];
          if (image == nil)
            image = [[NSImage imageNamed:
                               [NSString stringWithUTF8String:
793
					    SSDATA (XCDR (elt))]] retain];
794 795 796 797 798 799 800 801 802 803 804 805 806
        }
    }

  if (image == nil)
    {
      image = [[[NSWorkspace sharedWorkspace] iconForFileType: @"text"] retain];
      setMini = NO;
    }

  [f->output_data.ns->miniimage release];
  f->output_data.ns->miniimage = image;
  [view setMiniwindowImage: setMini];
  [pool release];
807
  unblock_input ();
808 809 810 811
}


static void
812
x_set_icon_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
813 814 815 816 817
{
  EmacsView *view = FRAME_NS_VIEW (f);
  id image = nil;
  BOOL setMini = YES;

818
  NSTRACE ("x_set_icon_type");
819 820 821

  if (!NILP (arg) && SYMBOLP (arg))
    {
822
      arg =build_string (SSDATA (SYMBOL_NAME (arg)));
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
      store_frame_param (f, Qicon_type, arg);
    }

  /* do it the implicit way */
  if (NILP (arg))
    {
      ns_implicitly_set_icon_type (f);
      return;
    }

  CHECK_STRING (arg);

  image = [EmacsImage allocInitFromFile: arg];
  if (image == nil)
    image =[NSImage imageNamed: [NSString stringWithUTF8String:
838
                                            SSDATA (arg)]];
839 840 841 842 843 844 845 846 847 848 849

  if (image == nil)
    {
      image = [NSImage imageNamed: @"text"];
      setMini = NO;
    }

  f->output_data.ns->miniimage = image;
  [view setMiniwindowImage: setMini];
}

850
/* This is the same as the xfns.c definition.  */
851
static void
Dmitry Antipov's avatar
Dmitry Antipov committed
852
x_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
853
{
854
  set_frame_cursor_types (f, arg);
855 856
}

857 858
/* called to set mouse pointer color, but all other terms use it to
   initialize pointer types (and don't set the color ;) */
859
static void
860
x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
861
{
862
  /* don't think we can do this on Nextstep */
863 864 865
}


866 867 868 869
#define Str(x) #x
#define Xstr(x) Str(x)

static Lisp_Object
870
ns_appkit_version_str (void)
871
{
872
  char tmp[256];
873 874 875

#ifdef NS_IMPL_GNUSTEP
  sprintf(tmp, "gnustep-gui-%s", Xstr(GNUSTEP_GUI_VERSION));
Paul Eggert's avatar
Paul Eggert committed
876
#elif defined (NS_IMPL_COCOA)
877 878 879 880 881
  NSString *osversion
    = [[NSProcessInfo processInfo] operatingSystemVersionString];
  sprintf(tmp, "appkit-%.2f %s",
          NSAppKitVersionNumber,
          [osversion UTF8String]);
882 883 884 885 886 887 888
#else
  tmp = "ns-unknown";
#endif
  return build_string (tmp);
}


889 890 891 892
/* This is for use by x-server-version and collapses all version info we
   have into a single int.  For a better picture of the implementation
   running, use ns_appkit_version_str.*/
static int
893
ns_appkit_version_int (void)
894 895
{
#ifdef NS_IMPL_GNUSTEP
896
  return GNUSTEP_GUI_MAJOR_VERSION * 100 + GNUSTEP_GUI_MINOR_VERSION;
Paul Eggert's avatar
Paul Eggert committed
897
#elif defined (NS_IMPL_COCOA)
898 899 900 901 902 903
  return (int)NSAppKitVersionNumber;
#endif
  return 0;
}


904
static void
905
x_icon (struct frame *f, Lisp_Object parms)
906 907
/* --------------------------------------------------------------------------
   Strangely-named function to set icon position parameters in frame.
908
   This is irrelevant under macOS, but might be needed under GNUstep,
909 910 911 912 913 914 915
   depending on the window manager used.  Note, this is not a standard
   frame parameter-setter; it is called directly from x-create-frame.
   -------------------------------------------------------------------------- */
{
  Lisp_Object icon_x, icon_y;
  struct ns_display_info *dpyinfo = check_ns_display_info (Qnil);

916 917
  f->output_data.ns->icon_top = -1;
  f->output_data.ns->icon_left = -1;
918 919 920 921 922 923 924 925

  /* Set the position of the icon.  */
  icon_x = x_get_arg (dpyinfo, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
  icon_y = x_get_arg (dpyinfo, parms, Qicon_top, 0, 0,  RES_TYPE_NUMBER);
  if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
    {
      CHECK_NUMBER (icon_x);
      CHECK_NUMBER (icon_y);
926 927
      f->output_data.ns->icon_top = XINT (icon_y);
      f->output_data.ns->icon_left = XINT (icon_x);
928 929 930 931 932 933
    }
  else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
    error ("Both left and top icon corners of icon must be specified");
}


934
/* Note: see frame.c for template, also where generic functions are impl */
935