xfns.c 206 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
#include "bitmaps/gray.xbm"
50 51
#include "xsettings.h"

52 53 54 55 56 57 58
#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
59 60 61 62
#ifdef USE_GTK
#include "gtkutil.h"
#endif

63 64 65
#ifdef USE_X_TOOLKIT
#include <X11/Shell.h>

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

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

#include "widget.h"

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

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

98 99 100 101
#ifdef USE_LUCID
#include "../lwlib/xlwmenu.h"
#endif

Juanma Barranquero's avatar
Juanma Barranquero committed
102
#if !defined (NO_EDITRES)
103
#define HACK_EDITRES
104
extern void _XEditResCheckMessages (Widget, XtPointer, XEvent *, Boolean *);
Dan Nicolaescu's avatar
Dan Nicolaescu committed
105
#endif /* not defined NO_EDITRES */
106

107 108
/* Unique id counter for widgets created by the Lucid Widget Library.  */

109 110
extern LWLIB_ID widget_id_tick;

111 112 113 114
#ifdef USE_MOTIF

#endif /* USE_MOTIF */

115 116
#endif /* USE_X_TOOLKIT */

Kenichi Handa's avatar
Kenichi Handa committed
117 118 119 120
#ifdef USE_GTK

#endif /* USE_GTK */

Richard M. Stallman's avatar
Richard M. Stallman committed
121 122
#define MAXREQUEST(dpy) (XMaxRequestSize (dpy))

123
static ptrdiff_t image_cache_refcount;
124
#ifdef GLYPH_DEBUG
125
static int dpyinfo_refcount;
126 127
#endif

128 129
static struct x_display_info *x_display_info_for_name (Lisp_Object);

130
/* Let the user specify an X display with a Lisp object.
131
   OBJECT may be nil, a frame or a terminal object.
132 133 134
   nil stands for the selected frame--or, if that is not an X frame,
   the first X display on the list.  */

135
struct x_display_info *
136
check_x_display_info (Lisp_Object object)
137
{
138
  struct x_display_info *dpyinfo = NULL;
139

140
  if (NILP (object))
141
    {
Gerd Moellmann's avatar
Gerd Moellmann committed
142
      struct frame *sf = XFRAME (selected_frame);
143

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

155
      if (t->type != output_x_window)
156
        error ("Terminal %d is not an X display", t->id);
157

158
      dpyinfo = t->display_info.x;
159
    }
160 161
  else if (STRINGP (object))
    dpyinfo = x_display_info_for_name (object);
162 163
  else
    {
Dmitry Antipov's avatar
Dmitry Antipov committed
164
      struct frame *f = decode_window_system_frame (object);
165
      dpyinfo = FRAME_DISPLAY_INFO (f);
166
    }
167 168

  return dpyinfo;
169
}
170

171 172 173 174 175 176 177
/* 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.
178 179 180
   These are the positions of the containing window manager window,
   not Emacs's own window.  */
void
181 182 183 184 185 186 187 188
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,
189 190
                        int *yptr,
                        int *outer_border)
191
{
192
  int win_x, win_y, outer_x IF_LINT (= 0), outer_y IF_LINT (= 0);
193
  int real_x = 0, real_y = 0;
Paul Eggert's avatar
Paul Eggert committed
194
  bool had_errors = false;
195
  Window win = f->output_data.x->parent_desc;
196 197
  Atom actual_type;
  unsigned long actual_size, bytes_remaining;
198
  int rc, actual_format;
199
  struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
200 201 202 203
  long max_len = 400;
  Display *dpy = FRAME_X_DISPLAY (f);
  unsigned char *tmp_data = NULL;
  Atom target_type = XA_CARDINAL;
204
  unsigned int ow IF_LINT (= 0), oh IF_LINT (= 0);
205

206
  block_input ();
207

208
  x_catch_errors (dpy);
209

210 211 212 213 214 215 216 217 218 219
  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;

220
  if (win == dpyinfo->root_window)
221 222 223 224 225 226 227
    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 (;;)
228
    {
229 230 231
      Window wm_window, rootw;
      Window *tmp_children;
      unsigned int tmp_nchildren;
232
      int success;
233

234 235
      success = XQueryTree (FRAME_X_DISPLAY (f), win, &rootw,
			    &wm_window, &tmp_children, &tmp_nchildren);
236

237
      had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
238

239 240 241 242
      /* Don't free tmp_children if XQueryTree failed.  */
      if (! success)
	break;

243
      XFree (tmp_children);
244

245 246
      if (wm_window == rootw || had_errors)
        break;
247

248 249
      win = wm_window;
    }
250

251 252
  if (! had_errors)
    {
Ken Raeburn's avatar
Ken Raeburn committed
253
      unsigned int bw, ign;
254
      Window child, rootw;
255

256 257
      /* Get the real coordinates for the WM window upper left corner */
      XGetGeometry (FRAME_X_DISPLAY (f), win,
Ken Raeburn's avatar
Ken Raeburn committed
258
                    &rootw, &real_x, &real_y, &ow, &oh, &bw, &ign);
259

260
      if (outer_border)
Ken Raeburn's avatar
Ken Raeburn committed
261
        *outer_border = bw;
262 263 264 265 266 267 268 269 270 271 272

      /* 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
      */
273
      XTranslateCoordinates (FRAME_X_DISPLAY (f),
274

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

279
			     /* From-position, to-position.  */
280
                             real_x, real_y, &win_x, &win_y,
281

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

285
      if (FRAME_X_WINDOW (f) == FRAME_OUTER_WINDOW (f))
286
	{
287 288
          outer_x = win_x;
          outer_y = win_y;
289
	}
290 291 292
      else
        {
          XTranslateCoordinates (FRAME_X_DISPLAY (f),
293

294
                                 /* From-window, to-window.  */
295
                                 FRAME_DISPLAY_INFO (f)->root_window,
296
                                 FRAME_OUTER_WINDOW (f),
297

298 299
                                 /* From-position, to-position.  */
                                 real_x, real_y, &outer_x, &outer_y,
300

301 302
                                 /* Child of win.  */
                                 &child);
303
	}
304

305 306
      had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
    }
307

Ken Raeburn's avatar
Ken Raeburn committed
308
  if (!had_errors && dpyinfo->root_window == f->output_data.x->parent_desc)
309 310 311 312 313 314 315 316 317 318
    {
      /* 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)
        {
319
          long *fe = (long *)tmp_data;
320 321 322 323 324 325 326

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

Ken Raeburn's avatar
Ken Raeburn committed
327 328
      if (tmp_data) XFree (tmp_data);
    }
329

330
  x_uncatch_errors ();
331

332
  unblock_input ();
333 334

  if (had_errors) return;
335

336 337 338 339
  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;
340
  if (top_offset_y) *top_offset_y = -outer_y;
341

342 343
  if (xptr) *xptr = real_x;
  if (yptr) *yptr = real_y;
344

345
  if (right_offset_x || bottom_offset_y)
346 347 348 349 350 351 352 353 354 355
    {
      int xy_ign;
      unsigned int ign, fw, fh;
      Window rootw;

      XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
		    &rootw, &xy_ign, &xy_ign, &fw, &fh, &ign, &ign);
      if (right_offset_x) *right_offset_x = ow - fw + outer_x;
      if (bottom_offset_y) *bottom_offset_y = oh - fh + outer_y;
    }
356 357
}

358 359 360
/* 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.  */
361

362 363 364
void
x_real_positions (struct frame *f, int *xptr, int *yptr)
{
365 366
  x_real_pos_and_offsets (f, NULL, NULL, NULL, NULL, NULL, NULL, xptr, yptr,
                          NULL);
367 368
}

369

370
/* Get the mouse position in frame relative coordinates.  */
371

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
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);

401
  XTranslateCoordinates (FRAME_X_DISPLAY (f),
402

403 404 405
                         /* From-window, to-window.  */
                         FRAME_DISPLAY_INFO (f)->root_window,
                         FRAME_X_WINDOW (f),
406

407 408 409 410 411 412 413
                         /* From-position, to-position.  */
                         *x, *y, x, y,

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

  unblock_input ();
414
}
415 416 417 418

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

void
419
gamma_correct (struct frame *f, XColor *color)
420 421 422 423 424 425 426 427 428 429
{
  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;
    }
}


430
/* Decide if color named COLOR_NAME is valid for use on frame F.  If
431 432
   so, return the RGB values in COLOR.  If ALLOC_P,
   allocate the color.  Value is false if COLOR_NAME is invalid, or
433
   no color could be allocated.  */
434

435
bool
436
x_defined_color (struct frame *f, const char *color_name,
437
		 XColor *color, bool alloc_p)
Jim Blandy's avatar
Jim Blandy committed
438
{
Paul Eggert's avatar
Paul Eggert committed
439
  bool success_p = false;
440
  Colormap cmap = FRAME_X_COLORMAP (f);
Jim Blandy's avatar
Jim Blandy committed
441

442
  block_input ();
443 444 445 446
#ifdef USE_GTK
  success_p = xg_check_special_colors (f, color_name, color);
#endif
  if (!success_p)
447
    success_p = x_parse_color (f, color_name, color) != 0;
448 449
  if (success_p && alloc_p)
    success_p = x_alloc_nearest_color (f, cmap, color);
450
  unblock_input ();
Jim Blandy's avatar
Jim Blandy committed
451

452
  return success_p;
Jim Blandy's avatar
Jim Blandy committed
453 454
}

455 456 457 458

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

460
static int
Dmitry Antipov's avatar
Dmitry Antipov committed
461
x_decode_color (struct frame *f, Lisp_Object color_name, int mono_color)
Jim Blandy's avatar
Jim Blandy committed
462
{
463
  XColor cdef;
Jim Blandy's avatar
Jim Blandy committed
464

465
  CHECK_STRING (color_name);
Jim Blandy's avatar
Jim Blandy committed
466

Paul Eggert's avatar
Paul Eggert committed
467 468 469
#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.  */
470
  if (strcmp (SDATA (color_name), "black") == 0)
471
    return BLACK_PIX_DEFAULT (f);
472
  else if (strcmp (SDATA (color_name), "white") == 0)
473
    return WHITE_PIX_DEFAULT (f);
474
#endif
Jim Blandy's avatar
Jim Blandy committed
475

476
  /* Return MONO_COLOR for monochrome frames.  */
477
  if (FRAME_DISPLAY_INFO (f)->n_planes == 1)
478
    return mono_color;
Jim Blandy's avatar
Jim Blandy committed
479

480
  /* x_defined_color is responsible for coping with failures
481
     by looking for a near-miss.  */
Paul Eggert's avatar
Paul Eggert committed
482
  if (x_defined_color (f, SSDATA (color_name), &cdef, true))
483 484
    return cdef.pixel;

485
  signal_error ("Undefined color", color_name);
Jim Blandy's avatar
Jim Blandy committed
486
}
487 488


Jim Blandy's avatar
Jim Blandy committed
489

Gerd Moellmann's avatar
Gerd Moellmann committed
490 491 492 493 494
/* 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
495
x_set_wait_for_wm (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
Gerd Moellmann's avatar
Gerd Moellmann committed
496 497 498 499
{
  f->output_data.x->wait_for_wm = !NILP (new_value);
}

500 501 502 503 504
static void
x_set_tool_bar_position (struct frame *f,
                         Lisp_Object new_value,
                         Lisp_Object old_value)
{
505
  Lisp_Object choice = list4 (Qleft, Qright, Qtop, Qbottom);
506

507 508
  if (!NILP (Fmemq (new_value, choice)))
    {
509
#ifdef USE_GTK
510 511 512 513 514 515 516 517
      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");
518
#endif
519 520 521
    }
  else
    wrong_choice (choice, new_value);
522 523
}

524 525
#ifdef USE_GTK

526 527
/* 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.  */
528

Paul Eggert's avatar
Paul Eggert committed
529
bool
Dmitry Antipov's avatar
Dmitry Antipov committed
530
xg_set_icon (struct frame *f, Lisp_Object file)
531
{
Paul Eggert's avatar
Paul Eggert committed
532
  bool result = false;
533
  Lisp_Object found;
534

535 536 537 538 539 540
  found = x_find_image_file (file);

  if (! NILP (found))
    {
      GdkPixbuf *pixbuf;
      GError *err = NULL;
541
      char *filename = SSDATA (ENCODE_FILE (found));
542
      block_input ();
543 544 545 546 547 548 549 550 551

      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
552
	  result = true;
553 554 555 556
	}
      else
	g_error_free (err);

557
      unblock_input ();
558 559 560
    }

  return result;
561
}
562

Paul Eggert's avatar
Paul Eggert committed
563
bool
Dmitry Antipov's avatar
Dmitry Antipov committed
564
xg_set_icon_from_xpm_data (struct frame *f, const char **data)
565
{
566
  GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data (data);
567 568

  if (!pixbuf)
Paul Eggert's avatar
Paul Eggert committed
569
    return false;
570

571
  gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), pixbuf);
572
  g_object_unref (pixbuf);
Paul Eggert's avatar
Paul Eggert committed
573
  return true;
574
}
575 576
#endif /* USE_GTK */

Gerd Moellmann's avatar
Gerd Moellmann committed
577

Jim Blandy's avatar
Jim Blandy committed
578
/* Functions called only from `x_set_frame_param'
Jim Blandy's avatar
Jim Blandy committed
579 580
   to set individual parameters.

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

586
static void
587
x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
588
{
589 590
  struct x_output *x = f->output_data.x;
  unsigned long fg, old_fg;
591

592
  fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
593 594
  old_fg = FRAME_FOREGROUND_PIXEL (f);
  FRAME_FOREGROUND_PIXEL (f) = fg;
595

596
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
597
    {
598
      Display *dpy = FRAME_X_DISPLAY (f);
599

600
      block_input ();
601 602
      XSetForeground (dpy, x->normal_gc, fg);
      XSetBackground (dpy, x->reverse_gc, fg);
603

604 605 606 607 608 609
      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);
	}
610

611
      unblock_input ();
612

613
      update_face_from_frame_parameter (f, Qforeground_color, arg);
614

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

619
  unload_color (f, old_fg);
Jim Blandy's avatar
Jim Blandy committed
620 621
}

622
static void
623
x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
624
{
625 626
  struct x_output *x = f->output_data.x;
  unsigned long bg;
Jim Blandy's avatar
Jim Blandy committed
627

628
  bg = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
629 630
  unload_color (f, FRAME_BACKGROUND_PIXEL (f));
  FRAME_BACKGROUND_PIXEL (f) = bg;
631

632
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
633
    {
634
      Display *dpy = FRAME_X_DISPLAY (f);
635

636
      block_input ();
637 638 639 640 641
      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
642 643 644 645
#ifdef USE_GTK
      xg_set_background_color (f, bg);
#endif

646 647 648 649 650 651 652 653
#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)
	  {
654
	    Window window = XSCROLL_BAR (bar)->x_window;
655 656 657 658
	    XSetWindowBackground (dpy, window, bg);
	  }
      }
#endif /* USE_TOOLKIT_SCROLL_BARS */
Jim Blandy's avatar
Jim Blandy committed
659

660
      unblock_input ();
661
      update_face_from_frame_parameter (f, Qbackground_color, arg);
662

663
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
664
        redraw_frame (f);
Jim Blandy's avatar
Jim Blandy committed
665 666 667
    }
}

668
static void
669
x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
670
{
671 672
  struct x_output *x = f->output_data.x;
  Display *dpy = FRAME_X_DISPLAY (f);
673
  Cursor cursor, nontext_cursor, mode_cursor, hand_cursor;
674
  Cursor hourglass_cursor, horizontal_drag_cursor, vertical_drag_cursor;
675
  unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
676
  unsigned long mask_color = FRAME_BACKGROUND_PIXEL (f);
677

678
  /* Don't let pointers be invisible.  */
679
  if (mask_color == pixel)
680 681
    {
      x_free_colors (f, &pixel, 1);
Karoly Lorentey's avatar
Karoly Lorentey committed
682
      pixel = x_copy_color (f, FRAME_FOREGROUND_PIXEL (f));
683
    }
684

685 686
  unload_color (f, x->mouse_pixel);
  x->mouse_pixel = pixel;
Jim Blandy's avatar
Jim Blandy committed
687

688
  block_input ();
689

690
  /* It's not okay to crash if the user selects a screwy cursor.  */
691
  x_catch_errors (dpy);
692

693
  if (!NILP (Vx_pointer_shape))
Jim Blandy's avatar
Jim Blandy committed
694
    {
695
      CHECK_NUMBER (Vx_pointer_shape);
696
      cursor = XCreateFontCursor (dpy, XINT (Vx_pointer_shape));
Jim Blandy's avatar
Jim Blandy committed
697 698
    }
  else
699 700
    cursor = XCreateFontCursor (dpy, XC_xterm);
  x_check_errors (dpy, "bad text pointer cursor: %s");
Jim Blandy's avatar
Jim Blandy committed
701

702
  if (!NILP (Vx_nontext_pointer_shape))
Jim Blandy's avatar
Jim Blandy committed
703
    {
704
      CHECK_NUMBER (Vx_nontext_pointer_shape);
705 706
      nontext_cursor
	= XCreateFontCursor (dpy, XINT (Vx_nontext_pointer_shape));
Jim Blandy's avatar
Jim Blandy committed
707 708
    }
  else
709 710
    nontext_cursor = XCreateFontCursor (dpy, XC_left_ptr);
  x_check_errors (dpy, "bad nontext pointer cursor: %s");
Jim Blandy's avatar
Jim Blandy committed
711

712
  if (!NILP (Vx_hourglass_pointer_shape))
713
    {
714
      CHECK_NUMBER (Vx_hourglass_pointer_shape);
715 716
      hourglass_cursor
	= XCreateFontCursor (dpy, XINT (Vx_hourglass_pointer_shape));
717 718
    }
  else
719 720
    hourglass_cursor = XCreateFontCursor (dpy, XC_watch);
  x_check_errors (dpy, "bad hourglass pointer cursor: %s");
721

722
  if (!NILP (Vx_mode_pointer_shape))
Jim Blandy's avatar
Jim Blandy committed
723
    {
724
      CHECK_NUMBER (Vx_mode_pointer_shape);
725
      mode_cursor = XCreateFontCursor (dpy, XINT (Vx_mode_pointer_shape));
Jim Blandy's avatar
Jim Blandy committed
726 727
    }
  else
728 729
    mode_cursor = XCreateFontCursor (dpy, XC_xterm);
  x_check_errors (dpy, "bad modeline pointer cursor: %s");
730

731
  if (!NILP (Vx_sensitive_text_pointer_shape))
732
    {
733
      CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
734
      hand_cursor
735
	= XCreateFontCursor (dpy, XINT (Vx_sensitive_text_pointer_shape));
736 737
    }
  else
738
    hand_cursor = XCreateFontCursor (dpy, XC_hand2);
Jim Blandy's avatar
Jim Blandy committed
739

740 741
  if (!NILP (Vx_window_horizontal_drag_shape))
    {
Paul Eggert's avatar
Paul Eggert committed
742
      CHECK_TYPE_RANGED_INTEGER (unsigned, Vx_window_horizontal_drag_shape);
743
      horizontal_drag_cursor
744
	= XCreateFontCursor (dpy, XINT (Vx_window_horizontal_drag_shape));
745 746 747
    }
  else
    horizontal_drag_cursor
748
      = XCreateFontCursor (dpy, XC_sb_h_double_arrow);
749

750 751 752 753 754 755 756 757 758 759
  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);

760
  /* Check and report errors with the above calls.  */
761
  x_check_errors (dpy, "can't set cursor shape: %s");
762
  x_uncatch_errors_after_check ();
763

Jim Blandy's avatar
Jim Blandy committed
764 765 766
  {
    XColor fore_color, back_color;

767
    fore_color.pixel = x->mouse_pixel;
768
    x_query_color (f, &fore_color);
Jim Blandy's avatar
Jim Blandy committed
769
    back_color.pixel = mask_color;
770
    x_query_color (f, &back_color);
771

772 773 774
    XRecolorCursor (dpy, cursor, &fore_color, &back_color);
    XRecolorCursor (dpy, nontext_cursor, &fore_color, &back_color);
    XRecolorCursor (dpy, mode_cursor, &fore_color, &back_color);
775
    XRecolorCursor (dpy, hand_cursor, &fore_color, &back_color);
776 777
    XRecolorCursor (dpy, hourglass_cursor, &fore_color, &back_color);
    XRecolorCursor (dpy, horizontal_drag_cursor, &fore_color, &back_color);
778
    XRecolorCursor (dpy, vertical_drag_cursor, &fore_color, &back_color);
Jim Blandy's avatar
Jim Blandy committed
779 780
  }

781
  if (FRAME_X_WINDOW (f) != 0)
782 783
    XDefineCursor (dpy, FRAME_X_WINDOW (f),
                   f->output_data.x->current_cursor = cursor);
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803

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

805 806 807 808
  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
809

810 811 812 813
  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;
814

815 816 817 818 819
  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;

820
  XFlush (dpy);
821
  unblock_input ();
822 823

  update_face_from_frame_parameter (f, Qmouse_color, arg);
Jim Blandy's avatar
Jim Blandy committed
824 825
}

826
static void
827
x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
828
{
829
  unsigned long fore_pixel, pixel;
Paul Eggert's avatar
Paul Eggert committed
830
  bool fore_pixel_allocated_p = false, pixel_allocated_p = false;
831
  struct x_output *x = f->output_data.x;
Jim Blandy's avatar
Jim Blandy committed
832

833 834 835 836
  if (!NILP (Vx_cursor_fore_pixel))
    {
      fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
				   WHITE_PIX_DEFAULT (f));
Paul Eggert's avatar
Paul Eggert committed
837
      fore_pixel_allocated_p = true;
838
    }
Jim Blandy's avatar
Jim Blandy committed
839
  else
Karoly Lorentey's avatar
Karoly Lorentey committed
840
    fore_pixel = FRAME_BACKGROUND_PIXEL (f);
841

842
  pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
Paul Eggert's avatar
Paul Eggert committed
843
  pixel_allocated_p = true;
844

845
  /* Make sure that the cursor color differs from the background color.  */
Karoly Lorentey's avatar
Karoly Lorentey committed
846
  if (pixel == FRAME_BACKGROUND_PIXEL (f))
Jim Blandy's avatar
Jim Blandy committed
847
    {
848 849 850
      if (pixel_allocated_p)
	{
	  x_free_colors (f, &pixel, 1);
Paul Eggert's avatar
Paul Eggert committed
851
	  pixel_allocated_p = false;
852
	}
853

854
      pixel = x->mouse_pixel;
855
      if (pixel == fore_pixel)
856 857 858 859
	{
	  if (fore_pixel_allocated_p)
	    {
	      x_free_colors (f, &fore_pixel, 1);
Paul Eggert's avatar
Paul Eggert committed
860
	      fore_pixel_allocated_p = false;
861
	    }
Karoly Lorentey's avatar
Karoly Lorentey committed
862
	  fore_pixel = FRAME_BACKGROUND_PIXEL (f);
863
	}
Jim Blandy's avatar
Jim Blandy committed
864
    }
865

866
  unload_color (f, x->cursor_foreground_pixel);
867 868
  if (!fore_pixel_allocated_p)
    fore_pixel = x_copy_color (f, fore_pixel);
869
  x->cursor_foreground_pixel = fore_pixel;
Jim Blandy's avatar
Jim Blandy committed
870

871
  unload_color (f, x->cursor_pixel);
872 873
  if (!pixel_allocated_p)
    pixel = x_copy_color (f, pixel);
874
  x->cursor_pixel = pixel;
875

876
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
877
    {
878
      block_input ();
879 880
      XSetBackground (FRAME_X_DISPLAY (f), x->cursor_gc, x->cursor_pixel);
      XSetForeground (FRAME_X_DISPLAY (f), x->cursor_gc, fore_pixel);