xfns.c 207 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"
Jim Blandy's avatar
Jim Blandy committed
27
#include "frame.h"
Jim Blandy's avatar
Jim Blandy committed
28 29 30
#include "window.h"
#include "buffer.h"
#include "dispextern.h"
Jim Blandy's avatar
Jim Blandy committed
31
#include "keyboard.h"
32
#include "blockinput.h"
Karl Heuer's avatar
Karl Heuer committed
33
#include "charset.h"
Kenichi Handa's avatar
Kenichi Handa committed
34
#include "coding.h"
35
#include "termhooks.h"
Kenichi Handa's avatar
Kenichi Handa committed
36 37
#include "font.h"

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

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

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

55 56 57
#ifdef USE_X_TOOLKIT
#include <X11/Shell.h>

58
#ifndef USE_MOTIF
Chong Yidong's avatar
Chong Yidong committed
59 60
#ifdef HAVE_XAW3D
#include <X11/Xaw3d/Paned.h>
Chong Yidong's avatar
Chong Yidong committed
61
#include <X11/Xaw3d/Label.h>
Chong Yidong's avatar
Chong Yidong committed
62
#else /* !HAVE_XAW3D */
63 64
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Label.h>
Chong Yidong's avatar
Chong Yidong committed
65
#endif /* HAVE_XAW3D */
66
#endif /* USE_MOTIF */
67 68 69 70 71

#ifdef USG
#undef USG	/* ####KLUDGE for Solaris 2.2 and up */
#include <X11/Xos.h>
#define USG
72 73
#ifdef USG /* Pacify gcc -Wunused-macros.  */
#endif
74 75 76 77 78 79 80 81
#else
#include <X11/Xos.h>
#endif

#include "widget.h"

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

82 83 84 85
#ifdef USE_MOTIF
#include <Xm/Xm.h>
#include <Xm/DialogS.h>
#include <Xm/FileSB.h>
Jan D's avatar
Jan D committed
86 87
#include <Xm/List.h>
#include <Xm/TextF.h>
88 89
#endif

90 91 92 93
#ifdef USE_LUCID
#include "../lwlib/xlwmenu.h"
#endif

Juanma Barranquero's avatar
Juanma Barranquero committed
94
#if !defined (NO_EDITRES)
95
#define HACK_EDITRES
96
extern void _XEditResCheckMessages (Widget, XtPointer, XEvent *, Boolean *);
Dan Nicolaescu's avatar
Dan Nicolaescu committed
97
#endif /* not defined NO_EDITRES */
98

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

101 102
extern LWLIB_ID widget_id_tick;

103 104 105 106
#ifdef USE_MOTIF

#endif /* USE_MOTIF */

107 108
#endif /* USE_X_TOOLKIT */

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

#endif /* USE_GTK */

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

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

120 121
static struct x_display_info *x_display_info_for_name (Lisp_Object);

122
/* Let the user specify an X display with a Lisp object.
123
   OBJECT may be nil, a frame or a terminal object.
124 125 126
   nil stands for the selected frame--or, if that is not an X frame,
   the first X display on the list.  */

127
struct x_display_info *
128
check_x_display_info (Lisp_Object object)
129
{
130
  struct x_display_info *dpyinfo = NULL;
131

132
  if (NILP (object))
133
    {
Gerd Moellmann's avatar
Gerd Moellmann committed
134
      struct frame *sf = XFRAME (selected_frame);
135

Gerd Moellmann's avatar
Gerd Moellmann committed
136
      if (FRAME_X_P (sf) && FRAME_LIVE_P (sf))
137
	dpyinfo = FRAME_DISPLAY_INFO (sf);
138
      else if (x_display_list != 0)
139
	dpyinfo = x_display_list;
140 141 142
      else
	error ("X windows are not in use or not initialized");
    }
143
  else if (TERMINALP (object))
144
    {
145
      struct terminal *t = decode_live_terminal (object);
146

147
      if (t->type != output_x_window)
148
        error ("Terminal %d is not an X display", t->id);
149

150
      dpyinfo = t->display_info.x;
151
    }
152 153
  else if (STRINGP (object))
    dpyinfo = x_display_info_for_name (object);
154 155
  else
    {
Dmitry Antipov's avatar
Dmitry Antipov committed
156
      struct frame *f = decode_window_system_frame (object);
157
      dpyinfo = FRAME_DISPLAY_INFO (f);
158
    }
159 160

  return dpyinfo;
161
}
162

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

198
  block_input ();
199

200
  x_catch_errors (dpy);
201

202 203 204 205 206 207 208 209 210 211
  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;

212
  if (win == dpyinfo->root_window)
213 214 215 216 217 218 219
    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 (;;)
220
    {
221 222 223
      Window wm_window, rootw;
      Window *tmp_children;
      unsigned int tmp_nchildren;
224
      int success;
225

226 227
      success = XQueryTree (FRAME_X_DISPLAY (f), win, &rootw,
			    &wm_window, &tmp_children, &tmp_nchildren);
228

229
      had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
230

231 232 233 234
      /* Don't free tmp_children if XQueryTree failed.  */
      if (! success)
	break;

235
      XFree (tmp_children);
236

237 238
      if (wm_window == rootw || had_errors)
        break;
239

240 241
      win = wm_window;
    }
242

243 244
  if (! had_errors)
    {
Ken Raeburn's avatar
Ken Raeburn committed
245
      unsigned int bw, ign;
246
      Window child, rootw;
247

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

252
      if (outer_border)
Ken Raeburn's avatar
Ken Raeburn committed
253
        *outer_border = bw;
254 255 256 257 258 259 260 261 262 263 264

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

267
			     /* From-window, to-window.  */
268
			     FRAME_DISPLAY_INFO (f)->root_window,
269
                             FRAME_X_WINDOW (f),
270

271
			     /* From-position, to-position.  */
272
                             real_x, real_y, &win_x, &win_y,
273

274 275
			     /* Child of win.  */
			     &child);
276

277
      if (FRAME_X_WINDOW (f) == FRAME_OUTER_WINDOW (f))
278
	{
279 280
          outer_x = win_x;
          outer_y = win_y;
281
	}
282 283 284
      else
        {
          XTranslateCoordinates (FRAME_X_DISPLAY (f),
285

286
                                 /* From-window, to-window.  */
287
                                 FRAME_DISPLAY_INFO (f)->root_window,
288
                                 FRAME_OUTER_WINDOW (f),
289

290 291
                                 /* From-position, to-position.  */
                                 real_x, real_y, &outer_x, &outer_y,
292

293 294
                                 /* Child of win.  */
                                 &child);
295
	}
296

297 298
      had_errors = x_had_errors_p (FRAME_X_DISPLAY (f));
    }
299

Ken Raeburn's avatar
Ken Raeburn committed
300
  if (!had_errors && dpyinfo->root_window == f->output_data.x->parent_desc)
301 302 303 304 305 306 307 308 309 310
    {
      /* 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)
        {
311
          long *fe = (long *)tmp_data;
312 313 314 315 316 317 318

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

Ken Raeburn's avatar
Ken Raeburn committed
319 320
      if (tmp_data) XFree (tmp_data);
    }
321

322
  x_uncatch_errors ();
323

324
  unblock_input ();
325 326

  if (had_errors) return;
327

328 329 330 331
  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;
332
  if (top_offset_y) *top_offset_y = -outer_y;
333

334 335
  if (xptr) *xptr = real_x;
  if (yptr) *yptr = real_y;
336

337
  if (right_offset_x || bottom_offset_y)
338 339 340 341 342 343 344 345 346 347
    {
      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;
    }
348 349
}

350 351 352
/* 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.  */
353

354 355 356
void
x_real_positions (struct frame *f, int *xptr, int *yptr)
{
357 358
  x_real_pos_and_offsets (f, NULL, NULL, NULL, NULL, NULL, NULL, xptr, yptr,
                          NULL);
359 360
}

361

362
/* Get the mouse position in frame relative coordinates.  */
363

364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
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);

393
  XTranslateCoordinates (FRAME_X_DISPLAY (f),
394

395 396 397
                         /* From-window, to-window.  */
                         FRAME_DISPLAY_INFO (f)->root_window,
                         FRAME_X_WINDOW (f),
398

399 400 401 402 403 404 405
                         /* From-position, to-position.  */
                         *x, *y, x, y,

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

  unblock_input ();
406
}
407 408 409 410

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

void
411
gamma_correct (struct frame *f, XColor *color)
412 413 414 415 416 417 418 419 420 421
{
  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;
    }
}


422
/* Decide if color named COLOR_NAME is valid for use on frame F.  If
423 424
   so, return the RGB values in COLOR.  If ALLOC_P,
   allocate the color.  Value is false if COLOR_NAME is invalid, or
425
   no color could be allocated.  */
426

427
bool
428
x_defined_color (struct frame *f, const char *color_name,
429
		 XColor *color, bool alloc_p)
Jim Blandy's avatar
Jim Blandy committed
430
{
Paul Eggert's avatar
Paul Eggert committed
431
  bool success_p = false;
432
  Colormap cmap = FRAME_X_COLORMAP (f);
Jim Blandy's avatar
Jim Blandy committed
433

434
  block_input ();
435 436 437 438
#ifdef USE_GTK
  success_p = xg_check_special_colors (f, color_name, color);
#endif
  if (!success_p)
439
    success_p = x_parse_color (f, color_name, color) != 0;
440 441
  if (success_p && alloc_p)
    success_p = x_alloc_nearest_color (f, cmap, color);
442
  unblock_input ();
Jim Blandy's avatar
Jim Blandy committed
443

444
  return success_p;
Jim Blandy's avatar
Jim Blandy committed
445 446
}

447 448 449 450

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

452
static int
Dmitry Antipov's avatar
Dmitry Antipov committed
453
x_decode_color (struct frame *f, Lisp_Object color_name, int mono_color)
Jim Blandy's avatar
Jim Blandy committed
454
{
455
  XColor cdef;
Jim Blandy's avatar
Jim Blandy committed
456

457
  CHECK_STRING (color_name);
Jim Blandy's avatar
Jim Blandy committed
458

Paul Eggert's avatar
Paul Eggert committed
459 460 461
#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.  */
462
  if (strcmp (SDATA (color_name), "black") == 0)
463
    return BLACK_PIX_DEFAULT (f);
464
  else if (strcmp (SDATA (color_name), "white") == 0)
465
    return WHITE_PIX_DEFAULT (f);
466
#endif
Jim Blandy's avatar
Jim Blandy committed
467

468
  /* Return MONO_COLOR for monochrome frames.  */
469
  if (FRAME_DISPLAY_INFO (f)->n_planes == 1)
470
    return mono_color;
Jim Blandy's avatar
Jim Blandy committed
471

472
  /* x_defined_color is responsible for coping with failures
473
     by looking for a near-miss.  */
Paul Eggert's avatar
Paul Eggert committed
474
  if (x_defined_color (f, SSDATA (color_name), &cdef, true))
475 476
    return cdef.pixel;

477
  signal_error ("Undefined color", color_name);
Jim Blandy's avatar
Jim Blandy committed
478
}
479 480


Jim Blandy's avatar
Jim Blandy committed
481

Gerd Moellmann's avatar
Gerd Moellmann committed
482 483 484 485 486
/* 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
487
x_set_wait_for_wm (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
Gerd Moellmann's avatar
Gerd Moellmann committed
488 489 490 491
{
  f->output_data.x->wait_for_wm = !NILP (new_value);
}

492 493 494 495 496
static void
x_set_tool_bar_position (struct frame *f,
                         Lisp_Object new_value,
                         Lisp_Object old_value)
{
497
  Lisp_Object choice = list4 (Qleft, Qright, Qtop, Qbottom);
498

499 500
  if (!NILP (Fmemq (new_value, choice)))
    {
501
#ifdef USE_GTK
502 503 504 505 506 507 508 509
      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");
510
#endif
511 512 513
    }
  else
    wrong_choice (choice, new_value);
514 515
}

516 517
#ifdef USE_GTK

518 519
/* 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.  */
520

Paul Eggert's avatar
Paul Eggert committed
521
bool
Dmitry Antipov's avatar
Dmitry Antipov committed
522
xg_set_icon (struct frame *f, Lisp_Object file)
523
{
Paul Eggert's avatar
Paul Eggert committed
524
  bool result = false;
525
  Lisp_Object found;
526

527 528 529 530 531 532
  found = x_find_image_file (file);

  if (! NILP (found))
    {
      GdkPixbuf *pixbuf;
      GError *err = NULL;
533
      char *filename = SSDATA (ENCODE_FILE (found));
534
      block_input ();
535 536 537 538 539 540 541 542 543

      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
544
	  result = true;
545 546 547 548
	}
      else
	g_error_free (err);

549
      unblock_input ();
550 551 552
    }

  return result;
553
}
554

Paul Eggert's avatar
Paul Eggert committed
555
bool
Dmitry Antipov's avatar
Dmitry Antipov committed
556
xg_set_icon_from_xpm_data (struct frame *f, const char **data)
557
{
558
  GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data (data);
559 560

  if (!pixbuf)
Paul Eggert's avatar
Paul Eggert committed
561
    return false;
562

563
  gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), pixbuf);
564
  g_object_unref (pixbuf);
Paul Eggert's avatar
Paul Eggert committed
565
  return true;
566
}
567 568
#endif /* USE_GTK */

Gerd Moellmann's avatar
Gerd Moellmann committed
569

Jim Blandy's avatar
Jim Blandy committed
570
/* Functions called only from `x_set_frame_param'
Jim Blandy's avatar
Jim Blandy committed
571 572
   to set individual parameters.

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

578
static void
579
x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
580
{
581 582
  struct x_output *x = f->output_data.x;
  unsigned long fg, old_fg;
583

584
  fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
585 586
  old_fg = FRAME_FOREGROUND_PIXEL (f);
  FRAME_FOREGROUND_PIXEL (f) = fg;
587

588
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
589
    {
590
      Display *dpy = FRAME_X_DISPLAY (f);
591

592
      block_input ();
593 594
      XSetForeground (dpy, x->normal_gc, fg);
      XSetBackground (dpy, x->reverse_gc, fg);
595

596 597 598 599 600 601
      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);
	}
602

603
      unblock_input ();
604

605
      update_face_from_frame_parameter (f, Qforeground_color, arg);
606

607
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
608
        redraw_frame (f);
Jim Blandy's avatar
Jim Blandy committed
609
    }
610

611
  unload_color (f, old_fg);
Jim Blandy's avatar
Jim Blandy committed
612 613
}

614
static void
615
x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
616
{
617 618
  struct x_output *x = f->output_data.x;
  unsigned long bg;
Jim Blandy's avatar
Jim Blandy committed
619

620
  bg = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
621 622
  unload_color (f, FRAME_BACKGROUND_PIXEL (f));
  FRAME_BACKGROUND_PIXEL (f) = bg;
623

624
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
625
    {
626
      Display *dpy = FRAME_X_DISPLAY (f);
627

628
      block_input ();
629 630 631 632 633
      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
634 635 636 637
#ifdef USE_GTK
      xg_set_background_color (f, bg);
#endif

638 639 640 641 642 643 644 645
#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)
	  {
646
	    Window window = XSCROLL_BAR (bar)->x_window;
647 648 649 650
	    XSetWindowBackground (dpy, window, bg);
	  }
      }
#endif /* USE_TOOLKIT_SCROLL_BARS */
Jim Blandy's avatar
Jim Blandy committed
651

652
      unblock_input ();
653
      update_face_from_frame_parameter (f, Qbackground_color, arg);
654

655
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
656
        redraw_frame (f);
Jim Blandy's avatar
Jim Blandy committed
657 658 659
    }
}

660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
/* 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,
  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[] = {
  { "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 },
};

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

740
static void
741
x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
742
{
743 744
  struct x_output *x = f->output_data.x;
  Display *dpy = FRAME_X_DISPLAY (f);
745
  struct mouse_cursor_data cursor_data = { -1, -1 };
746
  unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
747
  unsigned long mask_color = FRAME_BACKGROUND_PIXEL (f);
748
  int i;
749

750
  /* Don't let pointers be invisible.  */
751
  if (mask_color == pixel)
752 753
    {
      x_free_colors (f, &pixel, 1);
Karoly Lorentey's avatar
Karoly Lorentey committed
754
      pixel = x_copy_color (f, FRAME_FOREGROUND_PIXEL (f));
755
    }
756

757 758
  unload_color (f, x->mouse_pixel);
  x->mouse_pixel = pixel;
Jim Blandy's avatar
Jim Blandy committed
759

760
  for (i = 0; i < mouse_cursor_max; i++)
761
    {
762 763 764 765 766 767 768 769
      Lisp_Object shape_var = *mouse_cursor_types[i].shape_var_ptr;
      if (!NILP (shape_var))
	{
	  CHECK_TYPE_RANGED_INTEGER (unsigned, shape_var);
	  cursor_data.cursor_num[i] = XINT (shape_var);
	}
      else
	cursor_data.cursor_num[i] = mouse_cursor_types[i].default_shape;
770
    }
771

772
  block_input ();
773

774 775
  /* 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
776

777
  for (i = 0; i < mouse_cursor_max; i++)
778
    {
779 780 781 782
      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]);
783 784
    }

785 786 787
  /* Now sync up and process all received errors from cursor
     creation.  */
  if (x_had_errors_p (dpy))
788
    {
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
      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);
810 811
    }

812
  x_uncatch_errors_after_check ();
813

Jim Blandy's avatar
Jim Blandy committed
814
  {
815 816 817 818 819 820 821 822
    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++)
      XRecolorCursor (dpy, cursor_data.cursor[i], &colors[0], &colors[1]);
Jim Blandy's avatar
Jim Blandy committed
823 824
  }

825
  if (FRAME_X_WINDOW (f) != 0)
826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
    {
      f->output_data.x->current_cursor = cursor_data.cursor[mouse_cursor_text];
      XDefineCursor (dpy, FRAME_X_WINDOW (f),
		     f->output_data.x->current_cursor);
    }

#define INSTALL_CURSOR(FIELD, SHORT_INDEX)				\
  eassert (x->FIELD != cursor_data.cursor[mouse_cursor_ ## SHORT_INDEX]); \
  if (x->FIELD != 0)							\
    XFreeCursor (dpy, x->FIELD);					\
  x->FIELD = cursor_data.cursor[mouse_cursor_ ## SHORT_INDEX];

  INSTALL_CURSOR (text_cursor, text);
  INSTALL_CURSOR (nontext_cursor, nontext);
  INSTALL_CURSOR (hourglass_cursor, hourglass);
  INSTALL_CURSOR (modeline_cursor, mode);
  INSTALL_CURSOR (hand_cursor, hand);
  INSTALL_CURSOR (horizontal_drag_cursor, horizontal_drag);
  INSTALL_CURSOR (vertical_drag_cursor, vertical_drag);

#undef INSTALL_CURSOR
847

848
  XFlush (dpy);
849
  unblock_input ();
850 851

  update_face_from_frame_parameter (f, Qmouse_color, arg);
Jim Blandy's avatar
Jim Blandy committed
852 853
}

854
static void
855
x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
856
{
857
  unsigned long fore_pixel, pixel;
Paul Eggert's avatar
Paul Eggert committed
858
  bool fore_pixel_allocated_p = false, pixel_allocated_p = false;
859
  struct x_output *x = f->output_data.x;
Jim Blandy's avatar
Jim Blandy committed
860

861 862 863 864
  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
865
      fore_pixel_allocated_p = true;
866
    }
Jim Blandy's avatar
Jim Blandy committed
867
  else
Karoly Lorentey's avatar
Karoly Lorentey committed
868
    fore_pixel = FRAME_BACKGROUND_PIXEL (f);
869

870
  pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
Paul Eggert's avatar
Paul Eggert committed
871
  pixel_allocated_p = true;
872

873
  /* Make sure that the cursor color differs from the background color.  */
Karoly Lorentey's avatar
Karoly Lorentey committed
874
  if (pixel == FRAME_BACKGROUND_PIXEL (f))
Jim Blandy's avatar
Jim Blandy committed
875
    {
876 877 878
      if (pixel_allocated_p)
	{
	  x_free_colors (f, &pixel, 1);
Paul Eggert's avatar
Paul Eggert committed
879
	  pixel_allocated_p = false;
880
	}
881

882
      pixel = x->mouse_pixel;
883
      if (pixel == fore_pixel)
884 885 886 887
	{
	  if (fore_pixel_allocated_p)
	    {
	      x_free_colors (f, &fore_pixel, 1);
Paul Eggert's avatar
Paul Eggert committed
888
	      fore_pixel_allocated_p = false;
889
	    }
Karoly Lorentey's avatar
Karoly Lorentey committed
890
	  fore_pixel = FRAME_BACKGROUND_PIXEL (f);
891
	}
Jim Blandy's avatar
Jim Blandy committed
892
    }
893

894
  unload_color (f, x->cursor_foreground_pixel);
895 896
  if (!fore_pixel_allocated_p)
    fore_pixel = x_copy_color (f, fore_pixel);
897
  x->cursor_foreground_pixel = fore_pixel;
Jim Blandy's avatar
Jim Blandy committed
898

899
  unload_color (f, x->cursor_pixel);
900 901
  if (!pixel_allocated_p)
    pixel = x_copy_color (f, pixel);
902
  x->cursor_pixel = pixel;
903

904
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
905
    {
906
      block_input ();
907 908
      XSetBackground (FRAME_X_DISPLAY (f), x->cursor_gc, x->cursor_pixel);
      XSetForeground (FRAME_X_DISPLAY (f), x->cursor_gc, fore_pixel);
909
      unblock_input ();
Jim Blandy's avatar
Jim Blandy committed
910

911
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
912
	{
Paul Eggert's avatar
Paul Eggert committed
913 914
	  x_update_cursor (f, false);
	  x_update_cursor (f, true);
Jim Blandy's avatar
Jim Blandy committed
915 916
	}
    }
917 918

  update_face_from_frame_parameter (f, Qcursor_color, arg);
Jim Blandy's avatar
Jim Blandy committed
919
}
920

Jim Blandy's avatar
Jim Blandy committed
921
/* Set the border-color of frame F to pixel value PIX.
Jim Blandy's avatar
Jim Blandy committed
922
   Note that this does not fully take effect if done before
Jim Blandy's avatar
Jim Blandy committed
923
   F has an x-window.  */
Jim Blandy's avatar
Jim Blandy committed
924

925
static void
926
x_set_border_pixel (struct frame *f, int pix)
Jim Blandy's avatar
Jim Blandy committed
927
{
928
  unload_color (f, f->output_data.x->border_pixel);
929
  f->output_data.x->border_pixel = pix;
Jim Blandy's avatar
Jim Blandy committed
930

931
  if (FRAME_X_WINDOW (f) != 0 && f->border_width > 0)
Jim Blandy's avatar
Jim Blandy committed
932
    {
933
      block_input ();