xfns.c 237 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-2017 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>
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
  Window win = (FRAME_PARENT_FRAME (f)
		? FRAME_X_WINDOW (FRAME_PARENT_FRAME (f))
		: f->output_data.x->parent_desc);
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
  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
243 244
  Atom actual_type;
  unsigned long actual_size, bytes_remaining;
245
  int rc, actual_format;
246 247
  Display *dpy = FRAME_X_DISPLAY (f);
  unsigned char *tmp_data = NULL;
248
#endif
249

250 251 252 253 254 255 256 257 258 259
  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;

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

263 264 265 266 267 268 269
  block_input ();

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

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

#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
293 294
      Window *tmp_children;
      unsigned int tmp_nchildren;
295
      int success;
296

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

300
      had_errors = x_had_errors_p (dpy);
301

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

306
      XFree (tmp_children);
307
#endif
308

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

312 313
      win = wm_window;
    }
314

315 316
  if (! had_errors)
    {
317 318 319 320 321 322 323 324
#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
325
      Window child, rootw;
326 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
      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));

358 359
      if ((dpyinfo->root_window == f->output_data.x->parent_desc)
	  && !FRAME_PARENT_FRAME (f))
360 361 362 363 364 365 366
	/* 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
367

368
      /* Get the real coordinates for the WM window upper left corner */
369 370 371 372 373 374 375 376 377 378 379 380 381 382
#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
383
      XGetGeometry (dpy, win,
384 385
		    &rootw, &real_x, &real_y, &ow, &oh, &bw, &ign);
#endif
386 387 388 389 390 391 392 393 394 395

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

         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
413
      XTranslateCoordinates (dpy,
414

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

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

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

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

429
      if (FRAME_X_WINDOW (f) == FRAME_OUTER_WINDOW (f))
430
	{
431 432
          outer_x = win_x;
          outer_y = win_y;
433
	}
434 435
      else
        {
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
#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
451
          XTranslateCoordinates (dpy,
452

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

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

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

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

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

473 474
  if ((dpyinfo->root_window == f->output_data.x->parent_desc)
      && !FRAME_PARENT_FRAME (f))
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
		 XColor *color, bool alloc_p)
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.  */
Paul Eggert's avatar
Paul Eggert committed
701
  if (x_defined_color (f, SSDATA (color_name), &cdef, true))
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 802 803 804 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 864 865 866 867 868 869 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
/**
 * 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 ();
      /* For some reason the third and fourth argument in the following
	 call must be identic: In the corresponding XGetWindowProperty
	 call in getMotifHints, xfwm has the third and seventh arg both
	 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);
      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);
    }
}


970 971
#ifdef USE_GTK

972 973
/* 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.  */
974

Paul Eggert's avatar
Paul Eggert committed
975
bool
Dmitry Antipov's avatar
Dmitry Antipov committed
976
xg_set_icon (struct frame *f, Lisp_Object file)
977
{
Paul Eggert's avatar
Paul Eggert committed
978
  bool result = false;
979
  Lisp_Object found;
980

981 982 983 984 985 986
  found = x_find_image_file (file);

  if (! NILP (found))
    {
      GdkPixbuf *pixbuf;
      GError *err = NULL;
987
      char *filename = SSDATA (ENCODE_FILE (found));
988
      block_input ();
989 990 991 992 993 994 995 996 997

      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
998
	  result = true;
999 1000 1001 1002
	}
      else
	g_error_free (err);

1003
      unblock_input ();
1004 1005 1006
    }

  return result;
1007
}
1008

Paul Eggert's avatar
Paul Eggert committed
1009
bool
Dmitry Antipov's avatar
Dmitry Antipov committed
1010
xg_set_icon_from_xpm_data (struct frame *f, const char **data)
1011
{
1012
  GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data (data);
1013 1014

  if (!pixbuf)
Paul Eggert's avatar
Paul Eggert committed
1015
    return false;
1016

1017
  gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), pixbuf);
1018
  g_object_unref (pixbuf);
Paul Eggert's avatar
Paul Eggert committed
1019
  return true;
1020
}
1021 1022
#endif /* USE_GTK */

Gerd Moellmann's avatar
Gerd Moellmann committed
1023

Jim Blandy's avatar
Jim Blandy committed
1024
/* Functions called only from `x_set_frame_param'
Jim Blandy's avatar
Jim Blandy committed
1025 1026
   to set individual parameters.

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

1032
static void
1033
x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
1034
{
1035 1036
  struct x_output *x = f->output_data.x;
  unsigned long fg, old_fg;
1037

1038
  fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
1039 1040
  old_fg = FRAME_FOREGROUND_PIXEL (f);
  FRAME_FOREGROUND_PIXEL (f) = fg;
1041

1042
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
1043
    {
1044
      Display *dpy = FRAME_X_DISPLAY (f);
1045

1046
      block_input ();
1047 1048
      XSetForeground (dpy, x->normal_gc, fg);
      XSetBackground (dpy, x->reverse_gc, fg);
1049

1050 1051 1052 1053 1054 1055
      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);
	}
1056

1057
      unblock_input ();
1058

1059
      update_face_from_frame_parameter (f, Qforeground_color, arg);
1060

1061
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
1062
        redraw_frame (f);
Jim Blandy's avatar
Jim Blandy committed
1063
    }
1064

1065
  unload_color (f, old_fg);
Jim Blandy's avatar
Jim Blandy committed
1066 1067
}

1068
static void
1069
x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
Jim Blandy's avatar
Jim Blandy committed
1070
{
1071 1072
  struct x_output *x = f->output_data.x;
  unsigned long bg;
Jim Blandy's avatar
Jim Blandy committed
1073

1074
  bg = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
Karoly Lorentey's avatar
Karoly Lorentey committed
1075 1076
  unload_color (f, FRAME_BACKGROUND_PIXEL (f));
  FRAME_BACKGROUND_PIXEL (f) = bg;
1077

1078
  if (FRAME_X_WINDOW (f) != 0)
Jim Blandy's avatar
Jim Blandy committed
1079
    {
1080
      Display *dpy = FRAME_X_DISPLAY (f);
1081

1082
      block_input ();
1083 1084 1085 1086 1087
      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
1088 1089 1090 1091
#ifdef USE_GTK
      xg_set_background_color (f, bg);
#endif

1092 1093 1094 1095 1096 1097 1098 1099
#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)
	  {
1100
	    Window window = XSCROLL_BAR (bar)->x_window;
1101 1102 1103 1104
	    XSetWindowBackground (dpy, window, bg);
	  }
      }
#endif /* USE_TOOLKIT_SCROLL_BARS */
Jim Blandy's avatar
Jim Blandy committed
1105

1106
      unblock_input ();
1107
      update_face_from_frame_parameter (f, Qbackground_color, arg);
1108

1109
      if (FRAME_VISIBLE_P (f))
Jim Blandy's avatar
Jim Blandy committed
1110
        redraw_frame (f);
Jim Blandy's avatar
Jim Blandy committed
1111 1112 1113
    }
}

1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149