xfns.c 191 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-2014 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"
Paul Eggert's avatar
Paul Eggert committed
27
#include "menu.h"
Jim Blandy's avatar
Jim Blandy committed
28
#include "frame.h"
Jim Blandy's avatar
Jim Blandy committed
29
#include "window.h"
30
#include "character.h"
Jim Blandy's avatar
Jim Blandy committed
31
#include "buffer.h"
Kenichi Handa's avatar
Kenichi Handa committed
32
#include "intervals.h"
Jim Blandy's avatar
Jim Blandy committed
33
#include "dispextern.h"
Jim Blandy's avatar
Jim Blandy committed
34
#include "keyboard.h"
35
#include "blockinput.h"
36
#include <epaths.h>
Karl Heuer's avatar
Karl Heuer committed
37
#include "charset.h"
Kenichi Handa's avatar
Kenichi Handa committed
38
#include "coding.h"
Karl Heuer's avatar
Karl Heuer committed
39
#include "fontset.h"
40 41
#include "systime.h"
#include "termhooks.h"
42
#include "atimer.h"
43
#include "termchar.h"
Kenichi Handa's avatar
Kenichi Handa committed
44 45
#include "font.h"

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

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

55 56
#include "xsettings.h"

57 58 59 60 61 62 63
#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
64 65 66 67
#ifdef USE_GTK
#include "gtkutil.h"
#endif

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

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

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

#include "widget.h"

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

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

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

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

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

114 115
extern LWLIB_ID widget_id_tick;

116 117 118 119
#ifdef USE_MOTIF

#endif /* USE_MOTIF */

120 121
#endif /* USE_X_TOOLKIT */

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

#endif /* USE_GTK */

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

128 129
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
}

332
/* Get the mouse position in frame relative coordinates.  */
333

334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
void
x_relative_mouse_position (struct frame *f, int *x, int *y)
{
  Window root, dummy_window;
  int dummy;

  eassert (FRAME_X_P (f));

  block_input ();

  XQueryPointer (FRAME_X_DISPLAY (f),
                 DefaultRootWindow (FRAME_X_DISPLAY (f)),

                 /* The root window which contains the pointer.  */
                 &root,

                 /* Window pointer is on, not used  */
                 &dummy_window,

                 /* The position on that root window.  */
                 x, y,

                 /* x/y in dummy_window coordinates, not used.  */
                 &dummy, &dummy,

                 /* Modifier keys and pointer buttons, about which
                    we don't care.  */
                 (unsigned int *) &dummy);

  unblock_input ();

  /* Translate root window coordinates to window coordinates.  */
  *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
  *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
}
369 370 371 372

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

void
373
gamma_correct (struct frame *f, XColor *color)
374 375 376 377 378 379 380 381 382 383
{
  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;
    }
}


384
/* Decide if color named COLOR_NAME is valid for use on frame F.  If
385 386
   so, return the RGB values in COLOR.  If ALLOC_P,
   allocate the color.  Value is false if COLOR_NAME is invalid, or
387
   no color could be allocated.  */
388

389
bool
390
x_defined_color (struct frame *f, const char *color_name,
391
		 XColor *color, bool alloc_p)
Jim Blandy's avatar
Jim Blandy committed
392
{
393
  bool success_p = 0;
394 395
  Display *dpy = FRAME_X_DISPLAY (f);
  Colormap cmap = FRAME_X_COLORMAP (f);
Jim Blandy's avatar
Jim Blandy committed
396

397
  block_input ();
398 399 400 401
#ifdef USE_GTK
  success_p = xg_check_special_colors (f, color_name, color);
#endif
  if (!success_p)
402
    success_p = XParseColor (dpy, cmap, color_name, color) != 0;
403 404
  if (success_p && alloc_p)
    success_p = x_alloc_nearest_color (f, cmap, color);
405
  unblock_input ();
Jim Blandy's avatar
Jim Blandy committed
406

407
  return success_p;
Jim Blandy's avatar
Jim Blandy committed
408 409
}

410 411 412 413

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

415
static int
Dmitry Antipov's avatar
Dmitry Antipov committed
416
x_decode_color (struct frame *f, Lisp_Object color_name, int mono_color)
Jim Blandy's avatar
Jim Blandy committed
417
{
418
  XColor cdef;
Jim Blandy's avatar
Jim Blandy committed
419

420
  CHECK_STRING (color_name);
Jim Blandy's avatar
Jim Blandy committed
421

422 423 424
#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.  */
425
  if (strcmp (SDATA (color_name), "black") == 0)
426
    return BLACK_PIX_DEFAULT (f);
427
  else if (strcmp (SDATA (color_name), "white") == 0)
428
    return WHITE_PIX_DEFAULT (f);
429
#endif
Jim Blandy's avatar
Jim Blandy committed
430

431
  /* Return MONO_COLOR for monochrome frames.  */
432
  if (FRAME_DISPLAY_INFO (f)->n_planes == 1)
433
    return mono_color;
Jim Blandy's avatar
Jim Blandy committed
434

435
  /* x_defined_color is responsible for coping with failures
436
     by looking for a near-miss.  */
437
  if (x_defined_color (f, SSDATA (color_name), &cdef, 1))
438 439
    return cdef.pixel;

440
  signal_error ("Undefined color", color_name);
Jim Blandy's avatar
Jim Blandy committed
441
}
442 443


Jim Blandy's avatar
Jim Blandy committed
444

Gerd Moellmann's avatar
Gerd Moellmann committed
445 446 447 448 449
/* 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
450
x_set_wait_for_wm (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
Gerd Moellmann's avatar
Gerd Moellmann committed
451 452 453 454
{
  f->output_data.x->wait_for_wm = !NILP (new_value);
}

455 456 457 458 459 460 461 462 463 464 465
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
466 467
  xg_change_toolbar_position (f, new_value);
  fset_tool_bar_position (f, new_value);
468 469 470
#endif
}

471 472
#ifdef USE_GTK

473 474
/* 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.  */
475 476

int
Dmitry Antipov's avatar
Dmitry Antipov committed
477
xg_set_icon (struct frame *f, Lisp_Object file)
478
{
479 480
  int result = 0;
  Lisp_Object found;
481

482 483 484 485 486 487
  found = x_find_image_file (file);

  if (! NILP (found))
    {
      GdkPixbuf *pixbuf;
      GError *err = NULL;
488
      char *filename = SSDATA (found);
489
      block_input ();
490 491 492 493 494 495 496 497 498 499 500 501 502 503

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

504
      unblock_input ();
505 506 507
    }

  return result;
508
}
509 510

int
Dmitry Antipov's avatar
Dmitry Antipov committed
511
xg_set_icon_from_xpm_data (struct frame *f, const char **data)
512
{
513
  GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data (data);
514 515

  if (!pixbuf)
516
    return 0;
517

518
  gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), pixbuf);
519 520 521
  g_object_unref (pixbuf);
  return 1;
}
522 523
#endif /* USE_GTK */

Gerd Moellmann's avatar
Gerd Moellmann committed
524

Jim Blandy's avatar
Jim Blandy committed
525
/* Functions called only from `x_set_frame_param'
Jim Blandy's avatar
Jim Blandy committed
526 527
   to set individual parameters.

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

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

539
  fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
540 541
  old_fg = FRAME_FOREGROUND_PIXEL (f);
  FRAME_FOREGROUND_PIXEL (f) = fg;
542

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

547
      block_input ();
548 549
      XSetForeground (dpy, x->normal_gc, fg);
      XSetBackground (dpy, x->reverse_gc, fg);
550

551 552 553 554 555 556
      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);
	}
557

558
      unblock_input ();
559

560
      update_face_from_frame_parameter (f, Qforeground_color, arg);
561

562
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
563
        redraw_frame (f);
Jim Blandy's avatar
Jim Blandy committed
564
    }
565

566
  unload_color (f, old_fg);
Jim Blandy's avatar
Jim Blandy committed
567 568
}

569
static void
570
x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
571
{
572 573
  struct x_output *x = f->output_data.x;
  unsigned long bg;
Jim Blandy's avatar
Jim Blandy committed
574

575
  bg = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
576 577
  unload_color (f, FRAME_BACKGROUND_PIXEL (f));
  FRAME_BACKGROUND_PIXEL (f) = bg;
578

579
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
580
    {
581
      Display *dpy = FRAME_X_DISPLAY (f);
582

583
      block_input ();
584 585 586 587 588
      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
589 590 591 592
#ifdef USE_GTK
      xg_set_background_color (f, bg);
#endif

593 594 595 596 597 598 599 600
#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)
	  {
601
	    Window window = XSCROLL_BAR (bar)->x_window;
602 603 604 605
	    XSetWindowBackground (dpy, window, bg);
	  }
      }
#endif /* USE_TOOLKIT_SCROLL_BARS */
Jim Blandy's avatar
Jim Blandy committed
606

607
      unblock_input ();
608
      update_face_from_frame_parameter (f, Qbackground_color, arg);
609

610
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
611
        redraw_frame (f);
Jim Blandy's avatar
Jim Blandy committed
612 613 614
    }
}

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

625
  /* Don't let pointers be invisible.  */
626
  if (mask_color == pixel)
627 628
    {
      x_free_colors (f, &pixel, 1);
Karoly Lorentey's avatar
Karoly Lorentey committed
629
      pixel = x_copy_color (f, FRAME_FOREGROUND_PIXEL (f));
630
    }
631

632 633
  unload_color (f, x->mouse_pixel);
  x->mouse_pixel = pixel;
Jim Blandy's avatar
Jim Blandy committed
634

635
  block_input ();
636

637
  /* It's not okay to crash if the user selects a screwy cursor.  */
638
  x_catch_errors (dpy);
639

640
  if (!NILP (Vx_pointer_shape))
Jim Blandy's avatar
Jim Blandy committed
641
    {
642
      CHECK_NUMBER (Vx_pointer_shape);
643
      cursor = XCreateFontCursor (dpy, XINT (Vx_pointer_shape));
Jim Blandy's avatar
Jim Blandy committed
644 645
    }
  else
646 647
    cursor = XCreateFontCursor (dpy, XC_xterm);
  x_check_errors (dpy, "bad text pointer cursor: %s");
Jim Blandy's avatar
Jim Blandy committed
648

649
  if (!NILP (Vx_nontext_pointer_shape))
Jim Blandy's avatar
Jim Blandy committed
650
    {
651
      CHECK_NUMBER (Vx_nontext_pointer_shape);
652 653
      nontext_cursor
	= XCreateFontCursor (dpy, XINT (Vx_nontext_pointer_shape));
Jim Blandy's avatar
Jim Blandy committed
654 655
    }
  else
656 657
    nontext_cursor = XCreateFontCursor (dpy, XC_left_ptr);
  x_check_errors (dpy, "bad nontext pointer cursor: %s");
Jim Blandy's avatar
Jim Blandy committed
658

659
  if (!NILP (Vx_hourglass_pointer_shape))
660
    {
661
      CHECK_NUMBER (Vx_hourglass_pointer_shape);
662 663
      hourglass_cursor
	= XCreateFontCursor (dpy, XINT (Vx_hourglass_pointer_shape));
664 665
    }
  else
666 667
    hourglass_cursor = XCreateFontCursor (dpy, XC_watch);
  x_check_errors (dpy, "bad hourglass pointer cursor: %s");
668

669
  if (!NILP (Vx_mode_pointer_shape))
Jim Blandy's avatar
Jim Blandy committed
670
    {
671
      CHECK_NUMBER (Vx_mode_pointer_shape);
672
      mode_cursor = XCreateFontCursor (dpy, XINT (Vx_mode_pointer_shape));
Jim Blandy's avatar
Jim Blandy committed
673 674
    }
  else
675 676
    mode_cursor = XCreateFontCursor (dpy, XC_xterm);
  x_check_errors (dpy, "bad modeline pointer cursor: %s");
677

678
  if (!NILP (Vx_sensitive_text_pointer_shape))
679
    {
680
      CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
681
      hand_cursor
682
	= XCreateFontCursor (dpy, XINT (Vx_sensitive_text_pointer_shape));
683 684
    }
  else
685
    hand_cursor = XCreateFontCursor (dpy, XC_hand2);
Jim Blandy's avatar
Jim Blandy committed
686

687 688
  if (!NILP (Vx_window_horizontal_drag_shape))
    {
Paul Eggert's avatar
Paul Eggert committed
689
      CHECK_TYPE_RANGED_INTEGER (unsigned, Vx_window_horizontal_drag_shape);
690
      horizontal_drag_cursor
691
	= XCreateFontCursor (dpy, XINT (Vx_window_horizontal_drag_shape));
692 693 694
    }
  else
    horizontal_drag_cursor
695
      = XCreateFontCursor (dpy, XC_sb_h_double_arrow);
696

697 698 699 700 701 702 703 704 705 706
  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);

707
  /* Check and report errors with the above calls.  */
708
  x_check_errors (dpy, "can't set cursor shape: %s");
709
  x_uncatch_errors ();
710

Jim Blandy's avatar
Jim Blandy committed
711 712 713
  {
    XColor fore_color, back_color;

714
    fore_color.pixel = x->mouse_pixel;
715
    x_query_color (f, &fore_color);
Jim Blandy's avatar
Jim Blandy committed
716
    back_color.pixel = mask_color;
717
    x_query_color (f, &back_color);
718

719 720 721
    XRecolorCursor (dpy, cursor, &fore_color, &back_color);
    XRecolorCursor (dpy, nontext_cursor, &fore_color, &back_color);
    XRecolorCursor (dpy, mode_cursor, &fore_color, &back_color);
722
    XRecolorCursor (dpy, hand_cursor, &fore_color, &back_color);
723 724
    XRecolorCursor (dpy, hourglass_cursor, &fore_color, &back_color);
    XRecolorCursor (dpy, horizontal_drag_cursor, &fore_color, &back_color);
725
    XRecolorCursor (dpy, vertical_drag_cursor, &fore_color, &back_color);
Jim Blandy's avatar
Jim Blandy committed
726 727
  }

728
  if (FRAME_X_WINDOW (f) != 0)
729 730
    XDefineCursor (dpy, FRAME_X_WINDOW (f),
                   f->output_data.x->current_cursor = cursor);
731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750

  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;
751

752 753 754 755
  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
756

757 758 759 760
  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;
761

762 763 764 765 766
  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;

767
  XFlush (dpy);
768
  unblock_input ();
769 770

  update_face_from_frame_parameter (f, Qmouse_color, arg);
Jim Blandy's avatar
Jim Blandy committed
771 772
}

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

780 781 782 783 784 785
  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
786
  else
Karoly Lorentey's avatar
Karoly Lorentey committed
787
    fore_pixel = FRAME_BACKGROUND_PIXEL (f);
788

789
  pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
790
  pixel_allocated_p = 1;
791

792
  /* Make sure that the cursor color differs from the background color.  */
Karoly Lorentey's avatar
Karoly Lorentey committed
793
  if (pixel == FRAME_BACKGROUND_PIXEL (f))
Jim Blandy's avatar
Jim Blandy committed
794
    {
795 796 797 798 799
      if (pixel_allocated_p)
	{
	  x_free_colors (f, &pixel, 1);
	  pixel_allocated_p = 0;
	}
800

801
      pixel = x->mouse_pixel;
802
      if (pixel == fore_pixel)
803 804 805 806 807 808
	{
	  if (fore_pixel_allocated_p)
	    {
	      x_free_colors (f, &fore_pixel, 1);
	      fore_pixel_allocated_p = 0;
	    }
Karoly Lorentey's avatar
Karoly Lorentey committed
809
	  fore_pixel = FRAME_BACKGROUND_PIXEL (f);
810
	}
Jim Blandy's avatar
Jim Blandy committed
811
    }
812