xfns.c 255 KB
Newer Older
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-2020 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 <https://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>
Paul Eggert's avatar
Paul Eggert committed
22
#include <stdlib.h>
23
#include <math.h>
24 25
#include <unistd.h>

Jim Blandy's avatar
Jim Blandy committed
26 27
#include "lisp.h"
#include "xterm.h"
Jim Blandy's avatar
Jim Blandy committed
28
#include "frame.h"
Jim Blandy's avatar
Jim Blandy committed
29 30 31
#include "window.h"
#include "buffer.h"
#include "dispextern.h"
Jim Blandy's avatar
Jim Blandy committed
32
#include "keyboard.h"
33
#include "blockinput.h"
Karl Heuer's avatar
Karl Heuer committed
34
#include "charset.h"
Kenichi Handa's avatar
Kenichi Handa committed
35
#include "coding.h"
36
#include "termhooks.h"
Kenichi Handa's avatar
Kenichi Handa committed
37 38
#include "font.h"

39 40
#include <sys/types.h>
#include <sys/stat.h>
Jim Blandy's avatar
Jim Blandy committed
41

42
#include "bitmaps/gray.xbm"
43 44
#include "xsettings.h"

45 46 47 48 49 50 51
#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
52 53 54 55
#ifdef USE_GTK
#include "gtkutil.h"
#endif

56 57 58 59
#ifdef HAVE_XDBE
#include <X11/extensions/Xdbe.h>
#endif

60 61 62
#ifdef USE_X_TOOLKIT
#include <X11/Shell.h>

63
#ifndef USE_MOTIF
Chong Yidong's avatar
Chong Yidong committed
64 65
#ifdef HAVE_XAW3D
#include <X11/Xaw3d/Paned.h>
Chong Yidong's avatar
Chong Yidong committed
66
#include <X11/Xaw3d/Label.h>
Chong Yidong's avatar
Chong Yidong committed
67
#else /* !HAVE_XAW3D */
68 69
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Label.h>
Chong Yidong's avatar
Chong Yidong committed
70
#endif /* HAVE_XAW3D */
71
#endif /* USE_MOTIF */
72 73 74 75 76

#ifdef USG
#undef USG	/* ####KLUDGE for Solaris 2.2 and up */
#include <X11/Xos.h>
#define USG
77 78
#ifdef USG /* Pacify gcc -Wunused-macros.  */
#endif
79 80 81 82 83 84 85 86
#else
#include <X11/Xos.h>
#endif

#include "widget.h"

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

87 88 89 90
#ifdef USE_MOTIF
#include <Xm/Xm.h>
#include <Xm/DialogS.h>
#include <Xm/FileSB.h>
Jan D's avatar
Jan D committed
91 92
#include <Xm/List.h>
#include <Xm/TextF.h>
93
#include <Xm/MwmUtil.h>
94 95
#endif

96 97 98 99
#ifdef USE_LUCID
#include "../lwlib/xlwmenu.h"
#endif

100 101
/* Unique id counter for widgets created by the Lucid Widget Library.  */

102 103
extern LWLIB_ID widget_id_tick;

104 105 106 107
#ifdef USE_MOTIF

#endif /* USE_MOTIF */

108 109
#endif /* USE_X_TOOLKIT */

Kenichi Handa's avatar
Kenichi Handa committed
110 111 112 113
#ifdef USE_GTK

#endif /* USE_GTK */

Richard M. Stallman's avatar
Richard M. Stallman committed
114 115
#define MAXREQUEST(dpy) (XMaxRequestSize (dpy))

116
static ptrdiff_t image_cache_refcount;
117
#ifdef GLYPH_DEBUG
118
static int dpyinfo_refcount;
119 120
#endif

121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
#ifndef USE_MOTIF
#ifndef USE_GTK
/** #define MWM_HINTS_FUNCTIONS     (1L << 0) **/
#define MWM_HINTS_DECORATIONS   (1L << 1)
/** #define MWM_HINTS_INPUT_MODE    (1L << 2) **/
/** #define MWM_HINTS_STATUS        (1L << 3) **/

#define MWM_DECOR_ALL           (1L << 0)
/** #define MWM_DECOR_BORDER        (1L << 1) **/
/** #define MWM_DECOR_RESIZEH       (1L << 2) **/
/** #define MWM_DECOR_TITLE         (1L << 3) **/
/** #define MWM_DECOR_MENU          (1L << 4) **/
/** #define MWM_DECOR_MINIMIZE      (1L << 5) **/
/** #define MWM_DECOR_MAXIMIZE      (1L << 6) **/

/** #define _XA_MOTIF_WM_HINTS "_MOTIF_WM_HINTS" **/

typedef struct {
    unsigned long flags;
    unsigned long functions;
    unsigned long decorations;
    long input_mode;
    unsigned long status;
} PropMotifWmHints;

#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
#endif /* NOT USE_GTK */
#endif /* NOT USE_MOTIF */

150
static struct x_display_info *x_display_info_for_name (Lisp_Object);
151
static void set_up_x_back_buffer (struct frame *f);
152

153
/* Let the user specify an X display with a Lisp object.
154
   OBJECT may be nil, a frame or a terminal object.
155 156 157
   nil stands for the selected frame--or, if that is not an X frame,
   the first X display on the list.  */

158
struct x_display_info *
159
check_x_display_info (Lisp_Object object)
160
{
161
  struct x_display_info *dpyinfo = NULL;
162

163
  if (NILP (object))
164
    {
Gerd Moellmann's avatar
Gerd Moellmann committed
165
      struct frame *sf = XFRAME (selected_frame);
166

Gerd Moellmann's avatar
Gerd Moellmann committed
167
      if (FRAME_X_P (sf) && FRAME_LIVE_P (sf))
168
	dpyinfo = FRAME_DISPLAY_INFO (sf);
169
      else if (x_display_list != 0)
170
	dpyinfo = x_display_list;
171 172 173
      else
	error ("X windows are not in use or not initialized");
    }
174
  else if (TERMINALP (object))
175
    {
176
      struct terminal *t = decode_live_terminal (object);
177

178
      if (t->type != output_x_window)
179
        error ("Terminal %d is not an X display", t->id);
180

181
      dpyinfo = t->display_info.x;
182
    }
183 184
  else if (STRINGP (object))
    dpyinfo = x_display_info_for_name (object);
185 186
  else
    {
Dmitry Antipov's avatar
Dmitry Antipov committed
187
      struct frame *f = decode_window_system_frame (object);
188
      dpyinfo = FRAME_DISPLAY_INFO (f);
189
    }
190 191

  return dpyinfo;
192
}
193

194 195 196 197 198 199 200
/* Return the screen positions and offsets of frame F.
   Store the offsets between FRAME_OUTER_WINDOW and the containing
   window manager window into LEFT_OFFSET_X, RIGHT_OFFSET_X,
   TOP_OFFSET_Y and BOTTOM_OFFSET_Y.
   Store the offsets between FRAME_X_WINDOW and the containing
   window manager window into X_PIXELS_DIFF and Y_PIXELS_DIFF.
   Store the screen positions of frame F into XPTR and YPTR.
201 202 203
   These are the positions of the containing window manager window,
   not Emacs's own window.  */
void
204 205 206 207 208 209 210 211
x_real_pos_and_offsets (struct frame *f,
                        int *left_offset_x,
                        int *right_offset_x,
                        int *top_offset_y,
                        int *bottom_offset_y,
                        int *x_pixels_diff,
                        int *y_pixels_diff,
                        int *xptr,
212 213
                        int *yptr,
                        int *outer_border)
214
{
215
  int win_x = 0, win_y = 0, outer_x = 0, outer_y = 0;
216
  int real_x = 0, real_y = 0;
Paul Eggert's avatar
Paul Eggert committed
217
  bool had_errors = false;
218 219 220
  struct frame *parent_frame = FRAME_PARENT_FRAME (f);
  Window win = (parent_frame
		? FRAME_X_WINDOW (parent_frame)
221
		: f->output_data.x->parent_desc);
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
  struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
  long max_len = 400;
  Atom target_type = XA_CARDINAL;
  unsigned int ow = 0, oh = 0;
  unsigned int fw = 0, fh = 0;
  unsigned int bw = 0;
  /* We resort to XCB if possible because there are several X calls
     here which require responses from the server but do not have data
     dependencies between them.  Using XCB lets us pipeline requests,
     whereas with Xlib we must wait for each answer before sending the
     next request.

     For a non-local display, the round-trip time could be a few tens
     of milliseconds, depending on the network distance.  It doesn't
     take a lot of those to add up to a noticeable hesitation in
     responding to user actions.  */
#ifdef USE_XCB
  xcb_connection_t *xcb_conn = dpyinfo->xcb_connection;
  xcb_get_property_cookie_t prop_cookie;
  xcb_get_geometry_cookie_t outer_geom_cookie;
  bool sent_requests = false;
#else
244 245
  Atom actual_type;
  unsigned long actual_size, bytes_remaining;
246
  int rc, actual_format;
247 248
  Display *dpy = FRAME_X_DISPLAY (f);
  unsigned char *tmp_data = NULL;
249
#endif
250

251 252 253 254 255 256 257 258 259 260
  if (x_pixels_diff) *x_pixels_diff = 0;
  if (y_pixels_diff) *y_pixels_diff = 0;
  if (left_offset_x) *left_offset_x = 0;
  if (top_offset_y) *top_offset_y = 0;
  if (right_offset_x) *right_offset_x = 0;
  if (bottom_offset_y) *bottom_offset_y = 0;
  if (xptr) *xptr = 0;
  if (yptr) *yptr = 0;
  if (outer_border) *outer_border = 0;

261
  if (win == dpyinfo->root_window)
262 263
    win = FRAME_OUTER_WINDOW (f);

264 265 266 267 268 269 270
  block_input ();

#ifndef USE_XCB
  /* If we're using XCB, all errors are checked for on each call.  */
  x_catch_errors (dpy);
#endif

271 272 273 274 275
  /* 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 (;;)
276
    {
Paul Eggert's avatar
Paul Eggert committed
277
      Window wm_window UNINIT, rootw UNINIT;
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293

#ifdef USE_XCB
      xcb_query_tree_cookie_t query_tree_cookie;
      xcb_query_tree_reply_t *query_tree;

      query_tree_cookie = xcb_query_tree (xcb_conn, win);
      query_tree = xcb_query_tree_reply (xcb_conn, query_tree_cookie, NULL);
      if (query_tree == NULL)
	had_errors = true;
      else
	{
	  wm_window = query_tree->parent;
	  rootw = query_tree->root;
	  free (query_tree);
	}
#else
294 295
      Window *tmp_children;
      unsigned int tmp_nchildren;
296
      int success;
297

298
      success = XQueryTree (dpy, win, &rootw,
299
			    &wm_window, &tmp_children, &tmp_nchildren);
300

301
      had_errors = x_had_errors_p (dpy);
302

303 304 305 306
      /* Don't free tmp_children if XQueryTree failed.  */
      if (! success)
	break;

307
      XFree (tmp_children);
308
#endif
309

Paul Eggert's avatar
Paul Eggert committed
310
      if (had_errors || wm_window == rootw)
311
        break;
312

313 314
      win = wm_window;
    }
315

316 317
  if (! had_errors)
    {
318 319 320 321 322 323 324 325
#ifdef USE_XCB
      xcb_get_geometry_cookie_t geom_cookie;
      xcb_translate_coordinates_cookie_t trans_cookie;
      xcb_translate_coordinates_cookie_t outer_trans_cookie;

      xcb_translate_coordinates_reply_t *trans;
      xcb_get_geometry_reply_t *geom;
#else
326
      Window child, rootw;
327 328 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
      unsigned int ign;
#endif

#ifdef USE_XCB
      /* Fire off the requests that don't have data dependencies.

         Once we've done this, we must collect the results for each
         one before returning, even if other errors are detected,
         making the other responses moot.  */
      geom_cookie = xcb_get_geometry (xcb_conn, win);

      trans_cookie =
        xcb_translate_coordinates (xcb_conn,
                                   /* From-window, to-window.  */
                                   FRAME_DISPLAY_INFO (f)->root_window,
                                   FRAME_X_WINDOW (f),

                                   /* From-position.  */
                                   0, 0);
      if (FRAME_X_WINDOW (f) != FRAME_OUTER_WINDOW (f))
        outer_trans_cookie =
          xcb_translate_coordinates (xcb_conn,
                                     /* From-window, to-window.  */
                                     FRAME_DISPLAY_INFO (f)->root_window,
                                     FRAME_OUTER_WINDOW (f),

                                     /* From-position.  */
                                     0, 0);
      if (right_offset_x || bottom_offset_y)
	outer_geom_cookie = xcb_get_geometry (xcb_conn,
					      FRAME_OUTER_WINDOW (f));

359 360
      if (!parent_frame
	  && dpyinfo->root_window == f->output_data.x->parent_desc)
361 362 363 364 365 366 367
	/* Try _NET_FRAME_EXTENTS if our parent is the root window.  */
	prop_cookie = xcb_get_property (xcb_conn, 0, win,
					dpyinfo->Xatom_net_frame_extents,
					target_type, 0, max_len);

      sent_requests = true;
#endif
368

369
      /* Get the real coordinates for the WM window upper left corner */
370 371 372 373 374 375 376 377 378 379 380 381 382 383
#ifdef USE_XCB
      geom = xcb_get_geometry_reply (xcb_conn, geom_cookie, NULL);
      if (geom)
	{
	  real_x = geom->x;
	  real_y = geom->y;
	  ow = geom->width;
	  oh = geom->height;
	  bw = geom->border_width;
	  free (geom);
	}
      else
	had_errors = true;
#else
384
      XGetGeometry (dpy, win,
385 386
		    &rootw, &real_x, &real_y, &ow, &oh, &bw, &ign);
#endif
387 388 389 390 391 392 393 394 395 396

      /* 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
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413

         Since we don't care about the child window corresponding to
         the actual coordinates, we can send zero to get the offsets
         and compute the resulting coordinates below.  This reduces
         the data dependencies between calls and lets us pipeline the
         requests better in the XCB case.  */
#ifdef USE_XCB
      trans = xcb_translate_coordinates_reply (xcb_conn, trans_cookie, NULL);
      if (trans)
	{
	  win_x = trans->dst_x;
	  win_y = trans->dst_y;
	  free (trans);
	}
      else
	had_errors = true;
#else
414
      XTranslateCoordinates (dpy,
415

416
			     /* From-window, to-window.  */
417
			     FRAME_DISPLAY_INFO (f)->root_window,
418
                             FRAME_X_WINDOW (f),
419

420
			     /* From-position, to-position.  */
421
                             0, 0, &win_x, &win_y,
422

423 424
			     /* Child of win.  */
			     &child);
425
#endif
426

427 428 429
      win_x += real_x;
      win_y += real_y;

430
      if (FRAME_X_WINDOW (f) == FRAME_OUTER_WINDOW (f))
431
	{
432 433
          outer_x = win_x;
          outer_y = win_y;
434
	}
435 436
      else
        {
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
#ifdef USE_XCB
          xcb_translate_coordinates_reply_t *outer_trans;

          outer_trans = xcb_translate_coordinates_reply (xcb_conn,
                                                         outer_trans_cookie,
                                                         NULL);
          if (outer_trans)
            {
              outer_x = outer_trans->dst_x;
              outer_y = outer_trans->dst_y;
              free (outer_trans);
            }
          else
	    had_errors = true;
#else
452
          XTranslateCoordinates (dpy,
453

454
                                 /* From-window, to-window.  */
455
                                 FRAME_DISPLAY_INFO (f)->root_window,
456
                                 FRAME_OUTER_WINDOW (f),
457

458
                                 /* From-position, to-position.  */
459
                                 0, 0, &outer_x, &outer_y,
460

461 462
                                 /* Child of win.  */
                                 &child);
463
#endif
464 465 466

	  outer_x += real_x;
	  outer_y += real_y;
467
	}
468

469
#ifndef USE_XCB
470
      had_errors = x_had_errors_p (dpy);
471
#endif
472
    }
473

474
  if (!parent_frame && dpyinfo->root_window == f->output_data.x->parent_desc)
475 476
    {
      /* Try _NET_FRAME_EXTENTS if our parent is the root window.  */
477 478 479 480 481 482 483 484 485 486 487
#ifdef USE_XCB
      /* Make sure we didn't get an X error early and skip sending the
         request.  */
      if (sent_requests)
        {
          xcb_get_property_reply_t *prop;

          prop = xcb_get_property_reply (xcb_conn, prop_cookie, NULL);
          if (prop)
            {
              if (prop->type == target_type
488 489 490
                  && prop->format == 32
                  && (xcb_get_property_value_length (prop)
		      == 4 * sizeof (int32_t)))
491
                {
492
                  int32_t *fe = xcb_get_property_value (prop);
493 494 495 496 497 498 499 500 501 502 503

                  outer_x = -fe[0];
                  outer_y = -fe[2];
                  real_x -= fe[0];
                  real_y -= fe[2];
                }
              free (prop);
            }
          /* Xlib version doesn't set had_errors here.  Intentional or bug?  */
        }
#else
504 505 506 507 508 509 510 511
      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)
        {
512
          long *fe = (long *)tmp_data;
513 514 515 516 517 518 519

          outer_x = -fe[0];
          outer_y = -fe[2];
          real_x -= fe[0];
          real_y -= fe[2];
        }

Ken Raeburn's avatar
Ken Raeburn committed
520
      if (tmp_data) XFree (tmp_data);
521
#endif
Ken Raeburn's avatar
Ken Raeburn committed
522
    }
523

524 525
  if (right_offset_x || bottom_offset_y)
    {
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
#ifdef USE_XCB
      /* Make sure we didn't get an X error early and skip sending the
         request.  */
      if (sent_requests)
        {
          xcb_get_geometry_reply_t *outer_geom;

          outer_geom = xcb_get_geometry_reply (xcb_conn, outer_geom_cookie,
                                               NULL);
          if (outer_geom)
            {
              fw = outer_geom->width;
              fh = outer_geom->height;
              free (outer_geom);
            }
          else
	    had_errors = true;
        }
#else
545 546 547 548 549 550
      int xy_ign;
      unsigned int ign;
      Window rootw;

      XGetGeometry (dpy, FRAME_OUTER_WINDOW (f),
		    &rootw, &xy_ign, &xy_ign, &fw, &fh, &ign, &ign);
551
#endif
552 553
    }

554
#ifndef USE_XCB
555
  x_uncatch_errors ();
556
#endif
557

558
  unblock_input ();
559 560

  if (had_errors) return;
561

562 563 564 565
  if (x_pixels_diff) *x_pixels_diff = -win_x;
  if (y_pixels_diff) *y_pixels_diff = -win_y;

  if (left_offset_x) *left_offset_x = -outer_x;
566
  if (top_offset_y) *top_offset_y = -outer_y;
567

568 569
  if (xptr) *xptr = real_x;
  if (yptr) *yptr = real_y;
570

571 572
  if (outer_border) *outer_border = bw;

573 574
  if (right_offset_x) *right_offset_x = ow - fw + outer_x;
  if (bottom_offset_y) *bottom_offset_y = oh - fh + outer_y;
575 576
}

577 578 579
/* Store the screen positions of frame F into XPTR and YPTR.
   These are the positions of the containing window manager window,
   not Emacs's own window.  */
580

581 582 583
void
x_real_positions (struct frame *f, int *xptr, int *yptr)
{
584 585
  x_real_pos_and_offsets (f, NULL, NULL, NULL, NULL, NULL, NULL, xptr, yptr,
                          NULL);
586 587
}

588

589
/* Get the mouse position in frame relative coordinates.  */
590

591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
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);

620
  XTranslateCoordinates (FRAME_X_DISPLAY (f),
621

622 623 624
                         /* From-window, to-window.  */
                         FRAME_DISPLAY_INFO (f)->root_window,
                         FRAME_X_WINDOW (f),
625

626 627 628 629 630 631 632
                         /* From-position, to-position.  */
                         *x, *y, x, y,

                         /* Child of win.  */
                         &dummy_window);

  unblock_input ();
633
}
634 635 636 637

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

void
638
gamma_correct (struct frame *f, XColor *color)
639 640 641 642 643 644 645 646 647 648
{
  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;
    }
}


649
/* Decide if color named COLOR_NAME is valid for use on frame F.  If
650 651
   so, return the RGB values in COLOR.  If ALLOC_P,
   allocate the color.  Value is false if COLOR_NAME is invalid, or
652
   no color could be allocated.  */
653

654
bool
655
x_defined_color (struct frame *f, const char *color_name,
656
		 Emacs_Color *color, bool alloc_p, bool _makeIndex)
Jim Blandy's avatar
Jim Blandy committed
657
{
Paul Eggert's avatar
Paul Eggert committed
658
  bool success_p = false;
659
  Colormap cmap = FRAME_X_COLORMAP (f);
Jim Blandy's avatar
Jim Blandy committed
660

661
  block_input ();
662 663 664 665
#ifdef USE_GTK
  success_p = xg_check_special_colors (f, color_name, color);
#endif
  if (!success_p)
666
    success_p = x_parse_color (f, color_name, color) != 0;
667 668
  if (success_p && alloc_p)
    success_p = x_alloc_nearest_color (f, cmap, color);
669
  unblock_input ();
Jim Blandy's avatar
Jim Blandy committed
670

671
  return success_p;
Jim Blandy's avatar
Jim Blandy committed
672 673
}

674 675 676 677

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

679
static int
Dmitry Antipov's avatar
Dmitry Antipov committed
680
x_decode_color (struct frame *f, Lisp_Object color_name, int mono_color)
Jim Blandy's avatar
Jim Blandy committed
681
{
682
  XColor cdef;
Jim Blandy's avatar
Jim Blandy committed
683

684
  CHECK_STRING (color_name);
Jim Blandy's avatar
Jim Blandy committed
685

Paul Eggert's avatar
Paul Eggert committed
686 687 688
#if false /* 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.  */
689
  if (strcmp (SDATA (color_name), "black") == 0)
690
    return BLACK_PIX_DEFAULT (f);
691
  else if (strcmp (SDATA (color_name), "white") == 0)
692
    return WHITE_PIX_DEFAULT (f);
693
#endif
Jim Blandy's avatar
Jim Blandy committed
694

695
  /* Return MONO_COLOR for monochrome frames.  */
696
  if (FRAME_DISPLAY_INFO (f)->n_planes == 1)
697
    return mono_color;
Jim Blandy's avatar
Jim Blandy committed
698

699
  /* x_defined_color is responsible for coping with failures
700
     by looking for a near-miss.  */
701
  if (x_defined_color (f, SSDATA (color_name), &cdef, true, false))
702 703
    return cdef.pixel;

704
  signal_error ("Undefined color", color_name);
Jim Blandy's avatar
Jim Blandy committed
705
}
706 707


Jim Blandy's avatar
Jim Blandy committed
708

Gerd Moellmann's avatar
Gerd Moellmann committed
709 710 711 712 713
/* 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
714
x_set_wait_for_wm (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
Gerd Moellmann's avatar
Gerd Moellmann committed
715 716 717 718
{
  f->output_data.x->wait_for_wm = !NILP (new_value);
}

719 720 721 722 723
static void
x_set_tool_bar_position (struct frame *f,
                         Lisp_Object new_value,
                         Lisp_Object old_value)
{
724
  Lisp_Object choice = list4 (Qleft, Qright, Qtop, Qbottom);
725

726 727
  if (!NILP (Fmemq (new_value, choice)))
    {
728
#ifdef USE_GTK
729 730 731 732 733 734 735 736
      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");
737
#endif
738 739 740
    }
  else
    wrong_choice (choice, new_value);
741 742
}

743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
static void
x_set_inhibit_double_buffering (struct frame *f,
                                Lisp_Object new_value,
                                Lisp_Object old_value)
{
  block_input ();
  if (FRAME_X_WINDOW (f) && !EQ (new_value, old_value))
    {
      bool want_double_buffering = NILP (new_value);
      bool was_double_buffered = FRAME_X_DOUBLE_BUFFERED_P (f);
      /* font_drop_xrender_surfaces in xftfont does something only if
         we're double-buffered, so call font_drop_xrender_surfaces before
         and after any potential change.  One of the calls will end up
         being a no-op.  */
      if (want_double_buffering != was_double_buffered)
        font_drop_xrender_surfaces (f);
      if (FRAME_X_DOUBLE_BUFFERED_P (f) && !want_double_buffering)
        tear_down_x_back_buffer (f);
      else if (!FRAME_X_DOUBLE_BUFFERED_P (f) && want_double_buffering)
        set_up_x_back_buffer (f);
      if (FRAME_X_DOUBLE_BUFFERED_P (f) != was_double_buffered)
        {
          SET_FRAME_GARBAGED (f);
          font_drop_xrender_surfaces (f);
        }
    }
  unblock_input ();
}

772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
/**
 * x_set_undecorated:
 *
 * Set frame F's `undecorated' parameter.  If non-nil, F's window-system
 * window is drawn without decorations, title, minimize/maximize boxes
 * and external borders.  This usually means that the window cannot be
 * dragged, resized, iconified, maximized or deleted with the mouse.  If
 * nil, draw the frame with all the elements listed above unless these
 * have been suspended via window manager settings.
 *
 * Some window managers may not honor this parameter.
 */
static void
x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
{
  if (!EQ (new_value, old_value))
    {
      FRAME_UNDECORATED (f) = NILP (new_value) ? false : true;
#ifdef USE_GTK
      xg_set_undecorated (f, new_value);
#else
      Display *dpy = FRAME_X_DISPLAY (f);
      PropMotifWmHints hints;
      Atom prop = XInternAtom (dpy, "_MOTIF_WM_HINTS", False);

      memset (&hints, 0, sizeof(hints));
      hints.flags = MWM_HINTS_DECORATIONS;
      hints.decorations = NILP (new_value) ? MWM_DECOR_ALL : 0;

      block_input ();
802 803 804
      /* For some reason the third and fourth arguments in the following
	 call must be identical: In the corresponding XGetWindowProperty
	 call in getMotifHints, xfwm has the third and seventh args both
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
	 display_info->atoms[MOTIF_WM_HINTS].  Obviously, YMMV.   */
      XChangeProperty (dpy, FRAME_OUTER_WINDOW (f), prop, prop, 32,
		       PropModeReplace, (unsigned char *) &hints,
		       PROP_MOTIF_WM_HINTS_ELEMENTS);
      unblock_input ();

#endif /* USE_GTK */
    }
}

/**
 * x_set_parent_frame:
 *
 * Set frame F's `parent-frame' parameter.  If non-nil, make F a child
 * frame of the frame specified by that parameter.  Technically, this
 * makes F's window-system window a child window of the parent frame's
 * window-system window.  If nil, make F's window-system window a
 * top-level window--a child of its display's root window.
 *
 * A child frame is clipped at the native edges of its parent frame.
 * Its `left' and `top' parameters specify positions relative to the
 * top-left corner of its parent frame's native rectangle.  Usually,
 * moving a parent frame moves all its child frames too, keeping their
 * position relative to the parent unaltered.  When a parent frame is
 * iconified or made invisible, its child frames are made invisible.
 * When a parent frame is deleted, its child frames are deleted too.
 *
 * A visible child frame always appears on top of its parent frame thus
 * obscuring parts of it.  When a frame has more than one child frame,
 * their stacking order is specified just as that of non-child frames
 * relative to their display.
 *
 * Whether a child frame has a menu or tool bar may be window-system or
 * window manager dependent.  It's advisable to disable both via the
 * frame parameter settings.
 *
 * Some window managers may not honor this parameter.
 */
static void
x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
{
  struct frame *p = NULL;

  if (!NILP (new_value)
      && (!FRAMEP (new_value)
	  || !FRAME_LIVE_P (p = XFRAME (new_value))
	  || !FRAME_X_P (p)))
    {
      store_frame_param (f, Qparent_frame, old_value);
      error ("Invalid specification of `parent-frame'");
    }

  if (p != FRAME_PARENT_FRAME (f))
    {
      block_input ();
      XReparentWindow
	(FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
	 p ? FRAME_X_WINDOW (p) : DefaultRootWindow (FRAME_X_DISPLAY (f)),
	 f->left_pos, f->top_pos);
864 865 866 867 868 869
#ifdef USE_GTK
      if (EQ (x_gtk_resize_child_frames, Qresize_mode))
	gtk_container_set_resize_mode
	  (GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)),
	   p ? GTK_RESIZE_IMMEDIATE : GTK_RESIZE_QUEUE);
#endif
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 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 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975
      unblock_input ();

      fset_parent_frame (f, new_value);
    }
}

/**
 * x_set_no_focus_on_map:
 *
 * Set frame F's `no-focus-on-map' parameter which, if non-nil, means
 * that F's window-system window does not want to receive input focus
 * when it is mapped.  (A frame's window is mapped when the frame is
 * displayed for the first time and when the frame changes its state
 * from `iconified' or `invisible' to `visible'.)
 *
 * Some window managers may not honor this parameter.
 */
static void
x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
{
  if (!EQ (new_value, old_value))
    {
#ifdef USE_GTK
      xg_set_no_focus_on_map (f, new_value);
#else /* not USE_GTK */
      Display *dpy = FRAME_X_DISPLAY (f);
      Atom prop = XInternAtom (dpy, "_NET_WM_USER_TIME", False);
      Time timestamp = NILP (new_value) ? CurrentTime : 0;

      XChangeProperty (dpy, FRAME_OUTER_WINDOW (f), prop,
		       XA_CARDINAL, 32, PropModeReplace,
		       (unsigned char *) &timestamp, 1);
#endif /* USE_GTK */
      FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
    }
}

/**
 * x_set_no_accept_focus:
 *
 * Set frame F's `no-accept-focus' parameter which, if non-nil, hints
 * that F's window-system window does not want to receive input focus
 * via mouse clicks or by moving the mouse into it.
 *
 * If non-nil, this may have the unwanted side-effect that a user cannot
 * scroll a non-selected frame with the mouse.
 *
 * Some window managers may not honor this parameter.
 */
static void
x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
{
  if (!EQ (new_value, old_value))
    {
#ifdef USE_GTK
      xg_set_no_accept_focus (f, new_value);
#else /* not USE_GTK */
#ifdef USE_X_TOOLKIT
      Arg al[1];

      XtSetArg (al[0], XtNinput, NILP (new_value) ? True : False);
      XtSetValues (f->output_data.x->widget, al, 1);
#else /* not USE_X_TOOLKIT */
      Window window = FRAME_X_WINDOW (f);

      f->output_data.x->wm_hints.input = NILP (new_value) ? True : False;
      XSetWMHints (FRAME_X_DISPLAY (f), window, &f->output_data.x->wm_hints);
#endif /* USE_X_TOOLKIT */
#endif /* USE_GTK */
      FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
    }
}

/**
 * x_set_override_redirect:
 *
 * Set frame F's `override_redirect' parameter which, if non-nil, hints
 * that the window manager doesn't want to deal with F.  Usually, such
 * frames have no decorations and always appear on top of all frames.
 *
 * Some window managers may not honor this parameter.
 */
static void
x_set_override_redirect (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
{
  if (!EQ (new_value, old_value))
    {
      /* Here (xfwm) override_redirect can be changed for invisible
	 frames only.  */
      x_make_frame_invisible (f);

#ifdef USE_GTK
      xg_set_override_redirect (f, new_value);
#else /* not USE_GTK */
      XSetWindowAttributes attributes;

      attributes.override_redirect = NILP (new_value) ? False : True;
      XChangeWindowAttributes (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
			       CWOverrideRedirect, &attributes);
#endif
      x_make_frame_visible (f);
      FRAME_OVERRIDE_REDIRECT (f) = !NILP (new_value);
    }
}


976 977
#ifdef USE_GTK

978 979
/* 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.  */
980

Paul Eggert's avatar
Paul Eggert committed
981
bool
Dmitry Antipov's avatar
Dmitry Antipov committed
982
xg_set_icon (struct frame *f, Lisp_Object file)
983
{
Paul Eggert's avatar
Paul Eggert committed
984
  bool result = false;
985
  Lisp_Object found;
986

987
  found = image_find_image_file (file);
988 989 990 991 992

  if (! NILP (found))
    {
      GdkPixbuf *pixbuf;
      GError *err = NULL;
993
      char *filename = SSDATA (ENCODE_FILE (found));
994
      block_input ();
995 996 997 998 999 1000 1001 1002 1003

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

Paul Eggert's avatar
Paul Eggert committed
1004
	  result = true;
1005 1006 1007 1008
	}
      else
	g_error_free (err);

1009
      unblock_input ();
1010 1011 1012
    }

  return result;
1013
}
1014

Paul Eggert's avatar
Paul Eggert committed
1015
bool
Dmitry Antipov's avatar
Dmitry Antipov committed
1016
xg_set_icon_from_xpm_data (struct frame *f, const char **data)
1017
{
1018
  GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data (data);
1019 1020

  if (!pixbuf)
Paul Eggert's avatar
Paul Eggert committed
1021
    return false;
1022

1023
  gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), pixbuf);
1024
  g_object_unref (pixbuf);
Paul Eggert's avatar
Paul Eggert committed
1025
  return true;
1026
}
1027 1028
#endif /* USE_GTK */

Gerd Moellmann's avatar
Gerd Moellmann committed
1029

1030
/* Functions called only from `gui_set_frame_parameters'
Jim Blandy's avatar
Jim Blandy committed
1031 1032
   to set individual parameters.

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

1038
static void
1039
x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
1040
{
1041 1042
  struct x_output *x = f->output_data.x;
  unsigned long fg, old_fg;
1043

1044
  fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
1045 1046
  old_fg = FRAME_FOREGROUND_PIXEL (f);
  FRAME_FOREGROUND_PIXEL (f) = fg;
1047

1048
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
1049
    {
1050
      Display *dpy = FRAME_X_DISPLAY (f);
1051

1052
      block_input ();
1053 1054
      XSetForeground (dpy, x->normal_gc, fg);
      XSetBackground (dpy, x->reverse_gc, fg);
1055

1056 1057 1058 1059 1060 1061
      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);
	}
1062

1063
      unblock_input ();
1064

1065
      update_face_from_frame_parameter (f, Qforeground_color, arg);
1066

1067
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
1068
        redraw_frame (f);
Jim Blandy's avatar
Jim Blandy committed
1069
    }
1070

1071
  unload_color (f, old_fg);
Jim Blandy's avatar
Jim Blandy committed
1072 1073
}

1074
static void
1075
x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
1076
{
1077 1078
  struct x_output *x = f->output_data.x;
  unsigned long bg;
Jim Blandy's avatar
Jim Blandy committed
1079

1080
  bg = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
1081 1082
  unload_color (f, FRAME_BACKGROUND_PIXEL (f));
  FRAME_BACKGROUND_PIXEL (f) = bg;
1083

1084
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
1085
    {
1086
      Display *dpy = FRAME_X_DISPLAY (f);
1087

1088
      block_input ();
1089 1090 1091 1092 1093
      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
1094 1095 1096 1097
#ifdef USE_GTK
      xg_set_background_color (f, bg);
#endif

1098 1099 1100 1101 1102 1103 1104 1105
#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)
	  {
1106
	    Window window = XSCROLL_BAR (bar)->x_window;
1107 1108 1109 1110
	    XSetWindowBackground (dpy, window, bg);
	  }
      }
#endif /* USE_TOOLKIT_SCROLL_BARS */
Jim Blandy's avatar
Jim Blandy committed
1111

1112
      unblock_input ();
1113
      update_face_from_frame_parameter (f, Qbackground_color, arg);
1114

1115
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
1116
        redraw_frame (f);
Jim Blandy's avatar
Jim Blandy committed
1117 1118 1119
    }
}

1120 1121 1122 1123 1124 1125 1126 1127 1128
/* This array must stay in sync with the mouse_cursor_types array below!  */
enum mouse_cursor {
  mouse_cursor_text,
  mouse_cursor_nontext,
  mouse_cursor_hourglass,
  mouse_cursor_mode,
  mouse_cursor_hand,
  mouse_cursor_horizontal_drag,
  mouse_cursor_vertical_drag,
1129 1130 1131 1132 1133 1134 1135 1136
  mouse_cursor_left_edge,
  mouse_cursor_top_left_corner,
  mouse_cursor_top_edge,
  mouse_cursor_top_right_corner,
  mouse_cursor_right_edge,
  mouse_cursor_bottom_right_corner,
  mouse_cursor_bottom_edge,
  mouse_cursor_bottom_left_corner,
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
  mouse_cursor_max
};

struct mouse_cursor_types {
  /* Printable name for error messages (optional).  */
  const char *name;

  /* Lisp variable controlling the cursor shape.  */
  /* FIXME: A couple of these variables are defined in the C code but
     are not actually accessible from Lisp.  They should probably be
     made accessible or removed.  */
  Lisp_Object *shape_var_ptr;

  /* The default shape.  */
  int default_shape;
};

/* This array must stay in sync with enum mouse_cursor above!  */
static const struct mouse_cursor_types mouse_cursor_types[] = {
1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
  { "text",      &Vx_pointer_shape,                    XC_xterm               },
  { "nontext",   &Vx_nontext_pointer_shape,            XC_left_ptr            },
  { "hourglass", &Vx_hourglass_pointer_shape,          XC_watch               },
  { "modeline",  &Vx_mode_pointer_shape,               XC_xterm               },
  { NULL,        &Vx_sensitive_text_pointer_shape,     XC_hand2               },
  { NULL,        &Vx_window_horizontal_drag_shape,     XC_sb_h_double_arrow   },
  { NULL,        &Vx_window_vertical_drag_shape,       XC_sb_v_double_arrow   },
  { NULL,        &Vx_window_left_edge_shape,           XC_left_side           },
  { NULL,        &Vx_window_top_left_corner_shape,     XC_top_left_corner     },
  { NULL,        &Vx_window_top_edge_shape,            XC_top_side            },
  { NULL,        &Vx_window_top_right_corner_shape,    XC_top_right_corner    },
  { NULL,        &Vx_window_right_edge_shape,          XC_right_side          },
  { NULL,        &Vx_window_bottom_right_corner_shape, XC_bottom_right_corner },
  { NULL,        &Vx_window_bottom_edge_shape,         XC_bottom_side         },
  { NULL,        &Vx_window_bottom_left_corner_shape,  XC_bottom_left_corner  },
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215
};

struct mouse_cursor_data {
  /* Last index for which XCreateFontCursor has been called, and thus
     the last index for which x_request_serial[] is valid.  */
  int last_cursor_create_request;

  /* Last index for which an X error event was received in response to
     attempting to create the cursor.  */
  int error_cursor;

  /* Cursor numbers chosen.  */
  unsigned int cursor_num[mouse_cursor_max];

  /* Allocated Cursor values, or zero for failed attempts.  */
  Cursor cursor[mouse_cursor_max];

  /* X serial numbers for the first request sent by XCreateFontCursor.
     Note that there may be more than one request sent.  */
  unsigned long x_request_serial[mouse_cursor_max];

  /* If an error has been received, a pointer to where the current
     error-message text is stored.  */
  char *error_string;
};

static void
x_set_mouse_color_handler (Display *dpy, XErrorEvent *event,
			   char *error_string, void *data)
{
  struct mouse_cursor_data *cursor_data = data;
  int i;

  cursor_data->error_cursor = -1;
  cursor_data->error_string = error_string;
  for (i = 0; i < cursor_data->last_cursor_create_request; i++)
    {
      if (event->serial >= cursor_data->x_request_serial[i])
	cursor_data->error_cursor = i;
    }
  if (cursor_data->error_cursor >= 0)
    /* If we failed to allocate it, don't try to free it.  */
    cursor_data->cursor[cursor_data->error_cursor] = 0;
}

1216
static void
1217
x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
1218
{
1219 1220
  struct x_output *x = f->output_data.x;
  Display *dpy = FRAME_X_DISPLAY (f);
1221
  struct mouse_cursor_data cursor_data = { -1, -1 };
1222
  unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
1223
  unsigned long mask_color = FRAME_BACKGROUND_PIXEL (f);
1224
  int i;
1225

1226
  /* Don't let pointers be invisible.  */
1227
  if (mask_color == pixel)
1228 1229
    {
      x_free_colors (f, &pixel, 1);
Karoly Lorentey's avatar
Karoly Lorentey committed
1230
      pixel = x_copy_color (f, FRAME_FOREGROUND_PIXEL (f));
1231
    }
1232

1233 1234
  unload_color (f, x->mouse_pixel);
  x->mouse_pixel = pixel;
Jim Blandy's avatar
Jim Blandy committed
1235

1236
  for (i = 0; i < mouse_cursor_max; i++)
1237
    {
1238
      Lisp_Object shape_var = *mouse_cursor_types[i].shape_var_ptr;
Paul Eggert's avatar
Paul Eggert committed
1239 1240 1241 1242
      cursor_data.cursor_num[i]
	= (!NILP (shape_var)
	   ? check_uinteger_max (shape_var, UINT_MAX)
	   : mouse_cursor_types[i].default_shape);
1243
    }
1244

1245
  block_input ();
1246

1247 1248
  /* It's not okay to crash if the user selects a screwy cursor.  */
  x_catch_errors_with_handler (dpy, x_set_mouse_color_handler, &cursor_data);
Jim Blandy's avatar
Jim Blandy committed
1249

1250
  for (i = 0; i < mouse_cursor_max; i++)
1251
    {
1252 1253 1254 1255
      cursor_data.x_request_serial[i] = XNextRequest (dpy);
      cursor_data.last_cursor_create_request = i;
      cursor_data.cursor[i] = XCreateFontCursor (dpy,
						 cursor_data.cursor_num[i]);
1256 1257
    }

1258 1259 1260
  /* Now sync up and process all received errors from cursor
     creation.  */
  if (x_had_errors_p (dpy))
1261
    {
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282
      const char *bad_cursor_name = NULL;
      /* Bounded by X_ERROR_MESSAGE_SIZE in xterm.c.  */
      size_t message_length = strlen (cursor_data.error_string);
      char *xmessage = alloca (1 + message_length);
      memcpy (xmessage, cursor_data.error_string, message_length);

      x_uncatch_errors ();

      /* Free any successfully created cursors.  */
      for (i = 0; i < mouse_cursor_max; i++)
	if (cursor_data.cursor[i] != 0)
	  XFreeCursor (dpy, cursor_data.cursor[i]);

      /* This should only be able to fail if the server's serial
	 number tracking is broken.  */
      if (cursor_data.error_cursor >= 0)
	bad_cursor_name = mouse_cursor_types[cursor_data.error_cursor].name;
      if (bad_cursor_name)
	error ("bad %s pointer cursor: %s", bad_cursor_name, xmessage);
      else
	error ("can't set cursor shape: %s", xmessage);
1283 1284
    }

1285
  x_uncatch_errors_after_check ();
1286

Jim Blandy's avatar
Jim Blandy committed
1287
  {
1288 1289 1290 1291 1292 1293 1294 1295
    XColor colors[2]; /* 0=foreground, 1=background */

    colors[0].pixel = x->mouse_pixel;
    colors[1].pixel = mask_color;
    x_query_colors (f, colors, 2);

    for (i = 0; i < mouse_cursor_max; i++)