xfns.c 192 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

Paul Eggert's avatar
Paul Eggert committed
3
Copyright (C) 1989, 1992-2015 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
#ifdef GLYPH_DEBUG
129 130
static ptrdiff_t image_cache_refcount;
static int dpyinfo_refcount;
131 132
#endif

133 134
static struct x_display_info *x_display_info_for_name (Lisp_Object);

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

140
struct x_display_info *
141
check_x_display_info (Lisp_Object object)
142
{
143
  struct x_display_info *dpyinfo = NULL;
144

145
  if (NILP (object))
146
    {
Gerd Moellmann's avatar
Gerd Moellmann committed
147
      struct frame *sf = XFRAME (selected_frame);
148

Gerd Moellmann's avatar
Gerd Moellmann committed
149
      if (FRAME_X_P (sf) && FRAME_LIVE_P (sf))
150
	dpyinfo = FRAME_DISPLAY_INFO (sf);
151
      else if (x_display_list != 0)
152
	dpyinfo = x_display_list;
153 154 155
      else
	error ("X windows are not in use or not initialized");
    }
156
  else if (TERMINALP (object))
157
    {
158
      struct terminal *t = decode_live_terminal (object);
159

160
      if (t->type != output_x_window)
161
        error ("Terminal %d is not an X display", t->id);
162

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

  return dpyinfo;
174
}
175

176
/* Store the screen positions of frame F into XPTR and YPTR.
177 178 179 180
   These are the positions of the containing window manager window,
   not Emacs's own window.  */

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

196
  block_input ();
197

198
  x_catch_errors (dpy);
199

200
  if (win == dpyinfo->root_window)
201 202 203 204 205 206 207
    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 (;;)
208
    {
209 210 211
      Window wm_window, rootw;
      Window *tmp_children;
      unsigned int tmp_nchildren;
212
      int success;
213

214 215
      success = XQueryTree (FRAME_X_DISPLAY (f), win, &rootw,
			    &wm_window, &tmp_children, &tmp_nchildren);
216

217
      had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
218

219 220 221 222
      /* Don't free tmp_children if XQueryTree failed.  */
      if (! success)
	break;

223
      XFree (tmp_children);
224

225 226
      if (wm_window == rootw || had_errors)
        break;
227

228 229
      win = wm_window;
    }
230

231 232
  if (! had_errors)
    {
233
      unsigned int ign;
234
      Window child, rootw;
235

236 237 238 239 240 241 242 243 244 245 246 247 248 249
      /* 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
      */
250
      XTranslateCoordinates (FRAME_X_DISPLAY (f),
251

252
			     /* From-window, to-window.  */
253
			     FRAME_DISPLAY_INFO (f)->root_window,
254
                             FRAME_X_WINDOW (f),
255

256
			     /* From-position, to-position.  */
257
                             real_x, real_y, &win_x, &win_y,
258

259 260
			     /* Child of win.  */
			     &child);
261

262
      if (FRAME_X_WINDOW (f) == FRAME_OUTER_WINDOW (f))
263
	{
264 265
          outer_x = win_x;
          outer_y = win_y;
266
	}
267 268 269
      else
        {
          XTranslateCoordinates (FRAME_X_DISPLAY (f),
270

271
                                 /* From-window, to-window.  */
272
                                 FRAME_DISPLAY_INFO (f)->root_window,
273
                                 FRAME_OUTER_WINDOW (f),
274

275 276
                                 /* From-position, to-position.  */
                                 real_x, real_y, &outer_x, &outer_y,
277

278 279
                                 /* Child of win.  */
                                 &child);
280
	}
281

282 283
      had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
    }
284

285 286 287 288 289 290 291 292 293 294 295 296

  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)
        {
297
          unsigned int ign;
298
          Window rootw;
299
          long *fe = (long *)tmp_data;
300 301 302 303 304 305 306 307 308 309 310 311

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

312
  x_uncatch_errors ();
313

314
  unblock_input ();
315 316

  if (had_errors) return;
317

318 319 320 321 322
  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;
323 324 325

  *xptr = real_x;
  *yptr = real_y;
326 327
}

328
/* Get the mouse position in frame relative coordinates.  */
329

330 331 332 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
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);
}
365 366 367 368

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

void
369
gamma_correct (struct frame *f, XColor *color)
370 371 372 373 374 375 376 377 378 379
{
  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;
    }
}


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

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

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

403
  return success_p;
Jim Blandy's avatar
Jim Blandy committed
404 405
}

406 407 408 409

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

411
static int
Dmitry Antipov's avatar
Dmitry Antipov committed
412
x_decode_color (struct frame *f, Lisp_Object color_name, int mono_color)
Jim Blandy's avatar
Jim Blandy committed
413
{
414
  XColor cdef;
Jim Blandy's avatar
Jim Blandy committed
415

416
  CHECK_STRING (color_name);
Jim Blandy's avatar
Jim Blandy committed
417

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

427
  /* Return MONO_COLOR for monochrome frames.  */
428
  if (FRAME_DISPLAY_INFO (f)->n_planes == 1)
429
    return mono_color;
Jim Blandy's avatar
Jim Blandy committed
430

431
  /* x_defined_color is responsible for coping with failures
432
     by looking for a near-miss.  */
433
  if (x_defined_color (f, SSDATA (color_name), &cdef, 1))
434 435
    return cdef.pixel;

436
  signal_error ("Undefined color", color_name);
Jim Blandy's avatar
Jim Blandy committed
437
}
438 439


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

451 452 453 454 455
static void
x_set_tool_bar_position (struct frame *f,
                         Lisp_Object new_value,
                         Lisp_Object old_value)
{
456
  Lisp_Object choice = list4 (Qleft, Qright, Qtop, Qbottom);
457

458 459
  if (!NILP (Fmemq (new_value, choice)))
    {
460
#ifdef USE_GTK
461 462 463 464 465 466 467 468
      if (!EQ (new_value, old_value))
	{
	  xg_change_toolbar_position (f, new_value);
	  fset_tool_bar_position (f, new_value);
	}
#else
      if (!EQ (new_value, Qtop))
	error ("The only supported tool bar position is top");
469
#endif
470 471 472
    }
  else
    wrong_choice (choice, new_value);
473 474
}

475 476
#ifdef USE_GTK

477 478
/* 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.  */
479 480

int
Dmitry Antipov's avatar
Dmitry Antipov committed
481
xg_set_icon (struct frame *f, Lisp_Object file)
482
{
483 484
  int result = 0;
  Lisp_Object found;
485

486 487 488 489 490 491
  found = x_find_image_file (file);

  if (! NILP (found))
    {
      GdkPixbuf *pixbuf;
      GError *err = NULL;
492
      char *filename = SSDATA (found);
493
      block_input ();
494 495 496 497 498 499 500 501 502 503 504 505 506 507

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

508
      unblock_input ();
509 510 511
    }

  return result;
512
}
513 514

int
Dmitry Antipov's avatar
Dmitry Antipov committed
515
xg_set_icon_from_xpm_data (struct frame *f, const char **data)
516
{
517
  GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data (data);
518 519

  if (!pixbuf)
520
    return 0;
521

522
  gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), pixbuf);
523 524 525
  g_object_unref (pixbuf);
  return 1;
}
526 527
#endif /* USE_GTK */

Gerd Moellmann's avatar
Gerd Moellmann committed
528

Jim Blandy's avatar
Jim Blandy committed
529
/* Functions called only from `x_set_frame_param'
Jim Blandy's avatar
Jim Blandy committed
530 531
   to set individual parameters.

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

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

543
  fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
544 545
  old_fg = FRAME_FOREGROUND_PIXEL (f);
  FRAME_FOREGROUND_PIXEL (f) = fg;
546

547
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
548
    {
549
      Display *dpy = FRAME_X_DISPLAY (f);
550

551
      block_input ();
552 553
      XSetForeground (dpy, x->normal_gc, fg);
      XSetBackground (dpy, x->reverse_gc, fg);
554

555 556 557 558 559 560
      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);
	}
561

562
      unblock_input ();
563

564
      update_face_from_frame_parameter (f, Qforeground_color, arg);
565

566
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
567
        redraw_frame (f);
Jim Blandy's avatar
Jim Blandy committed
568
    }
569

570
  unload_color (f, old_fg);
Jim Blandy's avatar
Jim Blandy committed
571 572
}

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

579
  bg = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
580 581
  unload_color (f, FRAME_BACKGROUND_PIXEL (f));
  FRAME_BACKGROUND_PIXEL (f) = bg;
582

583
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
584
    {
585
      Display *dpy = FRAME_X_DISPLAY (f);
586

587
      block_input ();
588 589 590 591 592
      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
593 594 595 596
#ifdef USE_GTK
      xg_set_background_color (f, bg);
#endif

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

611
      unblock_input ();
612
      update_face_from_frame_parameter (f, Qbackground_color, arg);
613

614
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
615
        redraw_frame (f);
Jim Blandy's avatar
Jim Blandy committed
616 617 618
    }
}

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

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

636 637
  unload_color (f, x->mouse_pixel);
  x->mouse_pixel = pixel;
Jim Blandy's avatar
Jim Blandy committed
638

639
  block_input ();
640

641
  /* It's not okay to crash if the user selects a screwy cursor.  */
642
  x_catch_errors (dpy);
643

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

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

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

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

682
  if (!NILP (Vx_sensitive_text_pointer_shape))
683
    {
684
      CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
685
      hand_cursor
686
	= XCreateFontCursor (dpy, XINT (Vx_sensitive_text_pointer_shape));
687 688
    }
  else
689
    hand_cursor = XCreateFontCursor (dpy, XC_hand2);
Jim Blandy's avatar
Jim Blandy committed
690

691 692
  if (!NILP (Vx_window_horizontal_drag_shape))
    {
Paul Eggert's avatar
Paul Eggert committed
693
      CHECK_TYPE_RANGED_INTEGER (unsigned, Vx_window_horizontal_drag_shape);
694
      horizontal_drag_cursor
695
	= XCreateFontCursor (dpy, XINT (Vx_window_horizontal_drag_shape));
696 697 698
    }
  else
    horizontal_drag_cursor
699
      = XCreateFontCursor (dpy, XC_sb_h_double_arrow);
700

701 702 703 704 705 706 707 708 709 710
  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);

711
  /* Check and report errors with the above calls.  */
712
  x_check_errors (dpy, "can't set cursor shape: %s");
713
  x_uncatch_errors ();
714

Jim Blandy's avatar
Jim Blandy committed
715 716 717
  {
    XColor fore_color, back_color;

718
    fore_color.pixel = x->mouse_pixel;
719
    x_query_color (f, &fore_color);
Jim Blandy's avatar
Jim Blandy committed
720
    back_color.pixel = mask_color;
721
    x_query_color (f, &back_color);
722

723 724 725
    XRecolorCursor (dpy, cursor, &fore_color, &back_color);
    XRecolorCursor (dpy, nontext_cursor, &fore_color, &back_color);
    XRecolorCursor (dpy, mode_cursor, &fore_color, &back_color);
726
    XRecolorCursor (dpy, hand_cursor, &fore_color, &back_color);
727 728
    XRecolorCursor (dpy, hourglass_cursor, &fore_color, &back_color);
    XRecolorCursor (dpy, horizontal_drag_cursor, &fore_color, &back_color);
729
    XRecolorCursor (dpy, vertical_drag_cursor, &fore_color, &back_color);
Jim Blandy's avatar
Jim Blandy committed
730 731
  }

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

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

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

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

766 767 768 769 770
  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;

771
  XFlush (dpy);
772
  unblock_input ();
773 774

  update_face_from_frame_parameter (f, Qmouse_color, arg);
Jim Blandy's avatar
Jim Blandy committed
775 776
}

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

784 785 786 787 788 789
  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
790
  else
Karoly Lorentey's avatar
Karoly Lorentey committed
791
    fore_pixel = FRAME_BACKGROUND_PIXEL (f);
792

793
  pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
794
  pixel_allocated_p = 1;
795

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

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

817
  unload_color (f, x->cursor_foreground_pixel);
818 819
  if (!fore_pixel_allocated_p)
    fore_pixel = x_copy_color (f, fore_pixel);
820
  x->cursor_foreground_pixel = fore_pixel;
Jim Blandy's avatar
Jim Blandy committed
821

822
  unload_color (f, x->cursor_pixel);
823 824
  if (!pixel_allocated_p)
    pixel = x_copy_color (f, pixel);
825
  x->cursor_pixel = pixel;
826

827
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
828
    {
829
      block_input ();
830 831
      XSetBackground (FRAME_X_DISPLAY (f), x->cursor_gc, x->cursor_pixel);
      XSetForeground (FRAME_X_DISPLAY (f), x->cursor_gc, fore_pixel);
832
      unblock_input ();
Jim Blandy's avatar
Jim Blandy committed
833