xfns.c 186 KB
Newer Older
Jim Blandy's avatar
Jim Blandy committed
1
/* Functions for the X window system.
Glenn Morris's avatar
Glenn Morris committed
2

3
Copyright (C) 1989, 1992-2013 Free Software Foundation, Inc.
Jim Blandy's avatar
Jim Blandy committed
4 5 6

This file is part of GNU Emacs.

7
GNU Emacs is free software: you can redistribute it and/or modify
Jim Blandy's avatar
Jim Blandy committed
8
it under the terms of the GNU General Public License as published by
9 10
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jim Blandy's avatar
Jim Blandy committed
11 12 13 14 15 16 17

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
18
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Jim Blandy's avatar
Jim Blandy committed
19

Richard M. Stallman's avatar
Richard M. Stallman committed
20
#include <config.h>
21
#include <stdio.h>
22
#include <math.h>
23 24
#include <unistd.h>

Jim Blandy's avatar
Jim Blandy committed
25 26
#include "lisp.h"
#include "xterm.h"
Jim Blandy's avatar
Jim Blandy committed
27
#include "frame.h"
Jim Blandy's avatar
Jim Blandy committed
28
#include "window.h"
29
#include "character.h"
Jim Blandy's avatar
Jim Blandy committed
30
#include "buffer.h"
Kenichi Handa's avatar
Kenichi Handa committed
31
#include "intervals.h"
Jim Blandy's avatar
Jim Blandy committed
32
#include "dispextern.h"
Jim Blandy's avatar
Jim Blandy committed
33
#include "keyboard.h"
34
#include "blockinput.h"
35
#include <epaths.h>
Karl Heuer's avatar
Karl Heuer committed
36
#include "charset.h"
Kenichi Handa's avatar
Kenichi Handa committed
37
#include "coding.h"
Karl Heuer's avatar
Karl Heuer committed
38
#include "fontset.h"
39 40
#include "systime.h"
#include "termhooks.h"
41
#include "atimer.h"
42
#include "termchar.h"
Kenichi Handa's avatar
Kenichi Handa committed
43 44
#include "font.h"

45 46
#include <sys/types.h>
#include <sys/stat.h>
Jim Blandy's avatar
Jim Blandy committed
47

48
#if 1 /* Used to be #ifdef EMACS_BITMAP_FILES, but this should always work.  */
49 50
#include "bitmaps/gray.xbm"
#else
Jim Blandy's avatar
Jim Blandy committed
51
#include <X11/bitmaps/gray>
52
#endif
Jim Blandy's avatar
Jim Blandy committed
53

54 55
#include "xsettings.h"

56 57 58 59 60 61 62
#ifdef HAVE_XRANDR
#include <X11/extensions/Xrandr.h>
#endif
#ifdef HAVE_XINERAMA
#include <X11/extensions/Xinerama.h>
#endif

Jan Djärv's avatar
Jan Djärv committed
63 64 65 66
#ifdef USE_GTK
#include "gtkutil.h"
#endif

67 68 69
#ifdef USE_X_TOOLKIT
#include <X11/Shell.h>

70
#ifndef USE_MOTIF
Chong Yidong's avatar
Chong Yidong committed
71 72
#ifdef HAVE_XAW3D
#include <X11/Xaw3d/Paned.h>
Chong Yidong's avatar
Chong Yidong committed
73
#include <X11/Xaw3d/Label.h>
Chong Yidong's avatar
Chong Yidong committed
74
#else /* !HAVE_XAW3D */
75 76
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Label.h>
Chong Yidong's avatar
Chong Yidong committed
77
#endif /* HAVE_XAW3D */
78
#endif /* USE_MOTIF */
79 80 81 82 83

#ifdef USG
#undef USG	/* ####KLUDGE for Solaris 2.2 and up */
#include <X11/Xos.h>
#define USG
84 85
#ifdef USG /* Pacify gcc -Wunused-macros.  */
#endif
86 87 88 89 90 91 92 93
#else
#include <X11/Xos.h>
#endif

#include "widget.h"

#include "../lwlib/lwlib.h"

94 95 96 97
#ifdef USE_MOTIF
#include <Xm/Xm.h>
#include <Xm/DialogS.h>
#include <Xm/FileSB.h>
Jan D's avatar
Jan D committed
98 99
#include <Xm/List.h>
#include <Xm/TextF.h>
100 101
#endif

102 103 104 105
#ifdef USE_LUCID
#include "../lwlib/xlwmenu.h"
#endif

Juanma Barranquero's avatar
Juanma Barranquero committed
106
#if !defined (NO_EDITRES)
107
#define HACK_EDITRES
108
extern void _XEditResCheckMessages (Widget, XtPointer, XEvent *, Boolean *);
Dan Nicolaescu's avatar
Dan Nicolaescu committed
109
#endif /* not defined NO_EDITRES */
110

111 112
/* Unique id counter for widgets created by the Lucid Widget Library.  */

113 114
extern LWLIB_ID widget_id_tick;

115 116 117 118
#ifdef USE_MOTIF

#endif /* USE_MOTIF */

119 120
#endif /* USE_X_TOOLKIT */

Kenichi Handa's avatar
Kenichi Handa committed
121 122 123 124
#ifdef USE_GTK

#endif /* USE_GTK */

Richard M. Stallman's avatar
Richard M. Stallman committed
125 126
#define MAXREQUEST(dpy) (XMaxRequestSize (dpy))

127 128 129
static Lisp_Object Qsuppress_icon;
static Lisp_Object Qundefined_color;
static Lisp_Object Qcompound_text, Qcancel_timer;
130
Lisp_Object Qfont_param;
Jim Blandy's avatar
Jim Blandy committed
131

132
#ifdef GLYPH_DEBUG
133 134
static ptrdiff_t image_cache_refcount;
static int dpyinfo_refcount;
135 136
#endif

137 138
static struct x_display_info *x_display_info_for_name (Lisp_Object);

139
/* Let the user specify an X display with a Lisp object.
140
   OBJECT may be nil, a frame or a terminal object.
141 142 143
   nil stands for the selected frame--or, if that is not an X frame,
   the first X display on the list.  */

144
struct x_display_info *
145
check_x_display_info (Lisp_Object object)
146
{
147
  struct x_display_info *dpyinfo = NULL;
148

149
  if (NILP (object))
150
    {
Gerd Moellmann's avatar
Gerd Moellmann committed
151
      struct frame *sf = XFRAME (selected_frame);
152

Gerd Moellmann's avatar
Gerd Moellmann committed
153
      if (FRAME_X_P (sf) && FRAME_LIVE_P (sf))
154
	dpyinfo = FRAME_DISPLAY_INFO (sf);
155
      else if (x_display_list != 0)
156
	dpyinfo = x_display_list;
157 158 159
      else
	error ("X windows are not in use or not initialized");
    }
160
  else if (TERMINALP (object))
161
    {
162
      struct terminal *t = get_terminal (object, 1);
163

164
      if (t->type != output_x_window)
165
        error ("Terminal %d is not an X display", t->id);
166

167
      dpyinfo = t->display_info.x;
168
    }
169 170
  else if (STRINGP (object))
    dpyinfo = x_display_info_for_name (object);
171 172
  else
    {
Dmitry Antipov's avatar
Dmitry Antipov committed
173
      struct frame *f = decode_window_system_frame (object);
174
      dpyinfo = FRAME_DISPLAY_INFO (f);
175
    }
176 177

  return dpyinfo;
178
}
179

180
/* Store the screen positions of frame F into XPTR and YPTR.
181 182 183 184
   These are the positions of the containing window manager window,
   not Emacs's own window.  */

void
Dmitry Antipov's avatar
Dmitry Antipov committed
185
x_real_positions (struct frame *f, int *xptr, int *yptr)
186
{
187
  int win_x, win_y, outer_x IF_LINT (= 0), outer_y IF_LINT (= 0);
188 189 190
  int real_x = 0, real_y = 0;
  int had_errors = 0;
  Window win = f->output_data.x->parent_desc;
191 192
  Atom actual_type;
  unsigned long actual_size, bytes_remaining;
193
  int rc, actual_format;
194
  struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
195 196 197 198
  long max_len = 400;
  Display *dpy = FRAME_X_DISPLAY (f);
  unsigned char *tmp_data = NULL;
  Atom target_type = XA_CARDINAL;
199

200
  block_input ();
201

202
  x_catch_errors (dpy);
203

204
  if (win == dpyinfo->root_window)
205 206 207 208 209 210 211
    win = FRAME_OUTER_WINDOW (f);

  /* This loop traverses up the containment tree until we hit the root
     window.  Window managers may intersect many windows between our window
     and the root window.  The window we find just before the root window
     should be the outer WM window. */
  for (;;)
212
    {
213 214 215
      Window wm_window, rootw;
      Window *tmp_children;
      unsigned int tmp_nchildren;
216
      int success;
217

218 219
      success = XQueryTree (FRAME_X_DISPLAY (f), win, &rootw,
			    &wm_window, &tmp_children, &tmp_nchildren);
220

221
      had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
222

223 224 225 226
      /* Don't free tmp_children if XQueryTree failed.  */
      if (! success)
	break;

227
      XFree (tmp_children);
228

229 230
      if (wm_window == rootw || had_errors)
        break;
231

232 233
      win = wm_window;
    }
234

235 236
  if (! had_errors)
    {
237
      unsigned int ign;
238
      Window child, rootw;
239

240 241 242 243 244 245 246 247 248 249 250 251 252 253
      /* Get the real coordinates for the WM window upper left corner */
      XGetGeometry (FRAME_X_DISPLAY (f), win,
                    &rootw, &real_x, &real_y, &ign, &ign, &ign, &ign);

      /* Translate real coordinates to coordinates relative to our
         window.  For our window, the upper left corner is 0, 0.
         Since the upper left corner of the WM window is outside
         our window, win_x and win_y will be negative:

         ------------------          ---> x
         |      title                |
         | -----------------         v y
         | |  our window
      */
254
      XTranslateCoordinates (FRAME_X_DISPLAY (f),
255

256
			     /* From-window, to-window.  */
257
			     FRAME_DISPLAY_INFO (f)->root_window,
258
                             FRAME_X_WINDOW (f),
259

260
			     /* From-position, to-position.  */
261
                             real_x, real_y, &win_x, &win_y,
262

263 264
			     /* Child of win.  */
			     &child);
265

266
      if (FRAME_X_WINDOW (f) == FRAME_OUTER_WINDOW (f))
267
	{
268 269
          outer_x = win_x;
          outer_y = win_y;
270
	}
271 272 273
      else
        {
          XTranslateCoordinates (FRAME_X_DISPLAY (f),
274

275
                                 /* From-window, to-window.  */
276
                                 FRAME_DISPLAY_INFO (f)->root_window,
277
                                 FRAME_OUTER_WINDOW (f),
278

279 280
                                 /* From-position, to-position.  */
                                 real_x, real_y, &outer_x, &outer_y,
281

282 283
                                 /* Child of win.  */
                                 &child);
284
	}
285

286 287
      had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
    }
288

289 290 291 292 293 294 295 296 297 298 299 300

  if (dpyinfo->root_window == f->output_data.x->parent_desc)
    {
      /* Try _NET_FRAME_EXTENTS if our parent is the root window.  */
      rc = XGetWindowProperty (dpy, win, dpyinfo->Xatom_net_frame_extents,
                               0, max_len, False, target_type,
                               &actual_type, &actual_format, &actual_size,
                               &bytes_remaining, &tmp_data);

      if (rc == Success && actual_type == target_type && !x_had_errors_p (dpy)
          && actual_size == 4 && actual_format == 32)
        {
301
          unsigned int ign;
302
          Window rootw;
303
          long *fe = (long *)tmp_data;
304 305 306 307 308 309 310 311 312 313 314 315

          XGetGeometry (FRAME_X_DISPLAY (f), win,
                        &rootw, &real_x, &real_y, &ign, &ign, &ign, &ign);
          outer_x = -fe[0];
          outer_y = -fe[2];
          real_x -= fe[0];
          real_y -= fe[2];
        }
    }

  if (tmp_data) XFree (tmp_data);

316
  x_uncatch_errors ();
317

318
  unblock_input ();
319 320

  if (had_errors) return;
321

322 323 324 325 326
  f->x_pixels_diff = -win_x;
  f->y_pixels_diff = -win_y;

  FRAME_X_OUTPUT (f)->x_pixels_outer_diff = -outer_x;
  FRAME_X_OUTPUT (f)->y_pixels_outer_diff = -outer_y;
327 328 329

  *xptr = real_x;
  *yptr = real_y;
330 331
}

Jim Blandy's avatar
Jim Blandy committed
332

333

334 335 336 337

/* Gamma-correct COLOR on frame F.  */

void
338
gamma_correct (struct frame *f, XColor *color)
339 340 341 342 343 344 345 346 347 348
{
  if (f->gamma)
    {
      color->red = pow (color->red / 65535.0, f->gamma) * 65535.0 + 0.5;
      color->green = pow (color->green / 65535.0, f->gamma) * 65535.0 + 0.5;
      color->blue = pow (color->blue / 65535.0, f->gamma) * 65535.0 + 0.5;
    }
}


349
/* Decide if color named COLOR_NAME is valid for use on frame F.  If
350 351
   so, return the RGB values in COLOR.  If ALLOC_P,
   allocate the color.  Value is false if COLOR_NAME is invalid, or
352
   no color could be allocated.  */
353

354
bool
355
x_defined_color (struct frame *f, const char *color_name,
356
		 XColor *color, bool alloc_p)
Jim Blandy's avatar
Jim Blandy committed
357
{
358
  bool success_p = 0;
359 360
  Display *dpy = FRAME_X_DISPLAY (f);
  Colormap cmap = FRAME_X_COLORMAP (f);
Jim Blandy's avatar
Jim Blandy committed
361

362
  block_input ();
363 364 365 366
#ifdef USE_GTK
  success_p = xg_check_special_colors (f, color_name, color);
#endif
  if (!success_p)
367
    success_p = XParseColor (dpy, cmap, color_name, color) != 0;
368 369
  if (success_p && alloc_p)
    success_p = x_alloc_nearest_color (f, cmap, color);
370
  unblock_input ();
Jim Blandy's avatar
Jim Blandy committed
371

372
  return success_p;
Jim Blandy's avatar
Jim Blandy committed
373 374
}

375 376 377 378

/* Return the pixel color value for color COLOR_NAME on frame F.  If F
   is a monochrome frame, return MONO_COLOR regardless of what ARG says.
   Signal an error if color can't be allocated.  */
Jim Blandy's avatar
Jim Blandy committed
379

380
static int
Dmitry Antipov's avatar
Dmitry Antipov committed
381
x_decode_color (struct frame *f, Lisp_Object color_name, int mono_color)
Jim Blandy's avatar
Jim Blandy committed
382
{
383
  XColor cdef;
Jim Blandy's avatar
Jim Blandy committed
384

385
  CHECK_STRING (color_name);
Jim Blandy's avatar
Jim Blandy committed
386

387 388 389
#if 0 /* Don't do this.  It's wrong when we're not using the default
	 colormap, it makes freeing difficult, and it's probably not
	 an important optimization.  */
390
  if (strcmp (SDATA (color_name), "black") == 0)
391
    return BLACK_PIX_DEFAULT (f);
392
  else if (strcmp (SDATA (color_name), "white") == 0)
393
    return WHITE_PIX_DEFAULT (f);
394
#endif
Jim Blandy's avatar
Jim Blandy committed
395

396
  /* Return MONO_COLOR for monochrome frames.  */
397
  if (FRAME_DISPLAY_INFO (f)->n_planes == 1)
398
    return mono_color;
Jim Blandy's avatar
Jim Blandy committed
399

400
  /* x_defined_color is responsible for coping with failures
401
     by looking for a near-miss.  */
402
  if (x_defined_color (f, SSDATA (color_name), &cdef, 1))
403 404
    return cdef.pixel;

405
  signal_error ("Undefined color", color_name);
Jim Blandy's avatar
Jim Blandy committed
406
}
407 408


Jim Blandy's avatar
Jim Blandy committed
409

Gerd Moellmann's avatar
Gerd Moellmann committed
410 411 412 413 414
/* Change the `wait-for-wm' frame parameter of frame F.  OLD_VALUE is
   the previous value of that parameter, NEW_VALUE is the new value.
   See also the comment of wait_for_wm in struct x_output.  */

static void
415
x_set_wait_for_wm (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
Gerd Moellmann's avatar
Gerd Moellmann committed
416 417 418 419
{
  f->output_data.x->wait_for_wm = !NILP (new_value);
}

420 421 422 423 424 425 426 427 428 429 430
static void
x_set_tool_bar_position (struct frame *f,
                         Lisp_Object new_value,
                         Lisp_Object old_value)
{
  if (! EQ (new_value, Qleft) && ! EQ (new_value, Qright)
      && ! EQ (new_value, Qbottom) && ! EQ (new_value, Qtop))
    return;
  if (EQ (new_value, old_value)) return;

#ifdef USE_GTK
431 432
  xg_change_toolbar_position (f, new_value);
  fset_tool_bar_position (f, new_value);
433 434 435
#endif
}

436 437
#ifdef USE_GTK

438 439
/* Set icon from FILE for frame F.  By using GTK functions the icon
   may be any format that GdkPixbuf knows about, i.e. not just bitmaps.  */
440 441

int
Dmitry Antipov's avatar
Dmitry Antipov committed
442
xg_set_icon (struct frame *f, Lisp_Object file)
443
{
444 445
  int result = 0;
  Lisp_Object found;
446

447 448 449 450 451 452
  found = x_find_image_file (file);

  if (! NILP (found))
    {
      GdkPixbuf *pixbuf;
      GError *err = NULL;
453
      char *filename = SSDATA (found);
454
      block_input ();
455 456 457 458 459 460 461 462 463 464 465 466 467 468

      pixbuf = gdk_pixbuf_new_from_file (filename, &err);

      if (pixbuf)
	{
	  gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
			       pixbuf);
	  g_object_unref (pixbuf);

	  result = 1;
	}
      else
	g_error_free (err);

469
      unblock_input ();
470 471 472
    }

  return result;
473
}
474 475

int
Dmitry Antipov's avatar
Dmitry Antipov committed
476
xg_set_icon_from_xpm_data (struct frame *f, const char **data)
477
{
478
  GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data (data);
479 480

  if (!pixbuf)
481
    return 0;
482

483
  gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), pixbuf);
484 485 486
  g_object_unref (pixbuf);
  return 1;
}
487 488
#endif /* USE_GTK */

Gerd Moellmann's avatar
Gerd Moellmann committed
489

Jim Blandy's avatar
Jim Blandy committed
490
/* Functions called only from `x_set_frame_param'
Jim Blandy's avatar
Jim Blandy committed
491 492
   to set individual parameters.

493
   If FRAME_X_WINDOW (f) is 0,
Jim Blandy's avatar
Jim Blandy committed
494
   the frame is being created and its X-window does not exist yet.
Jim Blandy's avatar
Jim Blandy committed
495 496 497
   In that case, just record the parameter's new value
   in the standard place; do not attempt to change the window.  */

498
static void
499
x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
500
{
501 502
  struct x_output *x = f->output_data.x;
  unsigned long fg, old_fg;
503

504
  fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
505 506
  old_fg = FRAME_FOREGROUND_PIXEL (f);
  FRAME_FOREGROUND_PIXEL (f) = fg;
507

508
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
509
    {
510
      Display *dpy = FRAME_X_DISPLAY (f);
511

512
      block_input ();
513 514
      XSetForeground (dpy, x->normal_gc, fg);
      XSetBackground (dpy, x->reverse_gc, fg);
515

516 517 518 519 520 521
      if (x->cursor_pixel == old_fg)
	{
	  unload_color (f, x->cursor_pixel);
	  x->cursor_pixel = x_copy_color (f, fg);
	  XSetBackground (dpy, x->cursor_gc, x->cursor_pixel);
	}
522

523
      unblock_input ();
524

525
      update_face_from_frame_parameter (f, Qforeground_color, arg);
526

527
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
528
        redraw_frame (f);
Jim Blandy's avatar
Jim Blandy committed
529
    }
530

531
  unload_color (f, old_fg);
Jim Blandy's avatar
Jim Blandy committed
532 533
}

534
static void
535
x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
536
{
537 538
  struct x_output *x = f->output_data.x;
  unsigned long bg;
Jim Blandy's avatar
Jim Blandy committed
539

540
  bg = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
541 542
  unload_color (f, FRAME_BACKGROUND_PIXEL (f));
  FRAME_BACKGROUND_PIXEL (f) = bg;
543

544
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
545
    {
546
      Display *dpy = FRAME_X_DISPLAY (f);
547

548
      block_input ();
549 550 551 552 553
      XSetBackground (dpy, x->normal_gc, bg);
      XSetForeground (dpy, x->reverse_gc, bg);
      XSetWindowBackground (dpy, FRAME_X_WINDOW (f), bg);
      XSetForeground (dpy, x->cursor_gc, bg);

Jan Djärv's avatar
Jan Djärv committed
554 555 556 557
#ifdef USE_GTK
      xg_set_background_color (f, bg);
#endif

558 559 560 561 562 563 564 565
#ifndef USE_TOOLKIT_SCROLL_BARS /* Turns out to be annoying with
				   toolkit scroll bars.  */
      {
	Lisp_Object bar;
	for (bar = FRAME_SCROLL_BARS (f);
	     !NILP (bar);
	     bar = XSCROLL_BAR (bar)->next)
	  {
566
	    Window window = XSCROLL_BAR (bar)->x_window;
567 568 569 570
	    XSetWindowBackground (dpy, window, bg);
	  }
      }
#endif /* USE_TOOLKIT_SCROLL_BARS */
Jim Blandy's avatar
Jim Blandy committed
571

572
      unblock_input ();
573
      update_face_from_frame_parameter (f, Qbackground_color, arg);
574

575
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
576
        redraw_frame (f);
Jim Blandy's avatar
Jim Blandy committed
577 578 579
    }
}

580
static Cursor
581
make_invisible_cursor (struct frame *f)
582 583 584 585 586
{
  Display *dpy = FRAME_X_DISPLAY (f);
  static char const no_data[] = { 0 };
  Pixmap pix;
  XColor col;
587
  Cursor c = 0;
588 589

  x_catch_errors (dpy);
590
  pix = XCreateBitmapFromData (dpy, FRAME_DISPLAY_INFO (f)->root_window,
591 592 593
                               no_data, 1, 1);
  if (! x_had_errors_p (dpy) && pix != None)
    {
594
      Cursor pixc;
595 596 597
      col.pixel = 0;
      col.red = col.green = col.blue = 0;
      col.flags = DoRed | DoGreen | DoBlue;
598 599 600
      pixc = XCreatePixmapCursor (dpy, pix, pix, &col, &col, 0, 0);
      if (! x_had_errors_p (dpy) && pixc != None)
        c = pixc;
601 602 603 604 605 606 607 608
      XFreePixmap (dpy, pix);
    }

  x_uncatch_errors ();

  return c;
}

609
static void
610
x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
611
{
612 613
  struct x_output *x = f->output_data.x;
  Display *dpy = FRAME_X_DISPLAY (f);
614
  Cursor cursor, nontext_cursor, mode_cursor, hand_cursor;
615
  Cursor hourglass_cursor, horizontal_drag_cursor, vertical_drag_cursor;
616
  unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
617
  unsigned long mask_color = FRAME_BACKGROUND_PIXEL (f);
618

619
  /* Don't let pointers be invisible.  */
620
  if (mask_color == pixel)
621 622
    {
      x_free_colors (f, &pixel, 1);
Karoly Lorentey's avatar
Karoly Lorentey committed
623
      pixel = x_copy_color (f, FRAME_FOREGROUND_PIXEL (f));
624
    }
625

626 627
  unload_color (f, x->mouse_pixel);
  x->mouse_pixel = pixel;
Jim Blandy's avatar
Jim Blandy committed
628

629
  block_input ();
630

631
  /* It's not okay to crash if the user selects a screwy cursor.  */
632
  x_catch_errors (dpy);
633

634
  if (!NILP (Vx_pointer_shape))
Jim Blandy's avatar
Jim Blandy committed
635
    {
636
      CHECK_NUMBER (Vx_pointer_shape);
637
      cursor = XCreateFontCursor (dpy, XINT (Vx_pointer_shape));
Jim Blandy's avatar
Jim Blandy committed
638 639
    }
  else
640 641
    cursor = XCreateFontCursor (dpy, XC_xterm);
  x_check_errors (dpy, "bad text pointer cursor: %s");
Jim Blandy's avatar
Jim Blandy committed
642

643
  if (!NILP (Vx_nontext_pointer_shape))
Jim Blandy's avatar
Jim Blandy committed
644
    {
645
      CHECK_NUMBER (Vx_nontext_pointer_shape);
646 647
      nontext_cursor
	= XCreateFontCursor (dpy, XINT (Vx_nontext_pointer_shape));
Jim Blandy's avatar
Jim Blandy committed
648 649
    }
  else
650 651
    nontext_cursor = XCreateFontCursor (dpy, XC_left_ptr);
  x_check_errors (dpy, "bad nontext pointer cursor: %s");
Jim Blandy's avatar
Jim Blandy committed
652

653
  if (!NILP (Vx_hourglass_pointer_shape))
654
    {
655
      CHECK_NUMBER (Vx_hourglass_pointer_shape);
656 657
      hourglass_cursor
	= XCreateFontCursor (dpy, XINT (Vx_hourglass_pointer_shape));
658 659
    }
  else
660 661
    hourglass_cursor = XCreateFontCursor (dpy, XC_watch);
  x_check_errors (dpy, "bad hourglass pointer cursor: %s");
662

663
  if (!NILP (Vx_mode_pointer_shape))
Jim Blandy's avatar
Jim Blandy committed
664
    {
665
      CHECK_NUMBER (Vx_mode_pointer_shape);
666
      mode_cursor = XCreateFontCursor (dpy, XINT (Vx_mode_pointer_shape));
Jim Blandy's avatar
Jim Blandy committed
667 668
    }
  else
669 670
    mode_cursor = XCreateFontCursor (dpy, XC_xterm);
  x_check_errors (dpy, "bad modeline pointer cursor: %s");
671

672
  if (!NILP (Vx_sensitive_text_pointer_shape))
673
    {
674
      CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
675
      hand_cursor
676
	= XCreateFontCursor (dpy, XINT (Vx_sensitive_text_pointer_shape));
677 678
    }
  else
679
    hand_cursor = XCreateFontCursor (dpy, XC_hand2);
Jim Blandy's avatar
Jim Blandy committed
680

681 682
  if (!NILP (Vx_window_horizontal_drag_shape))
    {
683
      CHECK_NUMBER (Vx_window_horizontal_drag_shape);
684
      horizontal_drag_cursor
685
	= XCreateFontCursor (dpy, XINT (Vx_window_horizontal_drag_shape));
686 687 688
    }
  else
    horizontal_drag_cursor
689
      = XCreateFontCursor (dpy, XC_sb_h_double_arrow);
690

691 692 693 694 695 696 697 698 699 700
  if (!NILP (Vx_window_vertical_drag_shape))
    {
      CHECK_NUMBER (Vx_window_vertical_drag_shape);
      vertical_drag_cursor
	= XCreateFontCursor (dpy, XINT (Vx_window_vertical_drag_shape));
    }
  else
    vertical_drag_cursor
      = XCreateFontCursor (dpy, XC_sb_v_double_arrow);

701
  /* Check and report errors with the above calls.  */
702
  x_check_errors (dpy, "can't set cursor shape: %s");
703
  x_uncatch_errors ();
704

Jim Blandy's avatar
Jim Blandy committed
705 706 707
  {
    XColor fore_color, back_color;

708
    fore_color.pixel = x->mouse_pixel;
709
    x_query_color (f, &fore_color);
Jim Blandy's avatar
Jim Blandy committed
710
    back_color.pixel = mask_color;
711
    x_query_color (f, &back_color);
712

713 714 715
    XRecolorCursor (dpy, cursor, &fore_color, &back_color);
    XRecolorCursor (dpy, nontext_cursor, &fore_color, &back_color);
    XRecolorCursor (dpy, mode_cursor, &fore_color, &back_color);
716
    XRecolorCursor (dpy, hand_cursor, &fore_color, &back_color);
717 718
    XRecolorCursor (dpy, hourglass_cursor, &fore_color, &back_color);
    XRecolorCursor (dpy, horizontal_drag_cursor, &fore_color, &back_color);
Jim Blandy's avatar
Jim Blandy committed
719 720
  }

721
  if (FRAME_X_WINDOW (f) != 0)
722 723
    XDefineCursor (dpy, FRAME_X_WINDOW (f),
                   f->output_data.x->current_cursor = cursor);
724

725 726
  if (FRAME_DISPLAY_INFO (f)->invisible_cursor == 0)
    FRAME_DISPLAY_INFO (f)->invisible_cursor = make_invisible_cursor (f);
727

728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
  if (cursor != x->text_cursor
      && x->text_cursor != 0)
    XFreeCursor (dpy, x->text_cursor);
  x->text_cursor = cursor;

  if (nontext_cursor != x->nontext_cursor
      && x->nontext_cursor != 0)
    XFreeCursor (dpy, x->nontext_cursor);
  x->nontext_cursor = nontext_cursor;

  if (hourglass_cursor != x->hourglass_cursor
      && x->hourglass_cursor != 0)
    XFreeCursor (dpy, x->hourglass_cursor);
  x->hourglass_cursor = hourglass_cursor;

  if (mode_cursor != x->modeline_cursor
      && x->modeline_cursor != 0)
    XFreeCursor (dpy, f->output_data.x->modeline_cursor);
  x->modeline_cursor = mode_cursor;
747

748 749 750 751
  if (hand_cursor != x->hand_cursor
      && x->hand_cursor != 0)
    XFreeCursor (dpy, x->hand_cursor);
  x->hand_cursor = hand_cursor;
Jim Blandy's avatar
Jim Blandy committed
752

753 754 755 756
  if (horizontal_drag_cursor != x->horizontal_drag_cursor
      && x->horizontal_drag_cursor != 0)
    XFreeCursor (dpy, x->horizontal_drag_cursor);
  x->horizontal_drag_cursor = horizontal_drag_cursor;
757

758 759 760 761 762
  if (vertical_drag_cursor != x->vertical_drag_cursor
      && x->vertical_drag_cursor != 0)
    XFreeCursor (dpy, x->vertical_drag_cursor);
  x->vertical_drag_cursor = vertical_drag_cursor;

763
  XFlush (dpy);
764
  unblock_input ();
765 766

  update_face_from_frame_parameter (f, Qmouse_color, arg);
Jim Blandy's avatar
Jim Blandy committed
767 768
}

769
static void
770
x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
771
{
772
  unsigned long fore_pixel, pixel;
773
  bool fore_pixel_allocated_p = 0, pixel_allocated_p = 0;
774
  struct x_output *x = f->output_data.x;
Jim Blandy's avatar
Jim Blandy committed
775

776 777 778 779 780 781
  if (!NILP (Vx_cursor_fore_pixel))
    {
      fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
				   WHITE_PIX_DEFAULT (f));
      fore_pixel_allocated_p = 1;
    }
Jim Blandy's avatar
Jim Blandy committed
782
  else
Karoly Lorentey's avatar
Karoly Lorentey committed
783
    fore_pixel = FRAME_BACKGROUND_PIXEL (f);
784

785
  pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
786
  pixel_allocated_p = 1;
787

788
  /* Make sure that the cursor color differs from the background color.  */
Karoly Lorentey's avatar
Karoly Lorentey committed
789
  if (pixel == FRAME_BACKGROUND_PIXEL (f))
Jim Blandy's avatar
Jim Blandy committed
790
    {
791 792 793 794 795
      if (pixel_allocated_p)
	{
	  x_free_colors (f, &pixel, 1);
	  pixel_allocated_p = 0;
	}
Juanma Barranquero's avatar