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

3
Copyright (C) 1989, 1992-1994, 2005-2006, 2008-2014 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 25 26 27 28
Originally by Carl Edman
Updated by Christian Limpach (chris@nice.ch)
OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
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 51
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
#include "macfont.h"
#endif
52 53
#endif

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
#if 0
int fns_trace_num = 1;
#define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",        \
                                  __FILE__, __LINE__, ++fns_trace_num)
#else
#define NSTRACE(x)
#endif

#ifdef HAVE_NS

extern NSArray *ns_send_types, *ns_return_types, *ns_drag_types;

extern Lisp_Object Qforeground_color;
extern Lisp_Object Qbackground_color;
extern Lisp_Object Qcursor_color;
extern Lisp_Object Qinternal_border_width;
extern Lisp_Object Qvisibility;
extern Lisp_Object Qcursor_type;
extern Lisp_Object Qicon_type;
extern Lisp_Object Qicon_name;
extern Lisp_Object Qicon_left;
extern Lisp_Object Qicon_top;
extern Lisp_Object Qtop;
extern Lisp_Object Qdisplay;
extern Lisp_Object Qvertical_scroll_bars;
79
extern Lisp_Object Qhorizontal_scroll_bars;
80 81 82 83
extern Lisp_Object Qauto_raise;
extern Lisp_Object Qauto_lower;
extern Lisp_Object Qbox;
extern Lisp_Object Qscroll_bar_width;
84
extern Lisp_Object Qscroll_bar_height;
85 86 87 88 89 90
extern Lisp_Object Qx_resource_name;
extern Lisp_Object Qface_set_after_frame_default;
extern Lisp_Object Qunderline, Qundefined;
extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;

Jan D's avatar
Jan D committed
91

92 93 94
Lisp_Object Qbuffered;
Lisp_Object Qfontsize;

95
EmacsTooltip *ns_tooltip = nil;
96 97

/* Need forward declaration here to preserve organizational integrity of file */
98
Lisp_Object Fx_open_connection (Lisp_Object, Lisp_Object, Lisp_Object);
99

100 101 102
/* Static variables to handle applescript execution.  */
static Lisp_Object as_script, *as_result;
static int as_status;
103

104
#ifdef GLYPH_DEBUG
105 106 107
static ptrdiff_t image_cache_refcount;
#endif

108

109 110 111 112 113 114
/* ==========================================================================

    Internal utility functions

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

115 116 117
/* 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,
118
   the first Nextstep display on the list.  */
119

120
static struct ns_display_info *
121
check_ns_display_info (Lisp_Object object)
122
{
123 124 125
  struct ns_display_info *dpyinfo = NULL;

  if (NILP (object))
126
    {
127 128 129
      struct frame *sf = XFRAME (selected_frame);

      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);
139 140

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

143
      dpyinfo = t->display_info.ns;
144
    }
145 146
  else if (STRINGP (object))
    dpyinfo = ns_display_info_for_name (object);
147 148
  else
    {
Dmitry Antipov's avatar
Dmitry Antipov committed
149
      struct frame *f = decode_window_system_frame (object);
150
      dpyinfo = FRAME_DISPLAY_INFO (f);
151
    }
152 153

  return dpyinfo;
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
}


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.  */
struct ns_display_info *
176
ns_display_info_for_name (Lisp_Object name)
177 178 179 180 181
{
  struct ns_display_info *dpyinfo;

  CHECK_STRING (name);

182 183 184
  for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
    if (!NILP (Fstring_equal (XCAR (dpyinfo->name_list_element), name)))
      return dpyinfo;
185

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

188 189
  Fx_open_connection (name, Qnil, Qnil);
  dpyinfo = x_display_list;
190 191

  if (dpyinfo == 0)
192
    error ("Display on %s not responding.\n", SDATA (name));
193 194 195 196

  return dpyinfo;
}

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
static NSString *
ns_filename_from_panel (NSSavePanel *panel)
{
#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  NSURL *url = [panel URL];
  NSString *str = [url path];
  return str;
#else
  return [panel filename];
#endif
}

static NSString *
ns_directory_from_panel (NSSavePanel *panel)
{
#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  NSURL *url = [panel directoryURL];
  NSString *str = [url path];
  return str;
#else
  return [panel directory];
#endif
}
220 221 222 223 224 225 226 227

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;
228
  NSMenuItem *item;
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
  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
280
x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
281 282
{
  NSColor *col;
283
  EmacsCGFloat r, g, b, alpha;
284 285 286 287 288 289 290 291 292 293 294

  if (ns_lisp_to_color (arg, &col))
    {
      store_frame_param (f, Qforeground_color, oldval);
      error ("Unknown color");
    }

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

295 296 297 298
  [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));

299 300 301 302 303 304 305 306 307 308 309
  if (FRAME_NS_VIEW (f))
    {
      update_face_from_frame_parameter (f, Qforeground_color, arg);
      /*recompute_basic_faces (f); */
      if (FRAME_VISIBLE_P (f))
        redraw_frame (f);
    }
}


static void
310
x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
311 312 313 314
{
  struct face *face;
  NSColor *col;
  NSView *view = FRAME_NS_VIEW (f);
315
  EmacsCGFloat r, g, b, alpha;
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330

  if (ns_lisp_to_color (arg, &col))
    {
      store_frame_param (f, Qbackground_color, oldval);
      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;
331 332 333 334 335

  [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));

336 337 338 339
  if (view != nil)
    {
      [[view window] setBackgroundColor: col];

340
      if (alpha != (EmacsCGFloat) 1.0)
341 342 343 344 345 346 347
          [[view window] setOpaque: NO];
      else
          [[view window] setOpaque: YES];

      face = FRAME_DEFAULT_FACE (f);
      if (face)
        {
348
          col = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f);
349 350
          face->background = ns_index_color
            ([col colorWithAlphaComponent: alpha], f);
351 352 353 354 355 356 357 358 359 360 361

          update_face_from_frame_parameter (f, Qbackground_color, arg);
        }

      if (FRAME_VISIBLE_P (f))
        redraw_frame (f);
    }
}


static void
362
x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
363 364 365 366 367 368 369 370 371
{
  NSColor *col;

  if (ns_lisp_to_color (arg, &col))
    {
      store_frame_param (f, Qcursor_color, oldval);
      error ("Unknown color");
    }

372 373
  [FRAME_CURSOR_COLOR (f) release];
  FRAME_CURSOR_COLOR (f) = [col retain];
374 375 376 377 378 379 380 381 382

  if (FRAME_VISIBLE_P (f))
    {
      x_update_cursor (f, 0);
      x_update_cursor (f, 1);
    }
  update_face_from_frame_parameter (f, Qcursor_color, arg);
}

383

384
static void
385
x_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
386 387
{
  NSView *view = FRAME_NS_VIEW (f);
388
  NSTRACE (x_set_icon_name);
389 390 391 392 393 394 395 396 397 398

  /* 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;

399
  fset_icon_name (f, arg);
400 401 402

  if (NILP (arg))
    {
403 404
      if (!NILP (f->title))
        arg = f->title;
405
      else
406
        /* Explicit name and no icon-name -> explicit_name.  */
407
        if (f->explicit_name)
408
          arg = f->name;
409 410
        else
          {
411 412 413
            /* No explicit name and no icon-name ->
               name has to be rebuild from icon_title_format.  */
            windows_or_buffers_changed = 62;
414 415 416 417 418
            return;
          }
    }

  /* Don't change the name if it's already NAME.  */
419 420
  if ([[view window] miniwindowTitle]
      && ([[[view window] miniwindowTitle]
421
             isEqualToString: [NSString stringWithUTF8String:
422
					  SSDATA (arg)]]))
423 424 425
    return;

  [[view window] setMiniwindowTitle:
426
        [NSString stringWithUTF8String: SSDATA (arg)]];
427 428 429
}

static void
Dmitry Antipov's avatar
Dmitry Antipov committed
430
ns_set_name_internal (struct frame *f, Lisp_Object name)
431
{
432 433 434
  struct gcpro gcpro1;
  Lisp_Object encoded_name, encoded_icon_name;
  NSString *str;
435 436
  NSView *view = FRAME_NS_VIEW (f);

437 438 439
  GCPRO1 (name);
  encoded_name = ENCODE_UTF_8 (name);
  UNGCPRO;
440

441
  str = [NSString stringWithUTF8String: SSDATA (encoded_name)];
442

443 444 445
  /* Don't change the name if it's already NAME.  */
  if (! [[[view window] title] isEqualToString: str])
    [[view window] setTitle: str];
446

447
  if (!STRINGP (f->icon_name))
448
    encoded_icon_name = encoded_name;
449
  else
450
    encoded_icon_name = ENCODE_UTF_8 (f->icon_name);
451

452
  str = [NSString stringWithUTF8String: SSDATA (encoded_icon_name)];
453

454 455
  if ([[view window] miniwindowTitle]
      && ! [[[view window] miniwindowTitle] isEqualToString: str])
456
    [[view window] setMiniwindowTitle: str];
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471

}

static void
ns_set_name (struct frame *f, Lisp_Object name, int explicit)
{
  NSTRACE (ns_set_name);

  /* 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))
472
        update_mode_lines = 21;
473 474 475 476 477 478 479

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

  if (NILP (name))
480
    name = build_string ([ns_app_name UTF8String]);
481 482 483 484
  else
    CHECK_STRING (name);

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

488
  fset_name (f, name);
489

490
  /* Title overrides explicit name.  */
491 492
  if (! NILP (f->title))
    name = f->title;
493

494
  ns_set_name_internal (f, name);
495 496 497 498 499 500 501
}


/* 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
502
x_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
503
{
504
  NSTRACE (x_explicitly_set_name);
505 506 507 508 509 510 511 512
  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
513
x_implicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
514 515
{
  NSTRACE (x_implicitly_set_name);
516 517 518 519

  /* Deal with NS specific format t.  */
  if (FRAME_NS_P (f) && ((FRAME_ICONIFIED_P (f) && EQ (Vicon_title_format, Qt))
                         || EQ (Vframe_title_format, Qt)))
520
    ns_set_name_as_filename (f);
521 522 523 524 525 526
  else
    ns_set_name (f, arg, 0);
}


/* Change the title of frame F to NAME.
527
   If NAME is nil, use the frame name as the title.  */
528 529

static void
530
x_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name)
531
{
532
  NSTRACE (x_set_title);
533
  /* Don't change the title if it's already NAME.  */
534
  if (EQ (name, f->title))
535 536
    return;

537
  update_mode_lines = 22;
538

539
  fset_title (f, name);
540 541

  if (NILP (name))
542
    name = f->name;
543 544 545 546
  else
    CHECK_STRING (name);

  ns_set_name_internal (f, name);
547 548 549 550 551 552
}


void
ns_set_name_as_filename (struct frame *f)
{
553
  NSView *view;
554
  Lisp_Object name, filename;
555
  Lisp_Object buf = XWINDOW (f->selected_window)->contents;
556 557
  const char *title;
  NSAutoreleasePool *pool;
558
  struct gcpro gcpro1;
559 560
  Lisp_Object encoded_name, encoded_filename;
  NSString *str;
561 562
  NSTRACE (ns_set_name_as_filename);

Jan Djärv's avatar
Jan Djärv committed
563
  if (f->explicit_name || ! NILP (f->title))
564 565
    return;

566
  block_input ();
567
  pool = [[NSAutoreleasePool alloc] init];
Jan Djärv's avatar
Jan Djärv committed
568 569
  filename = BVAR (XBUFFER (buf), filename);
  name = BVAR (XBUFFER (buf), name);
570 571

  if (NILP (name))
572 573 574 575 576 577
    {
      if (! NILP (filename))
        name = Ffile_name_nondirectory (filename);
      else
        name = build_string ([ns_app_name UTF8String]);
    }
578

579 580 581 582
  GCPRO1 (name);
  encoded_name = ENCODE_UTF_8 (name);
  UNGCPRO;

583 584
  view = FRAME_NS_VIEW (f);

585 586 587
  title = FRAME_ICONIFIED_P (f) ? [[[view window] miniwindowTitle] UTF8String]
                                : [[[view window] title] UTF8String];

588
  if (title && (! strcmp (title, SSDATA (encoded_name))))
589 590
    {
      [pool release];
591
      unblock_input ();
592 593 594
      return;
    }

595
  str = [NSString stringWithUTF8String: SSDATA (encoded_name)];
596 597 598 599
  if (str == nil) str = @"Bad coding";

  if (FRAME_ICONIFIED_P (f))
    [[view window] setMiniwindowTitle: str];
600
  else
601
    {
602 603 604
      NSString *fstr;

      if (! NILP (filename))
605
        {
606 607 608 609
          GCPRO1 (filename);
          encoded_filename = ENCODE_UTF_8 (filename);
          UNGCPRO;

610
          fstr = [NSString stringWithUTF8String: SSDATA (encoded_filename)];
611 612 613 614 615 616 617 618
          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
619 620
        }
      else
621 622 623 624
        fstr = @"";

      [[view window] setRepresentedFilename: fstr];
      [[view window] setTitle: str];
625
      fset_name (f, name);
626
    }
627

628
  [pool release];
629
  unblock_input ();
630 631 632 633
}


void
634
ns_set_doc_edited (struct frame *f, Lisp_Object arg)
635 636 637
{
  NSView *view = FRAME_NS_VIEW (f);
  NSAutoreleasePool *pool;
638
  if (!MINI_WINDOW_P (XWINDOW (f->selected_window)))
639
    {
640
      block_input ();
641 642 643
      pool = [[NSAutoreleasePool alloc] init];
      [[view window] setDocumentEdited: !NILP (arg)];
      [pool release];
644
      unblock_input ();
645
    }
646 647 648
}


649 650
void
x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
651 652 653 654 655
{
  int nlines;
  if (FRAME_MINIBUF_ONLY_P (f))
    return;

656
  if (TYPE_RANGED_INTEGERP (int, value))
657 658 659 660 661 662 663 664
    nlines = XINT (value);
  else
    nlines = 0;

  FRAME_MENU_BAR_LINES (f) = 0;
  if (nlines)
    {
      FRAME_EXTERNAL_MENU_BAR (f) = 1;
665 666
      /* does for all frames, whereas we just want for one frame
	 [NSMenu setMenuBarVisible: YES]; */
667 668 669 670 671
    }
  else
    {
      if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
        free_frame_menubar (f);
672
      /*      [NSMenu setMenuBarVisible: NO]; */
673 674 675 676 677
      FRAME_EXTERNAL_MENU_BAR (f) = 0;
    }
}


678
/* toolbar support */
679 680
void
x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
681 682 683 684 685 686
{
  int nlines;

  if (FRAME_MINIBUF_ONLY_P (f))
    return;

687
  if (RANGED_INTEGERP (0, value, INT_MAX))
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
    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;
        }
    }

706
  x_set_window_size (f, 0, f->text_cols, f->text_lines, 0);
707 708 709
}


710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
void
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);
  FRAME_INTERNAL_BORDER_WIDTH (f) = XINT (arg);
  if (FRAME_INTERNAL_BORDER_WIDTH (f) < 0)
    FRAME_INTERNAL_BORDER_WIDTH (f) = 0;

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

  if (FRAME_X_WINDOW (f) != 0)
    adjust_frame_size (f, -1, -1, 3, 0);

  SET_FRAME_GARBAGED (f);
}


730
static void
731 732 733 734
ns_implicitly_set_icon_type (struct frame *f)
{
  Lisp_Object tem;
  EmacsView *view = FRAME_NS_VIEW (f);
735
  id image = nil;
736 737 738 739 740 741
  Lisp_Object chain, elt;
  NSAutoreleasePool *pool;
  BOOL setMini = YES;

  NSTRACE (ns_implicitly_set_icon_type);

742
  block_input ();
743 744
  pool = [[NSAutoreleasePool alloc] init];
  if (f->output_data.ns->miniimage
745
      && [[NSString stringWithUTF8String: SSDATA (f->name)]
746 747 748
               isEqualToString: [(NSImage *)f->output_data.ns->miniimage name]])
    {
      [pool release];
749
      unblock_input ();
750 751 752
      return;
    }

753
  tem = assq_no_quit (Qicon_type, f->param_alist);
754 755 756
  if (CONSP (tem) && ! NILP (XCDR (tem)))
    {
      [pool release];
757
      unblock_input ();
758 759 760 761
      return;
    }

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

  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];
797
  unblock_input ();
798 799 800 801
}


static void
802
x_set_icon_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
803 804 805 806 807
{
  EmacsView *view = FRAME_NS_VIEW (f);
  id image = nil;
  BOOL setMini = YES;

808
  NSTRACE (x_set_icon_type);
809 810 811

  if (!NILP (arg) && SYMBOLP (arg))
    {
812
      arg =build_string (SSDATA (SYMBOL_NAME (arg)));
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
      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:
828
                                            SSDATA (arg)]];
829 830 831 832 833 834 835 836 837 838 839 840

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

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


841
/* TODO: move to nsterm? */
842 843 844 845 846
int
ns_lisp_to_cursor_type (Lisp_Object arg)
{
  char *str;
  if (XTYPE (arg) == Lisp_String)
847
    str = SSDATA (arg);
848
  else if (XTYPE (arg) == Lisp_Symbol)
849
    str = SSDATA (SYMBOL_NAME (arg));
850
  else return -1;
851 852 853 854 855
  if (!strcmp (str, "box"))	return FILLED_BOX_CURSOR;
  if (!strcmp (str, "hollow"))	return HOLLOW_BOX_CURSOR;
  if (!strcmp (str, "hbar"))	return HBAR_CURSOR;
  if (!strcmp (str, "bar"))	return BAR_CURSOR;
  if (!strcmp (str, "no"))	return NO_CURSOR;
856 857 858 859 860 861 862 863 864
  return -1;
}


Lisp_Object
ns_cursor_type_to_lisp (int arg)
{
  switch (arg)
    {
865 866 867 868 869 870
    case FILLED_BOX_CURSOR: return Qbox;
    case HOLLOW_BOX_CURSOR: return intern ("hollow");
    case HBAR_CURSOR:	    return intern ("hbar");
    case BAR_CURSOR:	    return intern ("bar");
    case NO_CURSOR:
    default:		    return intern ("no");
871 872 873
    }
}

874
/* This is the same as the xfns.c definition.  */
875
static void
Dmitry Antipov's avatar
Dmitry Antipov committed
876
x_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
877
{
878
  set_frame_cursor_types (f, arg);
879 880
}

881 882
/* called to set mouse pointer color, but all other terms use it to
   initialize pointer types (and don't set the color ;) */
883
static void
884
x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
885
{
886
  /* don't think we can do this on Nextstep */
887 888 889
}


890 891 892 893
#define Str(x) #x
#define Xstr(x) Str(x)

static Lisp_Object
894
ns_appkit_version_str (void)
895
{
896
  char tmp[256];
897 898 899

#ifdef NS_IMPL_GNUSTEP
  sprintf(tmp, "gnustep-gui-%s", Xstr(GNUSTEP_GUI_VERSION));
Paul Eggert's avatar
Paul Eggert committed
900
#elif defined (NS_IMPL_COCOA)
901 902 903 904 905
  NSString *osversion
    = [[NSProcessInfo processInfo] operatingSystemVersionString];
  sprintf(tmp, "appkit-%.2f %s",
          NSAppKitVersionNumber,
          [osversion UTF8String]);
906 907 908 909 910 911 912
#else
  tmp = "ns-unknown";
#endif
  return build_string (tmp);
}


913 914 915 916
/* 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
917
ns_appkit_version_int (void)
918 919
{
#ifdef NS_IMPL_GNUSTEP
920
  return GNUSTEP_GUI_MAJOR_VERSION * 100 + GNUSTEP_GUI_MINOR_VERSION;
Paul Eggert's avatar
Paul Eggert committed
921
#elif defined (NS_IMPL_COCOA)
922 923 924 925 926 927
  return (int)NSAppKitVersionNumber;
#endif
  return 0;
}


928
static void
929
x_icon (struct frame *f, Lisp_Object parms)
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
/* --------------------------------------------------------------------------
   Strangely-named function to set icon position parameters in frame.
   This is irrelevant under OS X, but might be needed under GNUstep,
   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);

  f->output_data.ns->icon_top = Qnil;
  f->output_data.ns->icon_left = Qnil;

  /* 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);
      f->output_data.ns->icon_top = icon_y;
      f->output_data.ns->icon_left = 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
/* Note: see frame.c for template, also where generic functions are impl */
959 960 961 962
frame_parm_handler ns_frame_parm_handlers[] =
{
  x_set_autoraise, /* generic OK */
  x_set_autolower, /* generic OK */
963
  x_set_background_color,
964 965
  0, /* x_set_border_color,  may be impossible under Nextstep */
  0, /* x_set_border_width,  may be impossible under Nextstep */
966 967
  x_set_cursor_color,
  x_set_cursor_type,
968
  x_set_font, /* generic OK */
969 970 971
  x_set_foreground_color,
  x_set_icon_name,
  x_set_icon_type,
972
  x_set_internal_border_width, /* generic OK */
973 974
  0, /* x_set_right_divider_width */
  0, /* x_set_bottom_divider_width */
975
  x_set_menu_bar_lines,
976 977
  x_set_mouse_color,
  x_explicitly_set_name,
978
  x_set_scroll_bar_width, /* generic OK */
979
  x_set_scroll_bar_height, /* generic OK */
980
  x_set_title,
981 982
  x_set_unsplittable, /* generic OK */
  x_set_vertical_scroll_bars, /* generic OK */
983
  x_set_horizontal_scroll_bars, /* generic OK */
984
  x_set_visibility, /* generic OK */
985
  x_set_tool_bar_lines,
986 987 988 989
  0, /* x_set_scroll_bar_foreground, will ignore (not possible on NS) */
  0, /* x_set_scroll_bar_background,  will ignore (not possible on NS) */
  x_set_screen_gamma, /* generic OK */
  x_set_line_spacing, /* generic OK, sets f->extra_line_spacing to int */
990 991
  x_set_left_fringe, /* generic OK */
  x_set_right_fringe, /* generic OK */
992
  0, /* x_set_wait_for_wm, will ignore */
993
  x_set_fullscreen, /* generic OK */
994
  x_set_font_backend, /* generic OK */
995
  x_set_alpha,
996 997
  0, /* x_set_sticky */
  0, /* x_set_tool_bar_position */
998 999 1000
};


1001 1002 1003
/* Handler for signals raised during x_create_frame.
   FRAME is the frame which is partially constructed.  */

1004
static void
1005 1006 1007 1008 1009 1010 1011 1012
unwind_create_frame (Lisp_Object frame)
{
  struct frame *f = XFRAME (frame);

  /* If frame is already dead, nothing to do.  This can happen if the
     display is disconnected after the frame has become official, but
     before x_create_frame removes the unwind protect.  */
  if (!FRAME_LIVE_P (f))
1013
    return;
1014 1015

  /* If frame is ``official'', nothing to do.  */
Jan Djärv's avatar
Jan Djärv committed
1016
  if (NILP (Fmemq (frame, Vframe_list)))
1017
    {
1018
#if defined GLYPH_DEBUG && defined ENABLE_CHECKING
1019
      struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1020 1021 1022 1023 1024
#endif

      x_free_frame_resources (f);
      free_glyphs (f);

1025
#ifdef GLYPH_DEBUG
1026
      /* Check that reference counts are indeed correct.  */
1027
      eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount);
1028 1029 1030 1031
#endif
    }
}

1032 1033 1034 1035
/*
 * Read geometry related parameters from preferences if not in PARMS.
 * Returns the union of parms and any preferences read.
 */
1036

1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
static Lisp_Object
get_geometry_from_preferences (struct ns_display_info *dpyinfo,
                               Lisp_Object parms)
{
  struct {
    const char *val;
    const char *cls;
    Lisp_Object tem;
  } r[] = {
    { "width",  "Width", Qwidth },
    { "height", "Height", Qheight },
    { "left", "Left", Qleft },
    { "top", "Top", Qtop },
  };

  int i;
1053
  for (i = 0; i < ARRAYELTS (r); ++i)
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
    {
      if (NILP (Fassq (r[i].tem, parms)))
        {
          Lisp_Object value
            = x_get_arg (dpyinfo, parms, r[i].tem, r[i].val, r[i].cls,
                         RES_TYPE_NUMBER);
          if (! EQ (value, Qunbound))
            parms = Fcons (Fcons (r[i].tem, value), parms);
        }
    }
1064

1065 1066
  return parms;
}
1067 1068 1069 1070 1071 1072 1073

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

    Lisp definitions

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

1074
DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
1075
       1, 1, 0,
1076
       doc: /* Make a new Nextstep window, called a "frame" in Emacs terms.
1077 1078 1079 1080 1081
Return an Emacs frame object.
PARMS is an alist of frame parameters.
If the parameters specify that the frame should not have a minibuffer,
and do not specify a specific minibuffer window to use,
then `default-minibuffer-frame' must be a frame whose minibuffer can
1082 1083 1084
be shared by the new frame.

This function is an internal primitive--use `make-frame' instead.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
1085
     (Lisp_Object parms)
1086 1087 1088 1089 1090
{
  struct frame *f;
  Lisp_Object frame, tem;
  Lisp_Object name;
  int minibuffer_only = 0;
1091
  long window_prompting = 0;
1092
  int width, height;